mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-21 14:48:53 +00:00
derivation updates
This commit is contained in:
parent
490618ebd6
commit
33c99cb2a5
7 changed files with 168 additions and 68 deletions
|
@ -13,6 +13,9 @@ import 'package:web3dart/contracts/erc20.dart';
|
||||||
import 'package:cw_core/node.dart';
|
import 'package:cw_core/node.dart';
|
||||||
|
|
||||||
class NanoClient {
|
class NanoClient {
|
||||||
|
// bit of a hack since we need access to a node in a weird location:
|
||||||
|
static const String BACKUP_NODE_URI = "rpc.nano.to";
|
||||||
|
|
||||||
final _httpClient = Client();
|
final _httpClient = Client();
|
||||||
StreamSubscription<Transfer>? subscription;
|
StreamSubscription<Transfer>? subscription;
|
||||||
Node? _node;
|
Node? _node;
|
||||||
|
@ -97,23 +100,4 @@ class NanoClient {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<int> _getDecimalPlacesForContract(DeployedContract contract) async {
|
|
||||||
// final String abi = await rootBundle.loadString("assets/abi_json/erc20_abi.json");
|
|
||||||
// final contractAbi = ContractAbi.fromJson(abi, "ERC20");
|
|
||||||
//
|
|
||||||
// final contract = DeployedContract(
|
|
||||||
// contractAbi,
|
|
||||||
// EthereumAddress.fromHex(_erc20Currencies[erc20Currency]!),
|
|
||||||
// );
|
|
||||||
// final decimalsFunction = contract.function('decimals');
|
|
||||||
// final decimals = await _client!.call(
|
|
||||||
// contract: contract,
|
|
||||||
// function: decimalsFunction,
|
|
||||||
// params: [],
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// int exponent = int.parse(decimals.first.toString());
|
|
||||||
// return exponent;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import 'package:cw_nano/nano_client.dart';
|
||||||
import 'package:cw_nano/nano_transaction_history.dart';
|
import 'package:cw_nano/nano_transaction_history.dart';
|
||||||
import 'package:cw_nano/nano_transaction_info.dart';
|
import 'package:cw_nano/nano_transaction_info.dart';
|
||||||
import 'package:cw_nano/nano_util.dart';
|
import 'package:cw_nano/nano_util.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet_info.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:cw_nano/nano_wallet_addresses.dart';
|
import 'package:cw_nano/nano_wallet_addresses.dart';
|
||||||
|
@ -27,20 +28,17 @@ part 'nano_wallet.g.dart';
|
||||||
|
|
||||||
class NanoWallet = NanoWalletBase with _$NanoWallet;
|
class NanoWallet = NanoWalletBase with _$NanoWallet;
|
||||||
|
|
||||||
enum DerivationType { bip39, nano }
|
|
||||||
|
|
||||||
abstract class NanoWalletBase
|
abstract class NanoWalletBase
|
||||||
extends WalletBase<NanoBalance, NanoTransactionHistory, NanoTransactionInfo> with Store {
|
extends WalletBase<NanoBalance, NanoTransactionHistory, NanoTransactionInfo> with Store {
|
||||||
NanoWalletBase({
|
NanoWalletBase({
|
||||||
required WalletInfo walletInfo,
|
required NanoWalletInfo walletInfo,
|
||||||
required String mnemonic,
|
required String mnemonic,
|
||||||
required String password,
|
required String password,
|
||||||
required DerivationType derivationType,
|
|
||||||
NanoBalance? initialBalance,
|
NanoBalance? initialBalance,
|
||||||
}) : syncStatus = NotConnectedSyncStatus(),
|
}) : syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
_derivationType = derivationType,
|
_derivationType = walletInfo.derivationType,
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
_client = NanoClient(),
|
_client = NanoClient(),
|
||||||
walletAddresses = NanoWalletAddresses(walletInfo),
|
walletAddresses = NanoWalletAddresses(walletInfo),
|
||||||
|
@ -86,8 +84,6 @@ abstract class NanoWalletBase
|
||||||
|
|
||||||
await walletAddresses.init();
|
await walletAddresses.init();
|
||||||
await transactionHistory.init();
|
await transactionHistory.init();
|
||||||
|
|
||||||
// walletAddresses.address = _privateKey.address.toString();
|
|
||||||
await save();
|
await save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +123,58 @@ abstract class NanoWalletBase
|
||||||
@override
|
@override
|
||||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
print("g");
|
print("g");
|
||||||
throw UnimplementedError();
|
print(credentials);
|
||||||
|
// throw UnimplementedError();
|
||||||
|
|
||||||
|
// final _credentials = credentials as EthereumTransactionCredentials;
|
||||||
|
// final outputs = _credentials.outputs;
|
||||||
|
// final hasMultiDestination = outputs.length > 1;
|
||||||
|
// final _erc20Balance = balance[_credentials.currency]!;
|
||||||
|
// BigInt totalAmount = BigInt.zero;
|
||||||
|
// int exponent =
|
||||||
|
// _credentials.currency is Erc20Token ? (_credentials.currency as Erc20Token).decimal : 18;
|
||||||
|
// BigInt amountToEthereumMultiplier = BigInt.from(pow(10, exponent));
|
||||||
|
|
||||||
|
// if (hasMultiDestination) {
|
||||||
|
// if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
|
||||||
|
// throw EthereumTransactionCreationException(_credentials.currency);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// final totalOriginalAmount = EthereumFormatter.parseEthereumAmountToDouble(
|
||||||
|
// outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
|
||||||
|
// totalAmount = BigInt.from(totalOriginalAmount) * amountToEthereumMultiplier;
|
||||||
|
|
||||||
|
// if (_erc20Balance.balance < totalAmount) {
|
||||||
|
// throw EthereumTransactionCreationException(_credentials.currency);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// final output = outputs.first;
|
||||||
|
// final BigInt allAmount = _erc20Balance.balance - BigInt.from(feeRate(_credentials.priority!));
|
||||||
|
// final totalOriginalAmount =
|
||||||
|
// EthereumFormatter.parseEthereumAmountToDouble(output.formattedCryptoAmount ?? 0);
|
||||||
|
// totalAmount = output.sendAll
|
||||||
|
// ? allAmount
|
||||||
|
// : BigInt.from(totalOriginalAmount) * amountToEthereumMultiplier;
|
||||||
|
|
||||||
|
// if (_erc20Balance.balance < totalAmount) {
|
||||||
|
// throw EthereumTransactionCreationException(_credentials.currency);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// final pendingEthereumTransaction = await _client.signTransaction(
|
||||||
|
// privateKey: _privateKey,
|
||||||
|
// toAddress: _credentials.outputs.first.address,
|
||||||
|
// amount: totalAmount.toString(),
|
||||||
|
// gas: _priorityFees[_credentials.priority!.raw],
|
||||||
|
// priority: _credentials.priority!,
|
||||||
|
// currency: _credentials.currency,
|
||||||
|
// exponent: exponent,
|
||||||
|
// contractAddress: _credentials.currency is Erc20Token
|
||||||
|
// ? (_credentials.currency as Erc20Token).contractAddress
|
||||||
|
// : null,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return pendingEthereumTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateTransactions() async {
|
Future<void> updateTransactions() async {
|
||||||
|
@ -178,9 +225,10 @@ abstract class NanoWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> rescan({required int height}) {
|
Future<void> rescan({required int height}) async {
|
||||||
print("k");
|
fetchTransactions();
|
||||||
throw UnimplementedError("rescan");
|
_updateBalance();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -235,17 +283,20 @@ abstract class NanoWalletBase
|
||||||
derivationType = DerivationType.nano;
|
derivationType = DerivationType.nano;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NanoWallet(
|
final nanoWalletInfo = NanoWalletInfo(
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
derivationType: derivationType,
|
||||||
|
);
|
||||||
|
|
||||||
|
return NanoWallet(
|
||||||
|
walletInfo: nanoWalletInfo,
|
||||||
password: password,
|
password: password,
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
initialBalance: balance,
|
initialBalance: balance,
|
||||||
derivationType: derivationType,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateBalance() async {
|
Future<void> _updateBalance() async {
|
||||||
// this.balance.update(CryptoCurrency.nano, (value) => (await _client.getBalance(_publicAddress)));
|
|
||||||
balance[currency] = await _client.getBalance(_publicAddress);
|
balance[currency] = await _client.getBalance(_publicAddress);
|
||||||
await save();
|
await save();
|
||||||
}
|
}
|
||||||
|
|
23
cw_nano/lib/nano_wallet_info.dart
Normal file
23
cw_nano/lib/nano_wallet_info.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
|
enum DerivationType { bip39, nano }
|
||||||
|
|
||||||
|
class NanoWalletInfo extends WalletInfo {
|
||||||
|
DerivationType derivationType;
|
||||||
|
|
||||||
|
NanoWalletInfo({required WalletInfo walletInfo, required this.derivationType})
|
||||||
|
: super(
|
||||||
|
walletInfo.id,
|
||||||
|
walletInfo.name,
|
||||||
|
walletInfo.type,
|
||||||
|
walletInfo.isRecovery,
|
||||||
|
walletInfo.restoreHeight,
|
||||||
|
walletInfo.timestamp,
|
||||||
|
walletInfo.dirPath,
|
||||||
|
walletInfo.path,
|
||||||
|
walletInfo.address,
|
||||||
|
walletInfo.yatEid,
|
||||||
|
walletInfo.yatLastUsedAddressRaw,
|
||||||
|
walletInfo.showIntroCakePayCard,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,15 +1,18 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:cw_core/node.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:cw_nano/nano_balance.dart';
|
||||||
|
import 'package:cw_nano/nano_client.dart';
|
||||||
import 'package:cw_nano/nano_mnemonic.dart';
|
import 'package:cw_nano/nano_mnemonic.dart';
|
||||||
// import 'package:cw_nano/nano_mnemonics.dart';
|
import 'package:cw_nano/nano_util.dart';
|
||||||
import 'package:cw_nano/nano_wallet.dart';
|
import 'package:cw_nano/nano_wallet.dart';
|
||||||
import 'package:cw_nano/nano_wallet_creation_credentials.dart';
|
import 'package:cw_nano/nano_wallet_info.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
|
@ -62,11 +65,16 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
Future<WalletBase> create(NanoNewWalletCredentials credentials) async {
|
Future<WalletBase> create(NanoNewWalletCredentials credentials) async {
|
||||||
print("nano_wallet_service create");
|
print("nano_wallet_service create");
|
||||||
final mnemonic = bip39.generateMnemonic();
|
final mnemonic = bip39.generateMnemonic();
|
||||||
final wallet = NanoWallet(
|
|
||||||
|
final nanoWalletInfo = NanoWalletInfo(
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
derivationType: DerivationType.nano,
|
||||||
|
);
|
||||||
|
|
||||||
|
final wallet = NanoWallet(
|
||||||
|
walletInfo: nanoWalletInfo,
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
derivationType: DerivationType.bip39,
|
|
||||||
);
|
);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
@ -102,35 +110,69 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<DerivationType> compareDerivationMethods({String? mnemonic, String? seedKey}) async {
|
Future<DerivationType> compareDerivationMethods({String? mnemonic, String? seedKey}) async {
|
||||||
// TODO:
|
if (seedKey?.length == 128) {
|
||||||
return DerivationType.nano;
|
return DerivationType.bip39;
|
||||||
|
}
|
||||||
|
if (mnemonic?.split(' ').length == 12) {
|
||||||
|
return DerivationType.bip39;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
NanoClient nanoClient = NanoClient();
|
||||||
|
// TODO: figure out how to load the current node uri in this context:
|
||||||
|
nanoClient.connect(Node(
|
||||||
|
uri: NanoClient.BACKUP_NODE_URI,
|
||||||
|
type: WalletType.nano,
|
||||||
|
));
|
||||||
|
|
||||||
|
late String publicAddressStandard;
|
||||||
|
late String publicAddressBip39;
|
||||||
|
|
||||||
|
if (seedKey == null) {
|
||||||
|
seedKey = bip39.mnemonicToEntropy(mnemonic).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
publicAddressBip39 = await NanoUtil.hdSeedToAddress(seedKey, 0);
|
||||||
|
publicAddressStandard = await NanoUtil.seedToAddress(seedKey, 0);
|
||||||
|
|
||||||
|
// check if either has a balance:
|
||||||
|
|
||||||
|
NanoBalance bip39Balance = await nanoClient.getBalance(publicAddressBip39);
|
||||||
|
NanoBalance standardBalance = await nanoClient.getBalance(publicAddressStandard);
|
||||||
|
|
||||||
|
// TODO: this is super basic implementation, and if both addresses have balances
|
||||||
|
// it might not be the one that the user wants, though it is unlikely
|
||||||
|
if (bip39Balance.currentBalance > standardBalance.currentBalance) {
|
||||||
|
return DerivationType.bip39;
|
||||||
|
} else {
|
||||||
|
return DerivationType.nano;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return DerivationType.nano;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async {
|
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async {
|
||||||
throw UnimplementedError("restoreFromKeys");
|
throw UnimplementedError("restoreFromKeys");
|
||||||
|
|
||||||
DerivationType derivationType = DerivationType.bip39;
|
// TODO: mnemonic can't be derived from the seedKey in the nanostandard derivation
|
||||||
|
// which complicates things
|
||||||
|
|
||||||
if (credentials.seedKey.length == 128) {
|
// DerivationType derivationType = await compareDerivationMethods(seedKey: credentials.seedKey);
|
||||||
derivationType = DerivationType.bip39;
|
// String? mnemonic;
|
||||||
} else {
|
// final nanoWalletInfo = NanoWalletInfo(
|
||||||
// we don't know for sure, but probably the nano standard:
|
// walletInfo: credentials.walletInfo!,
|
||||||
derivationType = await compareDerivationMethods(seedKey: credentials.seedKey);
|
// derivationType: derivationType,
|
||||||
}
|
// );
|
||||||
|
// final wallet = await NanoWallet(
|
||||||
String? mnemonic;
|
// password: credentials.password!,
|
||||||
|
// mnemonic: mnemonic ?? "", // we can't derive the mnemonic from the key in all cases
|
||||||
final wallet = await NanoWallet(
|
// walletInfo: nanoWalletInfo,
|
||||||
password: credentials.password!,
|
// );
|
||||||
mnemonic: mnemonic ?? "", // we can't derive the mnemonic from the key in all cases
|
// await wallet.init();
|
||||||
walletInfo: credentials.walletInfo!,
|
// await wallet.save();
|
||||||
derivationType: derivationType,
|
// return wallet;
|
||||||
);
|
|
||||||
|
|
||||||
await wallet.init();
|
|
||||||
await wallet.save();
|
|
||||||
return wallet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -143,20 +185,17 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||||
throw NanoMnemonicIsIncorrectException();
|
throw NanoMnemonicIsIncorrectException();
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivationType derivationType = DerivationType.bip39;
|
DerivationType derivationType = await compareDerivationMethods(mnemonic: credentials.mnemonic);
|
||||||
|
|
||||||
if (credentials.mnemonic.split(' ').length == 12) {
|
final nanoWalletInfo = NanoWalletInfo(
|
||||||
derivationType = DerivationType.bip39;
|
walletInfo: credentials.walletInfo!,
|
||||||
} else {
|
derivationType: derivationType,
|
||||||
// we don't know for sure, but probably the nano standard:
|
);
|
||||||
derivationType = await compareDerivationMethods(mnemonic: credentials.mnemonic);
|
|
||||||
}
|
|
||||||
|
|
||||||
final wallet = await NanoWallet(
|
final wallet = await NanoWallet(
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: nanoWalletInfo,
|
||||||
derivationType: derivationType,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cw_nano/nano_wallet.dart';
|
import 'package:cw_nano/nano_wallet.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet_info.dart';
|
||||||
import 'package:cw_nano/nano_wallet_service.dart';
|
import 'package:cw_nano/nano_wallet_service.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.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:cw_nano/nano_wallet.dart';
|
import 'package:cw_nano/nano_wallet.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet_info.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';
|
||||||
|
|
|
@ -581,6 +581,7 @@ Future<void> generateNano(bool hasImplementation) async {
|
||||||
const nanoCWHeaders = """
|
const nanoCWHeaders = """
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
|
import 'package:cw_nano/nano_wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
|
Loading…
Reference in a new issue