Add initial flow for ethereum

This commit is contained in:
OmarHatem 2022-12-28 17:02:04 +02:00
parent a2ad2ca82f
commit 2c7883e099
28 changed files with 2490 additions and 17 deletions

1
.gitignore vendored
View file

@ -120,6 +120,7 @@ cw_haven/android/.cxx/
lib/bitcoin/bitcoin.dart
lib/monero/monero.dart
lib/haven/haven.dart
lib/ethereum/ethereum.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png

View file

@ -53,7 +53,7 @@ class BitcoinWalletService extends WalletService<
@override
Future<void> remove(String wallet) async =>
File(await pathForWalletDir(name: wallet, type: WalletType.bitcoin))
File(await pathForWalletDir(name: wallet, type: getType()))
.delete(recursive: true);
@override

View file

@ -7,7 +7,8 @@ const walletTypes = [
WalletType.monero,
WalletType.bitcoin,
WalletType.litecoin,
WalletType.haven
WalletType.haven,
WalletType.ethereum,
];
const walletTypeTypeId = 5;
@ -26,7 +27,10 @@ enum WalletType {
litecoin,
@HiveField(4)
haven
haven,
@HiveField(5)
ethereum
}
int serializeToInt(WalletType type) {
@ -39,6 +43,8 @@ int serializeToInt(WalletType type) {
return 2;
case WalletType.haven:
return 3;
case WalletType.ethereum:
return 4;
default:
return -1;
}
@ -54,6 +60,8 @@ WalletType deserializeFromInt(int raw) {
return WalletType.litecoin;
case 3:
return WalletType.haven;
case 4:
return WalletType.ethereum;
default:
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
}
@ -69,6 +77,8 @@ String walletTypeToString(WalletType type) {
return 'Litecoin';
case WalletType.haven:
return 'Haven';
case WalletType.ethereum:
return 'Ethereum';
default:
return '';
}
@ -84,6 +94,8 @@ String walletTypeToDisplayName(WalletType type) {
return 'Litecoin (Electrum)';
case WalletType.haven:
return 'Haven';
case WalletType.ethereum:
return 'Ethereum';
default:
return '';
}
@ -99,6 +111,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
return CryptoCurrency.ltc;
case WalletType.haven:
return CryptoCurrency.xhv;
case WalletType.ethereum:
return CryptoCurrency.eth;
default:
throw Exception('Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
}

30
cw_ethereum/.gitignore vendored Normal file
View 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_ethereum/.metadata Normal file
View 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: eb6d86ee27deecba4a83536aa20f366a6044895c
channel: stable
project_type: package

3
cw_ethereum/CHANGELOG.md Normal file
View file

@ -0,0 +1,3 @@
## 0.0.1
* TODO: Describe initial release.

1
cw_ethereum/LICENSE Normal file
View file

@ -0,0 +1 @@
TODO: Add your license here.

39
cw_ethereum/README.md Normal file
View 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.

View 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

View file

@ -0,0 +1,7 @@
library cw_ethereum;
/// A Calculator.
class Calculator {
/// Returns [value] plus 1.
int addOne(int value) => value + 1;
}

View file

@ -0,0 +1,13 @@
import 'package:cw_core/balance.dart';
class EthereumBalance extends Balance {
EthereumBalance(super.available, super.additional);
@override
// TODO: implement formattedAdditionalBalance
String get formattedAdditionalBalance => throw UnimplementedError();
@override
// TODO: implement formattedAvailableBalance
String get formattedAvailableBalance => throw UnimplementedError();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
import 'dart:core';
import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_ethereum/ethereum_transaction_info.dart';
part 'ethereum_transaction_history.g.dart';
class EthereumTransactionHistory = EthereumTransactionHistoryBase
with _$EthereumTransactionHistory;
abstract class EthereumTransactionHistoryBase
extends TransactionHistoryBase<EthereumTransactionInfo> with Store {
EthereumTransactionHistoryBase() {
transactions = ObservableMap<String, EthereumTransactionInfo>();
}
@override
Future<void> save() async {}
@override
void addOne(EthereumTransactionInfo transaction) =>
transactions[transaction.id] = transaction;
@override
void addMany(Map<String, EthereumTransactionInfo> transactions) =>
this.transactions.addAll(transactions);
}

View file

@ -0,0 +1,27 @@
import 'package:cw_core/transaction_info.dart';
class EthereumTransactionInfo extends TransactionInfo {
@override
String amountFormatted() {
// TODO: implement amountFormatted
throw UnimplementedError();
}
@override
void changeFiatAmount(String amount) {
// TODO: implement changeFiatAmount
}
@override
String? feeFormatted() {
// TODO: implement feeFormatted
throw UnimplementedError();
}
@override
String fiatAmount() {
// TODO: implement fiatAmount
throw UnimplementedError();
}
}

View file

@ -0,0 +1,15 @@
import 'package:cw_core/wallet_base.dart';
import 'package:cw_ethereum/ethereum_balance.dart';
import 'package:cw_ethereum/ethereum_transaction_history.dart';
import 'package:cw_ethereum/ethereum_transaction_info.dart';
import 'package:mobx/mobx.dart';
part 'ethereum_wallet.g.dart';
class EthereumWallet = EthereumWalletBase with _$EthereumWallet;
abstract class EthereumWalletBase
extends WalletBase<EthereumBalance, EthereumTransactionHistory, EthereumTransactionInfo>
with Store {
EthereumWalletBase(super.walletInfo);
}

View file

@ -0,0 +1,23 @@
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart';
class EthereumNewWalletCredentials extends WalletCredentials {
EthereumNewWalletCredentials({required String name, WalletInfo? walletInfo})
: super(name: name, walletInfo: walletInfo);
}
class EthereumRestoreWalletFromSeedCredentials extends WalletCredentials {
EthereumRestoreWalletFromSeedCredentials(
{required String name, required String password, required this.mnemonic, WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
final String mnemonic;
}
class EthereumRestoreWalletFromWIFCredentials extends WalletCredentials {
EthereumRestoreWalletFromWIFCredentials(
{required String name, required String password, required this.wif, WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
final String wif;
}

View file

@ -0,0 +1,64 @@
import 'dart:io';
import 'package:cw_core/balance.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.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_wallet.dart';
import 'package:cw_ethereum/ethereum_wallet_creation_credentials.dart';
import 'package:hive/hive.dart';
class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
EthereumRestoreWalletFromSeedCredentials, EthereumRestoreWalletFromWIFCredentials> {
EthereumWalletService(this.walletInfoSource);
final Box<WalletInfo> walletInfoSource;
@override
Future<EthereumWallet> create(EthereumNewWalletCredentials credentials) async {
final path = await pathForWallet(name: credentials.name, type: getType());
await monero_wallet_manager.createWallet(
path: path,
password: credentials.password!,
);
final wallet = EthereumWallet(credentials.walletInfo!);
await wallet.init();
return wallet;
}
@override
WalletType getType() => WalletType.ethereum;
@override
Future<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: getType())).existsSync();
@override
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>> openWallet(
String name, String password) {
// TODO: implement openWallet
throw UnimplementedError();
}
@override
Future<void> remove(String wallet) async =>
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
@override
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
restoreFromKeys(credentials) {
throw UnimplementedError();
}
@override
Future<WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>>
restoreFromSeed(credentials) {
// TODO: implement restoreFromSeed
throw UnimplementedError();
}
}

60
cw_ethereum/pubspec.yaml Normal file
View file

@ -0,0 +1,60 @@
name: cw_ethereum
description: A new Flutter package project.
version: 0.0.1
publish_to: none
author: Cake Wallet
homepage: https://cakewallet.com
environment:
sdk: '>=2.18.2 <3.0.0'
flutter: ">=1.17.0"
dependencies:
flutter:
sdk: flutter
web3dart: ^2.5.1
mobx: ^2.0.7+4
cw_core:
path: ../cw_core
dev_dependencies:
flutter_test:
sdk: flutter
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

View file

@ -0,0 +1,12 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:cw_ethereum/cw_ethereum.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);
});
}

View file

@ -13,17 +13,17 @@ class MoneroTransactionInfo extends TransactionInfo {
MoneroTransactionInfo.fromMap(Map<String, Object?> map)
: id = (map['hash'] ?? '') as String,
height = (map['height'] ?? 0) as int,
direction =
parseTransactionDirectionFromNumber(map['direction'] as String) ??
TransactionDirection.incoming,
direction = map['direction'] != null
? parseTransactionDirectionFromNumber(map['direction'] as String)
: TransactionDirection.incoming,
date = DateTime.fromMillisecondsSinceEpoch(
(int.parse(map['timestamp'] as String) ?? 0) * 1000),
(int.tryParse(map['timestamp'] as String? ?? '') ?? 0) * 1000),
isPending = parseBoolFromString(map['isPending'] as String),
amount = map['amount'] as int,
accountIndex = int.parse(map['accountIndex'] as String),
addressIndex = map['addressIndex'] as int,
key = getTxKey((map['hash'] ?? '') as String),
fee = map['fee'] as int ?? 0 {
fee = map['fee'] as int? ?? 0 {
additionalInfo = <String, dynamic>{
'key': key,
'accountIndex': accountIndex,
@ -34,8 +34,7 @@ class MoneroTransactionInfo extends TransactionInfo {
MoneroTransactionInfo.fromRow(TransactionInfoRow row)
: id = row.getHash(),
height = row.blockHeight,
direction = parseTransactionDirectionFromInt(row.direction) ??
TransactionDirection.incoming,
direction = parseTransactionDirectionFromInt(row.direction),
date = DateTime.fromMillisecondsSinceEpoch(row.getDatetime() * 1000),
isPending = row.isPending != 0,
amount = row.getAmount(),

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/entities/mnemonic_item.dart';
@ -25,6 +26,8 @@ class SeedValidator extends Validator<MnemonicItem> {
return monero!.getMoneroWordList(language);
case WalletType.haven:
return haven!.getMoneroWordList(language);
case WalletType.ethereum:
return ethereum!.getEthereumWordList(language);
default:
return [];
}

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/core/yat_service.dart';
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/entities/wake_lock.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/ionia/ionia_anypay.dart';
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart';
@ -562,6 +563,8 @@ Future setup(
case WalletType.litecoin:
return bitcoin!.createLitecoinWalletService(
_walletInfoSource, _unspentCoinsInfoSource!);
case WalletType.ethereum:
return ethereum!.createEthereumWalletService(_walletInfoSource);
default:
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
}

View file

@ -0,0 +1,12 @@
part of 'ethereum.dart';
class CWEthereum extends Ethereum {
@override
List<String> getEthereumWordList(String language) {
return EthereumMnemonics.englishWordlist;
}
WalletService createEthereumWalletService(Box<WalletInfo> walletInfoSource) {
return EthereumWalletService(walletInfoSource);
}
}

View file

@ -55,6 +55,8 @@ class WalletTypeFormState extends State<WalletTypeForm> {
Image.asset('assets/images/wallet_type_light.png');
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);
WalletType? selected;
List<WalletType> types;
@ -120,6 +122,8 @@ class WalletTypeFormState extends State<WalletTypeForm> {
return litecoinIcon;
case WalletType.haven:
return havenIcon;
case WalletType.ethereum:
return ethereumIcon;
default:
throw Exception('_iconFor: Incorrect Wallet Type. Cannot find icon for Wallet Type: ${type.toString()}');
}

View file

@ -47,6 +47,8 @@ class WalletListBodyState extends State<WalletListBody> {
Image.asset('assets/images/close.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 scrollController = ScrollController();
final double tileHeight = 60;
Flushbar<void>? _progressBar;
@ -214,6 +216,8 @@ class WalletListBodyState extends State<WalletListBody> {
return litecoinIcon;
case WalletType.haven:
return havenIcon;
case WalletType.ethereum:
return ethereumIcon;
default:
return nonWalletTypeIcon;
}

View file

@ -10,7 +10,7 @@ case $APP_ANDROID_TYPE in
CONFIG_ARGS="--monero"
;;
$CAKEWALLET)
CONFIG_ARGS="--monero --bitcoin --haven"
CONFIG_ARGS="--monero --bitcoin --haven --ethereum"
;;
$HAVEN)
CONFIG_ARGS="--haven"

View file

@ -23,7 +23,7 @@ case $APP_IOS_TYPE in
CONFIG_ARGS="--monero"
;;
$CAKEWALLET)
CONFIG_ARGS="--monero --bitcoin --haven"
CONFIG_ARGS="--monero --bitcoin --haven --ethereum"
;;
$HAVEN)
CONFIG_ARGS="--haven"

View file

@ -1,9 +1,9 @@
import 'dart:convert';
import 'dart:io';
const bitcoinOutputPath = 'lib/bitcoin/bitcoin.dart';
const moneroOutputPath = 'lib/monero/monero.dart';
const havenOutputPath = 'lib/haven/haven.dart';
const ethereumOutputPath = 'lib/ethereum/ethereum.dart';
const walletTypesPath = 'lib/wallet_types.g.dart';
const pubspecDefaultPath = 'pubspec_default.yaml';
const pubspecOutputPath = 'pubspec.yaml';
@ -13,11 +13,13 @@ Future<void> main(List<String> args) async {
final hasBitcoin = args.contains('${prefix}bitcoin');
final hasMonero = args.contains('${prefix}monero');
final hasHaven = args.contains('${prefix}haven');
final hasEthereum = args.contains('${prefix}ethereum');
await generateBitcoin(hasBitcoin);
await generateMonero(hasMonero);
await generateHaven(hasHaven);
await generatePubspec(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven);
await generateWalletTypes(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven);
await generateEthereum(hasEthereum);
await generatePubspec(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven, hasEthereum: hasEthereum);
await generateWalletTypes(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven, hasEthereum: hasEthereum);
}
Future<void> generateBitcoin(bool hasImplementation) async {
@ -469,7 +471,39 @@ abstract class HavenAccountList {
await outputFile.writeAsString(output);
}
Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin, required bool hasHaven}) async {
Future<void> generateEthereum(bool hasImplementation) async {
final outputFile = File(ethereumOutputPath);
const ethereumCommonHeaders = """
""";
const ethereumCWHeaders = """
import 'package:cw_ethereum/ethereum_mnemonics.dart';
""";
const ethereumCwPart = "part 'cw_ethereum.dart';";
const ethereumContent = """
abstract class Ethereum {
List<String> getEthereumWordList(String language);
}
""";
const ethereumEmptyDefinition = 'Ethereum? ethereum;\n';
const ethereumCWDefinition = 'Ethereum? ethereum = CWEthereum();\n';
final output = '$ethereumCommonHeaders\n'
+ (hasImplementation ? '$ethereumCWHeaders\n' : '\n')
+ (hasImplementation ? '$ethereumCwPart\n\n' : '\n')
+ (hasImplementation ? ethereumCWDefinition : ethereumEmptyDefinition)
+ '\n'
+ ethereumContent;
if (outputFile.existsSync()) {
await outputFile.delete();
}
await outputFile.writeAsString(output);
}
Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin, required bool hasHaven, required bool hasEthereum}) async {
const cwCore = """
cw_core:
path: ./cw_core
@ -490,6 +524,10 @@ Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin,
cw_shared_external:
path: ./cw_shared_external
""";
const cwEthereum = """
cw_ethereum:
path: ./cw_ethereum
""";
final inputFile = File(pubspecOutputPath);
final inputText = await inputFile.readAsString();
final inputLines = inputText.split('\n');
@ -510,6 +548,10 @@ Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin,
output += '\n$cwHaven';
}
if (hasEthereum) {
output += '\n$cwEthereum';
}
final outputLines = output.split('\n');
inputLines.insertAll(dependenciesIndex + 1, outputLines);
final outputContent = inputLines.join('\n');
@ -522,7 +564,7 @@ Future<void> generatePubspec({required bool hasMonero, required bool hasBitcoin,
await outputFile.writeAsString(outputContent);
}
Future<void> generateWalletTypes({required bool hasMonero, required bool hasBitcoin, required bool hasHaven}) async {
Future<void> generateWalletTypes({required bool hasMonero, required bool hasBitcoin, required bool hasHaven, required bool hasEthereum}) async {
final walletTypesFile = File(walletTypesPath);
if (walletTypesFile.existsSync()) {
@ -545,6 +587,10 @@ Future<void> generateWalletTypes({required bool hasMonero, required bool hasBitc
outputContent += '\tWalletType.haven,\n';
}
if (hasEthereum) {
outputContent += '\tWalletType.ethereum,\n';
}
outputContent += '];\n';
await walletTypesFile.writeAsString(outputContent);
}