derivation updates

This commit is contained in:
fosse 2023-07-28 10:36:50 -04:00
parent 490618ebd6
commit 33c99cb2a5
7 changed files with 168 additions and 68 deletions

View file

@ -13,6 +13,9 @@ import 'package:web3dart/contracts/erc20.dart';
import 'package:cw_core/node.dart';
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();
StreamSubscription<Transfer>? subscription;
Node? _node;
@ -97,23 +100,4 @@ class NanoClient {
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;
// }
}

View file

@ -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_info.dart';
import 'package:cw_nano/nano_util.dart';
import 'package:cw_nano/nano_wallet_info.dart';
import 'package:mobx/mobx.dart';
import 'dart:async';
import 'package:cw_nano/nano_wallet_addresses.dart';
@ -27,20 +28,17 @@ part 'nano_wallet.g.dart';
class NanoWallet = NanoWalletBase with _$NanoWallet;
enum DerivationType { bip39, nano }
abstract class NanoWalletBase
extends WalletBase<NanoBalance, NanoTransactionHistory, NanoTransactionInfo> with Store {
NanoWalletBase({
required WalletInfo walletInfo,
required NanoWalletInfo walletInfo,
required String mnemonic,
required String password,
required DerivationType derivationType,
NanoBalance? initialBalance,
}) : syncStatus = NotConnectedSyncStatus(),
_password = password,
_mnemonic = mnemonic,
_derivationType = derivationType,
_derivationType = walletInfo.derivationType,
_isTransactionUpdating = false,
_client = NanoClient(),
walletAddresses = NanoWalletAddresses(walletInfo),
@ -86,8 +84,6 @@ abstract class NanoWalletBase
await walletAddresses.init();
await transactionHistory.init();
// walletAddresses.address = _privateKey.address.toString();
await save();
}
@ -127,7 +123,58 @@ abstract class NanoWalletBase
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
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 {
@ -178,9 +225,10 @@ abstract class NanoWalletBase
}
@override
Future<void> rescan({required int height}) {
print("k");
throw UnimplementedError("rescan");
Future<void> rescan({required int height}) async {
fetchTransactions();
_updateBalance();
return;
}
@override
@ -235,17 +283,20 @@ abstract class NanoWalletBase
derivationType = DerivationType.nano;
}
return NanoWallet(
final nanoWalletInfo = NanoWalletInfo(
walletInfo: walletInfo,
derivationType: derivationType,
);
return NanoWallet(
walletInfo: nanoWalletInfo,
password: password,
mnemonic: mnemonic,
initialBalance: balance,
derivationType: derivationType,
);
}
Future<void> _updateBalance() async {
// this.balance.update(CryptoCurrency.nano, (value) => (await _client.getBalance(_publicAddress)));
balance[currency] = await _client.getBalance(_publicAddress);
await save();
}

View 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,
);
}

View file

@ -1,15 +1,18 @@
import 'dart:io';
import 'package:cw_core/node.dart';
import 'package:cw_core/pathForWallet.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_service.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_mnemonics.dart';
import 'package:cw_nano/nano_util.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:bip39/bip39.dart' as bip39;
@ -62,11 +65,16 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
Future<WalletBase> create(NanoNewWalletCredentials credentials) async {
print("nano_wallet_service create");
final mnemonic = bip39.generateMnemonic();
final wallet = NanoWallet(
final nanoWalletInfo = NanoWalletInfo(
walletInfo: credentials.walletInfo!,
derivationType: DerivationType.nano,
);
final wallet = NanoWallet(
walletInfo: nanoWalletInfo,
mnemonic: mnemonic,
password: credentials.password!,
derivationType: DerivationType.bip39,
);
return wallet;
}
@ -102,35 +110,69 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
}
Future<DerivationType> compareDerivationMethods({String? mnemonic, String? seedKey}) async {
// TODO:
return DerivationType.nano;
if (seedKey?.length == 128) {
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
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async {
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.bip39;
} else {
// we don't know for sure, but probably the nano standard:
derivationType = await compareDerivationMethods(seedKey: credentials.seedKey);
}
String? mnemonic;
final wallet = await NanoWallet(
password: credentials.password!,
mnemonic: mnemonic ?? "", // we can't derive the mnemonic from the key in all cases
walletInfo: credentials.walletInfo!,
derivationType: derivationType,
);
await wallet.init();
await wallet.save();
return wallet;
// DerivationType derivationType = await compareDerivationMethods(seedKey: credentials.seedKey);
// String? mnemonic;
// final nanoWalletInfo = NanoWalletInfo(
// walletInfo: credentials.walletInfo!,
// derivationType: derivationType,
// );
// final wallet = await NanoWallet(
// password: credentials.password!,
// mnemonic: mnemonic ?? "", // we can't derive the mnemonic from the key in all cases
// walletInfo: nanoWalletInfo,
// );
// await wallet.init();
// await wallet.save();
// return wallet;
}
@override
@ -143,20 +185,17 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
throw NanoMnemonicIsIncorrectException();
}
DerivationType derivationType = DerivationType.bip39;
DerivationType derivationType = await compareDerivationMethods(mnemonic: credentials.mnemonic);
if (credentials.mnemonic.split(' ').length == 12) {
derivationType = DerivationType.bip39;
} else {
// we don't know for sure, but probably the nano standard:
derivationType = await compareDerivationMethods(mnemonic: credentials.mnemonic);
}
final nanoWalletInfo = NanoWalletInfo(
walletInfo: credentials.walletInfo!,
derivationType: derivationType,
);
final wallet = await NanoWallet(
password: credentials.password!,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
derivationType: derivationType,
walletInfo: nanoWalletInfo,
);
await wallet.init();

View file

@ -1,4 +1,5 @@
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:mobx/mobx.dart';
import 'package:cw_core/wallet_credentials.dart';

View file

@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cw_nano/nano_wallet.dart';
import 'package:cw_nano/nano_wallet_info.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/store/app_store.dart';

View file

@ -581,6 +581,7 @@ Future<void> generateNano(bool hasImplementation) async {
const nanoCWHeaders = """
import 'package:mobx/mobx.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/transaction_history.dart';
import 'package:cw_core/wallet_service.dart';