mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
CW-527-Add-Polygon-MATIC-Wallet (#1179)
* chore: Initial setup for polygon package * feat: Add polygon node urls * feat: Add Polygon(MATIC) wallet WIP * feat: Add Polygon(MATIC) wallet WIP * feat: Add Polygon MATIC wallet [skip ci] * fix: Issue with create/restore wallet for polygon * feat: Add erc20 tokens for polygon * feat: Adding Polygon MATIC Wallet * fix: Add build command for polygon to workflow file to fix failing action * fix: Switch evm to not display additional balance * chore: Sync with remote * fix: Revert change to inject app script * feat: Add polygon erc20 tokens * feat: Increase migration version * fix: Restore from QR address validator fix * fix: Adjust wallet connect connection flow to adapt to wallet type * fix: Make wallet fetch nfts based on the current wallet type * fix: Make wallet fetch nfts based on the current wallet type * fix: Try fetching transactions with moralis * fix: Requested review changes * fix: Error creating new wallet * fix: Revert script * fix: Exclude spam NFTs from nft listing API response * Update default_erc20_tokens.dart * replace matic with matic poly * Add polygon wallet scheme to app links * style: reformat default_settings_migration.dart * minor enhancement * fix using different wallet function for setting the transaction priorities * fix: Add chain to calls * Add USDC.e to initial coins * Add other default polygon node * Use Polygon scan some UI fixes * Add polygon scan api key to secrets generation code --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
parent
3b7f9a297c
commit
b3d579c24a
116 changed files with 2351 additions and 206 deletions
2
.github/workflows/pr_test_build.yml
vendored
2
.github/workflows/pr_test_build.yml
vendored
|
@ -97,6 +97,7 @@ jobs:
|
||||||
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
|
cd cw_polygon && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
flutter packages pub run build_runner build --delete-conflicting-outputs
|
flutter packages pub run build_runner build --delete-conflicting-outputs
|
||||||
|
|
||||||
- name: Add secrets
|
- name: Add secrets
|
||||||
|
@ -131,6 +132,7 @@ jobs:
|
||||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
|
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
|
||||||
|
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
|
||||||
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
|
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -126,6 +126,7 @@ lib/haven/haven.dart
|
||||||
lib/ethereum/ethereum.dart
|
lib/ethereum/ethereum.dart
|
||||||
lib/bitcoin_cash/bitcoin_cash.dart
|
lib/bitcoin_cash/bitcoin_cash.dart
|
||||||
lib/nano/nano.dart
|
lib/nano/nano.dart
|
||||||
|
lib/polygon/polygon.dart
|
||||||
|
|
||||||
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
|
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
|
||||||
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png
|
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png
|
||||||
|
|
|
@ -62,6 +62,9 @@
|
||||||
<data android:scheme="bitcoincash" />
|
<data android:scheme="bitcoincash" />
|
||||||
<data android:scheme="bitcoincash-wallet" />
|
<data android:scheme="bitcoincash-wallet" />
|
||||||
<data android:scheme="bitcoincash_wallet" />
|
<data android:scheme="bitcoincash_wallet" />
|
||||||
|
<data android:scheme="polygon" />
|
||||||
|
<data android:scheme="polygon-wallet" />
|
||||||
|
<data android:scheme="polygon_wallet" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<meta-data
|
<meta-data
|
||||||
|
|
6
assets/polygon_node_list.yml
Normal file
6
assets/polygon_node_list.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
-
|
||||||
|
uri: polygon-bor.publicnode.com
|
||||||
|
-
|
||||||
|
uri: polygon-rpc.com
|
||||||
|
-
|
||||||
|
uri: polygon.llamarpc.com
|
|
@ -19,6 +19,8 @@ CryptoCurrency currencyForWalletType(WalletType type) {
|
||||||
return CryptoCurrency.nano;
|
return CryptoCurrency.nano;
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return CryptoCurrency.banano;
|
return CryptoCurrency.banano;
|
||||||
|
case WalletType.polygon:
|
||||||
|
return CryptoCurrency.maticpoly;
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
|
throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
||||||
|
|
||||||
static const typeId = ERC20_TOKEN_TYPE_ID;
|
static const typeId = ERC20_TOKEN_TYPE_ID;
|
||||||
static const boxName = 'Erc20Tokens';
|
static const boxName = 'Erc20Tokens';
|
||||||
|
static const polygonBoxName = ' PolygonErc20Tokens';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(other) => (other is Erc20Token && other.contractAddress == contractAddress) ||
|
bool operator ==(other) => (other is Erc20Token && other.contractAddress == contractAddress) ||
|
||||||
|
|
|
@ -88,6 +88,8 @@ class Node extends HiveObject with Keyable {
|
||||||
} else {
|
} else {
|
||||||
return Uri.http(uriRaw, '');
|
return Uri.http(uriRaw, '');
|
||||||
}
|
}
|
||||||
|
case WalletType.polygon:
|
||||||
|
return Uri.https(uriRaw, '');
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected type ${type.toString()} for Node uri');
|
throw Exception('Unexpected type ${type.toString()} for Node uri');
|
||||||
}
|
}
|
||||||
|
@ -146,6 +148,8 @@ class Node extends HiveObject with Keyable {
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return requestNanoNode();
|
return requestNanoNode();
|
||||||
|
case WalletType.polygon:
|
||||||
|
return requestElectrumServer();
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ const walletTypes = [
|
||||||
WalletType.bitcoinCash,
|
WalletType.bitcoinCash,
|
||||||
WalletType.nano,
|
WalletType.nano,
|
||||||
WalletType.banano,
|
WalletType.banano,
|
||||||
|
WalletType.polygon,
|
||||||
];
|
];
|
||||||
|
|
||||||
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
||||||
|
@ -44,6 +45,8 @@ enum WalletType {
|
||||||
@HiveField(8)
|
@HiveField(8)
|
||||||
bitcoinCash,
|
bitcoinCash,
|
||||||
|
|
||||||
|
@HiveField(9)
|
||||||
|
polygon
|
||||||
}
|
}
|
||||||
|
|
||||||
int serializeToInt(WalletType type) {
|
int serializeToInt(WalletType type) {
|
||||||
|
@ -64,6 +67,8 @@ int serializeToInt(WalletType type) {
|
||||||
return 6;
|
return 6;
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
return 7;
|
return 7;
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 8;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -87,6 +92,8 @@ WalletType deserializeFromInt(int raw) {
|
||||||
return WalletType.banano;
|
return WalletType.banano;
|
||||||
case 7:
|
case 7:
|
||||||
return WalletType.bitcoinCash;
|
return WalletType.bitcoinCash;
|
||||||
|
case 8:
|
||||||
|
return WalletType.polygon;
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
|
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
|
||||||
}
|
}
|
||||||
|
@ -110,6 +117,8 @@ String walletTypeToString(WalletType type) {
|
||||||
return 'Nano';
|
return 'Nano';
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return 'Banano';
|
return 'Banano';
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 'Polygon';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -133,6 +142,8 @@ String walletTypeToDisplayName(WalletType type) {
|
||||||
return 'Nano (XNO)';
|
return 'Nano (XNO)';
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return 'Banano (BAN)';
|
return 'Banano (BAN)';
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 'Polygon (MATIC)';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -156,7 +167,10 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
|
||||||
return CryptoCurrency.nano;
|
return CryptoCurrency.nano;
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return CryptoCurrency.banano;
|
return CryptoCurrency.banano;
|
||||||
|
case WalletType.polygon:
|
||||||
|
return CryptoCurrency.maticpoly;
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
|
throw Exception(
|
||||||
|
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ import 'package:cw_ethereum/ethereum_transaction_priority.dart';
|
||||||
import 'package:cw_ethereum/.secrets.g.dart' as secrets;
|
import 'package:cw_ethereum/.secrets.g.dart' as secrets;
|
||||||
|
|
||||||
class EthereumClient {
|
class EthereumClient {
|
||||||
final _httpClient = Client();
|
final httpClient = Client();
|
||||||
Web3Client? _client;
|
Web3Client? _client;
|
||||||
|
|
||||||
bool connect(Node node) {
|
bool connect(Node node) {
|
||||||
try {
|
try {
|
||||||
_client = Web3Client(node.uri.toString(), _httpClient);
|
_client = Web3Client(node.uri.toString(), httpClient);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -74,9 +74,11 @@ class EthereumClient {
|
||||||
required int exponent,
|
required int exponent,
|
||||||
String? contractAddress,
|
String? contractAddress,
|
||||||
}) async {
|
}) async {
|
||||||
assert(currency == CryptoCurrency.eth || contractAddress != null);
|
assert(currency == CryptoCurrency.eth ||
|
||||||
|
currency == CryptoCurrency.maticpoly ||
|
||||||
|
contractAddress != null);
|
||||||
|
|
||||||
bool _isEthereum = currency == CryptoCurrency.eth;
|
bool _isEVMCompatibleChain = currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
|
||||||
|
|
||||||
final price = _client!.getGasPrice();
|
final price = _client!.getGasPrice();
|
||||||
|
|
||||||
|
@ -84,19 +86,23 @@ class EthereumClient {
|
||||||
from: privateKey.address,
|
from: privateKey.address,
|
||||||
to: EthereumAddress.fromHex(toAddress),
|
to: EthereumAddress.fromHex(toAddress),
|
||||||
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
|
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
|
||||||
value: _isEthereum ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
|
value: _isEVMCompatibleChain ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
|
||||||
);
|
);
|
||||||
|
|
||||||
final signedTransaction = await _client!.signTransaction(privateKey, transaction);
|
final chainId = _getChainIdForCurrency(currency);
|
||||||
|
|
||||||
|
final signedTransaction =
|
||||||
|
await _client!.signTransaction(privateKey, transaction, chainId: chainId);
|
||||||
|
|
||||||
final Function _sendTransaction;
|
final Function _sendTransaction;
|
||||||
|
|
||||||
if (_isEthereum) {
|
if (_isEVMCompatibleChain) {
|
||||||
_sendTransaction = () async => await sendTransaction(signedTransaction);
|
_sendTransaction = () async => await sendTransaction(signedTransaction);
|
||||||
} else {
|
} else {
|
||||||
final erc20 = ERC20(
|
final erc20 = ERC20(
|
||||||
client: _client!,
|
client: _client!,
|
||||||
address: EthereumAddress.fromHex(contractAddress!),
|
address: EthereumAddress.fromHex(contractAddress!),
|
||||||
|
chainId: chainId,
|
||||||
);
|
);
|
||||||
|
|
||||||
_sendTransaction = () async {
|
_sendTransaction = () async {
|
||||||
|
@ -118,6 +124,16 @@ class EthereumClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _getChainIdForCurrency(CryptoCurrency currency) {
|
||||||
|
switch (currency) {
|
||||||
|
case CryptoCurrency.maticpoly:
|
||||||
|
return 137;
|
||||||
|
case CryptoCurrency.eth:
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> sendTransaction(Uint8List signedTransaction) async =>
|
Future<String> sendTransaction(Uint8List signedTransaction) async =>
|
||||||
await _client!.sendRawTransaction(prependTransactionType(0x02, signedTransaction));
|
await _client!.sendRawTransaction(prependTransactionType(0x02, signedTransaction));
|
||||||
|
|
||||||
|
@ -198,7 +214,7 @@ I/flutter ( 4474): Gas Used: 53000
|
||||||
Future<List<EthereumTransactionModel>> fetchTransactions(String address,
|
Future<List<EthereumTransactionModel>> fetchTransactions(String address,
|
||||||
{String? contractAddress}) async {
|
{String? contractAddress}) async {
|
||||||
try {
|
try {
|
||||||
final response = await _httpClient.get(Uri.https("api.etherscan.io", "/api", {
|
final response = await httpClient.get(Uri.https("api.etherscan.io", "/api", {
|
||||||
"module": "account",
|
"module": "account",
|
||||||
"action": contractAddress != null ? "tokentx" : "txlist",
|
"action": contractAddress != null ? "tokentx" : "txlist",
|
||||||
if (contractAddress != null) "contractaddress": contractAddress,
|
if (contractAddress != null) "contractaddress": contractAddress,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:cw_core/format_amount.dart';
|
import 'package:cw_core/format_amount.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
@ -34,8 +36,10 @@ class EthereumTransactionInfo extends TransactionInfo {
|
||||||
final String? to;
|
final String? to;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String amountFormatted() =>
|
String amountFormatted() {
|
||||||
'${formatAmount((ethAmount / BigInt.from(10).pow(exponent)).toString())} $tokenSymbol';
|
final amount = formatAmount((ethAmount / BigInt.from(10).pow(exponent)).toString());
|
||||||
|
return '${amount.substring(0, min(10, amount.length))} $tokenSymbol';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String fiatAmount() => _fiatAmount ?? '';
|
String fiatAmount() => _fiatAmount ?? '';
|
||||||
|
@ -44,7 +48,10 @@ class EthereumTransactionInfo extends TransactionInfo {
|
||||||
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
|
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String feeFormatted() => '${(ethFee / BigInt.from(10).pow(18)).toString()} ETH';
|
String feeFormatted() {
|
||||||
|
final amount = (ethFee / BigInt.from(10).pow(18)).toString();
|
||||||
|
return '${amount.substring(0, min(10, amount.length))} ETH';
|
||||||
|
}
|
||||||
|
|
||||||
factory EthereumTransactionInfo.fromJson(Map<String, dynamic> data) {
|
factory EthereumTransactionInfo.fromJson(Map<String, dynamic> data) {
|
||||||
return EthereumTransactionInfo(
|
return EthereumTransactionInfo(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//! Model used for in parsing transactions fetched using etherscan
|
||||||
class EthereumTransactionModel {
|
class EthereumTransactionModel {
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
final String hash;
|
final String hash;
|
||||||
|
|
|
@ -21,8 +21,8 @@ class PendingEthereumTransaction with PendingTransaction {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get amountFormatted {
|
String get amountFormatted {
|
||||||
final _amount = BigInt.parse(amount) / BigInt.from(pow(10, exponent));
|
final _amount = (BigInt.parse(amount) / BigInt.from(pow(10, exponent))).toString();
|
||||||
return _amount.toStringAsFixed(min(15, _amount.toString().length));
|
return _amount.substring(0, min(10, _amount.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -30,8 +30,8 @@ class PendingEthereumTransaction with PendingTransaction {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get feeFormatted {
|
String get feeFormatted {
|
||||||
final _fee = fee / BigInt.from(pow(10, 18));
|
final _fee = (fee / BigInt.from(pow(10, 18))).toString();
|
||||||
return _fee.toStringAsFixed(min(15, _fee.toString().length));
|
return _fee.substring(0, min(10, _fee.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
30
cw_polygon/.gitignore
vendored
Normal file
30
cw_polygon/.gitignore
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||||
|
/pubspec.lock
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.packages
|
||||||
|
build/
|
10
cw_polygon/.metadata
Normal file
10
cw_polygon/.metadata
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
|
||||||
|
channel: stable
|
||||||
|
|
||||||
|
project_type: package
|
3
cw_polygon/CHANGELOG.md
Normal file
3
cw_polygon/CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## 0.0.1
|
||||||
|
|
||||||
|
* TODO: Describe initial release.
|
1
cw_polygon/LICENSE
Normal file
1
cw_polygon/LICENSE
Normal file
|
@ -0,0 +1 @@
|
||||||
|
TODO: Add your license here.
|
39
cw_polygon/README.md
Normal file
39
cw_polygon/README.md
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<!--
|
||||||
|
This README describes the package. If you publish this package to pub.dev,
|
||||||
|
this README's contents appear on the landing page for your package.
|
||||||
|
|
||||||
|
For information about how to write a good package README, see the guide for
|
||||||
|
[writing package pages](https://dart.dev/guides/libraries/writing-package-pages).
|
||||||
|
|
||||||
|
For general information about developing packages, see the Dart guide for
|
||||||
|
[creating packages](https://dart.dev/guides/libraries/create-library-packages)
|
||||||
|
and the Flutter guide for
|
||||||
|
[developing packages and plugins](https://flutter.dev/developing-packages).
|
||||||
|
-->
|
||||||
|
|
||||||
|
TODO: Put a short description of the package here that helps potential users
|
||||||
|
know whether this package might be useful for them.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
TODO: List what your package can do. Maybe include images, gifs, or videos.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
TODO: List prerequisites and provide or point to information on how to
|
||||||
|
start using the package.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
TODO: Include short and useful examples for package users. Add longer examples
|
||||||
|
to `/example` folder.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
const like = 'sample';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Additional information
|
||||||
|
|
||||||
|
TODO: Tell users more about the package: where to find more information, how to
|
||||||
|
contribute to the package, how to file issues, what response they can expect
|
||||||
|
from the package authors, and more.
|
4
cw_polygon/analysis_options.yaml
Normal file
4
cw_polygon/analysis_options.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
7
cw_polygon/lib/cw_polygon.dart
Normal file
7
cw_polygon/lib/cw_polygon.dart
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
library cw_polygon;
|
||||||
|
|
||||||
|
/// A Calculator.
|
||||||
|
class Calculator {
|
||||||
|
/// Returns [value] plus 1.
|
||||||
|
int addOne(int value) => value + 1;
|
||||||
|
}
|
86
cw_polygon/lib/default_erc20_tokens.dart
Normal file
86
cw_polygon/lib/default_erc20_tokens.dart
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/erc20_token.dart';
|
||||||
|
|
||||||
|
class DefaultPolygonErc20Tokens {
|
||||||
|
final List<Erc20Token> _defaultTokens = [
|
||||||
|
Erc20Token(
|
||||||
|
name: "Wrapped Ether",
|
||||||
|
symbol: "WETH",
|
||||||
|
contractAddress: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
|
||||||
|
decimal: 18,
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "Tether USD (PoS)",
|
||||||
|
symbol: "USDT",
|
||||||
|
contractAddress: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
|
||||||
|
decimal: 6,
|
||||||
|
enabled: true,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "USD Coin",
|
||||||
|
symbol: "USDC",
|
||||||
|
contractAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
||||||
|
decimal: 6,
|
||||||
|
enabled: true,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "USD Coin (POS)",
|
||||||
|
symbol: "USDC.e",
|
||||||
|
contractAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
|
||||||
|
decimal: 6,
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "Avalanche Token",
|
||||||
|
symbol: "AVAX",
|
||||||
|
contractAddress: "0x2C89bbc92BD86F8075d1DEcc58C7F4E0107f286b",
|
||||||
|
decimal: 18,
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "Wrapped BTC (PoS)",
|
||||||
|
symbol: "WBTC",
|
||||||
|
contractAddress: "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6",
|
||||||
|
decimal: 8,
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "Dai (PoS)",
|
||||||
|
symbol: "DAI",
|
||||||
|
contractAddress: "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
|
||||||
|
decimal: 18,
|
||||||
|
enabled: true,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "SHIBA INU (PoS)",
|
||||||
|
symbol: "SHIB",
|
||||||
|
contractAddress: "0x6f8a06447Ff6FcF75d803135a7de15CE88C1d4ec",
|
||||||
|
decimal: 18,
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
Erc20Token(
|
||||||
|
name: "Uniswap (PoS)",
|
||||||
|
symbol: "UNI",
|
||||||
|
contractAddress: "0xb33EaAd8d922B1083446DC23f610c2567fB5180f",
|
||||||
|
decimal: 18,
|
||||||
|
enabled: false,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
List<Erc20Token> get initialPolygonErc20Tokens => _defaultTokens.map((token) {
|
||||||
|
String? iconPath;
|
||||||
|
try {
|
||||||
|
iconPath = CryptoCurrency.all
|
||||||
|
.firstWhere((element) =>
|
||||||
|
element.title.toUpperCase() == token.symbol.toUpperCase())
|
||||||
|
.iconPath;
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
if (iconPath != null) {
|
||||||
|
return Erc20Token.copyWith(token, iconPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}).toList();
|
||||||
|
}
|
19
cw_polygon/lib/pending_polygon_transaction.dart
Normal file
19
cw_polygon/lib/pending_polygon_transaction.dart
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:cw_ethereum/pending_ethereum_transaction.dart';
|
||||||
|
|
||||||
|
class PendingPolygonTransaction extends PendingEthereumTransaction {
|
||||||
|
PendingPolygonTransaction({
|
||||||
|
required Function sendTransaction,
|
||||||
|
required Uint8List signedTransaction,
|
||||||
|
required BigInt fee,
|
||||||
|
required String amount,
|
||||||
|
required int exponent,
|
||||||
|
}) : super(
|
||||||
|
amount: amount,
|
||||||
|
sendTransaction: sendTransaction,
|
||||||
|
signedTransaction: signedTransaction,
|
||||||
|
fee: fee,
|
||||||
|
exponent: exponent,
|
||||||
|
);
|
||||||
|
}
|
34
cw_polygon/lib/polygon_client.dart
Normal file
34
cw_polygon/lib/polygon_client.dart
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:cw_ethereum/ethereum_client.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_model.dart';
|
||||||
|
import 'package:cw_ethereum/.secrets.g.dart' as secrets;
|
||||||
|
|
||||||
|
class PolygonClient extends EthereumClient {
|
||||||
|
@override
|
||||||
|
Future<List<PolygonTransactionModel>> fetchTransactions(String address,
|
||||||
|
{String? contractAddress}) async {
|
||||||
|
try {
|
||||||
|
final response = await httpClient.get(Uri.https("api.polygonscan.com", "/api", {
|
||||||
|
"module": "account",
|
||||||
|
"action": contractAddress != null ? "tokentx" : "txlist",
|
||||||
|
if (contractAddress != null) "contractaddress": contractAddress,
|
||||||
|
"address": address,
|
||||||
|
"apikey": secrets.polygonScanApiKey,
|
||||||
|
}));
|
||||||
|
|
||||||
|
final jsonResponse = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300 && jsonResponse['status'] != 0) {
|
||||||
|
return (jsonResponse['result'] as List)
|
||||||
|
.map((e) => PolygonTransactionModel.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
cw_polygon/lib/polygon_exceptions.dart
Normal file
6
cw_polygon/lib/polygon_exceptions.dart
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_ethereum/ethereum_exceptions.dart';
|
||||||
|
|
||||||
|
class PolygonTransactionCreationException extends EthereumTransactionCreationException {
|
||||||
|
PolygonTransactionCreationException(CryptoCurrency currency) : super(currency);
|
||||||
|
}
|
25
cw_polygon/lib/polygon_formatter.dart
Normal file
25
cw_polygon/lib/polygon_formatter.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
const polygonAmountLength = 12;
|
||||||
|
const polygonAmountDivider = 1000000000000;
|
||||||
|
final polygonAmountFormat = NumberFormat()
|
||||||
|
..maximumFractionDigits = polygonAmountLength
|
||||||
|
..minimumFractionDigits = 1;
|
||||||
|
|
||||||
|
class PolygonFormatter {
|
||||||
|
static int parsePolygonAmount(String amount) {
|
||||||
|
try {
|
||||||
|
return (double.parse(amount) * polygonAmountDivider).round();
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static double parsePolygonAmountToDouble(int amount) {
|
||||||
|
try {
|
||||||
|
return amount / polygonAmountDivider;
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
cw_polygon/lib/polygon_mnemonics_exception.dart
Normal file
5
cw_polygon/lib/polygon_mnemonics_exception.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class PolygonMnemonicIsIncorrectException implements Exception {
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'Polygon mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.';
|
||||||
|
}
|
18
cw_polygon/lib/polygon_transaction_credentials.dart
Normal file
18
cw_polygon/lib/polygon_transaction_credentials.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/output_info.dart';
|
||||||
|
import 'package:cw_ethereum/ethereum_transaction_credentials.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_priority.dart';
|
||||||
|
|
||||||
|
class PolygonTransactionCredentials extends EthereumTransactionCredentials {
|
||||||
|
PolygonTransactionCredentials(
|
||||||
|
List<OutputInfo> outputs, {
|
||||||
|
required PolygonTransactionPriority? priority,
|
||||||
|
required CryptoCurrency currency,
|
||||||
|
final int? feeRate,
|
||||||
|
}) : super(
|
||||||
|
outputs,
|
||||||
|
currency: currency,
|
||||||
|
priority: priority,
|
||||||
|
feeRate: feeRate,
|
||||||
|
);
|
||||||
|
}
|
77
cw_polygon/lib/polygon_transaction_history.dart
Normal file
77
cw_polygon/lib/polygon_transaction_history.dart
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:core';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_ethereum/file.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_info.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_core/transaction_history.dart';
|
||||||
|
|
||||||
|
part 'polygon_transaction_history.g.dart';
|
||||||
|
|
||||||
|
const transactionsHistoryFileName = 'polygon_transactions.json';
|
||||||
|
|
||||||
|
class PolygonTransactionHistory = PolygonTransactionHistoryBase with _$PolygonTransactionHistory;
|
||||||
|
|
||||||
|
abstract class PolygonTransactionHistoryBase extends TransactionHistoryBase<PolygonTransactionInfo>
|
||||||
|
with Store {
|
||||||
|
PolygonTransactionHistoryBase({required this.walletInfo, required String password})
|
||||||
|
: _password = password {
|
||||||
|
transactions = ObservableMap<String, PolygonTransactionInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
final WalletInfo walletInfo;
|
||||||
|
String _password;
|
||||||
|
|
||||||
|
Future<void> init() async => await _load();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> save() async {
|
||||||
|
try {
|
||||||
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
|
final data = json.encode({'transactions': transactions});
|
||||||
|
await writeData(path: path, password: _password, data: data);
|
||||||
|
} catch (e, s) {
|
||||||
|
print('Error while saving polygon transaction history: ${e.toString()}');
|
||||||
|
print(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addOne(PolygonTransactionInfo transaction) => transactions[transaction.id] = transaction;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addMany(Map<String, PolygonTransactionInfo> transactions) =>
|
||||||
|
this.transactions.addAll(transactions);
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _read() async {
|
||||||
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
|
final content = await read(path: path, password: _password);
|
||||||
|
if (content.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return json.decode(content) as Map<String, dynamic>;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _load() async {
|
||||||
|
try {
|
||||||
|
final content = await _read();
|
||||||
|
final txs = content['transactions'] as Map<String, dynamic>? ?? {};
|
||||||
|
|
||||||
|
txs.entries.forEach((entry) {
|
||||||
|
final val = entry.value;
|
||||||
|
|
||||||
|
if (val is Map<String, dynamic>) {
|
||||||
|
final tx = PolygonTransactionInfo.fromJson(val);
|
||||||
|
_update(tx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _update(PolygonTransactionInfo transaction) => transactions[transaction.id] = transaction;
|
||||||
|
}
|
49
cw_polygon/lib/polygon_transaction_info.dart
Normal file
49
cw_polygon/lib/polygon_transaction_info.dart
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
|
import 'package:cw_ethereum/ethereum_transaction_info.dart';
|
||||||
|
|
||||||
|
class PolygonTransactionInfo extends EthereumTransactionInfo {
|
||||||
|
PolygonTransactionInfo({
|
||||||
|
required String id,
|
||||||
|
required int height,
|
||||||
|
required BigInt ethAmount,
|
||||||
|
int exponent = 18,
|
||||||
|
required TransactionDirection direction,
|
||||||
|
required DateTime date,
|
||||||
|
required bool isPending,
|
||||||
|
required BigInt ethFee,
|
||||||
|
required int confirmations,
|
||||||
|
String tokenSymbol = "MATIC",
|
||||||
|
required String? to,
|
||||||
|
}) : super(
|
||||||
|
confirmations: confirmations,
|
||||||
|
id: id,
|
||||||
|
height: height,
|
||||||
|
ethAmount: ethAmount,
|
||||||
|
exponent: exponent,
|
||||||
|
direction: direction,
|
||||||
|
date: date,
|
||||||
|
isPending: isPending,
|
||||||
|
ethFee: ethFee,
|
||||||
|
to: to,
|
||||||
|
tokenSymbol: tokenSymbol,
|
||||||
|
);
|
||||||
|
|
||||||
|
factory PolygonTransactionInfo.fromJson(Map<String, dynamic> data) {
|
||||||
|
return PolygonTransactionInfo(
|
||||||
|
id: data['id'] as String,
|
||||||
|
height: data['height'] as int,
|
||||||
|
ethAmount: BigInt.parse(data['amount']),
|
||||||
|
exponent: data['exponent'] as int,
|
||||||
|
ethFee: BigInt.parse(data['fee']),
|
||||||
|
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
||||||
|
isPending: data['isPending'] as bool,
|
||||||
|
confirmations: data['confirmations'] as int,
|
||||||
|
tokenSymbol: data['tokenSymbol'] as String,
|
||||||
|
to: data['to'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String feeFormatted() => '${(ethFee / BigInt.from(10).pow(18)).toString()} MATIC';
|
||||||
|
}
|
49
cw_polygon/lib/polygon_transaction_model.dart
Normal file
49
cw_polygon/lib/polygon_transaction_model.dart
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import 'package:cw_ethereum/ethereum_transaction_model.dart';
|
||||||
|
|
||||||
|
class PolygonTransactionModel extends EthereumTransactionModel {
|
||||||
|
PolygonTransactionModel({
|
||||||
|
required DateTime date,
|
||||||
|
required String hash,
|
||||||
|
required String from,
|
||||||
|
required String to,
|
||||||
|
required BigInt amount,
|
||||||
|
required int gasUsed,
|
||||||
|
required BigInt gasPrice,
|
||||||
|
required String contractAddress,
|
||||||
|
required int confirmations,
|
||||||
|
required int blockNumber,
|
||||||
|
required String? tokenSymbol,
|
||||||
|
required int? tokenDecimal,
|
||||||
|
required bool isError,
|
||||||
|
}) : super(
|
||||||
|
amount: amount,
|
||||||
|
date: date,
|
||||||
|
hash: hash,
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
gasPrice: gasPrice,
|
||||||
|
gasUsed: gasUsed,
|
||||||
|
confirmations: confirmations,
|
||||||
|
contractAddress: contractAddress,
|
||||||
|
blockNumber: blockNumber,
|
||||||
|
tokenDecimal: tokenDecimal,
|
||||||
|
tokenSymbol: tokenSymbol,
|
||||||
|
isError: isError,
|
||||||
|
);
|
||||||
|
|
||||||
|
factory PolygonTransactionModel.fromJson(Map<String, dynamic> json) => PolygonTransactionModel(
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch(int.parse(json["timeStamp"]) * 1000),
|
||||||
|
hash: json["hash"],
|
||||||
|
from: json["from"],
|
||||||
|
to: json["to"],
|
||||||
|
amount: BigInt.parse(json["value"]),
|
||||||
|
gasUsed: int.parse(json["gasUsed"]),
|
||||||
|
gasPrice: BigInt.parse(json["gasPrice"]),
|
||||||
|
contractAddress: json["contractAddress"],
|
||||||
|
confirmations: int.parse(json["confirmations"]),
|
||||||
|
blockNumber: int.parse(json["blockNumber"]),
|
||||||
|
tokenSymbol: json["tokenSymbol"] ?? "MATIC",
|
||||||
|
tokenDecimal: int.tryParse(json["tokenDecimal"] ?? ""),
|
||||||
|
isError: json["isError"] == "1",
|
||||||
|
);
|
||||||
|
}
|
51
cw_polygon/lib/polygon_transaction_priority.dart
Normal file
51
cw_polygon/lib/polygon_transaction_priority.dart
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import 'package:cw_ethereum/ethereum_transaction_priority.dart';
|
||||||
|
|
||||||
|
class PolygonTransactionPriority extends EthereumTransactionPriority {
|
||||||
|
const PolygonTransactionPriority({required String title, required int raw, required int tip})
|
||||||
|
: super(title: title, raw: raw, tip: tip);
|
||||||
|
|
||||||
|
static const List<PolygonTransactionPriority> all = [fast, medium, slow];
|
||||||
|
static const PolygonTransactionPriority slow =
|
||||||
|
PolygonTransactionPriority(title: 'slow', raw: 0, tip: 1);
|
||||||
|
static const PolygonTransactionPriority medium =
|
||||||
|
PolygonTransactionPriority(title: 'Medium', raw: 1, tip: 2);
|
||||||
|
static const PolygonTransactionPriority fast =
|
||||||
|
PolygonTransactionPriority(title: 'Fast', raw: 2, tip: 4);
|
||||||
|
|
||||||
|
static PolygonTransactionPriority deserialize({required int raw}) {
|
||||||
|
switch (raw) {
|
||||||
|
case 0:
|
||||||
|
return slow;
|
||||||
|
case 1:
|
||||||
|
return medium;
|
||||||
|
case 2:
|
||||||
|
return fast;
|
||||||
|
default:
|
||||||
|
throw Exception('Unexpected token: $raw for PolygonTransactionPriority deserialize');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get units => 'gas';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
var label = '';
|
||||||
|
|
||||||
|
switch (this) {
|
||||||
|
case PolygonTransactionPriority.slow:
|
||||||
|
label = 'Slow';
|
||||||
|
break;
|
||||||
|
case PolygonTransactionPriority.medium:
|
||||||
|
label = 'Medium';
|
||||||
|
break;
|
||||||
|
case PolygonTransactionPriority.fast:
|
||||||
|
label = 'Fast';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
540
cw_polygon/lib/polygon_wallet.dart
Normal file
540
cw_polygon/lib/polygon_wallet.dart
Normal file
|
@ -0,0 +1,540 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/cake_hive.dart';
|
||||||
|
import 'package:cw_core/node.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
import 'package:cw_core/sync_status.dart';
|
||||||
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_ethereum/erc20_balance.dart';
|
||||||
|
import 'package:cw_ethereum/ethereum_formatter.dart';
|
||||||
|
import 'package:cw_ethereum/ethereum_transaction_model.dart';
|
||||||
|
import 'package:cw_ethereum/file.dart';
|
||||||
|
import 'package:cw_core/erc20_token.dart';
|
||||||
|
import 'package:cw_polygon/default_erc20_tokens.dart';
|
||||||
|
import 'package:cw_polygon/polygon_client.dart';
|
||||||
|
import 'package:cw_polygon/polygon_exceptions.dart';
|
||||||
|
import 'package:cw_polygon/polygon_formatter.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_credentials.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_history.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_info.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_model.dart';
|
||||||
|
import 'package:cw_polygon/polygon_transaction_priority.dart';
|
||||||
|
import 'package:cw_polygon/polygon_wallet_addresses.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:web3dart/crypto.dart';
|
||||||
|
import 'package:web3dart/web3dart.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
import 'package:bip32/bip32.dart' as bip32;
|
||||||
|
|
||||||
|
part 'polygon_wallet.g.dart';
|
||||||
|
|
||||||
|
class PolygonWallet = PolygonWalletBase with _$PolygonWallet;
|
||||||
|
|
||||||
|
abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
|
PolygonTransactionHistory, PolygonTransactionInfo> with Store {
|
||||||
|
PolygonWalletBase({
|
||||||
|
required WalletInfo walletInfo,
|
||||||
|
String? mnemonic,
|
||||||
|
String? privateKey,
|
||||||
|
required String password,
|
||||||
|
ERC20Balance? initialBalance,
|
||||||
|
}) : syncStatus = NotConnectedSyncStatus(),
|
||||||
|
_password = password,
|
||||||
|
_mnemonic = mnemonic,
|
||||||
|
_hexPrivateKey = privateKey,
|
||||||
|
_isTransactionUpdating = false,
|
||||||
|
_client = PolygonClient(),
|
||||||
|
walletAddresses = PolygonWalletAddresses(walletInfo),
|
||||||
|
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of({
|
||||||
|
CryptoCurrency.maticpoly: initialBalance ?? ERC20Balance(BigInt.zero)
|
||||||
|
}),
|
||||||
|
super(walletInfo) {
|
||||||
|
this.walletInfo = walletInfo;
|
||||||
|
transactionHistory =
|
||||||
|
PolygonTransactionHistory(walletInfo: walletInfo, password: password);
|
||||||
|
|
||||||
|
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
||||||
|
CakeHive.registerAdapter(Erc20TokenAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
|
_sharedPrefs.complete(SharedPreferences.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
final String? _mnemonic;
|
||||||
|
final String? _hexPrivateKey;
|
||||||
|
final String _password;
|
||||||
|
|
||||||
|
late final Box<Erc20Token> polygonErc20TokensBox;
|
||||||
|
|
||||||
|
late final EthPrivateKey _polygonPrivateKey;
|
||||||
|
|
||||||
|
EthPrivateKey get polygonPrivateKey => _polygonPrivateKey;
|
||||||
|
|
||||||
|
late PolygonClient _client;
|
||||||
|
|
||||||
|
int? _gasPrice;
|
||||||
|
int? _estimatedGas;
|
||||||
|
bool _isTransactionUpdating;
|
||||||
|
|
||||||
|
// TODO: remove after integrating our own node and having eth_newPendingTransactionFilter
|
||||||
|
Timer? _transactionsUpdateTimer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletAddresses walletAddresses;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@observable
|
||||||
|
SyncStatus syncStatus;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@observable
|
||||||
|
late ObservableMap<CryptoCurrency, ERC20Balance> balance;
|
||||||
|
|
||||||
|
Completer<SharedPreferences> _sharedPrefs = Completer();
|
||||||
|
|
||||||
|
Future<void> init() async {
|
||||||
|
polygonErc20TokensBox =
|
||||||
|
await CakeHive.openBox<Erc20Token>(Erc20Token.polygonBoxName);
|
||||||
|
await walletAddresses.init();
|
||||||
|
await transactionHistory.init();
|
||||||
|
_polygonPrivateKey = await getPrivateKey(
|
||||||
|
mnemonic: _mnemonic,
|
||||||
|
privateKey: _hexPrivateKey,
|
||||||
|
password: _password,
|
||||||
|
);
|
||||||
|
walletAddresses.address = _polygonPrivateKey.address.toString();
|
||||||
|
await save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
||||||
|
try {
|
||||||
|
if (priority is PolygonTransactionPriority) {
|
||||||
|
final priorityFee =
|
||||||
|
EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||||
|
return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} catch (e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> changePassword(String password) {
|
||||||
|
throw UnimplementedError("changePassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void close() {
|
||||||
|
_client.stop();
|
||||||
|
_transactionsUpdateTimer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
@override
|
||||||
|
Future<void> connectToNode({required Node node}) async {
|
||||||
|
try {
|
||||||
|
syncStatus = ConnectingSyncStatus();
|
||||||
|
|
||||||
|
final isConnected = _client.connect(node);
|
||||||
|
|
||||||
|
if (!isConnected) {
|
||||||
|
throw Exception("Polygon Node connection failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
_client.setListeners(_polygonPrivateKey.address, _onNewTransaction);
|
||||||
|
|
||||||
|
_setTransactionUpdateTimer();
|
||||||
|
|
||||||
|
syncStatus = ConnectedSyncStatus();
|
||||||
|
} catch (e) {
|
||||||
|
syncStatus = FailedSyncStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
|
final _credentials = credentials as PolygonTransactionCredentials;
|
||||||
|
final outputs = _credentials.outputs;
|
||||||
|
final hasMultiDestination = outputs.length > 1;
|
||||||
|
|
||||||
|
final CryptoCurrency transactionCurrency = balance.keys
|
||||||
|
.firstWhere((element) => element.title == _credentials.currency.title);
|
||||||
|
|
||||||
|
final _erc20Balance = balance[transactionCurrency]!;
|
||||||
|
BigInt totalAmount = BigInt.zero;
|
||||||
|
int exponent =
|
||||||
|
transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
|
||||||
|
num amountToPolygonMultiplier = pow(10, exponent);
|
||||||
|
|
||||||
|
// so far this can not be made with Polygon as Polygon does not support multiple recipients
|
||||||
|
if (hasMultiDestination) {
|
||||||
|
if (outputs.any(
|
||||||
|
(item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
|
||||||
|
throw PolygonTransactionCreationException(transactionCurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
final totalOriginalAmount = PolygonFormatter.parsePolygonAmountToDouble(
|
||||||
|
outputs.fold(
|
||||||
|
0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
|
||||||
|
totalAmount =
|
||||||
|
BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
|
||||||
|
|
||||||
|
if (_erc20Balance.balance < totalAmount) {
|
||||||
|
throw PolygonTransactionCreationException(transactionCurrency);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final output = outputs.first;
|
||||||
|
// since the fees are taken from Ethereum
|
||||||
|
// then no need to subtract the fees from the amount if send all
|
||||||
|
final BigInt allAmount;
|
||||||
|
if (transactionCurrency is Erc20Token) {
|
||||||
|
allAmount = _erc20Balance.balance;
|
||||||
|
} else {
|
||||||
|
allAmount = _erc20Balance.balance -
|
||||||
|
BigInt.from(calculateEstimatedFee(_credentials.priority!, null));
|
||||||
|
}
|
||||||
|
final totalOriginalAmount = EthereumFormatter.parseEthereumAmountToDouble(
|
||||||
|
output.formattedCryptoAmount ?? 0);
|
||||||
|
totalAmount = output.sendAll
|
||||||
|
? allAmount
|
||||||
|
: BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
|
||||||
|
|
||||||
|
if (_erc20Balance.balance < totalAmount) {
|
||||||
|
throw PolygonTransactionCreationException(transactionCurrency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final pendingPolygonTransaction = await _client.signTransaction(
|
||||||
|
privateKey: _polygonPrivateKey,
|
||||||
|
toAddress: _credentials.outputs.first.isParsedAddress
|
||||||
|
? _credentials.outputs.first.extractedAddress!
|
||||||
|
: _credentials.outputs.first.address,
|
||||||
|
amount: totalAmount.toString(),
|
||||||
|
gas: _estimatedGas!,
|
||||||
|
priority: _credentials.priority!,
|
||||||
|
currency: transactionCurrency,
|
||||||
|
exponent: exponent,
|
||||||
|
contractAddress: transactionCurrency is Erc20Token
|
||||||
|
? transactionCurrency.contractAddress
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
return pendingPolygonTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateTransactions() async {
|
||||||
|
try {
|
||||||
|
if (_isTransactionUpdating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool isPolygonScanEnabled = (await _sharedPrefs.future).getBool("use_polygonscan") ?? true;
|
||||||
|
if (!isPolygonScanEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isTransactionUpdating = true;
|
||||||
|
final transactions = await fetchTransactions();
|
||||||
|
transactionHistory.addMany(transactions);
|
||||||
|
await transactionHistory.save();
|
||||||
|
_isTransactionUpdating = false;
|
||||||
|
} catch (_) {
|
||||||
|
_isTransactionUpdating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Map<String, PolygonTransactionInfo>> fetchTransactions() async {
|
||||||
|
final address = _polygonPrivateKey.address.hex;
|
||||||
|
final transactions = await _client.fetchTransactions(address);
|
||||||
|
|
||||||
|
final List<Future<List<PolygonTransactionModel>>> polygonErc20TokensTransactions =
|
||||||
|
[];
|
||||||
|
|
||||||
|
for (var token in balance.keys) {
|
||||||
|
if (token is Erc20Token) {
|
||||||
|
polygonErc20TokensTransactions.add(_client.fetchTransactions(
|
||||||
|
address,
|
||||||
|
contractAddress: token.contractAddress,
|
||||||
|
) as Future<List<PolygonTransactionModel>>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final tokensTransaction = await Future.wait(polygonErc20TokensTransactions);
|
||||||
|
transactions.addAll(tokensTransaction.expand((element) => element));
|
||||||
|
|
||||||
|
final Map<String, PolygonTransactionInfo> result = {};
|
||||||
|
|
||||||
|
for (var transactionModel in transactions) {
|
||||||
|
if (transactionModel.isError) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[transactionModel.hash] = PolygonTransactionInfo(
|
||||||
|
id: transactionModel.hash,
|
||||||
|
height: transactionModel.blockNumber,
|
||||||
|
ethAmount: transactionModel.amount,
|
||||||
|
direction: transactionModel.from == address
|
||||||
|
? TransactionDirection.outgoing
|
||||||
|
: TransactionDirection.incoming,
|
||||||
|
isPending: false,
|
||||||
|
date: transactionModel.date,
|
||||||
|
confirmations: transactionModel.confirmations,
|
||||||
|
ethFee:
|
||||||
|
BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
|
||||||
|
exponent: transactionModel.tokenDecimal ?? 18,
|
||||||
|
tokenSymbol: transactionModel.tokenSymbol ?? "MATIC",
|
||||||
|
to: transactionModel.to,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object get keys => throw UnimplementedError("keys");
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> rescan({required int height}) {
|
||||||
|
throw UnimplementedError("rescan");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> save() async {
|
||||||
|
await walletAddresses.updateAddressesInBox();
|
||||||
|
final path = await makePath();
|
||||||
|
await write(path: path, password: _password, data: toJSON());
|
||||||
|
await transactionHistory.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get seed => _mnemonic;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privateKey => HEX.encode(_polygonPrivateKey.privateKey);
|
||||||
|
|
||||||
|
@action
|
||||||
|
@override
|
||||||
|
Future<void> startSync() async {
|
||||||
|
try {
|
||||||
|
syncStatus = AttemptingSyncStatus();
|
||||||
|
await _updateBalance();
|
||||||
|
await _updateTransactions();
|
||||||
|
_gasPrice = await _client.getGasUnitPrice();
|
||||||
|
_estimatedGas = await _client.getEstimatedGas();
|
||||||
|
|
||||||
|
Timer.periodic(const Duration(minutes: 1),
|
||||||
|
(timer) async => _gasPrice = await _client.getGasUnitPrice());
|
||||||
|
Timer.periodic(const Duration(seconds: 10),
|
||||||
|
(timer) async => _estimatedGas = await _client.getEstimatedGas());
|
||||||
|
|
||||||
|
syncStatus = SyncedSyncStatus();
|
||||||
|
} catch (e) {
|
||||||
|
syncStatus = FailedSyncStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> makePath() async =>
|
||||||
|
pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||||
|
|
||||||
|
String toJSON() => json.encode({
|
||||||
|
'mnemonic': _mnemonic,
|
||||||
|
'private_key': privateKey,
|
||||||
|
'balance': balance[currency]!.toJSON(),
|
||||||
|
});
|
||||||
|
|
||||||
|
static Future<PolygonWallet> open({
|
||||||
|
required String name,
|
||||||
|
required String password,
|
||||||
|
required WalletInfo walletInfo,
|
||||||
|
}) async {
|
||||||
|
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||||
|
final jsonSource = await read(path: path, password: password);
|
||||||
|
final data = json.decode(jsonSource) as Map;
|
||||||
|
final mnemonic = data['mnemonic'] as String?;
|
||||||
|
final privateKey = data['private_key'] as String?;
|
||||||
|
final balance = ERC20Balance.fromJSON(data['balance'] as String) ??
|
||||||
|
ERC20Balance(BigInt.zero);
|
||||||
|
|
||||||
|
return PolygonWallet(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
password: password,
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
privateKey: privateKey,
|
||||||
|
initialBalance: balance,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateBalance() async {
|
||||||
|
balance[currency] = await _fetchMaticBalance();
|
||||||
|
|
||||||
|
await _fetchErc20Balances();
|
||||||
|
await save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ERC20Balance> _fetchMaticBalance() async {
|
||||||
|
final balance = await _client.getBalance(_polygonPrivateKey.address);
|
||||||
|
return ERC20Balance(balance.getInWei);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchErc20Balances() async {
|
||||||
|
for (var token in polygonErc20TokensBox.values) {
|
||||||
|
try {
|
||||||
|
if (token.enabled) {
|
||||||
|
balance[token] = await _client.fetchERC20Balances(
|
||||||
|
_polygonPrivateKey.address,
|
||||||
|
token.contractAddress,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
balance.remove(token);
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<EthPrivateKey> getPrivateKey(
|
||||||
|
{String? mnemonic, String? privateKey, required String password}) async {
|
||||||
|
assert(mnemonic != null || privateKey != null);
|
||||||
|
|
||||||
|
if (privateKey != null) {
|
||||||
|
return EthPrivateKey.fromHex(privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
final seed = bip39.mnemonicToSeed(mnemonic!);
|
||||||
|
|
||||||
|
final root = bip32.BIP32.fromSeed(seed);
|
||||||
|
|
||||||
|
const _hdPathPolygon = "m/44'/60'/0'/0";
|
||||||
|
const index = 0;
|
||||||
|
final addressAtIndex = root.derivePath("$_hdPathPolygon/$index");
|
||||||
|
|
||||||
|
return EthPrivateKey.fromHex(
|
||||||
|
HEX.encode(addressAtIndex.privateKey as List<int>));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void>? updateBalance() async => await _updateBalance();
|
||||||
|
|
||||||
|
List<Erc20Token> get erc20Currencies => polygonErc20TokensBox.values.toList();
|
||||||
|
|
||||||
|
Future<void> addErc20Token(Erc20Token token) async {
|
||||||
|
String? iconPath;
|
||||||
|
try {
|
||||||
|
iconPath = CryptoCurrency.all
|
||||||
|
.firstWhere((element) =>
|
||||||
|
element.title.toUpperCase() == token.symbol.toUpperCase())
|
||||||
|
.iconPath;
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
final _token = Erc20Token(
|
||||||
|
name: token.name,
|
||||||
|
symbol: token.symbol,
|
||||||
|
contractAddress: token.contractAddress,
|
||||||
|
decimal: token.decimal,
|
||||||
|
enabled: token.enabled,
|
||||||
|
iconPath: iconPath,
|
||||||
|
);
|
||||||
|
|
||||||
|
await polygonErc20TokensBox.put(_token.contractAddress, _token);
|
||||||
|
|
||||||
|
if (_token.enabled) {
|
||||||
|
balance[_token] = await _client.fetchERC20Balances(
|
||||||
|
_polygonPrivateKey.address,
|
||||||
|
_token.contractAddress,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
balance.remove(_token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteErc20Token(Erc20Token token) async {
|
||||||
|
await token.delete();
|
||||||
|
|
||||||
|
balance.remove(token);
|
||||||
|
_updateBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Erc20Token?> getErc20Token(String contractAddress) async =>
|
||||||
|
await _client.getErc20Token(contractAddress);
|
||||||
|
|
||||||
|
void _onNewTransaction() {
|
||||||
|
_updateBalance();
|
||||||
|
_updateTransactions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addInitialTokens() {
|
||||||
|
final initialErc20Tokens =
|
||||||
|
DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
|
||||||
|
|
||||||
|
for (var token in initialErc20Tokens) {
|
||||||
|
polygonErc20TokensBox.put(token.contractAddress, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> renameWalletFiles(String newWalletName) async {
|
||||||
|
final currentWalletPath =
|
||||||
|
await pathForWallet(name: walletInfo.name, type: type);
|
||||||
|
final currentWalletFile = File(currentWalletPath);
|
||||||
|
|
||||||
|
final currentDirPath =
|
||||||
|
await pathForWalletDir(name: walletInfo.name, type: type);
|
||||||
|
final currentTransactionsFile =
|
||||||
|
File('$currentDirPath/$transactionsHistoryFileName');
|
||||||
|
|
||||||
|
// Copies current wallet files into new wallet name's dir and files
|
||||||
|
if (currentWalletFile.existsSync()) {
|
||||||
|
final newWalletPath =
|
||||||
|
await pathForWallet(name: newWalletName, type: type);
|
||||||
|
await currentWalletFile.copy(newWalletPath);
|
||||||
|
}
|
||||||
|
if (currentTransactionsFile.existsSync()) {
|
||||||
|
final newDirPath =
|
||||||
|
await pathForWalletDir(name: newWalletName, type: type);
|
||||||
|
await currentTransactionsFile
|
||||||
|
.copy('$newDirPath/$transactionsHistoryFileName');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete old name's dir and files
|
||||||
|
await Directory(currentDirPath).delete(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setTransactionUpdateTimer() {
|
||||||
|
if (_transactionsUpdateTimer?.isActive ?? false) {
|
||||||
|
_transactionsUpdateTimer!.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
_transactionsUpdateTimer = Timer.periodic(Duration(seconds: 10), (_) {
|
||||||
|
_updateTransactions();
|
||||||
|
_updateBalance();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePolygonScanUsageState(bool isEnabled) {
|
||||||
|
if (isEnabled) {
|
||||||
|
_updateTransactions();
|
||||||
|
_setTransactionUpdateTimer();
|
||||||
|
} else {
|
||||||
|
_transactionsUpdateTimer?.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String signMessage(String message, {String? address = null}) => bytesToHex(
|
||||||
|
_polygonPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
|
||||||
|
|
||||||
|
Web3Client? getWeb3Client() => _client.getWeb3Client();
|
||||||
|
}
|
5
cw_polygon/lib/polygon_wallet_addresses.dart
Normal file
5
cw_polygon/lib/polygon_wallet_addresses.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import 'package:cw_ethereum/ethereum_wallet_addresses.dart';
|
||||||
|
|
||||||
|
class PolygonWalletAddresses extends EthereumWalletAddresses {
|
||||||
|
PolygonWalletAddresses(super.walletInfo);
|
||||||
|
}
|
28
cw_polygon/lib/polygon_wallet_creation_credentials.dart
Normal file
28
cw_polygon/lib/polygon_wallet_creation_credentials.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
class PolygonNewWalletCredentials extends WalletCredentials {
|
||||||
|
PolygonNewWalletCredentials({required String name, WalletInfo? walletInfo})
|
||||||
|
: super(name: name, walletInfo: walletInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PolygonRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
PolygonRestoreWalletFromSeedCredentials(
|
||||||
|
{required String name,
|
||||||
|
required String password,
|
||||||
|
required this.mnemonic,
|
||||||
|
WalletInfo? walletInfo})
|
||||||
|
: super(name: name, password: password, walletInfo: walletInfo);
|
||||||
|
|
||||||
|
final String mnemonic;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PolygonRestoreWalletFromPrivateKey extends WalletCredentials {
|
||||||
|
PolygonRestoreWalletFromPrivateKey(
|
||||||
|
{required String name,
|
||||||
|
required String password,
|
||||||
|
required this.privateKey,
|
||||||
|
WalletInfo? walletInfo})
|
||||||
|
: super(name: name, password: password, walletInfo: walletInfo);
|
||||||
|
|
||||||
|
final String privateKey;
|
||||||
|
}
|
123
cw_polygon/lib/polygon_wallet_service.dart
Normal file
123
cw_polygon/lib/polygon_wallet_service.dart
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:cw_ethereum/ethereum_mnemonics.dart';
|
||||||
|
import 'package:cw_polygon/polygon_wallet.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'polygon_wallet_creation_credentials.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
|
class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
|
||||||
|
PolygonRestoreWalletFromSeedCredentials, PolygonRestoreWalletFromPrivateKey> {
|
||||||
|
PolygonWalletService(this.walletInfoSource);
|
||||||
|
|
||||||
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PolygonWallet> create(PolygonNewWalletCredentials credentials) async {
|
||||||
|
final strength = (credentials.seedPhraseLength == 12)
|
||||||
|
? 128
|
||||||
|
: (credentials.seedPhraseLength == 24)
|
||||||
|
? 256
|
||||||
|
: 128;
|
||||||
|
|
||||||
|
final mnemonic = bip39.generateMnemonic(strength: strength);
|
||||||
|
final wallet = PolygonWallet(
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
password: credentials.password!,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.init();
|
||||||
|
wallet.addInitialTokens();
|
||||||
|
await wallet.save();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletType getType() => WalletType.polygon;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isWalletExit(String name) async =>
|
||||||
|
File(await pathForWallet(name: name, type: getType())).existsSync();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PolygonWallet> openWallet(String name, String password) async {
|
||||||
|
final walletInfo =
|
||||||
|
walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
|
||||||
|
final wallet = await PolygonWalletBase.open(
|
||||||
|
name: name,
|
||||||
|
password: password,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.init();
|
||||||
|
await wallet.save();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> remove(String wallet) async {
|
||||||
|
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
|
||||||
|
final walletInfo = walletInfoSource.values
|
||||||
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
||||||
|
await walletInfoSource.delete(walletInfo.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PolygonWallet> restoreFromKeys(PolygonRestoreWalletFromPrivateKey credentials) async {
|
||||||
|
final wallet = PolygonWallet(
|
||||||
|
password: credentials.password!,
|
||||||
|
privateKey: credentials.privateKey,
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.init();
|
||||||
|
wallet.addInitialTokens();
|
||||||
|
await wallet.save();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PolygonWallet> restoreFromSeed(PolygonRestoreWalletFromSeedCredentials credentials) async {
|
||||||
|
if (!bip39.validateMnemonic(credentials.mnemonic)) {
|
||||||
|
throw EthereumMnemonicIsIncorrectException();
|
||||||
|
}
|
||||||
|
|
||||||
|
final wallet = PolygonWallet(
|
||||||
|
password: credentials.password!,
|
||||||
|
mnemonic: credentials.mnemonic,
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.init();
|
||||||
|
wallet.addInitialTokens();
|
||||||
|
await wallet.save();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> rename(String currentName, String password, String newName) async {
|
||||||
|
final currentWalletInfo = walletInfoSource.values
|
||||||
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
|
final currentWallet = await PolygonWalletBase.open(
|
||||||
|
password: password, name: currentName, walletInfo: currentWalletInfo);
|
||||||
|
|
||||||
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
|
||||||
|
final newWalletInfo = currentWalletInfo;
|
||||||
|
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||||
|
newWalletInfo.name = newName;
|
||||||
|
|
||||||
|
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||||
|
}
|
||||||
|
}
|
73
cw_polygon/pubspec.yaml
Normal file
73
cw_polygon/pubspec.yaml
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
name: cw_polygon
|
||||||
|
description: A new Flutter package project.
|
||||||
|
version: 0.0.1
|
||||||
|
publish_to: none
|
||||||
|
author: Cake Wallet
|
||||||
|
homepage: https://cakewallet.com
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.0.6 <4.0.0'
|
||||||
|
flutter: ">=1.17.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
cw_core:
|
||||||
|
path: ../cw_core
|
||||||
|
cw_ethereum:
|
||||||
|
path: ../cw_ethereum
|
||||||
|
mobx: ^2.0.7+4
|
||||||
|
intl: ^0.18.0
|
||||||
|
bip39: ^1.0.6
|
||||||
|
hive: ^2.2.3
|
||||||
|
collection: ^1.17.1
|
||||||
|
web3dart: ^2.7.1
|
||||||
|
bip32: ^2.0.0
|
||||||
|
hex: ^0.2.0
|
||||||
|
shared_preferences: ^2.0.15
|
||||||
|
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_lints: ^2.0.0
|
||||||
|
build_runner: ^2.1.11
|
||||||
|
mobx_codegen: ^2.0.7
|
||||||
|
hive_generator: ^1.1.3
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter packages.
|
||||||
|
flutter:
|
||||||
|
|
||||||
|
# To add assets to your package, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
#
|
||||||
|
# For details regarding assets in packages, see
|
||||||
|
# https://flutter.dev/assets-and-images/#from-packages
|
||||||
|
#
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||||
|
|
||||||
|
# To add custom fonts to your package, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts in packages, see
|
||||||
|
# https://flutter.dev/custom-fonts/#from-packages
|
12
cw_polygon/test/cw_polygon_test.dart
Normal file
12
cw_polygon/test/cw_polygon_test.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:cw_polygon/cw_polygon.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('adds one to input values', () {
|
||||||
|
final calculator = Calculator();
|
||||||
|
expect(calculator.addOne(2), 3);
|
||||||
|
expect(calculator.addOne(-7), -6);
|
||||||
|
expect(calculator.addOne(0), 1);
|
||||||
|
});
|
||||||
|
}
|
|
@ -160,6 +160,26 @@
|
||||||
<string>bitcoincash-wallet</string>
|
<string>bitcoincash-wallet</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>polygon</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>polygon</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>polygon-wallet</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>polygon-wallet</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
|
|
@ -271,6 +271,8 @@ class AddressValidator extends TextValidator {
|
||||||
'|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)';
|
'|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)';
|
||||||
case CryptoCurrency.eth:
|
case CryptoCurrency.eth:
|
||||||
return '0x[0-9a-zA-Z]{42}';
|
return '0x[0-9a-zA-Z]{42}';
|
||||||
|
case CryptoCurrency.maticpoly:
|
||||||
|
return '0x[0-9a-zA-Z]{42}';
|
||||||
case CryptoCurrency.nano:
|
case CryptoCurrency.nano:
|
||||||
return 'nano_[0-9a-zA-Z]{60}';
|
return 'nano_[0-9a-zA-Z]{60}';
|
||||||
case CryptoCurrency.banano:
|
case CryptoCurrency.banano:
|
||||||
|
|
|
@ -16,7 +16,7 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
|
||||||
|
|
||||||
final Map<String, String> queryParams = {
|
final Map<String, String> queryParams = {
|
||||||
'interval_count': '1',
|
'interval_count': '1',
|
||||||
'base': crypto,
|
'base': crypto.split(".").first,
|
||||||
'quote': fiat,
|
'quote': fiat,
|
||||||
'key': secrets.fiatApiKey,
|
'key': secrets.fiatApiKey,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/haven/haven.dart';
|
import 'package:cake_wallet/haven/haven.dart';
|
||||||
import 'package:cake_wallet/core/validator.dart';
|
import 'package:cake_wallet/core/validator.dart';
|
||||||
import 'package:cake_wallet/entities/mnemonic_item.dart';
|
import 'package:cake_wallet/entities/mnemonic_item.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
|
@ -34,6 +35,8 @@ class SeedValidator extends Validator<MnemonicItem> {
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return nano!.getNanoWordList(language);
|
return nano!.getNanoWordList(language);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.getPolygonWordList(language);
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:cake_wallet/core/wallet_connect/eth_transaction_model.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
|
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
||||||
|
@ -14,7 +15,6 @@ import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/utils/string_parsing.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/utils/string_parsing.dart';
|
||||||
import 'package:convert/convert.dart';
|
import 'package:convert/convert.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:eth_sig_util/eth_sig_util.dart';
|
import 'package:eth_sig_util/eth_sig_util.dart';
|
||||||
import 'package:eth_sig_util/util/utils.dart';
|
import 'package:eth_sig_util/util/utils.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
@ -46,13 +46,12 @@ class EvmChainServiceImpl implements ChainService {
|
||||||
required this.wcKeyService,
|
required this.wcKeyService,
|
||||||
required this.bottomSheetService,
|
required this.bottomSheetService,
|
||||||
required this.wallet,
|
required this.wallet,
|
||||||
Web3Client? ethClient,
|
Web3Client? web3Client,
|
||||||
}) : ethClient = ethClient ??
|
}) : ethClient = web3Client ??
|
||||||
Web3Client(
|
Web3Client(
|
||||||
appStore.settingsStore.getCurrentNode(WalletType.ethereum).uri.toString(),
|
appStore.settingsStore.getCurrentNode(appStore.wallet!.type).uri.toString(),
|
||||||
http.Client(),
|
http.Client(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
for (final String event in getEvents()) {
|
for (final String event in getEvents()) {
|
||||||
wallet.registerEventEmitter(chainId: getChainId(), event: event);
|
wallet.registerEventEmitter(chainId: getChainId(), event: event);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +137,8 @@ class EvmChainServiceImpl implements ChainService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Load the private key
|
// Load the private key
|
||||||
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
|
final List<ChainKeyModel> keys = wcKeyService
|
||||||
|
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||||
|
|
||||||
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
||||||
|
|
||||||
|
@ -176,13 +176,15 @@ class EvmChainServiceImpl implements ChainService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Load the private key
|
// Load the private key
|
||||||
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
|
final List<ChainKeyModel> keys = wcKeyService
|
||||||
|
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||||
|
|
||||||
final EthPrivateKey credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
final EthPrivateKey credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
||||||
|
|
||||||
final String signature = hex.encode(
|
final String signature = hex.encode(
|
||||||
credentials.signPersonalMessageToUint8List(
|
credentials.signPersonalMessageToUint8List(
|
||||||
Uint8List.fromList(utf8.encode(message)),
|
Uint8List.fromList(utf8.encode(message)),
|
||||||
|
chainId: getChainIdBasedOnWalletType(appStore.wallet!.type),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
log(signature);
|
log(signature);
|
||||||
|
@ -212,7 +214,8 @@ class EvmChainServiceImpl implements ChainService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the private key
|
// Load the private key
|
||||||
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
|
final List<ChainKeyModel> keys = wcKeyService
|
||||||
|
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||||
|
|
||||||
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
|
||||||
|
|
||||||
|
@ -232,7 +235,11 @@ class EvmChainServiceImpl implements ChainService {
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final result = await ethClient.sendTransaction(credentials, transaction);
|
final result = await ethClient.sendTransaction(
|
||||||
|
credentials,
|
||||||
|
transaction,
|
||||||
|
chainId: getChainIdBasedOnWalletType(appStore.wallet!.type),
|
||||||
|
);
|
||||||
|
|
||||||
log('Result: $result');
|
log('Result: $result');
|
||||||
|
|
||||||
|
@ -267,7 +274,8 @@ class EvmChainServiceImpl implements ChainService {
|
||||||
return authError;
|
return authError;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
|
final List<ChainKeyModel> keys = wcKeyService
|
||||||
|
.getKeysForChain(getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type));
|
||||||
|
|
||||||
return EthSigUtil.signTypedData(
|
return EthSigUtil.signTypedData(
|
||||||
privateKey: keys[0].privateKey,
|
privateKey: keys[0].privateKey,
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
abstract class WalletConnectKeyService {
|
abstract class WalletConnectKeyService {
|
||||||
/// Returns a list of all the keys.
|
/// Returns a list of all the keys.
|
||||||
|
@ -32,16 +34,36 @@ class KeyServiceImpl implements WalletConnectKeyService {
|
||||||
'eip155:42161',
|
'eip155:42161',
|
||||||
'eip155:80001',
|
'eip155:80001',
|
||||||
],
|
],
|
||||||
privateKey: ethereum!.getPrivateKey(wallet),
|
privateKey: _getPrivateKeyForWallet(wallet),
|
||||||
publicKey: ethereum!.getPublicKey(wallet),
|
publicKey: _getPublicKeyForWallet(wallet),
|
||||||
),
|
),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
late final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
late final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
||||||
|
|
||||||
late final List<ChainKeyModel> _keys;
|
late final List<ChainKeyModel> _keys;
|
||||||
|
|
||||||
|
static String _getPrivateKeyForWallet(WalletBase wallet) {
|
||||||
|
switch (wallet.type) {
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return ethereum!.getPrivateKey(wallet);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.getPrivateKey(wallet);
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _getPublicKeyForWallet(WalletBase wallet) {
|
||||||
|
switch (wallet.type) {
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return ethereum!.getPublicKey(wallet);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.getPublicKey(wallet);
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
@override
|
@override
|
||||||
List<String> getChains() {
|
List<String> getChains() {
|
||||||
final List<String> chainIds = [];
|
final List<String> chainIds = [];
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
|
import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
||||||
import 'package:cake_wallet/core/wallet_connect/models/session_request_model.dart';
|
import 'package:cake_wallet/core/wallet_connect/models/session_request_model.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_request_widget.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_request_widget.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
|
||||||
|
@ -164,8 +165,10 @@ abstract class Web3WalletServiceBase with Store {
|
||||||
|
|
||||||
void _onSessionProposal(SessionProposalEvent? args) async {
|
void _onSessionProposal(SessionProposalEvent? args) async {
|
||||||
if (args != null) {
|
if (args != null) {
|
||||||
|
final chaindIdNamespace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
|
||||||
final Widget modalWidget = Web3RequestModal(
|
final Widget modalWidget = Web3RequestModal(
|
||||||
child: ConnectionRequestWidget(
|
child: ConnectionRequestWidget(
|
||||||
|
chaindIdNamespace: chaindIdNamespace,
|
||||||
wallet: _web3Wallet,
|
wallet: _web3Wallet,
|
||||||
sessionProposal: SessionRequestModel(request: args.params),
|
sessionProposal: SessionRequestModel(request: args.params),
|
||||||
),
|
),
|
||||||
|
@ -232,12 +235,13 @@ abstract class Web3WalletServiceBase with Store {
|
||||||
@action
|
@action
|
||||||
Future<void> _onAuthRequest(AuthRequest? args) async {
|
Future<void> _onAuthRequest(AuthRequest? args) async {
|
||||||
if (args != null) {
|
if (args != null) {
|
||||||
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain('eip155:1');
|
final chaindIdNamespace = getChainNameSpaceAndIdBasedOnWalletType(appStore.wallet!.type);
|
||||||
|
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(chaindIdNamespace);
|
||||||
// Create the message to be signed
|
// Create the message to be signed
|
||||||
final String iss = 'did:pkh:eip155:1:${chainKeys.first.publicKey}';
|
final String iss = 'did:pkh:$chaindIdNamespace:${chainKeys.first.publicKey}';
|
||||||
|
|
||||||
final Widget modalWidget = Web3RequestModal(
|
final Widget modalWidget = Web3RequestModal(
|
||||||
child: ConnectionRequestWidget(
|
child: ConnectionRequestWidget(
|
||||||
|
chaindIdNamespace: chaindIdNamespace,
|
||||||
wallet: _web3Wallet,
|
wallet: _web3Wallet,
|
||||||
authRequest: AuthRequestModel(iss: iss, request: args),
|
authRequest: AuthRequestModel(iss: iss, request: args),
|
||||||
),
|
),
|
||||||
|
|
|
@ -18,6 +18,8 @@ import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/ionia/ionia_anypay.dart';
|
import 'package:cake_wallet/ionia/ionia_anypay.dart';
|
||||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||||
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
|
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
|
||||||
|
@ -750,7 +752,7 @@ Future<void> setup({
|
||||||
final wallet = getIt.get<AppStore>().wallet;
|
final wallet = getIt.get<AppStore>().wallet;
|
||||||
return ConnectionSyncPage(
|
return ConnectionSyncPage(
|
||||||
getIt.get<DashboardViewModel>(),
|
getIt.get<DashboardViewModel>(),
|
||||||
wallet?.type == WalletType.ethereum ? getIt.get<Web3WalletService>() : null,
|
isEVMCompatibleChain(wallet!.type) ? getIt.get<Web3WalletService>() : null,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -847,6 +849,8 @@ Future<void> setup({
|
||||||
.createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
|
.createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nano!.createNanoWalletService(_walletInfoSource);
|
return nano!.createNanoWalletService(_walletInfoSource);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.createPolygonWalletService(_walletInfoSource);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
|
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
|
||||||
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
|
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
|
||||||
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
|
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
|
||||||
const ethereumDefaultNodeUri = 'ethereum.publicnode.com';
|
const ethereumDefaultNodeUri = 'ethereum.publicnode.com';
|
||||||
|
const polygonDefaultNodeUri = 'polygon-bor.publicnode.com';
|
||||||
const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
|
const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
|
||||||
const nanoDefaultNodeUri = 'rpc.nano.to';
|
const nanoDefaultNodeUri = 'rpc.nano.to';
|
||||||
const nanoDefaultPowNodeUri = 'rpc.nano.to';
|
const nanoDefaultPowNodeUri = 'rpc.nano.to';
|
||||||
|
@ -65,6 +66,8 @@ Future<void> defaultSettingsMigration(
|
||||||
final migrationVersions =
|
final migrationVersions =
|
||||||
List<int>.generate(migrationVersionsLength, (i) => currentVersion + (i + 1));
|
List<int>.generate(migrationVersionsLength, (i) => currentVersion + (i + 1));
|
||||||
|
|
||||||
|
/// When you add a new case, increase the initialMigrationVersion parameter in the main.dart file.
|
||||||
|
/// This ensures that this switch case runs the newly added case.
|
||||||
await Future.forEach(migrationVersions, (int version) async {
|
await Future.forEach(migrationVersions, (int version) async {
|
||||||
try {
|
try {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
|
@ -175,6 +178,11 @@ Future<void> defaultSettingsMigration(
|
||||||
await changeBitcoinCurrentElectrumServerToDefault(
|
await changeBitcoinCurrentElectrumServerToDefault(
|
||||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||||
break;
|
break;
|
||||||
|
case 24:
|
||||||
|
await addPolygonNodeList(nodes: nodes);
|
||||||
|
await changePolygonCurrentNodeToDefault(
|
||||||
|
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||||
|
break;
|
||||||
case 25:
|
case 25:
|
||||||
await rewriteSecureStoragePin(secureStorage: secureStorage);
|
await rewriteSecureStoragePin(secureStorage: secureStorage);
|
||||||
break;
|
break;
|
||||||
|
@ -332,6 +340,11 @@ Node? getEthereumDefaultNode({required Box<Node> nodes}) {
|
||||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum);
|
nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node? getPolygonDefaultNode({required Box<Node> nodes}) {
|
||||||
|
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == polygonDefaultNodeUri) ??
|
||||||
|
nodes.values.firstWhereOrNull((node) => node.type == WalletType.polygon);
|
||||||
|
}
|
||||||
|
|
||||||
Node? getNanoDefaultNode({required Box<Node> nodes}) {
|
Node? getNanoDefaultNode({required Box<Node> nodes}) {
|
||||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == nanoDefaultNodeUri) ??
|
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == nanoDefaultNodeUri) ??
|
||||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.nano);
|
nodes.values.firstWhereOrNull((node) => node.type == WalletType.nano);
|
||||||
|
@ -575,6 +588,7 @@ Future<void> checkCurrentNodes(
|
||||||
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||||
final currentHavenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
final currentHavenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||||
final currentEthereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
final currentEthereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
||||||
|
final currentPolygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
|
||||||
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||||
final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
|
final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
|
||||||
final currentBitcoinCashNodeId =
|
final currentBitcoinCashNodeId =
|
||||||
|
@ -589,6 +603,8 @@ Future<void> checkCurrentNodes(
|
||||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentHavenNodeId);
|
nodeSource.values.firstWhereOrNull((node) => node.key == currentHavenNodeId);
|
||||||
final currentEthereumNodeServer =
|
final currentEthereumNodeServer =
|
||||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentEthereumNodeId);
|
nodeSource.values.firstWhereOrNull((node) => node.key == currentEthereumNodeId);
|
||||||
|
final currentPolygonNodeServer =
|
||||||
|
nodeSource.values.firstWhereOrNull((node) => node.key == currentPolygonNodeId);
|
||||||
final currentNanoNodeServer =
|
final currentNanoNodeServer =
|
||||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
|
nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
|
||||||
final currentNanoPowNodeServer =
|
final currentNanoPowNodeServer =
|
||||||
|
@ -648,6 +664,12 @@ Future<void> checkCurrentNodes(
|
||||||
await nodeSource.add(node);
|
await nodeSource.add(node);
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
|
await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentPolygonNodeServer == null) {
|
||||||
|
final node = Node(uri: polygonDefaultNodeUri, type: WalletType.polygon);
|
||||||
|
await nodeSource.add(node);
|
||||||
|
await sharedPreferences.setInt(PreferencesKey.currentPolygonNodeIdKey, node.key as int);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> resetBitcoinElectrumServer(
|
Future<void> resetBitcoinElectrumServer(
|
||||||
|
@ -742,3 +764,20 @@ Future<void> changeNanoCurrentPowNodeToDefault(
|
||||||
final nodeId = node?.key as int? ?? 0;
|
final nodeId = node?.key as int? ?? 0;
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentNanoPowNodeIdKey, nodeId);
|
await sharedPreferences.setInt(PreferencesKey.currentNanoPowNodeIdKey, nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> addPolygonNodeList({required Box<Node> nodes}) async {
|
||||||
|
final nodeList = await loadDefaultPolygonNodes();
|
||||||
|
for (var node in nodeList) {
|
||||||
|
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
|
||||||
|
await nodes.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> changePolygonCurrentNodeToDefault(
|
||||||
|
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||||
|
final node = getPolygonDefaultNode(nodes: nodes);
|
||||||
|
final nodeId = node?.key as int? ?? 0;
|
||||||
|
|
||||||
|
await sharedPreferences.setInt(PreferencesKey.currentPolygonNodeIdKey, nodeId);
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:ens_dart/ens_dart.dart';
|
import 'package:ens_dart/ens_dart.dart';
|
||||||
|
@ -13,6 +14,10 @@ class EnsRecord {
|
||||||
_client = ethereum!.getWeb3Client(wallet);
|
_client = ethereum!.getWeb3Client(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wallet != null && wallet.type == WalletType.polygon) {
|
||||||
|
_client = polygon!.getWeb3Client(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
if (_client == null) {
|
if (_client == null) {
|
||||||
_client = Web3Client("https://ethereum.publicnode.com", Client());
|
_client = Web3Client("https://ethereum.publicnode.com", Client());
|
||||||
}
|
}
|
||||||
|
@ -31,6 +36,7 @@ class EnsRecord {
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return await ens.withName(name).getCoinAddress(CoinType.XHV);
|
return await ens.withName(name).getCoinAddress(CoinType.XHV);
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
case WalletType.polygon:
|
||||||
default:
|
default:
|
||||||
return (await ens.withName(name).getAddress()).hex;
|
return (await ens.withName(name).getAddress()).hex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ class MainActions {
|
||||||
|
|
||||||
final bool Function(DashboardViewModel viewModel)? isEnabled;
|
final bool Function(DashboardViewModel viewModel)? isEnabled;
|
||||||
final bool Function(DashboardViewModel viewModel)? canShow;
|
final bool Function(DashboardViewModel viewModel)? canShow;
|
||||||
final Future<void> Function(BuildContext context, DashboardViewModel viewModel) onTap;
|
final Future<void> Function(
|
||||||
|
BuildContext context, DashboardViewModel viewModel) onTap;
|
||||||
|
|
||||||
MainActions._({
|
MainActions._({
|
||||||
required this.name,
|
required this.name,
|
||||||
|
@ -52,6 +53,7 @@ class MainActions {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
case WalletType.polygon:
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
switch (defaultBuyProvider) {
|
switch (defaultBuyProvider) {
|
||||||
case BuyProviderType.AskEachTime:
|
case BuyProviderType.AskEachTime:
|
||||||
|
@ -124,6 +126,7 @@ class MainActions {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
case WalletType.polygon:
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
if (viewModel.isEnabledSellAction) {
|
if (viewModel.isEnabledSellAction) {
|
||||||
final moonPaySellProvider = MoonPaySellProvider();
|
final moonPaySellProvider = MoonPaySellProvider();
|
||||||
|
|
|
@ -133,6 +133,22 @@ Future<List<Node>> loadDefaultNanoPowNodes() async {
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<Node>> loadDefaultPolygonNodes() async {
|
||||||
|
final nodesRaw = await rootBundle.loadString('assets/polygon_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.polygon;
|
||||||
|
nodes.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> resetToDefault(Box<Node> nodeSource) async {
|
Future<void> resetToDefault(Box<Node> nodeSource) async {
|
||||||
final moneroNodes = await loadDefaultNodes();
|
final moneroNodes = await loadDefaultNodes();
|
||||||
final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
|
final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
|
||||||
|
@ -141,6 +157,8 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
|
||||||
final havenNodes = await loadDefaultHavenNodes();
|
final havenNodes = await loadDefaultHavenNodes();
|
||||||
final ethereumNodes = await loadDefaultEthereumNodes();
|
final ethereumNodes = await loadDefaultEthereumNodes();
|
||||||
final nanoNodes = await loadDefaultNanoNodes();
|
final nanoNodes = await loadDefaultNanoNodes();
|
||||||
|
final polygonNodes = await loadDefaultPolygonNodes();
|
||||||
|
|
||||||
|
|
||||||
final nodes = moneroNodes +
|
final nodes = moneroNodes +
|
||||||
bitcoinElectrumServerList +
|
bitcoinElectrumServerList +
|
||||||
|
@ -148,7 +166,8 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
|
||||||
havenNodes +
|
havenNodes +
|
||||||
ethereumNodes +
|
ethereumNodes +
|
||||||
bitcoinCashElectrumServerList +
|
bitcoinCashElectrumServerList +
|
||||||
nanoNodes;
|
nanoNodes +
|
||||||
|
polygonNodes;
|
||||||
|
|
||||||
await nodeSource.clear();
|
await nodeSource.clear();
|
||||||
await nodeSource.addAll(nodes);
|
await nodeSource.addAll(nodes);
|
||||||
|
|
|
@ -6,6 +6,7 @@ class PreferencesKey {
|
||||||
static const currentLitecoinElectrumSererIdKey = 'current_node_id_ltc';
|
static const currentLitecoinElectrumSererIdKey = 'current_node_id_ltc';
|
||||||
static const currentHavenNodeIdKey = 'current_node_id_xhv';
|
static const currentHavenNodeIdKey = 'current_node_id_xhv';
|
||||||
static const currentEthereumNodeIdKey = 'current_node_id_eth';
|
static const currentEthereumNodeIdKey = 'current_node_id_eth';
|
||||||
|
static const currentPolygonNodeIdKey = 'current_node_id_matic';
|
||||||
static const currentNanoNodeIdKey = 'current_node_id_nano';
|
static const currentNanoNodeIdKey = 'current_node_id_nano';
|
||||||
static const currentNanoPowNodeIdKey = 'current_node_id_nano_pow';
|
static const currentNanoPowNodeIdKey = 'current_node_id_nano_pow';
|
||||||
static const currentBananoNodeIdKey = 'current_node_id_banano';
|
static const currentBananoNodeIdKey = 'current_node_id_banano';
|
||||||
|
@ -37,6 +38,7 @@ class PreferencesKey {
|
||||||
static const havenTransactionPriority = 'current_fee_priority_haven';
|
static const havenTransactionPriority = 'current_fee_priority_haven';
|
||||||
static const litecoinTransactionPriority = 'current_fee_priority_litecoin';
|
static const litecoinTransactionPriority = 'current_fee_priority_litecoin';
|
||||||
static const ethereumTransactionPriority = 'current_fee_priority_ethereum';
|
static const ethereumTransactionPriority = 'current_fee_priority_ethereum';
|
||||||
|
static const polygonTransactionPriority = 'current_fee_priority_polygon';
|
||||||
static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash';
|
static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash';
|
||||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||||
|
@ -50,6 +52,7 @@ class PreferencesKey {
|
||||||
static const sortBalanceBy = 'sort_balance_by';
|
static const sortBalanceBy = 'sort_balance_by';
|
||||||
static const pinNativeTokenAtTop = 'pin_native_token_at_top';
|
static const pinNativeTokenAtTop = 'pin_native_token_at_top';
|
||||||
static const useEtherscan = 'use_etherscan';
|
static const useEtherscan = 'use_etherscan';
|
||||||
|
static const usePolygonScan = 'use_polygonscan';
|
||||||
static const defaultNanoRep = 'default_nano_representative';
|
static const defaultNanoRep = 'default_nano_representative';
|
||||||
static const defaultBananoRep = 'default_banano_representative';
|
static const defaultBananoRep = 'default_banano_representative';
|
||||||
static const lookupsTwitter = 'looks_up_twitter';
|
static const lookupsTwitter = 'looks_up_twitter';
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/haven/haven.dart';
|
import 'package:cake_wallet/haven/haven.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
@ -24,6 +25,8 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return [];
|
return [];
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.getTransactionPriorities();
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
156
lib/polygon/cw_polygon.dart
Normal file
156
lib/polygon/cw_polygon.dart
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
part of 'polygon.dart';
|
||||||
|
|
||||||
|
class CWPolygon extends Polygon {
|
||||||
|
@override
|
||||||
|
List<String> getPolygonWordList(String language) => EthereumMnemonics.englishWordlist;
|
||||||
|
|
||||||
|
WalletService createPolygonWalletService(Box<WalletInfo> walletInfoSource) =>
|
||||||
|
PolygonWalletService(walletInfoSource);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createPolygonNewWalletCredentials({
|
||||||
|
required String name,
|
||||||
|
WalletInfo? walletInfo,
|
||||||
|
}) =>
|
||||||
|
PolygonNewWalletCredentials(name: name, walletInfo: walletInfo);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createPolygonRestoreWalletFromSeedCredentials({
|
||||||
|
required String name,
|
||||||
|
required String mnemonic,
|
||||||
|
required String password,
|
||||||
|
}) =>
|
||||||
|
PolygonRestoreWalletFromSeedCredentials(name: name, password: password, mnemonic: mnemonic);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletCredentials createPolygonRestoreWalletFromPrivateKey({
|
||||||
|
required String name,
|
||||||
|
required String privateKey,
|
||||||
|
required String password,
|
||||||
|
}) =>
|
||||||
|
PolygonRestoreWalletFromPrivateKey(name: name, password: password, privateKey: privateKey);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getAddress(WalletBase wallet) => (wallet as PolygonWallet).walletAddresses.address;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getPrivateKey(WalletBase wallet) {
|
||||||
|
final privateKeyHolder = (wallet as PolygonWallet).polygonPrivateKey;
|
||||||
|
String stringKey = bytesToHex(privateKeyHolder.privateKey);
|
||||||
|
return stringKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getPublicKey(WalletBase wallet) {
|
||||||
|
final privateKeyInUnitInt = (wallet as PolygonWallet).polygonPrivateKey;
|
||||||
|
final publicKey = privateKeyInUnitInt.address.hex;
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TransactionPriority getDefaultTransactionPriority() => PolygonTransactionPriority.medium;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TransactionPriority getPolygonTransactionPrioritySlow() => PolygonTransactionPriority.slow;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<TransactionPriority> getTransactionPriorities() => PolygonTransactionPriority.all;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TransactionPriority deserializePolygonTransactionPriority(int raw) =>
|
||||||
|
PolygonTransactionPriority.deserialize(raw: raw);
|
||||||
|
|
||||||
|
Object createPolygonTransactionCredentials(
|
||||||
|
List<Output> outputs, {
|
||||||
|
required TransactionPriority priority,
|
||||||
|
required CryptoCurrency currency,
|
||||||
|
int? feeRate,
|
||||||
|
}) =>
|
||||||
|
PolygonTransactionCredentials(
|
||||||
|
outputs
|
||||||
|
.map((out) => OutputInfo(
|
||||||
|
fiatAmount: out.fiatAmount,
|
||||||
|
cryptoAmount: out.cryptoAmount,
|
||||||
|
address: out.address,
|
||||||
|
note: out.note,
|
||||||
|
sendAll: out.sendAll,
|
||||||
|
extractedAddress: out.extractedAddress,
|
||||||
|
isParsedAddress: out.isParsedAddress,
|
||||||
|
formattedCryptoAmount: out.formattedCryptoAmount))
|
||||||
|
.toList(),
|
||||||
|
priority: priority as PolygonTransactionPriority,
|
||||||
|
currency: currency,
|
||||||
|
feeRate: feeRate,
|
||||||
|
);
|
||||||
|
|
||||||
|
Object createPolygonTransactionCredentialsRaw(
|
||||||
|
List<OutputInfo> outputs, {
|
||||||
|
TransactionPriority? priority,
|
||||||
|
required CryptoCurrency currency,
|
||||||
|
required int feeRate,
|
||||||
|
}) =>
|
||||||
|
PolygonTransactionCredentials(
|
||||||
|
outputs,
|
||||||
|
priority: priority as PolygonTransactionPriority?,
|
||||||
|
currency: currency,
|
||||||
|
feeRate: feeRate,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int formatterPolygonParseAmount(String amount) => PolygonFormatter.parsePolygonAmount(amount);
|
||||||
|
|
||||||
|
@override
|
||||||
|
double formatterPolygonAmountToDouble(
|
||||||
|
{TransactionInfo? transaction, BigInt? amount, int exponent = 18}) {
|
||||||
|
assert(transaction != null || amount != null);
|
||||||
|
|
||||||
|
if (transaction != null) {
|
||||||
|
transaction as PolygonTransactionInfo;
|
||||||
|
return transaction.ethAmount / BigInt.from(10).pow(transaction.exponent);
|
||||||
|
} else {
|
||||||
|
return (amount!) / BigInt.from(10).pow(exponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Erc20Token> getERC20Currencies(WalletBase wallet) {
|
||||||
|
final polygonWallet = wallet as PolygonWallet;
|
||||||
|
return polygonWallet.erc20Currencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> addErc20Token(WalletBase wallet, Erc20Token token) async =>
|
||||||
|
await (wallet as PolygonWallet).addErc20Token(token);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> deleteErc20Token(WalletBase wallet, Erc20Token token) async =>
|
||||||
|
await (wallet as PolygonWallet).deleteErc20Token(token);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
|
||||||
|
final polygonWallet = wallet as PolygonWallet;
|
||||||
|
return await polygonWallet.getErc20Token(contractAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) {
|
||||||
|
transaction as PolygonTransactionInfo;
|
||||||
|
if (transaction.tokenSymbol == CryptoCurrency.maticpoly.title) {
|
||||||
|
return CryptoCurrency.maticpoly;
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet as PolygonWallet;
|
||||||
|
return wallet.erc20Currencies.firstWhere(
|
||||||
|
(element) => transaction.tokenSymbol.toLowerCase() == element.symbol.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updatePolygonScanUsageState(WalletBase wallet, bool isEnabled) {
|
||||||
|
(wallet as PolygonWallet).updatePolygonScanUsageState(isEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Web3Client? getWeb3Client(WalletBase wallet) {
|
||||||
|
return (wallet as PolygonWallet).getWeb3Client();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,11 @@ import 'package:cake_wallet/core/fiat_conversion_service.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/update_haven_rate.dart';
|
import 'package:cake_wallet/entities/update_haven_rate.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cw_core/erc20_token.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
@ -33,10 +35,18 @@ Future<void> startFiatRateUpdate(
|
||||||
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Iterable<Erc20Token>? currencies;
|
||||||
if (appStore.wallet!.type == WalletType.ethereum) {
|
if (appStore.wallet!.type == WalletType.ethereum) {
|
||||||
final currencies =
|
currencies =
|
||||||
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appStore.wallet!.type == WalletType.polygon) {
|
||||||
|
currencies =
|
||||||
|
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currencies != null) {
|
||||||
for (final currency in currencies) {
|
for (final currency in currencies) {
|
||||||
() async {
|
() async {
|
||||||
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
||||||
|
|
|
@ -2,7 +2,8 @@ import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/update_haven_rate.dart';
|
import 'package:cake_wallet/entities/update_haven_rate.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
|
import 'package:cw_core/erc20_token.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
@ -107,10 +108,17 @@ void startCurrentWalletChangeReaction(
|
||||||
fiat: settingsStore.fiatCurrency,
|
fiat: settingsStore.fiatCurrency,
|
||||||
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
||||||
|
|
||||||
|
Iterable<Erc20Token>? currencies;
|
||||||
if (wallet.type == WalletType.ethereum) {
|
if (wallet.type == WalletType.ethereum) {
|
||||||
final currencies =
|
currencies =
|
||||||
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
}
|
||||||
|
if (wallet.type == WalletType.polygon) {
|
||||||
|
currencies =
|
||||||
|
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currencies != null) {
|
||||||
for (final currency in currencies) {
|
for (final currency in currencies) {
|
||||||
() async {
|
() async {
|
||||||
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
||||||
|
|
46
lib/reactions/wallet_connect.dart
Normal file
46
lib/reactions/wallet_connect.dart
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
bool isEVMCompatibleChain(WalletType walletType) {
|
||||||
|
switch (walletType) {
|
||||||
|
case WalletType.polygon:
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getChainNameSpaceAndIdBasedOnWalletType(WalletType walletType) {
|
||||||
|
switch (walletType) {
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return EVMChainId.ethereum.chain();
|
||||||
|
case WalletType.polygon:
|
||||||
|
return EVMChainId.polygon.chain();
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getChainIdBasedOnWalletType(WalletType walletType) {
|
||||||
|
switch (walletType) {
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 137;
|
||||||
|
|
||||||
|
// For now, we return eth chain Id as the default, we'll modify as we add more wallets
|
||||||
|
case WalletType.ethereum:
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getChainNameBasedOnWalletType(WalletType walletType) {
|
||||||
|
switch (walletType) {
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return 'eth';
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 'polygon';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||||
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
||||||
|
final polygonIcon = Image.asset('assets/images/matic_icon.png', height: 24, width: 24);
|
||||||
final bitcoinCashIcon = Image.asset('assets/images/bch_icon.png', height: 24, width: 24);
|
final bitcoinCashIcon = Image.asset('assets/images/bch_icon.png', height: 24, width: 24);
|
||||||
final nanoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
|
final nanoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
|
||||||
final bananoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
|
final bananoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
|
||||||
|
@ -150,6 +151,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
return nanoIcon;
|
return nanoIcon;
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return bananoIcon;
|
return bananoIcon;
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygonIcon;
|
||||||
default:
|
default:
|
||||||
return nonWalletTypeIcon;
|
return nonWalletTypeIcon;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
||||||
|
@ -13,7 +14,6 @@ import 'package:cake_wallet/utils/feature_flag.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
|
@ -32,12 +32,12 @@ class BalancePage extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final isEthereumWallet = dashboardViewModel.type == WalletType.ethereum;
|
final isEVMCompatible = isEVMCompatibleChain(dashboardViewModel.type);
|
||||||
return DefaultTabController(
|
return DefaultTabController(
|
||||||
length: isEthereumWallet ? 2 : 1,
|
length: isEVMCompatible ? 2 : 1,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (isEthereumWallet)
|
if (isEVMCompatible)
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -66,7 +66,7 @@ class BalancePage extends StatelessWidget {
|
||||||
physics: NeverScrollableScrollPhysics(),
|
physics: NeverScrollableScrollPhysics(),
|
||||||
children: [
|
children: [
|
||||||
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
|
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
|
||||||
if (isEthereumWallet) NFTListingPage(nftViewModel: nftViewModel)
|
if (isEVMCompatible) NFTListingPage(nftViewModel: nftViewModel)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -32,7 +32,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
this.ethereumIcon = Image.asset('assets/images/eth_icon.png'),
|
this.ethereumIcon = Image.asset('assets/images/eth_icon.png'),
|
||||||
this.nanoIcon = Image.asset('assets/images/nano_icon.png'),
|
this.nanoIcon = Image.asset('assets/images/nano_icon.png'),
|
||||||
this.bananoIcon = Image.asset('assets/images/nano_icon.png'),
|
this.bananoIcon = Image.asset('assets/images/nano_icon.png'),
|
||||||
this.bitcoinCashIcon = Image.asset('assets/images/bch_icon.png');
|
this.bitcoinCashIcon = Image.asset('assets/images/bch_icon.png'),
|
||||||
|
this.polygonIcon = Image.asset('assets/images/matic_icon.png');
|
||||||
|
|
||||||
|
|
||||||
final largeScreen = 731;
|
final largeScreen = 731;
|
||||||
|
@ -54,6 +55,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
Image bitcoinCashIcon;
|
Image bitcoinCashIcon;
|
||||||
Image nanoIcon;
|
Image nanoIcon;
|
||||||
Image bananoIcon;
|
Image bananoIcon;
|
||||||
|
Image polygonIcon;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -219,6 +222,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
return nanoIcon;
|
return nanoIcon;
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return bananoIcon;
|
return bananoIcon;
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygonIcon;
|
||||||
default:
|
default:
|
||||||
throw Exception('No icon for ${type.toString()}');
|
throw Exception('No icon for ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/currency.dart';
|
import 'package:cw_core/currency.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -23,6 +24,13 @@ class CurrencyInputField extends StatelessWidget {
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final bool isLight;
|
final bool isLight;
|
||||||
|
|
||||||
|
String get _currencyName {
|
||||||
|
if (selectedCurrency is CryptoCurrency) {
|
||||||
|
return (selectedCurrency as CryptoCurrency).title.toUpperCase();
|
||||||
|
}
|
||||||
|
return selectedCurrency.name.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final arrowBottomPurple = Image.asset(
|
final arrowBottomPurple = Image.asset(
|
||||||
|
@ -74,7 +82,7 @@ class CurrencyInputField extends StatelessWidget {
|
||||||
child: arrowBottomPurple,
|
child: arrowBottomPurple,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
selectedCurrency.name.toUpperCase(),
|
_currencyName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
@ -83,7 +91,7 @@ class CurrencyInputField extends StatelessWidget {
|
||||||
),
|
),
|
||||||
if (selectedCurrency.tag != null)
|
if (selectedCurrency.tag != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 3.0),
|
padding: const EdgeInsets.symmetric(horizontal: 3.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
||||||
|
|
|
@ -2,9 +2,9 @@ import 'dart:async';
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/core/totp_request_details.dart';
|
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/utils/payment_request.dart';
|
import 'package:cake_wallet/utils/payment_request.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
|
@ -169,7 +169,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
);
|
);
|
||||||
launchUri = null;
|
launchUri = null;
|
||||||
} else if (isWalletConnectLink) {
|
} else if (isWalletConnectLink) {
|
||||||
if (widget.appStore.wallet!.type == WalletType.ethereum) {
|
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
|
||||||
widget.navigatorKey.currentState?.pushNamed(
|
widget.navigatorKey.currentState?.pushNamed(
|
||||||
Routes.walletConnectConnectionsListing,
|
Routes.walletConnectConnectionsListing,
|
||||||
arguments: launchUri,
|
arguments: launchUri,
|
||||||
|
@ -205,7 +205,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
|
|
||||||
String? _getRouteToGo() {
|
String? _getRouteToGo() {
|
||||||
if (isWalletConnectLink) {
|
if (isWalletConnectLink) {
|
||||||
if (widget.appStore.wallet!.type != WalletType.ethereum) {
|
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
|
||||||
_nonETHWalletErrorToast(S.current.switchToETHWallet);
|
_nonETHWalletErrorToast(S.current.switchToETHWallet);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ class PreSeedPage extends BasePage {
|
||||||
PreSeedPage(this.type, this.advancedPrivacySettingsViewModel)
|
PreSeedPage(this.type, this.advancedPrivacySettingsViewModel)
|
||||||
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
|
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
|
||||||
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
|
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
|
||||||
seedPhraseLength = advancedPrivacySettingsViewModel.seedPhraseLength.value {
|
seedPhraseLength =
|
||||||
|
advancedPrivacySettingsViewModel.seedPhraseLength.value {
|
||||||
wordsCount = _wordsCount(type, seedPhraseLength);
|
wordsCount = _wordsCount(type, seedPhraseLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,14 +41,14 @@ class PreSeedPage extends BasePage {
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
padding: EdgeInsets.all(24),
|
padding: EdgeInsets.all(24),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight: MediaQuery.of(context).size.height * 0.3
|
maxHeight: MediaQuery.of(context).size.height * 0.3),
|
||||||
),
|
|
||||||
child: AspectRatio(aspectRatio: 1, child: image),
|
child: AspectRatio(aspectRatio: 1, child: image),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -58,12 +59,14 @@ class PreSeedPage extends BasePage {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
|
color: Theme.of(context)
|
||||||
|
.extension<CakeTextTheme>()!
|
||||||
|
.secondaryTextColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PrimaryButton(
|
PrimaryButton(
|
||||||
onPressed: () =>
|
onPressed: () => Navigator.of(context)
|
||||||
Navigator.of(context).popAndPushNamed(Routes.seed, arguments: true),
|
.popAndPushNamed(Routes.seed, arguments: true),
|
||||||
text: S.of(context).pre_seed_button_text,
|
text: S.of(context).pre_seed_button_text,
|
||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
textColor: Colors.white)
|
textColor: Colors.white)
|
||||||
|
@ -79,6 +82,7 @@ class PreSeedPage extends BasePage {
|
||||||
return 25;
|
return 25;
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
|
case WalletType.polygon:
|
||||||
return seedPhraseLength;
|
return seedPhraseLength;
|
||||||
default:
|
default:
|
||||||
return 24;
|
return 24;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||||
|
@ -8,7 +9,6 @@ import 'package:cake_wallet/utils/feature_flag.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
@ -85,7 +85,7 @@ class ConnectionSyncPage extends BasePage {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (dashboardViewModel.wallet.type == WalletType.ethereum) ...[
|
if (isEVMCompatibleChain(dashboardViewModel.wallet.type)) ...[
|
||||||
WalletConnectTile(
|
WalletConnectTile(
|
||||||
onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing),
|
onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing),
|
||||||
),
|
),
|
||||||
|
@ -101,6 +101,7 @@ class ConnectionSyncPage extends BasePage {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> _presentReconnectAlert(BuildContext context) async {
|
Future<void> _presentReconnectAlert(BuildContext context) async {
|
||||||
await showPopUp<void>(
|
await showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
@ -87,6 +87,14 @@ class PrivacyPage extends BasePage {
|
||||||
onValueChange: (BuildContext _, bool value) {
|
onValueChange: (BuildContext _, bool value) {
|
||||||
_privacySettingsViewModel.setUseEtherscan(value);
|
_privacySettingsViewModel.setUseEtherscan(value);
|
||||||
}),
|
}),
|
||||||
|
if (_privacySettingsViewModel.canUsePolygonScan)
|
||||||
|
SettingsSwitcherCell(
|
||||||
|
title: S.current.polygonscan_history,
|
||||||
|
value: _privacySettingsViewModel.usePolygonScan,
|
||||||
|
onValueChange: (BuildContext _, bool value) {
|
||||||
|
_privacySettingsViewModel.setUsePolygonScan(value);
|
||||||
|
},
|
||||||
|
),
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
title: S.current.domain_looks_up,
|
title: S.current.domain_looks_up,
|
||||||
handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage),
|
handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage),
|
||||||
|
|
|
@ -14,12 +14,14 @@ import 'connection_widget.dart';
|
||||||
class ConnectionRequestWidget extends StatefulWidget {
|
class ConnectionRequestWidget extends StatefulWidget {
|
||||||
const ConnectionRequestWidget({
|
const ConnectionRequestWidget({
|
||||||
required this.wallet,
|
required this.wallet,
|
||||||
|
required this.chaindIdNamespace,
|
||||||
this.authRequest,
|
this.authRequest,
|
||||||
this.sessionProposal,
|
this.sessionProposal,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Web3Wallet wallet;
|
final Web3Wallet wallet;
|
||||||
|
final String chaindIdNamespace;
|
||||||
final AuthRequestModel? authRequest;
|
final AuthRequestModel? authRequest;
|
||||||
final SessionRequestModel? sessionProposal;
|
final SessionRequestModel? sessionProposal;
|
||||||
|
|
||||||
|
@ -52,23 +54,26 @@ class _ConnectionRequestWidgetState extends State<ConnectionRequestWidget> {
|
||||||
|
|
||||||
return _ConnectionMetadataDisplayWidget(
|
return _ConnectionMetadataDisplayWidget(
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
|
wallet: widget.wallet,
|
||||||
authRequest: widget.authRequest,
|
authRequest: widget.authRequest,
|
||||||
sessionProposal: widget.sessionProposal,
|
sessionProposal: widget.sessionProposal,
|
||||||
wallet: widget.wallet,
|
chaindIdNamespace: widget.chaindIdNamespace,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ConnectionMetadataDisplayWidget extends StatelessWidget {
|
class _ConnectionMetadataDisplayWidget extends StatelessWidget {
|
||||||
const _ConnectionMetadataDisplayWidget({
|
const _ConnectionMetadataDisplayWidget({
|
||||||
required this.metadata,
|
|
||||||
required this.wallet,
|
required this.wallet,
|
||||||
this.authRequest,
|
required this.metadata,
|
||||||
required this.sessionProposal,
|
required this.sessionProposal,
|
||||||
|
required this.chaindIdNamespace,
|
||||||
|
this.authRequest,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ConnectionMetadata? metadata;
|
final ConnectionMetadata? metadata;
|
||||||
final Web3Wallet wallet;
|
final Web3Wallet wallet;
|
||||||
|
final String chaindIdNamespace;
|
||||||
final AuthRequestModel? authRequest;
|
final AuthRequestModel? authRequest;
|
||||||
final SessionRequestModel? sessionProposal;
|
final SessionRequestModel? sessionProposal;
|
||||||
|
|
||||||
|
@ -114,7 +119,11 @@ class _ConnectionMetadataDisplayWidget extends StatelessWidget {
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: authRequest != null,
|
visible: authRequest != null,
|
||||||
child: _AuthRequestWidget(wallet: wallet, authRequest: authRequest),
|
child: _AuthRequestWidget(
|
||||||
|
wallet: wallet,
|
||||||
|
authRequest: authRequest,
|
||||||
|
chaindIdNamespace: chaindIdNamespace,
|
||||||
|
),
|
||||||
|
|
||||||
//If authRequest is null, sessionProposal is not null.
|
//If authRequest is null, sessionProposal is not null.
|
||||||
replacement: _SessionProposalWidget(sessionProposal: sessionProposal!),
|
replacement: _SessionProposalWidget(sessionProposal: sessionProposal!),
|
||||||
|
@ -126,16 +135,21 @@ class _ConnectionMetadataDisplayWidget extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AuthRequestWidget extends StatelessWidget {
|
class _AuthRequestWidget extends StatelessWidget {
|
||||||
const _AuthRequestWidget({required this.wallet, this.authRequest});
|
const _AuthRequestWidget({
|
||||||
|
required this.wallet,
|
||||||
|
required this.chaindIdNamespace,
|
||||||
|
this.authRequest,
|
||||||
|
});
|
||||||
|
|
||||||
final Web3Wallet wallet;
|
final Web3Wallet wallet;
|
||||||
|
final String chaindIdNamespace;
|
||||||
final AuthRequestModel? authRequest;
|
final AuthRequestModel? authRequest;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final model = ConnectionModel(
|
final model = ConnectionModel(
|
||||||
text: wallet.formatAuthMessage(
|
text: wallet.formatAuthMessage(
|
||||||
iss: 'did:pkh:eip155:1:${authRequest!.iss}',
|
iss: 'did:pkh:$chaindIdNamespace:${authRequest!.iss}',
|
||||||
cacaoPayload: CacaoRequestPayload.fromPayloadParams(
|
cacaoPayload: CacaoRequestPayload.fromPayloadParams(
|
||||||
authRequest!.request.payloadParams,
|
authRequest!.request.payloadParams,
|
||||||
),
|
),
|
||||||
|
|
|
@ -49,6 +49,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
||||||
final bitcoinCashIcon = Image.asset('assets/images/bch_icon.png', height: 24, width: 24);
|
final bitcoinCashIcon = Image.asset('assets/images/bch_icon.png', height: 24, width: 24);
|
||||||
final nanoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
|
final nanoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
|
||||||
|
final polygonIcon = Image.asset('assets/images/matic_icon.png', height: 24, width: 24);
|
||||||
final scrollController = ScrollController();
|
final scrollController = ScrollController();
|
||||||
final double tileHeight = 60;
|
final double tileHeight = 60;
|
||||||
Flushbar<void>? _progressBar;
|
Flushbar<void>? _progressBar;
|
||||||
|
@ -256,6 +257,8 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
return bitcoinCashIcon;
|
return bitcoinCashIcon;
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nanoIcon;
|
return nanoIcon;
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygonIcon;
|
||||||
default:
|
default:
|
||||||
return nonWalletTypeIcon;
|
return nonWalletTypeIcon;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
@ -44,7 +44,7 @@ abstract class AppStoreBase with Store {
|
||||||
this.wallet = wallet;
|
this.wallet = wallet;
|
||||||
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
|
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
|
||||||
|
|
||||||
if (wallet.type == WalletType.ethereum) {
|
if (isEVMCompatibleChain(wallet.type)) {
|
||||||
getIt.get<Web3WalletService>().init();
|
getIt.get<Web3WalletService>().init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||||
import 'package:cake_wallet/entities/seed_type.dart';
|
import 'package:cake_wallet/entities/seed_type.dart';
|
||||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
|
@ -88,6 +89,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
required this.sortBalanceBy,
|
required this.sortBalanceBy,
|
||||||
required this.pinNativeTokenAtTop,
|
required this.pinNativeTokenAtTop,
|
||||||
required this.useEtherscan,
|
required this.useEtherscan,
|
||||||
|
required this.usePolygonScan,
|
||||||
required this.defaultNanoRep,
|
required this.defaultNanoRep,
|
||||||
required this.defaultBananoRep,
|
required this.defaultBananoRep,
|
||||||
required this.lookupsTwitter,
|
required this.lookupsTwitter,
|
||||||
|
@ -101,6 +103,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
TransactionPriority? initialHavenTransactionPriority,
|
TransactionPriority? initialHavenTransactionPriority,
|
||||||
TransactionPriority? initialLitecoinTransactionPriority,
|
TransactionPriority? initialLitecoinTransactionPriority,
|
||||||
TransactionPriority? initialEthereumTransactionPriority,
|
TransactionPriority? initialEthereumTransactionPriority,
|
||||||
|
TransactionPriority? initialPolygonTransactionPriority,
|
||||||
TransactionPriority? initialBitcoinCashTransactionPriority})
|
TransactionPriority? initialBitcoinCashTransactionPriority})
|
||||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||||
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
|
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
|
||||||
|
@ -165,6 +168,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
priority[WalletType.ethereum] = initialEthereumTransactionPriority;
|
priority[WalletType.ethereum] = initialEthereumTransactionPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initialPolygonTransactionPriority != null) {
|
||||||
|
priority[WalletType.polygon] = initialPolygonTransactionPriority;
|
||||||
|
}
|
||||||
|
|
||||||
if (initialBitcoinCashTransactionPriority != null) {
|
if (initialBitcoinCashTransactionPriority != null) {
|
||||||
priority[WalletType.bitcoinCash] = initialBitcoinCashTransactionPriority;
|
priority[WalletType.bitcoinCash] = initialBitcoinCashTransactionPriority;
|
||||||
}
|
}
|
||||||
|
@ -202,6 +209,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
key = PreferencesKey.bitcoinCashTransactionPriority;
|
key = PreferencesKey.bitcoinCashTransactionPriority;
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
key = PreferencesKey.polygonTransactionPriority;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
key = null;
|
key = null;
|
||||||
}
|
}
|
||||||
|
@ -245,8 +255,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => moneroSeedType,
|
(_) => moneroSeedType,
|
||||||
(SeedType moneroSeedType) => sharedPreferences.setInt(
|
(SeedType moneroSeedType) =>
|
||||||
PreferencesKey.moneroSeedType, moneroSeedType.raw));
|
sharedPreferences.setInt(PreferencesKey.moneroSeedType, moneroSeedType.raw));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => fiatApiMode,
|
(_) => fiatApiMode,
|
||||||
|
@ -343,8 +353,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => seedPhraseLength,
|
(_) => seedPhraseLength,
|
||||||
(SeedPhraseLength seedPhraseWordCount) =>
|
(SeedPhraseLength seedPhraseWordCount) => sharedPreferences.setInt(
|
||||||
sharedPreferences.setInt(PreferencesKey.currentSeedPhraseLength, seedPhraseWordCount.value));
|
PreferencesKey.currentSeedPhraseLength, seedPhraseWordCount.value));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => pinTimeOutDuration,
|
(_) => pinTimeOutDuration,
|
||||||
|
@ -388,6 +398,11 @@ abstract class SettingsStoreBase with Store {
|
||||||
(bool useEtherscan) =>
|
(bool useEtherscan) =>
|
||||||
_sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan));
|
_sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan));
|
||||||
|
|
||||||
|
reaction(
|
||||||
|
(_) => usePolygonScan,
|
||||||
|
(bool usePolygonScan) =>
|
||||||
|
_sharedPreferences.setBool(PreferencesKey.usePolygonScan, usePolygonScan));
|
||||||
|
|
||||||
reaction((_) => defaultNanoRep,
|
reaction((_) => defaultNanoRep,
|
||||||
(String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
|
(String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
|
||||||
|
|
||||||
|
@ -412,18 +427,16 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => lookupsUnstoppableDomains,
|
(_) => lookupsUnstoppableDomains,
|
||||||
(bool looksUpUnstoppableDomains) =>
|
(bool looksUpUnstoppableDomains) => _sharedPreferences.setBool(
|
||||||
_sharedPreferences.setBool(PreferencesKey.lookupsUnstoppableDomains, looksUpUnstoppableDomains));
|
PreferencesKey.lookupsUnstoppableDomains, looksUpUnstoppableDomains));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => lookupsOpenAlias,
|
(_) => lookupsOpenAlias,
|
||||||
(bool looksUpOpenAlias) =>
|
(bool looksUpOpenAlias) =>
|
||||||
_sharedPreferences.setBool(PreferencesKey.lookupsOpenAlias, looksUpOpenAlias));
|
_sharedPreferences.setBool(PreferencesKey.lookupsOpenAlias, looksUpOpenAlias));
|
||||||
|
|
||||||
reaction(
|
reaction((_) => lookupsENS,
|
||||||
(_) => lookupsENS,
|
(bool looksUpENS) => _sharedPreferences.setBool(PreferencesKey.lookupsENS, looksUpENS));
|
||||||
(bool looksUpENS) =>
|
|
||||||
_sharedPreferences.setBool(PreferencesKey.lookupsENS, looksUpENS));
|
|
||||||
|
|
||||||
this.nodes.observe((change) {
|
this.nodes.observe((change) {
|
||||||
if (change.newValue != null && change.key != null) {
|
if (change.newValue != null && change.key != null) {
|
||||||
|
@ -562,6 +575,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
bool useEtherscan;
|
bool useEtherscan;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool usePolygonScan;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
String defaultNanoRep;
|
String defaultNanoRep;
|
||||||
|
|
||||||
|
@ -651,6 +667,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
TransactionPriority? havenTransactionPriority;
|
TransactionPriority? havenTransactionPriority;
|
||||||
TransactionPriority? litecoinTransactionPriority;
|
TransactionPriority? litecoinTransactionPriority;
|
||||||
TransactionPriority? ethereumTransactionPriority;
|
TransactionPriority? ethereumTransactionPriority;
|
||||||
|
TransactionPriority? polygonTransactionPriority;
|
||||||
TransactionPriority? bitcoinCashTransactionPriority;
|
TransactionPriority? bitcoinCashTransactionPriority;
|
||||||
|
|
||||||
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
|
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
|
||||||
|
@ -662,9 +679,13 @@ abstract class SettingsStoreBase with Store {
|
||||||
sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!);
|
sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!);
|
||||||
}
|
}
|
||||||
if (sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority) != null) {
|
if (sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority) != null) {
|
||||||
ethereumTransactionPriority = bitcoin?.deserializeLitecoinTransactionPriority(
|
ethereumTransactionPriority = ethereum?.deserializeEthereumTransactionPriority(
|
||||||
sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!);
|
sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!);
|
||||||
}
|
}
|
||||||
|
if (sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority) != null) {
|
||||||
|
polygonTransactionPriority = polygon?.deserializePolygonTransactionPriority(
|
||||||
|
sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority)!);
|
||||||
|
}
|
||||||
if (sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority) != null) {
|
if (sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority) != null) {
|
||||||
bitcoinCashTransactionPriority = bitcoinCash?.deserializeBitcoinCashTransactionPriority(
|
bitcoinCashTransactionPriority = bitcoinCash?.deserializeBitcoinCashTransactionPriority(
|
||||||
sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!);
|
sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!);
|
||||||
|
@ -676,6 +697,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium();
|
litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium();
|
||||||
ethereumTransactionPriority ??= ethereum?.getDefaultTransactionPriority();
|
ethereumTransactionPriority ??= ethereum?.getDefaultTransactionPriority();
|
||||||
bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority();
|
bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority();
|
||||||
|
polygonTransactionPriority ??= polygon?.getDefaultTransactionPriority();
|
||||||
|
|
||||||
final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
|
final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
|
||||||
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
||||||
|
@ -749,12 +771,14 @@ abstract class SettingsStoreBase with Store {
|
||||||
final pinNativeTokenAtTop =
|
final pinNativeTokenAtTop =
|
||||||
sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
|
sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
|
||||||
final useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
final useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
||||||
|
final usePolygonScan = sharedPreferences.getBool(PreferencesKey.usePolygonScan) ?? true;
|
||||||
final defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
final defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
||||||
final defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
final defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
||||||
final lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
final lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
||||||
final lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
|
final lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
|
||||||
final lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
|
final lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
|
||||||
final lookupsUnstoppableDomains = sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
|
final lookupsUnstoppableDomains =
|
||||||
|
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
|
||||||
final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
||||||
final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
||||||
|
|
||||||
|
@ -774,6 +798,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
|
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
|
||||||
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||||
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
||||||
|
final polygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
|
||||||
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||||
final nanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
|
final nanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
|
||||||
final moneroNode = nodeSource.get(nodeId);
|
final moneroNode = nodeSource.get(nodeId);
|
||||||
|
@ -781,6 +806,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||||
final havenNode = nodeSource.get(havenNodeId);
|
final havenNode = nodeSource.get(havenNodeId);
|
||||||
final ethereumNode = nodeSource.get(ethereumNodeId);
|
final ethereumNode = nodeSource.get(ethereumNodeId);
|
||||||
|
final polygonNode = nodeSource.get(polygonNodeId);
|
||||||
final bitcoinCashElectrumServer = nodeSource.get(bitcoinCashElectrumServerId);
|
final bitcoinCashElectrumServer = nodeSource.get(bitcoinCashElectrumServerId);
|
||||||
final nanoNode = nodeSource.get(nanoNodeId);
|
final nanoNode = nodeSource.get(nanoNodeId);
|
||||||
final nanoPowNode = powNodeSource.get(nanoPowNodeId);
|
final nanoPowNode = powNodeSource.get(nanoPowNodeId);
|
||||||
|
@ -824,6 +850,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
nodes[WalletType.ethereum] = ethereumNode;
|
nodes[WalletType.ethereum] = ethereumNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (polygonNode != null) {
|
||||||
|
nodes[WalletType.polygon] = polygonNode;
|
||||||
|
}
|
||||||
|
|
||||||
if (bitcoinCashElectrumServer != null) {
|
if (bitcoinCashElectrumServer != null) {
|
||||||
nodes[WalletType.bitcoinCash] = bitcoinCashElectrumServer;
|
nodes[WalletType.bitcoinCash] = bitcoinCashElectrumServer;
|
||||||
}
|
}
|
||||||
|
@ -869,10 +899,12 @@ abstract class SettingsStoreBase with Store {
|
||||||
actionlistDisplayMode: actionListDisplayMode,
|
actionlistDisplayMode: actionListDisplayMode,
|
||||||
initialPinLength: pinLength,
|
initialPinLength: pinLength,
|
||||||
pinTimeOutDuration: pinCodeTimeOutDuration,
|
pinTimeOutDuration: pinCodeTimeOutDuration,
|
||||||
seedPhraseLength: seedPhraseWordCount,initialLanguageCode: savedLanguageCode,
|
seedPhraseLength: seedPhraseWordCount,
|
||||||
|
initialLanguageCode: savedLanguageCode,
|
||||||
sortBalanceBy: sortBalanceBy,
|
sortBalanceBy: sortBalanceBy,
|
||||||
pinNativeTokenAtTop: pinNativeTokenAtTop,
|
pinNativeTokenAtTop: pinNativeTokenAtTop,
|
||||||
useEtherscan: useEtherscan,
|
useEtherscan: useEtherscan,
|
||||||
|
usePolygonScan: usePolygonScan,
|
||||||
defaultNanoRep: defaultNanoRep,
|
defaultNanoRep: defaultNanoRep,
|
||||||
defaultBananoRep: defaultBananoRep,
|
defaultBananoRep: defaultBananoRep,
|
||||||
lookupsTwitter: lookupsTwitter,
|
lookupsTwitter: lookupsTwitter,
|
||||||
|
@ -900,6 +932,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
|
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
|
||||||
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||||
initialEthereumTransactionPriority: ethereumTransactionPriority,
|
initialEthereumTransactionPriority: ethereumTransactionPriority,
|
||||||
|
initialPolygonTransactionPriority: polygonTransactionPriority,
|
||||||
backgroundTasks: backgroundTasks,
|
backgroundTasks: backgroundTasks,
|
||||||
initialSyncMode: savedSyncMode,
|
initialSyncMode: savedSyncMode,
|
||||||
initialSyncAll: savedSyncAll,
|
initialSyncAll: savedSyncAll,
|
||||||
|
@ -934,6 +967,11 @@ abstract class SettingsStoreBase with Store {
|
||||||
sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!) ??
|
sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!) ??
|
||||||
priority[WalletType.ethereum]!;
|
priority[WalletType.ethereum]!;
|
||||||
}
|
}
|
||||||
|
if (sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority) != null) {
|
||||||
|
priority[WalletType.polygon] = polygon?.deserializePolygonTransactionPriority(
|
||||||
|
sharedPreferences.getInt(PreferencesKey.polygonTransactionPriority)!) ??
|
||||||
|
priority[WalletType.polygon]!;
|
||||||
|
}
|
||||||
if (sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority) != null) {
|
if (sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority) != null) {
|
||||||
priority[WalletType.bitcoinCash] = bitcoinCash?.deserializeBitcoinCashTransactionPriority(
|
priority[WalletType.bitcoinCash] = bitcoinCash?.deserializeBitcoinCashTransactionPriority(
|
||||||
sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!) ??
|
sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!) ??
|
||||||
|
@ -1027,12 +1065,14 @@ abstract class SettingsStoreBase with Store {
|
||||||
.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? sortBalanceBy.index];
|
.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? sortBalanceBy.index];
|
||||||
pinNativeTokenAtTop = sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
|
pinNativeTokenAtTop = sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
|
||||||
useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
||||||
|
usePolygonScan = sharedPreferences.getBool(PreferencesKey.usePolygonScan) ?? true;
|
||||||
defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
||||||
defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
||||||
lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
||||||
lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
|
lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
|
||||||
lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
|
lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
|
||||||
lookupsUnstoppableDomains = sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
|
lookupsUnstoppableDomains =
|
||||||
|
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
|
||||||
lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
||||||
lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
||||||
|
|
||||||
|
@ -1045,6 +1085,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
|
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
|
||||||
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||||
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
||||||
|
final polygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
|
||||||
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||||
final nanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
final nanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||||
final moneroNode = nodeSource.get(nodeId);
|
final moneroNode = nodeSource.get(nodeId);
|
||||||
|
@ -1052,6 +1093,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||||
final havenNode = nodeSource.get(havenNodeId);
|
final havenNode = nodeSource.get(havenNodeId);
|
||||||
final ethereumNode = nodeSource.get(ethereumNodeId);
|
final ethereumNode = nodeSource.get(ethereumNodeId);
|
||||||
|
final polygonNode = nodeSource.get(polygonNodeId);
|
||||||
final bitcoinCashNode = nodeSource.get(bitcoinCashElectrumServerId);
|
final bitcoinCashNode = nodeSource.get(bitcoinCashElectrumServerId);
|
||||||
final nanoNode = nodeSource.get(nanoNodeId);
|
final nanoNode = nodeSource.get(nanoNodeId);
|
||||||
|
|
||||||
|
@ -1075,6 +1117,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
nodes[WalletType.ethereum] = ethereumNode;
|
nodes[WalletType.ethereum] = ethereumNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (polygonNode != null) {
|
||||||
|
nodes[WalletType.polygon] = polygonNode;
|
||||||
|
}
|
||||||
|
|
||||||
if (bitcoinCashNode != null) {
|
if (bitcoinCashNode != null) {
|
||||||
nodes[WalletType.bitcoinCash] = bitcoinCashNode;
|
nodes[WalletType.bitcoinCash] = bitcoinCashNode;
|
||||||
}
|
}
|
||||||
|
@ -1110,6 +1156,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
await _sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, node.key as int);
|
await _sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, node.key as int);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
await _sharedPreferences.setInt(PreferencesKey.currentPolygonNodeIdKey, node.key as int);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1141,7 +1190,6 @@ abstract class SettingsStoreBase with Store {
|
||||||
trocadorProviderStates[providerName] = state;
|
trocadorProviderStates[providerName] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Future<String?> _getDeviceName() async {
|
static Future<String?> _getDeviceName() async {
|
||||||
String? deviceName = '';
|
String? deviceName = '';
|
||||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
|
@ -81,7 +82,7 @@ abstract class BalanceViewModelBase with Store {
|
||||||
bool get isFiatDisabled => settingsStore.fiatApiMode == FiatApiMode.disabled;
|
bool get isFiatDisabled => settingsStore.fiatApiMode == FiatApiMode.disabled;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isHomeScreenSettingsEnabled => wallet.type == WalletType.ethereum;
|
bool get isHomeScreenSettingsEnabled => isEVMCompatibleChain(wallet.type);
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get hasAccounts => wallet.type == WalletType.monero;
|
bool get hasAccounts => wallet.type == WalletType.monero;
|
||||||
|
@ -123,6 +124,7 @@ abstract class BalanceViewModelBase with Store {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
case WalletType.polygon:
|
||||||
return S.current.xmr_available_balance;
|
return S.current.xmr_available_balance;
|
||||||
default:
|
default:
|
||||||
return S.current.confirmed;
|
return S.current.confirmed;
|
||||||
|
@ -135,6 +137,7 @@ abstract class BalanceViewModelBase with Store {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
case WalletType.polygon:
|
||||||
return S.current.xmr_full_balance;
|
return S.current.xmr_full_balance;
|
||||||
default:
|
default:
|
||||||
return S.current.unconfirmed;
|
return S.current.unconfirmed;
|
||||||
|
@ -272,7 +275,8 @@ abstract class BalanceViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get hasAdditionalBalance => wallet.type != WalletType.ethereum;
|
bool get hasAdditionalBalance => !isEVMCompatibleChain(wallet.type);
|
||||||
|
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
List<BalanceRecord> get formattedBalances {
|
List<BalanceRecord> get formattedBalances {
|
||||||
|
|
|
@ -2,10 +2,12 @@ import 'package:cake_wallet/core/fiat_conversion_service.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/erc20_token.dart';
|
import 'package:cw_core/erc20_token.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'home_settings_view_model.g.dart';
|
part 'home_settings_view_model.g.dart';
|
||||||
|
@ -42,18 +44,41 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
void setPinNativeToken(bool value) => _settingsStore.pinNativeTokenAtTop = value;
|
void setPinNativeToken(bool value) => _settingsStore.pinNativeTokenAtTop = value;
|
||||||
|
|
||||||
Future<void> addErc20Token(Erc20Token token) async {
|
Future<void> addErc20Token(Erc20Token token) async {
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
|
||||||
await ethereum!.addErc20Token(_balanceViewModel.wallet, token);
|
await ethereum!.addErc20Token(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.polygon) {
|
||||||
|
await polygon!.addErc20Token(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
|
|
||||||
_updateTokensList();
|
_updateTokensList();
|
||||||
_updateFiatPrices(token);
|
_updateFiatPrices(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteErc20Token(Erc20Token token) async {
|
Future<void> deleteErc20Token(Erc20Token token) async {
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
|
||||||
await ethereum!.deleteErc20Token(_balanceViewModel.wallet, token);
|
await ethereum!.deleteErc20Token(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.polygon) {
|
||||||
|
await polygon!.deleteErc20Token(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
|
|
||||||
_updateTokensList();
|
_updateTokensList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Erc20Token?> getErc20Token(String contractAddress) async =>
|
Future<Erc20Token?> getErc20Token(String contractAddress) async {
|
||||||
await ethereum!.getErc20Token(_balanceViewModel.wallet, contractAddress);
|
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
|
||||||
|
return await ethereum!.getErc20Token(_balanceViewModel.wallet, contractAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.polygon) {
|
||||||
|
return await polygon!.getErc20Token(_balanceViewModel.wallet, contractAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
CryptoCurrency get nativeToken => _balanceViewModel.wallet.currency;
|
CryptoCurrency get nativeToken => _balanceViewModel.wallet.currency;
|
||||||
|
|
||||||
|
@ -69,7 +94,12 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
|
|
||||||
void changeTokenAvailability(Erc20Token token, bool value) async {
|
void changeTokenAvailability(Erc20Token token, bool value) async {
|
||||||
token.enabled = value;
|
token.enabled = value;
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
|
||||||
ethereum!.addErc20Token(_balanceViewModel.wallet, token);
|
ethereum!.addErc20Token(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.polygon) {
|
||||||
|
polygon!.addErc20Token(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
_refreshTokensList();
|
_refreshTokensList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +113,8 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (e2.enabled && !e1.enabled) {
|
} else if (e2.enabled && !e1.enabled) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!e1.enabled && !e2.enabled) { // if both are disabled then sort alphabetically
|
} else if (!e1.enabled && !e2.enabled) {
|
||||||
|
// if both are disabled then sort alphabetically
|
||||||
return e1.name.compareTo(e2.name);
|
return e1.name.compareTo(e2.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +123,7 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
|
|
||||||
tokens.clear();
|
tokens.clear();
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
|
||||||
tokens.addAll(ethereum!
|
tokens.addAll(ethereum!
|
||||||
.getERC20Currencies(_balanceViewModel.wallet)
|
.getERC20Currencies(_balanceViewModel.wallet)
|
||||||
.where((element) => _matchesSearchText(element))
|
.where((element) => _matchesSearchText(element))
|
||||||
|
@ -99,6 +131,15 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
..sort(_sortFunc));
|
..sort(_sortFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.polygon) {
|
||||||
|
tokens.addAll(polygon!
|
||||||
|
.getERC20Currencies(_balanceViewModel.wallet)
|
||||||
|
.where((element) => _matchesSearchText(element))
|
||||||
|
.toList()
|
||||||
|
..sort(_sortFunc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void _refreshTokensList() {
|
void _refreshTokensList() {
|
||||||
final _tokens = Set.of(tokens);
|
final _tokens = Set.of(tokens);
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
|
@ -39,23 +38,26 @@ abstract class NFTViewModelBase with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> getNFTAssetByWallet() async {
|
Future<void> getNFTAssetByWallet() async {
|
||||||
if (appStore.wallet!.type != WalletType.ethereum) return;
|
if (!isEVMCompatibleChain(appStore.wallet!.type)) return;
|
||||||
|
|
||||||
final walletAddress = appStore.wallet!.walletInfo.address;
|
final walletAddress = appStore.wallet!.walletInfo.address;
|
||||||
log('Fetching wallet NFTs for $walletAddress');
|
log('Fetching wallet NFTs for $walletAddress');
|
||||||
|
|
||||||
|
final chainName = getChainNameBasedOnWalletType(appStore.wallet!.type);
|
||||||
// the [chain] refers to the chain network that the nft is on
|
// the [chain] refers to the chain network that the nft is on
|
||||||
// the [format] refers to the number format type of the responses
|
// the [format] refers to the number format type of the responses
|
||||||
// the [normalizedMetadata] field is a boolean that determines if
|
// the [normalizedMetadata] field is a boolean that determines if
|
||||||
// the response would include a json string of the NFT Metadata that can be decoded
|
// the response would include a json string of the NFT Metadata that can be decoded
|
||||||
// and used within the wallet
|
// and used within the wallet
|
||||||
|
// the [excludeSpam] field is a boolean that determines if spam nfts be excluded from the response.
|
||||||
final uri = Uri.https(
|
final uri = Uri.https(
|
||||||
'deep-index.moralis.io',
|
'deep-index.moralis.io',
|
||||||
'/api/v2.2/$walletAddress/nft',
|
'/api/v2.2/$walletAddress/nft',
|
||||||
{
|
{
|
||||||
"chain": "eth",
|
"chain": chainName,
|
||||||
"format": "decimal",
|
"format": "decimal",
|
||||||
"media_items": "false",
|
"media_items": "false",
|
||||||
|
"exclude_spam": "true",
|
||||||
"normalizeMetadata": "true",
|
"normalizeMetadata": "true",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -94,7 +96,7 @@ abstract class NFTViewModelBase with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> importNFT(String tokenAddress, String tokenId) async {
|
Future<void> importNFT(String tokenAddress, String tokenId) async {
|
||||||
|
final chainName = getChainNameBasedOnWalletType(appStore.wallet!.type);
|
||||||
// the [chain] refers to the chain network that the nft is on
|
// the [chain] refers to the chain network that the nft is on
|
||||||
// the [format] refers to the number format type of the responses
|
// the [format] refers to the number format type of the responses
|
||||||
// the [normalizedMetadata] field is a boolean that determines if
|
// the [normalizedMetadata] field is a boolean that determines if
|
||||||
|
@ -104,7 +106,7 @@ abstract class NFTViewModelBase with Store {
|
||||||
'deep-index.moralis.io',
|
'deep-index.moralis.io',
|
||||||
'/api/v2.2/nft/$tokenAddress/$tokenId',
|
'/api/v2.2/nft/$tokenAddress/$tokenId',
|
||||||
{
|
{
|
||||||
"chain": "eth",
|
"chain": chainName,
|
||||||
"format": "decimal",
|
"format": "decimal",
|
||||||
"media_items": "false",
|
"media_items": "false",
|
||||||
"normalizeMetadata": "true",
|
"normalizeMetadata": "true",
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
@ -91,6 +92,13 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
cryptoAmount: ethereum!.formatterEthereumAmountToDouble(transaction: transaction),
|
cryptoAmount: ethereum!.formatterEthereumAmountToDouble(transaction: transaction),
|
||||||
price: price);
|
price: price);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
final asset = polygon!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||||
|
final price = balanceViewModel.fiatConvertationStore.prices[asset];
|
||||||
|
amount = calculateFiatAmountRaw(
|
||||||
|
cryptoAmount: polygon!.formatterPolygonAmountToDouble(transaction: transaction),
|
||||||
|
price: price);
|
||||||
|
break;
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
amount = calculateFiatAmountRaw(
|
amount = calculateFiatAmountRaw(
|
||||||
cryptoAmount: double.parse(nanoUtil!.getRawAsDecimalString(
|
cryptoAmount: double.parse(nanoUtil!.getRawAsDecimalString(
|
||||||
|
|
|
@ -28,10 +28,7 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
required this.tradesStore,
|
required this.tradesStore,
|
||||||
required this.sendViewModel})
|
required this.sendViewModel})
|
||||||
: trade = tradesStore.trade!,
|
: trade = tradesStore.trade!,
|
||||||
isSendable = tradesStore.trade!.from == wallet.currency ||
|
isSendable = _checkIfCanSend(tradesStore, wallet),
|
||||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
|
|
||||||
(wallet.currency == CryptoCurrency.eth &&
|
|
||||||
tradesStore.trade!.from.tag == CryptoCurrency.eth.title),
|
|
||||||
items = ObservableList<ExchangeTradeItem>() {
|
items = ObservableList<ExchangeTradeItem>() {
|
||||||
switch (trade.provider) {
|
switch (trade.provider) {
|
||||||
case ExchangeProviderDescription.changeNow:
|
case ExchangeProviderDescription.changeNow:
|
||||||
|
@ -155,4 +152,19 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
isCopied: true),
|
isCopied: true),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
|
||||||
|
bool _isEthToken() =>
|
||||||
|
wallet.currency == CryptoCurrency.eth &&
|
||||||
|
tradesStore.trade!.from.tag == CryptoCurrency.eth.title;
|
||||||
|
|
||||||
|
bool _isPolygonToken() =>
|
||||||
|
wallet.currency == CryptoCurrency.maticpoly &&
|
||||||
|
tradesStore.trade!.from.tag == CryptoCurrency.maticpoly.tag;
|
||||||
|
|
||||||
|
return tradesStore.trade!.from == wallet.currency ||
|
||||||
|
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
|
||||||
|
_isEthToken() ||
|
||||||
|
_isPolygonToken();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import 'package:cake_wallet/exchange/trade.dart';
|
||||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
@ -287,6 +288,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
return transactionPriority == ethereum!.getEthereumTransactionPrioritySlow();
|
return transactionPriority == ethereum!.getEthereumTransactionPrioritySlow();
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
return transactionPriority == bitcoinCash!.getBitcoinCashTransactionPrioritySlow();
|
return transactionPriority == bitcoinCash!.getBitcoinCashTransactionPrioritySlow();
|
||||||
|
case WalletType.polygon:
|
||||||
|
return transactionPriority == polygon!.getPolygonTransactionPrioritySlow();
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -626,6 +629,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
depositCurrency = CryptoCurrency.nano;
|
depositCurrency = CryptoCurrency.nano;
|
||||||
receiveCurrency = CryptoCurrency.xmr;
|
receiveCurrency = CryptoCurrency.xmr;
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
depositCurrency = CryptoCurrency.maticpoly;
|
||||||
|
receiveCurrency = CryptoCurrency.xmr;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -713,6 +720,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
_settingsStore.priority[wallet.type] = bitcoinCash!.getDefaultTransactionPriority();
|
_settingsStore.priority[wallet.type] = bitcoinCash!.getDefaultTransactionPriority();
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
_settingsStore.priority[wallet.type] = polygon!.getDefaultTransactionPriority();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,9 @@ abstract class NodeListViewModelBase with Store {
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
node = getNanoDefaultNode(nodes: _nodeSource)!;
|
node = getNanoDefaultNode(nodes: _nodeSource)!;
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
node = getPolygonDefaultNode(nodes: _nodeSource)!;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${_appStore.wallet!.type}');
|
throw Exception('Unexpected wallet type: ${_appStore.wallet!.type}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
@ -71,6 +72,9 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
|
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
|
||||||
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.createPolygonRestoreWalletFromPrivateKey(
|
||||||
|
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected type: ${restoreWallet.type.toString()}');
|
throw Exception('Unexpected type: ${restoreWallet.type.toString()}');
|
||||||
}
|
}
|
||||||
|
@ -95,6 +99,9 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
||||||
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
||||||
|
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected type: ${type.toString()}');
|
throw Exception('Unexpected type: ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ class WalletRestoreFromQRCode {
|
||||||
'litecoin-wallet': WalletType.litecoin,
|
'litecoin-wallet': WalletType.litecoin,
|
||||||
'litecoin_wallet': WalletType.litecoin,
|
'litecoin_wallet': WalletType.litecoin,
|
||||||
'ethereum-wallet': WalletType.ethereum,
|
'ethereum-wallet': WalletType.ethereum,
|
||||||
|
'polygon-wallet': WalletType.polygon,
|
||||||
'nano-wallet': WalletType.nano,
|
'nano-wallet': WalletType.nano,
|
||||||
'nano_wallet': WalletType.nano,
|
'nano_wallet': WalletType.nano,
|
||||||
'bitcoincash': WalletType.bitcoinCash,
|
'bitcoincash': WalletType.bitcoinCash,
|
||||||
|
@ -157,7 +158,16 @@ class WalletRestoreFromQRCode {
|
||||||
return WalletRestoreMode.keys;
|
return WalletRestoreMode.keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((type == WalletType.nano || type == WalletType.banano) && credentials.containsKey('hexSeed')) {
|
if (type == WalletType.polygon && credentials.containsKey('private_key')) {
|
||||||
|
final privateKey = credentials['private_key'] as String;
|
||||||
|
if (privateKey.isEmpty) {
|
||||||
|
throw Exception('Unexpected restore mode: private_key');
|
||||||
|
}
|
||||||
|
return WalletRestoreMode.keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((type == WalletType.nano || type == WalletType.banano) &&
|
||||||
|
credentials.containsKey('hexSeed')) {
|
||||||
final hexSeed = credentials['hexSeed'] as String;
|
final hexSeed = credentials['hexSeed'] as String;
|
||||||
if (hexSeed.isEmpty) {
|
if (hexSeed.isEmpty) {
|
||||||
throw Exception('Unexpected restore mode: hexSeed');
|
throw Exception('Unexpected restore mode: hexSeed');
|
||||||
|
|
|
@ -4,6 +4,8 @@ import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/haven/haven.dart';
|
import 'package:cake_wallet/haven/haven.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
|
import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -27,7 +29,8 @@ const String cryptoNumberPattern = '0.0';
|
||||||
class Output = OutputBase with _$Output;
|
class Output = OutputBase with _$Output;
|
||||||
|
|
||||||
abstract class OutputBase with Store {
|
abstract class OutputBase with Store {
|
||||||
OutputBase(this._wallet, this._settingsStore, this._fiatConversationStore, this.cryptoCurrencyHandler)
|
OutputBase(
|
||||||
|
this._wallet, this._settingsStore, this._fiatConversationStore, this.cryptoCurrencyHandler)
|
||||||
: _cryptoNumberFormat = NumberFormat(cryptoNumberPattern),
|
: _cryptoNumberFormat = NumberFormat(cryptoNumberPattern),
|
||||||
key = UniqueKey(),
|
key = UniqueKey(),
|
||||||
sendAll = false,
|
sendAll = false,
|
||||||
|
@ -65,8 +68,7 @@ abstract class OutputBase with Store {
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isParsedAddress =>
|
bool get isParsedAddress =>
|
||||||
parsedAddress.parseFrom != ParseFrom.notParsed &&
|
parsedAddress.parseFrom != ParseFrom.notParsed && parsedAddress.name.isNotEmpty;
|
||||||
parsedAddress.name.isNotEmpty;
|
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
int get formattedCryptoAmount {
|
int get formattedCryptoAmount {
|
||||||
|
@ -83,8 +85,7 @@ abstract class OutputBase with Store {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
_amount =
|
_amount = bitcoin!.formatterStringDoubleToBitcoinAmount(_cryptoAmount);
|
||||||
bitcoin!.formatterStringDoubleToBitcoinAmount(_cryptoAmount);
|
|
||||||
break;
|
break;
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
_amount = haven!.formatterMoneroParseAmount(amount: _cryptoAmount);
|
_amount = haven!.formatterMoneroParseAmount(amount: _cryptoAmount);
|
||||||
|
@ -92,6 +93,9 @@ abstract class OutputBase with Store {
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
_amount = ethereum!.formatterEthereumParseAmount(_cryptoAmount);
|
_amount = ethereum!.formatterEthereumParseAmount(_cryptoAmount);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
_amount = polygon!.formatterPolygonParseAmount(_cryptoAmount);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -130,6 +134,10 @@ abstract class OutputBase with Store {
|
||||||
if (_wallet.type == WalletType.ethereum) {
|
if (_wallet.type == WalletType.ethereum) {
|
||||||
return ethereum!.formatterEthereumAmountToDouble(amount: BigInt.from(fee));
|
return ethereum!.formatterEthereumAmountToDouble(amount: BigInt.from(fee));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_wallet.type == WalletType.polygon) {
|
||||||
|
return polygon!.formatterPolygonAmountToDouble(amount: BigInt.from(fee));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
}
|
}
|
||||||
|
@ -140,10 +148,11 @@ abstract class OutputBase with Store {
|
||||||
@computed
|
@computed
|
||||||
String get estimatedFeeFiatAmount {
|
String get estimatedFeeFiatAmount {
|
||||||
try {
|
try {
|
||||||
final currency = _wallet.type == WalletType.ethereum ? _wallet.currency : cryptoCurrencyHandler();
|
final currency = isEVMCompatibleChain(_wallet.type)
|
||||||
|
? _wallet.currency
|
||||||
|
: cryptoCurrencyHandler();
|
||||||
final fiat = calculateFiatAmountRaw(
|
final fiat = calculateFiatAmountRaw(
|
||||||
price: _fiatConversationStore.prices[currency]!,
|
price: _fiatConversationStore.prices[currency]!, cryptoAmount: estimatedFee);
|
||||||
cryptoAmount: estimatedFee);
|
|
||||||
return fiat;
|
return fiat;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return '0.00';
|
return '0.00';
|
||||||
|
@ -240,6 +249,7 @@ abstract class OutputBase with Store {
|
||||||
maximumFractionDigits = 12;
|
maximumFractionDigits = 12;
|
||||||
break;
|
break;
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
case WalletType.polygon:
|
||||||
maximumFractionDigits = 12;
|
maximumFractionDigits = 12;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -50,7 +50,9 @@ abstract class SendTemplateViewModelBase with Store {
|
||||||
TemplateValidator get templateValidator => TemplateValidator();
|
TemplateValidator get templateValidator => TemplateValidator();
|
||||||
|
|
||||||
bool get hasMultiRecipient =>
|
bool get hasMultiRecipient =>
|
||||||
_wallet.type != WalletType.haven && _wallet.type != WalletType.ethereum;
|
_wallet.type != WalletType.haven &&
|
||||||
|
_wallet.type != WalletType.ethereum &&
|
||||||
|
_wallet.type != WalletType.polygon;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
CryptoCurrency get cryptoCurrency => _wallet.currency;
|
CryptoCurrency get cryptoCurrency => _wallet.currency;
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
||||||
import 'package:cake_wallet/entities/contact_record.dart';
|
import 'package:cake_wallet/entities/contact_record.dart';
|
||||||
import 'package:cake_wallet/entities/wallet_contact.dart';
|
import 'package:cake_wallet/entities/wallet_contact.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||||
|
@ -42,7 +44,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
void onWalletChange(wallet) {
|
void onWalletChange(wallet) {
|
||||||
currencies = wallet.balance.keys.toList();
|
currencies = wallet.balance.keys.toList();
|
||||||
selectedCryptoCurrency = wallet.currency;
|
selectedCryptoCurrency = wallet.currency;
|
||||||
hasMultipleTokens = wallet.type == WalletType.ethereum;
|
hasMultipleTokens = isEVMCompatibleChain(wallet.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendViewModelBase(
|
SendViewModelBase(
|
||||||
|
@ -55,7 +57,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
) : state = InitialExecutionState(),
|
) : state = InitialExecutionState(),
|
||||||
currencies = appStore.wallet!.balance.keys.toList(),
|
currencies = appStore.wallet!.balance.keys.toList(),
|
||||||
selectedCryptoCurrency = appStore.wallet!.currency,
|
selectedCryptoCurrency = appStore.wallet!.currency,
|
||||||
hasMultipleTokens = appStore.wallet!.type == WalletType.ethereum,
|
hasMultipleTokens = isEVMCompatibleChain(appStore.wallet!.type),
|
||||||
outputs = ObservableList<Output>(),
|
outputs = ObservableList<Output>(),
|
||||||
_settingsStore = appStore.settingsStore,
|
_settingsStore = appStore.settingsStore,
|
||||||
fiatFromSettings = appStore.settingsStore.fiatCurrency,
|
fiatFromSettings = appStore.settingsStore.fiatCurrency,
|
||||||
|
@ -119,7 +121,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
try {
|
try {
|
||||||
if (pendingTransaction != null) {
|
if (pendingTransaction != null) {
|
||||||
final currency =
|
final currency =
|
||||||
walletType == WalletType.ethereum ? wallet.currency : selectedCryptoCurrency;
|
isEVMCompatibleChain(walletType) ? wallet.currency : selectedCryptoCurrency;
|
||||||
final fiat = calculateFiatAmount(
|
final fiat = calculateFiatAmount(
|
||||||
price: _fiatConversationStore.prices[currency]!,
|
price: _fiatConversationStore.prices[currency]!,
|
||||||
cryptoAmount: pendingTransaction!.feeFormatted);
|
cryptoAmount: pendingTransaction!.feeFormatted);
|
||||||
|
@ -372,6 +374,9 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
priority: priority!, currency: selectedCryptoCurrency);
|
priority: priority!, currency: selectedCryptoCurrency);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nano!.createNanoTransactionCredentials(outputs);
|
return nano!.createNanoTransactionCredentials(outputs);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.createPolygonTransactionCredentials(outputs,
|
||||||
|
priority: priority!, currency: selectedCryptoCurrency);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${wallet.type}');
|
throw Exception('Unexpected wallet type: ${wallet.type}');
|
||||||
}
|
}
|
||||||
|
@ -412,11 +417,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
WalletType walletType,
|
WalletType walletType,
|
||||||
CryptoCurrency currency,
|
CryptoCurrency currency,
|
||||||
) {
|
) {
|
||||||
if (walletType == WalletType.ethereum || walletType == WalletType.haven) {
|
if (walletType == WalletType.ethereum ||
|
||||||
|
walletType == WalletType.polygon ||
|
||||||
|
walletType == WalletType.haven) {
|
||||||
if (error.contains('gas required exceeds allowance') ||
|
if (error.contains('gas required exceeds allowance') ||
|
||||||
error.contains('insufficient funds for')) {
|
error.contains('insufficient funds for')) {
|
||||||
return S.current.do_not_have_enough_gas_asset(currency.toString());
|
return S.current.do_not_have_enough_gas_asset(currency.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
|
@ -12,8 +13,7 @@ import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||||
|
|
||||||
part 'privacy_settings_view_model.g.dart';
|
part 'privacy_settings_view_model.g.dart';
|
||||||
|
|
||||||
class
|
class PrivacySettingsViewModel = PrivacySettingsViewModelBase with _$PrivacySettingsViewModel;
|
||||||
PrivacySettingsViewModel = PrivacySettingsViewModelBase with _$PrivacySettingsViewModel;
|
|
||||||
|
|
||||||
abstract class PrivacySettingsViewModelBase with Store {
|
abstract class PrivacySettingsViewModelBase with Store {
|
||||||
PrivacySettingsViewModelBase(this._settingsStore, this._wallet);
|
PrivacySettingsViewModelBase(this._settingsStore, this._wallet);
|
||||||
|
@ -58,6 +58,9 @@ abstract class PrivacySettingsViewModelBase with Store {
|
||||||
@computed
|
@computed
|
||||||
bool get useEtherscan => _settingsStore.useEtherscan;
|
bool get useEtherscan => _settingsStore.useEtherscan;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get usePolygonScan => _settingsStore.usePolygonScan;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get lookupTwitter => _settingsStore.lookupsTwitter;
|
bool get lookupTwitter => _settingsStore.lookupsTwitter;
|
||||||
|
|
||||||
|
@ -78,6 +81,8 @@ abstract class PrivacySettingsViewModelBase with Store {
|
||||||
|
|
||||||
bool get canUseEtherscan => _wallet.type == WalletType.ethereum;
|
bool get canUseEtherscan => _wallet.type == WalletType.ethereum;
|
||||||
|
|
||||||
|
bool get canUsePolygonScan => _wallet.type == WalletType.polygon;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void setShouldSaveRecipientAddress(bool value) =>
|
void setShouldSaveRecipientAddress(bool value) =>
|
||||||
_settingsStore.shouldSaveRecipientAddress = value;
|
_settingsStore.shouldSaveRecipientAddress = value;
|
||||||
|
@ -120,4 +125,10 @@ abstract class PrivacySettingsViewModelBase with Store {
|
||||||
_settingsStore.useEtherscan = value;
|
_settingsStore.useEtherscan = value;
|
||||||
ethereum!.updateEtherscanUsageState(_wallet, value);
|
ethereum!.updateEtherscanUsageState(_wallet, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setUsePolygonScan(bool value) {
|
||||||
|
_settingsStore.usePolygonScan = value;
|
||||||
|
polygon!.updatePolygonScanUsageState(_wallet, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,9 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
_addNanoListItems(tx, dateFormat);
|
_addNanoListItems(tx, dateFormat);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
_addPolygonListItems(tx, dateFormat);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +129,8 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
return 'https://nanolooker.com/block/${txId}';
|
return 'https://nanolooker.com/block/${txId}';
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return 'https://bananolooker.com/block/${txId}';
|
return 'https://bananolooker.com/block/${txId}';
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 'https://polygonscan.com/tx/${txId}';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -148,6 +153,8 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
return S.current.view_transaction_on + 'nanolooker.com';
|
return S.current.view_transaction_on + 'nanolooker.com';
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return S.current.view_transaction_on + 'bananolooker.com';
|
return S.current.view_transaction_on + 'bananolooker.com';
|
||||||
|
case WalletType.polygon:
|
||||||
|
return S.current.view_transaction_on + 'polygonscan.com';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -237,7 +244,6 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
items.addAll(_items);
|
items.addAll(_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _addNanoListItems(TransactionInfo tx, DateFormat dateFormat) {
|
void _addNanoListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||||
final _items = [
|
final _items = [
|
||||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||||
|
@ -250,4 +256,21 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
|
|
||||||
items.addAll(_items);
|
items.addAll(_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _addPolygonListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||||
|
final _items = [
|
||||||
|
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
|
||||||
|
StandartListItem(title: S.current.confirmations, value: tx.confirmations.toString()),
|
||||||
|
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||||
|
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
|
||||||
|
if (tx.feeFormatted()?.isNotEmpty ?? false)
|
||||||
|
StandartListItem(title: S.current.transaction_details_fee, value: tx.feeFormatted()!),
|
||||||
|
if (showRecipientAddress && tx.to != null)
|
||||||
|
StandartListItem(title: S.current.transaction_details_recipient_address, value: tx.to!),
|
||||||
|
];
|
||||||
|
|
||||||
|
items.addAll(_items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||||
import 'package:cw_core/currency.dart';
|
import 'package:cw_core/currency.dart';
|
||||||
|
@ -139,6 +140,22 @@ class NanoURI extends PaymentURI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PolygonURI extends PaymentURI {
|
||||||
|
PolygonURI({required String amount, required String address})
|
||||||
|
: super(amount: amount, address: address);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
var base = 'polygon:' + address;
|
||||||
|
|
||||||
|
if (amount.isNotEmpty) {
|
||||||
|
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
|
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
|
||||||
WalletAddressListViewModelBase({
|
WalletAddressListViewModelBase({
|
||||||
required AppStore appStore,
|
required AppStore appStore,
|
||||||
|
@ -216,6 +233,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||||
return NanoURI(amount: amount, address: address.address);
|
return NanoURI(amount: amount, address: address.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wallet.type == WalletType.polygon) {
|
||||||
|
return PolygonURI(amount: amount, address: address.address);
|
||||||
|
}
|
||||||
|
|
||||||
throw Exception('Unexpected type: ${type.toString()}');
|
throw Exception('Unexpected type: ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +293,12 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||||
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wallet.type == WalletType.polygon) {
|
||||||
|
final primaryAddress = polygon!.getAddress(wallet);
|
||||||
|
|
||||||
|
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
||||||
|
}
|
||||||
|
|
||||||
return addressList;
|
return addressList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
@ -19,7 +20,8 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
: title = _appStore.wallet!.type == WalletType.bitcoin ||
|
: title = _appStore.wallet!.type == WalletType.bitcoin ||
|
||||||
_appStore.wallet!.type == WalletType.litecoin ||
|
_appStore.wallet!.type == WalletType.litecoin ||
|
||||||
_appStore.wallet!.type == WalletType.bitcoinCash ||
|
_appStore.wallet!.type == WalletType.bitcoinCash ||
|
||||||
_appStore.wallet!.type == WalletType.ethereum
|
_appStore.wallet!.type == WalletType.ethereum ||
|
||||||
|
_appStore.wallet!.type == WalletType.polygon
|
||||||
? S.current.wallet_seed
|
? S.current.wallet_seed
|
||||||
: S.current.wallet_keys,
|
: S.current.wallet_keys,
|
||||||
_restoreHeight = _appStore.wallet!.walletInfo.restoreHeight,
|
_restoreHeight = _appStore.wallet!.walletInfo.restoreHeight,
|
||||||
|
@ -98,7 +100,7 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_appStore.wallet!.type == WalletType.ethereum) {
|
if (isEVMCompatibleChain(_appStore.wallet!.type)) {
|
||||||
items.addAll([
|
items.addAll([
|
||||||
if (_appStore.wallet!.privateKey != null)
|
if (_appStore.wallet!.privateKey != null)
|
||||||
StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!),
|
StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!),
|
||||||
|
@ -151,6 +153,8 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
return 'nano-wallet';
|
return 'nano-wallet';
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return 'banano-wallet';
|
return 'banano-wallet';
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 'polygon-wallet';
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}');
|
throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/haven/haven.dart';
|
import 'package:cake_wallet/haven/haven.dart';
|
||||||
|
|
||||||
|
import '../polygon/polygon.dart';
|
||||||
|
|
||||||
part 'wallet_new_vm.g.dart';
|
part 'wallet_new_vm.g.dart';
|
||||||
|
|
||||||
class WalletNewVM = WalletNewVMBase with _$WalletNewVM;
|
class WalletNewVM = WalletNewVMBase with _$WalletNewVM;
|
||||||
|
@ -52,6 +54,8 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
||||||
return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name);
|
return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
return nano!.createNanoNewWalletCredentials(name: name);
|
return nano!.createNanoNewWalletCredentials(name: name);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.createPolygonNewWalletCredentials(name: name);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected type: ${type.toString()}');
|
throw Exception('Unexpected type: ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
|
@ -28,7 +29,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
: hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
: hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||||
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||||
hasRestoreFromPrivateKey =
|
hasRestoreFromPrivateKey =
|
||||||
type == WalletType.ethereum || type == WalletType.nano || type == WalletType.banano,
|
type == WalletType.ethereum ||
|
||||||
|
type == WalletType.polygon ||
|
||||||
|
type == WalletType.nano ||
|
||||||
|
type == WalletType.banano,
|
||||||
isButtonEnabled = false,
|
isButtonEnabled = false,
|
||||||
mode = WalletRestoreMode.seed,
|
mode = WalletRestoreMode.seed,
|
||||||
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) {
|
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) {
|
||||||
|
@ -36,6 +40,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
|
case WalletType.polygon:
|
||||||
availableModes = WalletRestoreMode.values;
|
availableModes = WalletRestoreMode.values;
|
||||||
break;
|
break;
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
|
@ -107,6 +112,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
mnemonic: seed,
|
mnemonic: seed,
|
||||||
password: password,
|
password: password,
|
||||||
derivationType: derivationType);
|
derivationType: derivationType);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
||||||
|
name: name,
|
||||||
|
mnemonic: seed,
|
||||||
|
password: password,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -153,6 +164,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
password: password,
|
password: password,
|
||||||
seedKey: options['private_key'] as String,
|
seedKey: options['private_key'] as String,
|
||||||
derivationType: options["derivationType"] as DerivationType);
|
derivationType: options["derivationType"] as DerivationType);
|
||||||
|
case WalletType.polygon:
|
||||||
|
return polygon!.createPolygonRestoreWalletFromPrivateKey(
|
||||||
|
name: name,
|
||||||
|
password: password,
|
||||||
|
privateKey: options['private_key'] as String,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ PODS:
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- tor (0.0.1)
|
||||||
- url_launcher_macos (0.0.1):
|
- url_launcher_macos (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- wakelock_plus (0.0.1):
|
- wakelock_plus (0.0.1):
|
||||||
|
@ -59,6 +60,7 @@ DEPENDENCIES:
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`)
|
- share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`)
|
||||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
|
- tor (from `Flutter/ephemeral/.symlinks/plugins/tor/macos`)
|
||||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||||
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
|
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
|
||||||
|
|
||||||
|
@ -91,6 +93,8 @@ EXTERNAL SOURCES:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||||
|
tor:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/tor/macos
|
||||||
url_launcher_macos:
|
url_launcher_macos:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
|
@ -98,7 +102,7 @@ EXTERNAL SOURCES:
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308
|
connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308
|
||||||
cw_monero: ec03de55a19c4a2b174ea687e0f4202edc716fa4
|
cw_monero: f8b7f104508efba2591548e76b5c058d05cba3f0
|
||||||
device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
|
device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
|
||||||
devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225
|
devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225
|
||||||
flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea
|
flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea
|
||||||
|
@ -110,6 +114,7 @@ SPEC CHECKSUMS:
|
||||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||||
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
|
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
|
||||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||||
|
tor: 2138c48428e696b83eacdda404de6d5574932e26
|
||||||
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
||||||
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
|
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,5 @@ cd cw_haven && flutter pub get && flutter packages pub run build_runner build --
|
||||||
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
|
cd cw_polygon && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
flutter packages pub run build_runner build --delete-conflicting-outputs
|
flutter packages pub run build_runner build --delete-conflicting-outputs
|
|
@ -147,6 +147,7 @@ flutter:
|
||||||
- assets/bitcoin_cash_electrum_server_list.yml
|
- assets/bitcoin_cash_electrum_server_list.yml
|
||||||
- assets/nano_node_list.yml
|
- assets/nano_node_list.yml
|
||||||
- assets/nano_pow_node_list.yml
|
- assets/nano_pow_node_list.yml
|
||||||
|
- assets/polygon_node_list.yml
|
||||||
- assets/text/
|
- assets/text/
|
||||||
- assets/faq/
|
- assets/faq/
|
||||||
- assets/animation/
|
- assets/animation/
|
||||||
|
|
|
@ -745,5 +745,6 @@
|
||||||
"seedtype_polyseed": "بوليسيد (16 كلمة)",
|
"seedtype_polyseed": "بوليسيد (16 كلمة)",
|
||||||
"seed_language_czech": "التشيكية",
|
"seed_language_czech": "التشيكية",
|
||||||
"seed_language_korean": "الكورية",
|
"seed_language_korean": "الكورية",
|
||||||
"seed_language_chinese_traditional": "تقاليد صينية)"
|
"seed_language_chinese_traditional": "تقاليد صينية)",
|
||||||
|
"polygonscan_history": "ﻥﺎﻜﺴﻧﻮﺠﻴﻟﻮﺑ ﺦﻳﺭﺎﺗ"
|
||||||
}
|
}
|
||||||
|
|
|
@ -741,5 +741,6 @@
|
||||||
"seedtype_polyseed": "Поли семе (16 думи)",
|
"seedtype_polyseed": "Поли семе (16 думи)",
|
||||||
"seed_language_czech": "Чех",
|
"seed_language_czech": "Чех",
|
||||||
"seed_language_korean": "Корейски",
|
"seed_language_korean": "Корейски",
|
||||||
"seed_language_chinese_traditional": "Традиционен китайски)"
|
"seed_language_chinese_traditional": "Традиционен китайски)",
|
||||||
|
"polygonscan_history": "История на PolygonScan"
|
||||||
}
|
}
|
||||||
|
|
|
@ -741,5 +741,6 @@
|
||||||
"seedtype_polyseed": "Polyseed (16 slov)",
|
"seedtype_polyseed": "Polyseed (16 slov)",
|
||||||
"seed_language_czech": "čeština",
|
"seed_language_czech": "čeština",
|
||||||
"seed_language_korean": "korejština",
|
"seed_language_korean": "korejština",
|
||||||
"seed_language_chinese_traditional": "Číňan (tradiční)"
|
"seed_language_chinese_traditional": "Číňan (tradiční)",
|
||||||
|
"polygonscan_history": "Historie PolygonScan"
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,5 +749,6 @@
|
||||||
"seedtype_polyseed": "Polyseed (16 Wörter)",
|
"seedtype_polyseed": "Polyseed (16 Wörter)",
|
||||||
"seed_language_czech": "Tschechisch",
|
"seed_language_czech": "Tschechisch",
|
||||||
"seed_language_korean": "Koreanisch",
|
"seed_language_korean": "Koreanisch",
|
||||||
"seed_language_chinese_traditional": "Chinesisch (Traditionell)"
|
"seed_language_chinese_traditional": "Chinesisch (Traditionell)",
|
||||||
|
"polygonscan_history": "PolygonScan-Verlauf"
|
||||||
}
|
}
|
||||||
|
|
|
@ -750,5 +750,6 @@
|
||||||
"seedtype_polyseed": "Polyseed (16 words)",
|
"seedtype_polyseed": "Polyseed (16 words)",
|
||||||
"seed_language_czech": "Czech",
|
"seed_language_czech": "Czech",
|
||||||
"seed_language_korean": "Korean",
|
"seed_language_korean": "Korean",
|
||||||
"seed_language_chinese_traditional": "Chinese (Traditional)"
|
"seed_language_chinese_traditional": "Chinese (Traditional)",
|
||||||
|
"polygonscan_history": "PolygonScan history"
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,5 +749,6 @@
|
||||||
"seedtype_polyseed": "Polieta (16 palabras)",
|
"seedtype_polyseed": "Polieta (16 palabras)",
|
||||||
"seed_language_czech": "checo",
|
"seed_language_czech": "checo",
|
||||||
"seed_language_korean": "coreano",
|
"seed_language_korean": "coreano",
|
||||||
"seed_language_chinese_traditional": "Chino (tradicional)"
|
"seed_language_chinese_traditional": "Chino (tradicional)",
|
||||||
|
"polygonscan_history": "Historial de PolygonScan"
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,5 +749,6 @@
|
||||||
"seedtype_polyseed": "Polyseed (16 mots)",
|
"seedtype_polyseed": "Polyseed (16 mots)",
|
||||||
"seed_language_czech": "tchèque",
|
"seed_language_czech": "tchèque",
|
||||||
"seed_language_korean": "coréen",
|
"seed_language_korean": "coréen",
|
||||||
"seed_language_chinese_traditional": "Chinois (Traditionnel)"
|
"seed_language_chinese_traditional": "Chinois (Traditionnel)",
|
||||||
|
"polygonscan_history": "Historique de PolygonScan"
|
||||||
}
|
}
|
||||||
|
|
|
@ -727,5 +727,6 @@
|
||||||
"seedtype_polyseed": "Polyseed (16 kalmomi)",
|
"seedtype_polyseed": "Polyseed (16 kalmomi)",
|
||||||
"seed_language_czech": "Czech",
|
"seed_language_czech": "Czech",
|
||||||
"seed_language_korean": "Yaren Koriya",
|
"seed_language_korean": "Yaren Koriya",
|
||||||
"seed_language_chinese_traditional": "Sinanci (na gargajiya)"
|
"seed_language_chinese_traditional": "Sinanci (na gargajiya)",
|
||||||
|
"polygonscan_history": "PolygonScan tarihin kowane zamani"
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,5 +749,6 @@
|
||||||
"seedtype_polyseed": "पॉलीसीड (16 शब्द)",
|
"seedtype_polyseed": "पॉलीसीड (16 शब्द)",
|
||||||
"seed_language_czech": "चेक",
|
"seed_language_czech": "चेक",
|
||||||
"seed_language_korean": "कोरियाई",
|
"seed_language_korean": "कोरियाई",
|
||||||
"seed_language_chinese_traditional": "चीनी पारंपरिक)"
|
"seed_language_chinese_traditional": "चीनी पारंपरिक)",
|
||||||
|
"polygonscan_history": "पॉलीगॉनस्कैन इतिहास"
|
||||||
}
|
}
|
||||||
|
|
|
@ -747,5 +747,6 @@
|
||||||
"seedtype_polyseed": "Poliseed (16 riječi)",
|
"seedtype_polyseed": "Poliseed (16 riječi)",
|
||||||
"seed_language_czech": "češki",
|
"seed_language_czech": "češki",
|
||||||
"seed_language_korean": "korejski",
|
"seed_language_korean": "korejski",
|
||||||
"seed_language_chinese_traditional": "Kinesko (tradicionalno)"
|
"seed_language_chinese_traditional": "Kinesko (tradicionalno)",
|
||||||
|
"polygonscan_history": "Povijest PolygonScan"
|
||||||
}
|
}
|
||||||
|
|
|
@ -737,5 +737,6 @@
|
||||||
"seedtype_polyseed": "Polyseed (16 kata)",
|
"seedtype_polyseed": "Polyseed (16 kata)",
|
||||||
"seed_language_czech": "Ceko",
|
"seed_language_czech": "Ceko",
|
||||||
"seed_language_korean": "Korea",
|
"seed_language_korean": "Korea",
|
||||||
"seed_language_chinese_traditional": "Cina (tradisional)"
|
"seed_language_chinese_traditional": "Cina (tradisional)",
|
||||||
|
"polygonscan_history": "Sejarah PolygonScan"
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,5 +749,6 @@
|
||||||
"seedtype_polyseed": "Polyseed (16 parole)",
|
"seedtype_polyseed": "Polyseed (16 parole)",
|
||||||
"seed_language_czech": "ceco",
|
"seed_language_czech": "ceco",
|
||||||
"seed_language_korean": "coreano",
|
"seed_language_korean": "coreano",
|
||||||
"seed_language_chinese_traditional": "Cinese tradizionale)"
|
"seed_language_chinese_traditional": "Cinese tradizionale)",
|
||||||
|
"polygonscan_history": "Cronologia PolygonScan"
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,5 +749,6 @@
|
||||||
"seedtype_polyseed": "ポリシード(16語)",
|
"seedtype_polyseed": "ポリシード(16語)",
|
||||||
"seed_language_czech": "チェコ",
|
"seed_language_czech": "チェコ",
|
||||||
"seed_language_korean": "韓国語",
|
"seed_language_korean": "韓国語",
|
||||||
"seed_language_chinese_traditional": "中国の伝統的な)"
|
"seed_language_chinese_traditional": "中国の伝統的な)",
|
||||||
|
"polygonscan_history": "ポリゴンスキャン履歴"
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue