mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-12 09:32:33 +00:00
Add initial send transaction flow
This commit is contained in:
parent
405cf2aaab
commit
268a6c3a05
14 changed files with 219 additions and 23 deletions
|
@ -202,7 +202,7 @@ packages:
|
|||
source: hosted
|
||||
version: "2.0.1"
|
||||
file:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file
|
||||
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||
|
|
|
@ -31,11 +31,27 @@ class EthereumClient {
|
|||
final result = await Future.wait(EthereumTransactionPriority.all.map(
|
||||
(priority) => _client!.estimateGas(
|
||||
maxPriorityFeePerGas: EtherAmount.fromUnitAndValue(EtherUnit.gwei, priority.tip),
|
||||
maxFeePerGas: EtherAmount.fromUnitAndValue(EtherUnit.gwei, 100),
|
||||
|
||||
// maxFeePerGas: EtherAmount.fromUnitAndValue(EtherUnit.gwei, 100),
|
||||
),
|
||||
));
|
||||
|
||||
return result.map((e) => e.toInt()).toList();
|
||||
}
|
||||
|
||||
Future<String> sendTransaction(String privateKey, String toAddress, String amount) async {
|
||||
final credentials = EthPrivateKey.fromHex(privateKey);
|
||||
|
||||
final transaction = Transaction(
|
||||
from: credentials.address,
|
||||
to: EthereumAddress.fromHex(toAddress),
|
||||
value: EtherAmount.fromUnitAndValue(EtherUnit.ether, amount),
|
||||
);
|
||||
|
||||
await _client!.signTransaction(credentials, transaction);
|
||||
|
||||
return await _client!.sendTransaction(
|
||||
credentials,
|
||||
transaction,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
6
cw_ethereum/lib/ethereum_exceptions.dart
Normal file
6
cw_ethereum/lib/ethereum_exceptions.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
class EthereumTransactionCreationException implements Exception {
|
||||
EthereumTransactionCreationException();
|
||||
|
||||
@override
|
||||
String toString() => 'Wrong balance. Not enough Ether on your balance.';
|
||||
}
|
6
cw_ethereum/lib/ethereum_formatter.dart
Normal file
6
cw_ethereum/lib/ethereum_formatter.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
import 'package:web3dart/web3dart.dart';
|
||||
|
||||
class EthereumFormatter {
|
||||
static int parseEthereumAmount(String amount) =>
|
||||
EtherAmount.fromUnitAndValue(EtherUnit.ether, amount).getInWei.toInt();
|
||||
}
|
10
cw_ethereum/lib/ethereum_transaction_credentials.dart
Normal file
10
cw_ethereum/lib/ethereum_transaction_credentials.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
import 'package:cw_core/output_info.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_priority.dart';
|
||||
|
||||
class EthereumTransactionCredentials {
|
||||
EthereumTransactionCredentials(this.outputs, {required this.priority, this.feeRate});
|
||||
|
||||
final List<OutputInfo> outputs;
|
||||
final EthereumTransactionPriority? priority;
|
||||
final int? feeRate;
|
||||
}
|
|
@ -12,11 +12,14 @@ import 'package:cw_core/wallet_base.dart';
|
|||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_ethereum/ethereum_balance.dart';
|
||||
import 'package:cw_ethereum/ethereum_client.dart';
|
||||
import 'package:cw_ethereum/ethereum_exceptions.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_credentials.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_history.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_info.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_priority.dart';
|
||||
import 'package:cw_ethereum/ethereum_wallet_addresses.dart';
|
||||
import 'package:cw_ethereum/file.dart';
|
||||
import 'package:cw_ethereum/pending_ethereum_transaction.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:web3dart/web3dart.dart';
|
||||
import 'package:ed25519_hd_key/ed25519_hd_key.dart';
|
||||
|
@ -50,7 +53,7 @@ abstract class EthereumWalletBase
|
|||
final String _mnemonic;
|
||||
final String _password;
|
||||
|
||||
late final String privateKey;
|
||||
late final String _privateKey;
|
||||
|
||||
late EthereumClient _client;
|
||||
|
||||
|
@ -69,9 +72,9 @@ abstract class EthereumWalletBase
|
|||
late ObservableMap<CryptoCurrency, EthereumBalance> balance;
|
||||
|
||||
Future<void> init() async {
|
||||
privateKey = await getPrivateKey(_mnemonic, _password);
|
||||
_privateKey = await getPrivateKey(_mnemonic, _password);
|
||||
transactionHistory = EthereumTransactionHistory();
|
||||
walletAddresses.address = EthPrivateKey.fromHex(privateKey).address.toString();
|
||||
walletAddresses.address = EthPrivateKey.fromHex(_privateKey).address.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -116,8 +119,78 @@ abstract class EthereumWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) {
|
||||
throw UnimplementedError("createTransaction");
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
final _credentials = credentials as EthereumTransactionCredentials;
|
||||
final outputs = _credentials.outputs;
|
||||
final hasMultiDestination = outputs.length > 1;
|
||||
final balance = await _client.getBalance(_privateKey);
|
||||
|
||||
if (hasMultiDestination) {
|
||||
outputs.any((element) => element.sendAll);
|
||||
}
|
||||
|
||||
|
||||
// if (hasMultiDestination) {
|
||||
// if (outputs.any((item) => item.sendAll
|
||||
// || (item.formattedCryptoAmount ?? 0) <= 0)) {
|
||||
// throw EthereumTransactionCreationException();
|
||||
// }
|
||||
//
|
||||
// final BigInt totalAmount = outputs.fold(0, (acc, value) =>
|
||||
// acc + (value.formattedCryptoAmount ?? 0));
|
||||
//
|
||||
// if (balance.getInWei < EtherAmount.inWei(totalAmount)) {
|
||||
// throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
|
||||
// }
|
||||
//
|
||||
// final moneroOutputs = outputs.map((output) {
|
||||
// final outputAddress = output.isParsedAddress
|
||||
// ? output.extractedAddress
|
||||
// : output.address;
|
||||
//
|
||||
// return MoneroOutput(
|
||||
// address: outputAddress!,
|
||||
// amount: output.cryptoAmount!.replaceAll(',', '.'));
|
||||
// }).toList();
|
||||
//
|
||||
// pendingTransactionDescription =
|
||||
// await transaction_history.createTransactionMultDest(
|
||||
// outputs: moneroOutputs,
|
||||
// priorityRaw: _credentials.priority.serialize(),
|
||||
// accountIndex: walletAddresses.account!.id);
|
||||
// } 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;
|
||||
//
|
||||
// if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
|
||||
// (formattedAmount == null && unlockedBalance <= 0)) {
|
||||
// final formattedBalance = moneroAmountToString(amount: unlockedBalance);
|
||||
//
|
||||
// throw MoneroTransactionCreationException(
|
||||
// 'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
|
||||
// }
|
||||
//
|
||||
// pendingTransactionDescription =
|
||||
// await transaction_history.createTransaction(
|
||||
// address: address!,
|
||||
// amount: amount,
|
||||
// priorityRaw: _credentials.priority.serialize(),
|
||||
// accountIndex: walletAddresses.account!.id);
|
||||
// }
|
||||
|
||||
return PendingEthereumTransaction(
|
||||
client: _client,
|
||||
credentials: _credentials,
|
||||
privateKey: _privateKey,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -211,7 +284,7 @@ abstract class EthereumWalletBase
|
|||
}
|
||||
|
||||
Future<EthereumBalance> _fetchBalances() async {
|
||||
final balance = await _client.getBalance(privateKey);
|
||||
final balance = await _client.getBalance(_privateKey);
|
||||
|
||||
return EthereumBalance(
|
||||
available: balance.getInEther.toInt(),
|
||||
|
|
38
cw_ethereum/lib/pending_ethereum_transaction.dart
Normal file
38
cw_ethereum/lib/pending_ethereum_transaction.dart
Normal file
|
@ -0,0 +1,38 @@
|
|||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_ethereum/ethereum_client.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_credentials.dart';
|
||||
|
||||
class PendingEthereumTransaction with PendingTransaction {
|
||||
final EthereumClient client;
|
||||
final EthereumTransactionCredentials credentials;
|
||||
final String privateKey;
|
||||
|
||||
PendingEthereumTransaction({
|
||||
required this.client,
|
||||
required this.credentials,
|
||||
required this.privateKey,
|
||||
});
|
||||
|
||||
@override
|
||||
// TODO: implement amountFormatted
|
||||
String get amountFormatted => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<void> commit() async {
|
||||
for (var output in credentials.outputs) {
|
||||
await client.sendTransaction(privateKey, output.address, output.cryptoAmount!);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement feeFormatted
|
||||
String get feeFormatted => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
// TODO: implement hex
|
||||
String get hex => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
// TODO: implement id
|
||||
String get id => throw UnimplementedError();
|
||||
}
|
|
@ -204,10 +204,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "13a6ccf6a459a125b3fcdb6ec73bd5ff90822e071207c663bfd1f70062d51d18"
|
||||
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "2.0.1"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -454,10 +454,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: a34ecd7fb548f8e57321fd8e50d865d266941b54e6c3b7758cf8f37c24116905
|
||||
sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
version: "2.1.5"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -651,10 +651,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: c0e3a4f7be7dae51d8f152230b86627e3397c1ba8c3fa58e63d44a9f3edc9cef
|
||||
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
version: "3.1.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -204,10 +204,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "13a6ccf6a459a125b3fcdb6ec73bd5ff90822e071207c663bfd1f70062d51d18"
|
||||
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "2.0.1"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -454,10 +454,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: a34ecd7fb548f8e57321fd8e50d865d266941b54e6c3b7758cf8f37c24116905
|
||||
sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
version: "2.1.5"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -651,10 +651,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: c0e3a4f7be7dae51d8f152230b86627e3397c1ba8c3fa58e63d44a9f3edc9cef
|
||||
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
version: "3.1.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -80,7 +80,7 @@ class CWBitcoin extends Bitcoin {
|
|||
isParsedAddress: out.isParsedAddress,
|
||||
formattedCryptoAmount: out.formattedCryptoAmount))
|
||||
.toList(),
|
||||
priority: priority != null ? priority as BitcoinTransactionPriority : null,
|
||||
priority: priority as BitcoinTransactionPriority,
|
||||
feeRate: feeRate);
|
||||
|
||||
@override
|
||||
|
|
|
@ -40,4 +40,33 @@ class CWEthereum extends Ethereum {
|
|||
final ethereumWallet = wallet as EthereumWallet;
|
||||
return ethereumWallet.feeRate(priority);
|
||||
}
|
||||
|
||||
Object createEthereumTransactionCredentials(List<Output> outputs,
|
||||
{required TransactionPriority priority, int? feeRate}) =>
|
||||
EthereumTransactionCredentials(
|
||||
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 EthereumTransactionPriority,
|
||||
feeRate: feeRate,
|
||||
);
|
||||
|
||||
Object createEthereumTransactionCredentialsRaw(List<OutputInfo> outputs,
|
||||
{TransactionPriority? priority, required int feeRate}) =>
|
||||
EthereumTransactionCredentials(
|
||||
outputs,
|
||||
priority: priority as EthereumTransactionPriority,
|
||||
feeRate: feeRate,
|
||||
);
|
||||
|
||||
@override
|
||||
int formatterEthereumParseAmount(String amount) => EthereumFormatter.parseEthereumAmount(amount);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/di.dart';
|
|||
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -70,7 +71,7 @@ abstract class OutputBase with Store {
|
|||
int amount = 0;
|
||||
|
||||
try {
|
||||
if (cryptoAmount?.isNotEmpty ?? false) {
|
||||
if (cryptoAmount.isNotEmpty) {
|
||||
final _cryptoAmount = cryptoAmount.replaceAll(',', '.');
|
||||
int _amount = 0;
|
||||
switch (walletType) {
|
||||
|
@ -88,6 +89,9 @@ abstract class OutputBase with Store {
|
|||
case WalletType.haven:
|
||||
_amount = haven!.formatterMoneroParseAmount(amount: _cryptoAmount);
|
||||
break;
|
||||
case WalletType.ethereum:
|
||||
_amount = ethereum!.formatterEthereumParseAmount(_cryptoAmount);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
|
@ -286,6 +287,14 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
return haven!.createHavenTransactionCreationCredentials(
|
||||
outputs: outputs, priority: priority, assetType: selectedCryptoCurrency.title);
|
||||
case WalletType.ethereum:
|
||||
final priority = _settingsStore.priority[_wallet.type];
|
||||
|
||||
if (priority == null) {
|
||||
throw Exception('Priority is null for wallet type: ${_wallet.type}');
|
||||
}
|
||||
|
||||
return ethereum!.createEthereumTransactionCredentials(outputs, priority: priority);
|
||||
default:
|
||||
throw Exception('Unexpected wallet type: ${_wallet.type}');
|
||||
}
|
||||
|
|
|
@ -477,6 +477,8 @@ Future<void> generateEthereum(bool hasImplementation) async {
|
|||
const ethereumCommonHeaders = """
|
||||
""";
|
||||
const ethereumCWHeaders = """
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cw_core/output_info.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
|
@ -501,6 +503,9 @@ abstract class Ethereum {
|
|||
List<TransactionPriority> getTransactionPriorities();
|
||||
TransactionPriority deserializeEthereumTransactionPriority(int raw);
|
||||
int getEstimatedFee(Object wallet, TransactionPriority priority);
|
||||
|
||||
Object createEthereumTransactionCredentials(List<Output> outputs, {required TransactionPriority priority, int? feeRate});
|
||||
Object createEthereumTransactionCredentialsRaw(List<OutputInfo> outputs, {TransactionPriority? priority, required int feeRate});
|
||||
}
|
||||
""";
|
||||
|
||||
|
|
Loading…
Reference in a new issue