diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml
index b67a4d937..eb08db295 100644
--- a/.github/workflows/pr_test_build.yml
+++ b/.github/workflows/pr_test_build.yml
@@ -2,11 +2,10 @@ name: PR Test Build
on:
pull_request:
- branches: [ main ]
+ branches: [main]
jobs:
PR_test_build:
-
runs-on: ubuntu-20.04
env:
STORE_PASS: test@cake_wallet
@@ -28,7 +27,7 @@ jobs:
- name: Flutter action
uses: subosito/flutter-action@v1
with:
- flutter-version: '3.10.x'
+ flutter-version: "3.10.x"
channel: stable
- name: Install package dependencies
@@ -93,6 +92,7 @@ jobs:
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_haven && 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 ..
flutter packages pub run build_runner build --delete-conflicting-outputs
- name: Add secrets
@@ -128,8 +128,10 @@ jobs:
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 chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> 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 robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
+ echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
- name: Rename app
run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties
@@ -139,18 +141,18 @@ jobs:
cd /opt/android/cake_wallet
flutter build apk --release
-# - name: Push to App Center
-# run: |
-# echo 'Installing App Center CLI tools'
-# npm install -g appcenter-cli
-# echo "Publishing test to App Center"
-# appcenter distribute release \
-# --group "Testers" \
-# --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \
-# --release-notes ${GITHUB_HEAD_REF} \
-# --app Cake-Labs/Cake-Wallet \
-# --token ${{ secrets.APP_CENTER_TOKEN }} \
-# --quiet
+ # - name: Push to App Center
+ # run: |
+ # echo 'Installing App Center CLI tools'
+ # npm install -g appcenter-cli
+ # echo "Publishing test to App Center"
+ # appcenter distribute release \
+ # --group "Testers" \
+ # --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \
+ # --release-notes ${GITHUB_HEAD_REF} \
+ # --app Cake-Labs/Cake-Wallet \
+ # --token ${{ secrets.APP_CENTER_TOKEN }} \
+ # --quiet
- name: Rename apk file
run: |
@@ -170,6 +172,6 @@ jobs:
token: ${{ secrets.SLACK_APP_TOKEN }}
path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk
channel: ${{ secrets.SLACK_APK_CHANNEL }}
- title: '${{github.head_ref}}.apk'
+ title: "${{github.head_ref}}.apk"
filename: ${{github.head_ref}}.apk
initial_comment: ${{ github.event.head_commit.message }}
diff --git a/.gitignore b/.gitignore
index 09583004b..e8fb0048c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -124,6 +124,7 @@ lib/bitcoin/bitcoin.dart
lib/monero/monero.dart
lib/haven/haven.dart
lib/ethereum/ethereum.dart
+lib/nano/nano.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png
diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml
index 9b3f47314..f22ba9c4f 100644
--- a/android/app/src/main/AndroidManifestBase.xml
+++ b/android/app/src/main/AndroidManifestBase.xml
@@ -25,10 +25,6 @@
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:exported="true">
-
diff --git a/android/app/src/main/res/drawable-night/launch_background.xml b/android/app/src/main/res/drawable-night/launch_background.xml
new file mode 100644
index 000000000..11d0cb8e6
--- /dev/null
+++ b/android/app/src/main/res/drawable-night/launch_background.xml
@@ -0,0 +1,6 @@
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 304732f88..50af1a418 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -1,12 +1,6 @@
-
-
-
-
-
+ -
+
+
diff --git a/assets/images/exolix.png b/assets/images/exolix.png
new file mode 100644
index 000000000..29e5f2db1
Binary files /dev/null and b/assets/images/exolix.png differ
diff --git a/assets/images/walletconnect_logo.png b/assets/images/walletconnect_logo.png
new file mode 100644
index 000000000..9024b972c
Binary files /dev/null and b/assets/images/walletconnect_logo.png differ
diff --git a/assets/nano_node_list.yml b/assets/nano_node_list.yml
new file mode 100644
index 000000000..63b4baec1
--- /dev/null
+++ b/assets/nano_node_list.yml
@@ -0,0 +1,6 @@
+-
+ uri: rpc.nano.to
+ useSSL: true
+ is_default: true
+-
+ uri: node.perish.co:9076
\ No newline at end of file
diff --git a/assets/nano_pow_node_list.yml b/assets/nano_pow_node_list.yml
new file mode 100644
index 000000000..b90845034
--- /dev/null
+++ b/assets/nano_pow_node_list.yml
@@ -0,0 +1,9 @@
+-
+ uri: rpc.nano.to
+ useSSL: true
+ is_default: true
+-
+ uri: workers.perish.co
+-
+ uri: worker.nanoriver.cc
+ useSSL: true
\ No newline at end of file
diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt
index cbe201cf8..9393f7768 100644
--- a/assets/text/Monerocom_Release_Notes.txt
+++ b/assets/text/Monerocom_Release_Notes.txt
@@ -1,3 +1,3 @@
-Enhance Monero coin control
-Add Filipino localization
-Bug Fixes
\ No newline at end of file
+Fix 2FA code issue
+Bug fixes
+Minor enhancements
\ No newline at end of file
diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt
index 263e7ccfe..1fd86c9ca 100644
--- a/assets/text/Release_Notes.txt
+++ b/assets/text/Release_Notes.txt
@@ -1,5 +1,4 @@
-New Buy Provider Robinhood
-Fix sending Ethereum issue
-Enhance Monero coin control
-Add Filipino localization
-Bug Fixes
\ No newline at end of file
+Ethereum enhancements and bug fixes
+Fix 2FA code issue
+Bug fixes
+Minor enhancements
\ No newline at end of file
diff --git a/configure_cake_wallet_android.sh b/configure_cake_wallet_android.sh
old mode 100644
new mode 100755
index b80ebc46e..792159f29
--- a/configure_cake_wallet_android.sh
+++ b/configure_cake_wallet_android.sh
@@ -7,4 +7,5 @@ cd cw_monero && flutter pub get && flutter packages pub run build_runner build -
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_haven && 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 ..
flutter packages pub run build_runner build --delete-conflicting-outputs
diff --git a/cw_bitcoin/lib/bitcoin_mnemonic.dart b/cw_bitcoin/lib/bitcoin_mnemonic.dart
index f4ebd7e5d..9163fcb11 100644
--- a/cw_bitcoin/lib/bitcoin_mnemonic.dart
+++ b/cw_bitcoin/lib/bitcoin_mnemonic.dart
@@ -2297,4 +2297,4 @@ final englishWordlist = [
'zero',
'zone',
'zoo'
-];
+];
\ No newline at end of file
diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart
index c4675df1c..2c66d02fe 100644
--- a/cw_bitcoin/lib/bitcoin_wallet.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet.dart
@@ -89,4 +89,4 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex);
}
-}
+}
\ No newline at end of file
diff --git a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
index 82173b2d2..37b272a1b 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart
@@ -20,4 +20,4 @@ class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials {
: super(name: name, password: password, walletInfo: walletInfo);
final String wif;
-}
+}
\ No newline at end of file
diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart
index bfadaf2a3..3a97e0682 100644
--- a/cw_bitcoin/lib/bitcoin_wallet_service.dart
+++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart
@@ -100,4 +100,4 @@ class BitcoinWalletService extends WalletService<
await wallet.init();
return wallet;
}
-}
+}
\ No newline at end of file
diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
index 6db0c23f2..def991ebe 100644
--- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart
+++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart
@@ -56,4 +56,4 @@ class ElectrumWallletSnapshot {
regularAddressIndex: regularAddressIndex,
changeAddressIndex: changeAddressIndex);
}
-}
+}
\ No newline at end of file
diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart
index 86ea3f214..f6ffcdc8b 100644
--- a/cw_core/lib/crypto_currency.dart
+++ b/cw_core/lib/crypto_currency.dart
@@ -90,6 +90,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen
CryptoCurrency.zrx,
CryptoCurrency.dydx,
CryptoCurrency.steth,
+ CryptoCurrency.banano,
];
static const havenCurrencies = [
@@ -119,7 +120,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen
static const eos = CryptoCurrency(title: 'EOS', fullName: 'EOS', raw: 7, name: 'eos', iconPath: 'assets/images/eos_icon.png');
static const eth = CryptoCurrency(title: 'ETH', fullName: 'Ethereum', raw: 8, name: 'eth', iconPath: 'assets/images/eth_icon.png');
static const ltc = CryptoCurrency(title: 'LTC', fullName: 'Litecoin', raw: 9, name: 'ltc', iconPath: 'assets/images/litecoin-ltc_icon.png');
- static const nano = CryptoCurrency(title: 'NANO', raw: 10, name: 'nano', iconPath: 'assets/images/nano.png');
+ static const nano = CryptoCurrency(title: 'XNO', raw: 10, fullName: 'Nano', name: 'xno', iconPath: 'assets/images/nano_icon.png');
static const trx = CryptoCurrency(title: 'TRX', fullName: 'TRON', raw: 11, name: 'trx', iconPath: 'assets/images/trx_icon.png');
static const usdt = CryptoCurrency(title: 'USDT', tag: 'OMNI', fullName: 'USDT Tether', raw: 12, name: 'usdt', iconPath: 'assets/images/usdt_icon.png');
static const usdterc20 = CryptoCurrency(title: 'USDT', tag: 'ETH', fullName: 'USDT Tether', raw: 13, name: 'usdterc20', iconPath: 'assets/images/usdterc20_icon.png');
@@ -198,6 +199,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen
static const zrx = CryptoCurrency(title: 'ZRX', tag: 'ETH', fullName: '0x Protocol', raw: 83, name: 'zrx', iconPath: 'assets/images/zrx_icon.png');
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png');
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png');
+ static const banano = CryptoCurrency(title: 'BAN', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png');
static final Map _rawCurrencyMap =
diff --git a/cw_core/lib/currency_for_wallet_type.dart b/cw_core/lib/currency_for_wallet_type.dart
index 8ac8c1fc6..2db858b30 100644
--- a/cw_core/lib/currency_for_wallet_type.dart
+++ b/cw_core/lib/currency_for_wallet_type.dart
@@ -13,6 +13,10 @@ CryptoCurrency currencyForWalletType(WalletType type) {
return CryptoCurrency.xhv;
case WalletType.ethereum:
return CryptoCurrency.eth;
+ case WalletType.nano:
+ return CryptoCurrency.nano;
+ case WalletType.banano:
+ return CryptoCurrency.banano;
default:
throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
}
diff --git a/cw_core/lib/hive_type_ids.dart b/cw_core/lib/hive_type_ids.dart
index 950f39e1f..4d4d1a6a8 100644
--- a/cw_core/lib/hive_type_ids.dart
+++ b/cw_core/lib/hive_type_ids.dart
@@ -1,4 +1,4 @@
-const CONTACT_TYPE_ID = 0;
+const CONTACT_TYPE_ID = 0;
const NODE_TYPE_ID = 1;
const TRANSACTION_TYPE_ID = 2;
const TRADE_TYPE_ID = 3;
@@ -11,3 +11,6 @@ const UNSPENT_COINS_INFO_TYPE_ID = 9;
const ANONPAY_INVOICE_INFO_TYPE_ID = 10;
const ADDRESS_INFO_TYPE_ID = 11;
const ERC20_TOKEN_TYPE_ID = 12;
+const NANO_ACCOUNT_TYPE_ID = 13;
+const POW_NODE_TYPE_ID = 14;
+const DERIVATION_TYPE_TYPE_ID = 15;
\ No newline at end of file
diff --git a/cw_core/lib/nano_account.dart b/cw_core/lib/nano_account.dart
new file mode 100644
index 000000000..91df62e75
--- /dev/null
+++ b/cw_core/lib/nano_account.dart
@@ -0,0 +1,23 @@
+import 'package:cw_core/hive_type_ids.dart';
+import 'package:hive/hive.dart';
+
+part 'nano_account.g.dart';
+
+@HiveType(typeId: NanoAccount.typeId)
+class NanoAccount extends HiveObject {
+ NanoAccount({required this.label, required this.id, this.balance, this.isSelected = false});
+
+ static const typeId = NANO_ACCOUNT_TYPE_ID;
+
+ @HiveField(0)
+ String label;
+
+ @HiveField(1)
+ final int id;
+
+ @HiveField(2)
+ bool isSelected;
+
+ @HiveField(3)
+ String? balance;
+}
diff --git a/cw_core/lib/nano_account_info_response.dart b/cw_core/lib/nano_account_info_response.dart
new file mode 100644
index 000000000..319bbb861
--- /dev/null
+++ b/cw_core/lib/nano_account_info_response.dart
@@ -0,0 +1,23 @@
+class AccountInfoResponse {
+ String frontier;
+ int confirmationHeight;
+ String balance;
+ String representative;
+ String? address;
+
+ AccountInfoResponse({
+ required this.frontier,
+ required this.balance,
+ required this.representative,
+ required this.confirmationHeight,
+ });
+
+ factory AccountInfoResponse.fromJson(Map json) {
+ return AccountInfoResponse(
+ frontier: json['frontier'] as String,
+ representative: json['representative'] as String,
+ balance: json['balance'] as String,
+ confirmationHeight: int.parse(json['confirmation_height'] as String),
+ );
+ }
+}
diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart
index 59a1450f6..a07030d64 100644
--- a/cw_core/lib/node.dart
+++ b/cw_core/lib/node.dart
@@ -9,19 +9,19 @@ import 'package:http/io_client.dart' as ioc;
part 'node.g.dart';
-Uri createUriFromElectrumAddress(String address) =>
- Uri.tryParse('tcp://$address')!;
+Uri createUriFromElectrumAddress(String address) => Uri.tryParse('tcp://$address')!;
@HiveType(typeId: Node.typeId)
class Node extends HiveObject with Keyable {
- Node(
- {this.login,
- this.password,
- this.useSSL,
- this.trusted = false,
- this.socksProxyAddress,
- String? uri,
- WalletType? type,}) {
+ Node({
+ this.login,
+ this.password,
+ this.useSSL,
+ this.trusted = false,
+ this.socksProxyAddress,
+ String? uri,
+ WalletType? type,
+ }) {
if (uri != null) {
uriRaw = uri;
}
@@ -78,6 +78,13 @@ class Node extends HiveObject with Keyable {
return Uri.http(uriRaw, '');
case WalletType.ethereum:
return Uri.https(uriRaw, '');
+ case WalletType.nano:
+ case WalletType.banano:
+ if (isSSL) {
+ return Uri.https(uriRaw, '');
+ } else {
+ return Uri.http(uriRaw, '');
+ }
default:
throw Exception('Unexpected type ${type.toString()} for Node uri');
}
@@ -86,13 +93,13 @@ class Node extends HiveObject with Keyable {
@override
bool operator ==(other) =>
other is Node &&
- (other.uriRaw == uriRaw &&
- other.login == login &&
- other.password == password &&
- other.typeRaw == typeRaw &&
- other.useSSL == useSSL &&
- other.trusted == trusted &&
- other.socksProxyAddress == socksProxyAddress);
+ (other.uriRaw == uriRaw &&
+ other.login == login &&
+ other.password == password &&
+ other.typeRaw == typeRaw &&
+ other.useSSL == useSSL &&
+ other.trusted == trusted &&
+ other.socksProxyAddress == socksProxyAddress);
@override
int get hashCode =>
@@ -120,7 +127,9 @@ class Node extends HiveObject with Keyable {
try {
switch (type) {
case WalletType.monero:
- return useSocksProxy ? requestNodeWithProxy(socksProxyAddress ?? '') : requestMoneroNode();
+ return useSocksProxy
+ ? requestNodeWithProxy(socksProxyAddress ?? '')
+ : requestMoneroNode();
case WalletType.bitcoin:
return requestElectrumServer();
case WalletType.litecoin:
@@ -129,6 +138,9 @@ class Node extends HiveObject with Keyable {
return requestMoneroNode();
case WalletType.ethereum:
return requestElectrumServer();
+ case WalletType.nano:
+ case WalletType.banano:
+ return requestNanoNode();
default:
return false;
}
@@ -141,27 +153,23 @@ class Node extends HiveObject with Keyable {
final path = '/json_rpc';
final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path);
final realm = 'monero-rpc';
- final body = {
- 'jsonrpc': '2.0',
- 'id': '0',
- 'method': 'get_info'
- };
+ final body = {'jsonrpc': '2.0', 'id': '0', 'method': 'get_info'};
try {
final authenticatingClient = HttpClient();
authenticatingClient.addCredentials(
- rpcUri,
- realm,
- HttpClientDigestCredentials(login ?? '', password ?? ''),
+ rpcUri,
+ realm,
+ HttpClientDigestCredentials(login ?? '', password ?? ''),
);
final http.Client client = ioc.IOClient(authenticatingClient);
final response = await client.post(
- rpcUri,
- headers: {'Content-Type': 'application/json'},
- body: json.encode(body),
+ rpcUri,
+ headers: {'Content-Type': 'application/json'},
+ body: json.encode(body),
);
client.close();
@@ -173,8 +181,24 @@ class Node extends HiveObject with Keyable {
}
}
- Future requestNodeWithProxy(String proxy) async {
+ Future requestNanoNode() async {
+ http.Response response = await http.post(
+ uri,
+ headers: {'Content-type': 'application/json'},
+ body: json.encode(
+ {
+ "action": "block_count",
+ },
+ ),
+ );
+ if (response.statusCode == 200) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ Future requestNodeWithProxy(String proxy) async {
if (proxy.isEmpty || !proxy.contains(':')) {
return false;
}
diff --git a/cw_core/lib/wallet_base.dart b/cw_core/lib/wallet_base.dart
index f8db67b24..d15ea42cd 100644
--- a/cw_core/lib/wallet_base.dart
+++ b/cw_core/lib/wallet_base.dart
@@ -13,9 +13,7 @@ import 'package:cw_core/sync_status.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/wallet_type.dart';
-abstract class WalletBase<
- BalanceType extends Balance,
- HistoryType extends TransactionHistoryBase,
+abstract class WalletBase {
WalletBase(this.walletInfo);
@@ -58,6 +56,9 @@ abstract class WalletBase<
Future connectToNode({required Node node});
+ // there is a default definition here because only coins with a pow node (nano based) need to override this
+ Future connectToPowNode({required Node node}) async {}
+
Future startSync();
Future createTransaction(Object credentials);
diff --git a/cw_core/lib/wallet_credentials.dart b/cw_core/lib/wallet_credentials.dart
index e028232e8..0cdf892bd 100644
--- a/cw_core/lib/wallet_credentials.dart
+++ b/cw_core/lib/wallet_credentials.dart
@@ -5,10 +5,15 @@ abstract class WalletCredentials {
required this.name,
this.height,
this.walletInfo,
- this.password});
+ this.password,
+ this.derivationType,
+ this.derivationPath,
+ });
final String name;
final int? height;
String? password;
+ DerivationType? derivationType;
+ String? derivationPath;
WalletInfo? walletInfo;
}
diff --git a/cw_core/lib/wallet_info.dart b/cw_core/lib/wallet_info.dart
index 210adb9a4..c4ccea00a 100644
--- a/cw_core/lib/wallet_info.dart
+++ b/cw_core/lib/wallet_info.dart
@@ -6,29 +6,92 @@ import 'package:hive/hive.dart';
part 'wallet_info.g.dart';
+@HiveType(typeId: DERIVATION_TYPE_TYPE_ID)
+enum DerivationType {
+ @HiveField(0)
+ unknown,
+ @HiveField(1)
+ def, // default is a reserved word
+ @HiveField(2)
+ nano,
+ @HiveField(3)
+ bip39,
+ @HiveField(4)
+ electrum1,
+ @HiveField(5)
+ electrum2,
+}
+
+class DerivationInfo {
+ DerivationInfo({
+ required this.derivationType,
+ this.derivationPath,
+ this.balance = "",
+ this.address = "",
+ this.height = 0,
+ this.script_type,
+ this.description,
+ });
+
+ String balance;
+ String address;
+ int height;
+ final DerivationType derivationType;
+ final String? derivationPath;
+ final String? script_type;
+ final String? description;
+}
+
@HiveType(typeId: WalletInfo.typeId)
class WalletInfo extends HiveObject {
- WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight,
- this.timestamp, this.dirPath, this.path, this.address, this.yatEid,
- this.yatLastUsedAddressRaw, this.showIntroCakePayCard)
+ WalletInfo(
+ this.id,
+ this.name,
+ this.type,
+ this.isRecovery,
+ this.restoreHeight,
+ this.timestamp,
+ this.dirPath,
+ this.path,
+ this.address,
+ this.yatEid,
+ this.yatLastUsedAddressRaw,
+ this.showIntroCakePayCard,
+ this.derivationType,
+ this.derivationPath)
: _yatLastUsedAddressController = StreamController.broadcast();
- factory WalletInfo.external(
- {required String id,
- required String name,
- required WalletType type,
- required bool isRecovery,
- required int restoreHeight,
- required DateTime date,
- required String dirPath,
- required String path,
- required String address,
- bool? showIntroCakePayCard,
- String yatEid ='',
- String yatLastUsedAddressRaw = ''}) {
- return WalletInfo(id, name, type, isRecovery, restoreHeight,
- date.millisecondsSinceEpoch, dirPath, path, address,
- yatEid, yatLastUsedAddressRaw, showIntroCakePayCard);
+ factory WalletInfo.external({
+ required String id,
+ required String name,
+ required WalletType type,
+ required bool isRecovery,
+ required int restoreHeight,
+ required DateTime date,
+ required String dirPath,
+ required String path,
+ required String address,
+ bool? showIntroCakePayCard,
+ String yatEid = '',
+ String yatLastUsedAddressRaw = '',
+ DerivationType? derivationType,
+ String? derivationPath,
+ }) {
+ return WalletInfo(
+ id,
+ name,
+ type,
+ isRecovery,
+ restoreHeight,
+ date.millisecondsSinceEpoch,
+ dirPath,
+ path,
+ address,
+ yatEid,
+ yatLastUsedAddressRaw,
+ showIntroCakePayCard,
+ derivationType,
+ derivationPath);
}
static const typeId = WALLET_INFO_TYPE_ID;
@@ -79,6 +142,12 @@ class WalletInfo extends HiveObject {
@HiveField(15)
List? usedAddresses;
+ @HiveField(16)
+ DerivationType? derivationType;
+
+ @HiveField(17)
+ String? derivationPath;
+
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
set yatLastUsedAddress(String address) {
@@ -89,7 +158,7 @@ class WalletInfo extends HiveObject {
String get yatEmojiId => yatEid ?? '';
bool get isShowIntroCakePayCard {
- if(showIntroCakePayCard == null) {
+ if (showIntroCakePayCard == null) {
return type != WalletType.haven;
}
return showIntroCakePayCard!;
diff --git a/cw_core/lib/wallet_service.dart b/cw_core/lib/wallet_service.dart
index f95bc1a44..f6d0ca192 100644
--- a/cw_core/lib/wallet_service.dart
+++ b/cw_core/lib/wallet_service.dart
@@ -1,9 +1,11 @@
+import 'package:cw_core/node.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart';
+import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
-abstract class WalletService {
+abstract class WalletService {
WalletType getType();
Future create(N credentials);
diff --git a/cw_core/lib/wallet_type.dart b/cw_core/lib/wallet_type.dart
index 62c2ad410..0125facaf 100644
--- a/cw_core/lib/wallet_type.dart
+++ b/cw_core/lib/wallet_type.dart
@@ -10,6 +10,8 @@ const walletTypes = [
WalletType.litecoin,
WalletType.haven,
WalletType.ethereum,
+ WalletType.nano,
+ WalletType.banano,
];
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
@@ -31,6 +33,12 @@ enum WalletType {
@HiveField(5)
ethereum,
+
+ @HiveField(6)
+ nano,
+
+ @HiveField(7)
+ banano,
}
int serializeToInt(WalletType type) {
@@ -45,6 +53,10 @@ int serializeToInt(WalletType type) {
return 3;
case WalletType.ethereum:
return 4;
+ case WalletType.nano:
+ return 5;
+ case WalletType.banano:
+ return 6;
default:
return -1;
}
@@ -62,6 +74,10 @@ WalletType deserializeFromInt(int raw) {
return WalletType.haven;
case 4:
return WalletType.ethereum;
+ case 5:
+ return WalletType.nano;
+ case 6:
+ return WalletType.banano;
default:
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
}
@@ -79,6 +95,10 @@ String walletTypeToString(WalletType type) {
return 'Haven';
case WalletType.ethereum:
return 'Ethereum';
+ case WalletType.nano:
+ return 'Nano';
+ case WalletType.banano:
+ return 'Banano';
default:
return '';
}
@@ -96,6 +116,10 @@ String walletTypeToDisplayName(WalletType type) {
return 'Haven (XHV)';
case WalletType.ethereum:
return 'Ethereum (ETH)';
+ case WalletType.nano:
+ return 'Nano (XNO)';
+ case WalletType.banano:
+ return 'Banano (BAN)';
default:
return '';
}
@@ -113,6 +137,10 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
return CryptoCurrency.xhv;
case WalletType.ethereum:
return CryptoCurrency.eth;
+ case WalletType.nano:
+ return CryptoCurrency.nano;
+ case WalletType.banano:
+ return CryptoCurrency.banano;
default:
throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
}
diff --git a/cw_ethereum/lib/ethereum_client.dart b/cw_ethereum/lib/ethereum_client.dart
index e10e79f1e..532eb2b99 100644
--- a/cw_ethereum/lib/ethereum_client.dart
+++ b/cw_ethereum/lib/ethereum_client.dart
@@ -65,13 +65,11 @@ class EthereumClient {
bool _isEthereum = currency == CryptoCurrency.eth;
- final price = await _client!.getGasPrice();
+ final price = _client!.getGasPrice();
final Transaction transaction = Transaction(
from: privateKey.address,
to: EthereumAddress.fromHex(toAddress),
- maxGas: gas,
- gasPrice: price,
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
value: _isEthereum ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
);
@@ -101,7 +99,7 @@ class EthereumClient {
return PendingEthereumTransaction(
signedTransaction: signedTransaction,
amount: amount,
- fee: BigInt.from(gas) * price.getInWei,
+ fee: BigInt.from(gas) * (await price).getInWei,
sendTransaction: _sendTransaction,
exponent: exponent,
);
@@ -210,6 +208,10 @@ I/flutter ( 4474): Gas Used: 53000
}
}
+ Web3Client? getWeb3Client() {
+ return _client;
+ }
+
// Future _getDecimalPlacesForContract(DeployedContract contract) async {
// final String abi = await rootBundle.loadString("assets/abi_json/erc20_abi.json");
// final contractAbi = ContractAbi.fromJson(abi, "ERC20");
diff --git a/cw_ethereum/lib/ethereum_wallet.dart b/cw_ethereum/lib/ethereum_wallet.dart
index 012b33a4b..21bde1233 100644
--- a/cw_ethereum/lib/ethereum_wallet.dart
+++ b/cw_ethereum/lib/ethereum_wallet.dart
@@ -77,6 +77,8 @@ abstract class EthereumWalletBase
late final EthPrivateKey _ethPrivateKey;
+ EthPrivateKey get ethPrivateKey => _ethPrivateKey;
+
late EthereumClient _client;
int? _gasPrice;
@@ -508,4 +510,6 @@ abstract class EthereumWalletBase
@override
String signMessage(String message, {String? address = null}) =>
bytesToHex(_ethPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
+
+ Web3Client? getWeb3Client() => _client.getWeb3Client();
}
diff --git a/cw_monero/ios/Classes/monero_api.cpp b/cw_monero/ios/Classes/monero_api.cpp
index 1cb01fac7..e04282fe8 100644
--- a/cw_monero/ios/Classes/monero_api.cpp
+++ b/cw_monero/ios/Classes/monero_api.cpp
@@ -234,7 +234,6 @@ extern "C"
}
void setUnlocked(bool unlocked);
-
};
Monero::Coins *m_coins;
@@ -568,7 +567,7 @@ extern "C"
_preferred_inputs.insert(std::string(*preferred_inputs));
preferred_inputs++;
}
-
+
auto priority = static_cast(priority_raw);
std::string _payment_id;
Monero::PendingTransaction *transaction;
diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart
index f9b3c1997..75c1df89e 100644
--- a/cw_monero/lib/monero_wallet.dart
+++ b/cw_monero/lib/monero_wallet.dart
@@ -37,10 +37,10 @@ const moneroBlockSize = 1000;
class MoneroWallet = MoneroWalletBase with _$MoneroWallet;
-abstract class MoneroWalletBase extends WalletBase with Store {
- MoneroWalletBase({required WalletInfo walletInfo,
- required Box unspentCoinsInfo})
+abstract class MoneroWalletBase
+ extends WalletBase with Store {
+ MoneroWalletBase(
+ {required WalletInfo walletInfo, required Box unspentCoinsInfo})
: balance = ObservableMap.of({
CryptoCurrency.xmr: MoneroBalance(
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
@@ -112,12 +112,12 @@ abstract class MoneroWalletBase extends WalletBase init() async {
await walletAddresses.init();
- balance = ObservableMap.of(
- {
- currency: MoneroBalance(
- fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id),
- unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id))
- });
+ balance = ObservableMap.of({
+ currency: MoneroBalance(
+ fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account!.id),
+ unlockedBalance:
+ monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id))
+ });
_setListeners();
await updateTransactions();
@@ -125,15 +125,14 @@ abstract class MoneroWalletBase extends WalletBase await save());
+ _autoSaveTimer =
+ Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
}
+
@override
Future? updateBalance() => null;
@@ -153,7 +152,8 @@ abstract class MoneroWalletBase extends WalletBase 1;
final unlockedBalance =
- monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
+ monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
var allInputsAmount = 0;
PendingTransactionDescription pendingTransactionDescription;
@@ -208,56 +208,42 @@ abstract class MoneroWalletBase extends WalletBase item.sendAll
- || (item.formattedCryptoAmount ?? 0) <= 0)) {
+ if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.');
}
- final int totalAmount = outputs.fold(0, (acc, value) =>
- acc + (value.formattedCryptoAmount ?? 0));
+ final int totalAmount =
+ outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
final estimatedFee = calculateEstimatedFee(_credentials.priority, totalAmount);
if (unlockedBalance < totalAmount) {
throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.');
}
- if (allInputsAmount < totalAmount + estimatedFee) {
+ if (!spendAllCoins && (allInputsAmount < totalAmount + estimatedFee)) {
throw MoneroTransactionNoInputsException(inputs.length);
}
final moneroOutputs = outputs.map((output) {
- final outputAddress = output.isParsedAddress
- ? output.extractedAddress
- : output.address;
+ final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address;
- return MoneroOutput(
- address: outputAddress!,
- amount: output.cryptoAmount!.replaceAll(',', '.'));
+ return MoneroOutput(
+ address: outputAddress!, amount: output.cryptoAmount!.replaceAll(',', '.'));
}).toList();
- pendingTransactionDescription =
- await transaction_history.createTransactionMultDest(
+ pendingTransactionDescription = await transaction_history.createTransactionMultDest(
outputs: moneroOutputs,
priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account!.id,
preferredInputs: inputs);
} else {
final output = outputs.first;
- final address = output.isParsedAddress
- ? output.extractedAddress
- : output.address;
- final amount = output.sendAll
- ? null
- : output.cryptoAmount!.replaceAll(',', '.');
- final formattedAmount = output.sendAll
- ? null
- : output.formattedCryptoAmount;
+ final address = output.isParsedAddress ? output.extractedAddress : output.address;
+ final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
+ final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount;
if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
(formattedAmount == null && unlockedBalance <= 0)) {
@@ -268,8 +254,9 @@ abstract class MoneroWalletBase extends WalletBase
- element.walletId.contains(id) && element.hash.contains(coin.hash));
+ final coinInfoList = unspentCoinsInfo.values
+ .where((element) => element.walletId.contains(id) && element.hash.contains(coin.hash));
if (coinInfoList.isNotEmpty) {
final coinInfo = coinInfoList.first;
@@ -447,16 +430,15 @@ abstract class MoneroWalletBase extends WalletBase _addCoinInfo(MoneroUnspent coin) async {
final newInfo = UnspentCoinsInfo(
- walletId: id,
- hash: coin.hash,
- isFrozen: coin.isFrozen,
- isSending: coin.isSending,
- noteRaw: coin.note,
- address: coin.address,
- value: coin.value,
- vout: 0,
- keyImage: coin.keyImage
- );
+ walletId: id,
+ hash: coin.hash,
+ isFrozen: coin.isFrozen,
+ isSending: coin.isSending,
+ noteRaw: coin.note,
+ address: coin.address,
+ value: coin.value,
+ vout: 0,
+ keyImage: coin.keyImage);
await unspentCoinsInfo.add(newInfo);
}
@@ -464,8 +446,8 @@ abstract class MoneroWalletBase extends WalletBase _refreshUnspentCoinsInfo() async {
try {
final List keys = [];
- final currentWalletUnspentCoins = unspentCoinsInfo.values
- .where((element) => element.walletId.contains(id));
+ final currentWalletUnspentCoins =
+ unspentCoinsInfo.values.where((element) => element.walletId.contains(id));
if (currentWalletUnspentCoins.isNotEmpty) {
currentWalletUnspentCoins.forEach((element) {
@@ -486,16 +468,14 @@ abstract class MoneroWalletBase extends WalletBase
- monero_wallet.getAddress(
- accountIndex: accountIndex,
- addressIndex: addressIndex);
+ monero_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex);
@override
Future