* hv
* Change build version
wownero
mkyq 2 years ago committed by GitHub
parent e7e419bc83
commit 01150ef2a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

7
.gitignore vendored

@ -111,8 +111,11 @@ ios/build
*.sublime-project
shared_external/**
cw_shared_external/**
cw_haven/**
cw_shared_external/ios/External/
# cw_haven/**
cw_haven/ios/External/
cw_haven/android/.externalNativeBuild/
cw_haven/android/.cxx/
lib/bitcoin/bitcoin.dart
lib/monero/monero.dart

@ -0,0 +1,11 @@
package com.cakewallet.haven;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
@Override
public void registerWith(PluginRegistry registry) {}
}

@ -0,0 +1,90 @@
package com.cakewallet.haven;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterFragmentActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.WindowManager;
import com.unstoppabledomains.resolution.DomainResolution;
import com.unstoppabledomains.resolution.Resolution;
import java.security.SecureRandom;
public class MainActivity extends FlutterFragmentActivity {
final String UTILS_CHANNEL = "com.cake_wallet/native_utils";
final int UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK = 24;
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
MethodChannel utilsChannel =
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),
UTILS_CHANNEL);
utilsChannel.setMethodCallHandler(this::handle);
}
private void handle(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
Handler handler = new Handler(Looper.getMainLooper());
try {
switch (call.method) {
case "enableWakeScreen":
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
handler.post(() -> result.success(true));
break;
case "disableWakeScreen":
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
handler.post(() -> result.success(true));
break;
case "sec_random":
int count = call.argument("count");
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[count];
random.nextBytes(bytes);
handler.post(() -> result.success(bytes));
break;
case "getUnstoppableDomainAddress":
int version = Build.VERSION.SDK_INT;
if (version >= UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK) {
getUnstoppableDomainAddress(call, result);
} else {
handler.post(() -> result.success(""));
}
break;
default:
handler.post(() -> result.notImplemented());
}
} catch (Exception e) {
handler.post(() -> result.error("UNCAUGHT_ERROR", e.getMessage(), null));
}
}
private void getUnstoppableDomainAddress(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
DomainResolution resolution = new Resolution();
Handler handler = new Handler(Looper.getMainLooper());
String domain = call.argument("domain");
String ticker = call.argument("ticker");
AsyncTask.execute(() -> {
try {
String address = resolution.getAddress(domain, ticker);
handler.post(() -> result.success(address));
} catch (Exception e) {
System.out.println("Expected Address, but got " + e.getMessage());
handler.post(() -> result.success(""));
}
});
}
}

@ -0,0 +1,6 @@
-
uri: vault.havenprotocol.org:443
login: super
password: super
useSSL: true
is_default: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

@ -33,6 +33,7 @@ import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_bitcoin/electrum.dart';
import 'package:hex/hex.dart';
import 'package:cw_core/crypto_currency.dart';
part 'electrum_wallet.g.dart';
@ -49,9 +50,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
@required this.mnemonic,
ElectrumClient electrumClient,
ElectrumBalance initialBalance})
: balance = initialBalance ??
const ElectrumBalance(confirmed: 0, unconfirmed: 0),
hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
: hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
network: networkType)
.derivePath("m/0'/0"),
syncStatus = NotConnectedSyncStatus(),
@ -59,6 +58,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
_feeRates = <int>[],
_isTransactionUpdating = false,
super(walletInfo) {
balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of({
currency: initialBalance ?? const ElectrumBalance(confirmed: 0, unconfirmed: 0)});
this.electrumClient = electrumClient ?? ElectrumClient();
this.walletInfo = walletInfo;
this.unspentCoinsInfo = unspentCoinsInfo;
@ -82,7 +83,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
@override
@observable
ElectrumBalance balance;
ObservableMap<CryptoCurrency, ElectrumBalance> balance;
@override
@observable
@ -233,7 +234,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
final totalAmount = amount + fee;
if (totalAmount > balance.confirmed || totalAmount > allInputsAmount) {
if (totalAmount > balance[currency].confirmed || totalAmount > allInputsAmount) {
throw BitcoinTransactionWrongBalanceException(currency);
}
@ -326,7 +327,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
'account_index': walletAddresses.currentReceiveAddressIndex.toString(),
'change_address_index': walletAddresses.currentChangeAddressIndex.toString(),
'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
'balance': balance?.toJSON()
'balance': balance[currency]?.toJSON()
});
int feeRate(TransactionPriority priority) {
@ -617,7 +618,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
}
Future<void> _updateBalance() async {
balance = await _fetchBalances();
balance[currency] = await _fetchBalances();
await save();
}

@ -1,5 +1,3 @@
import 'package:cw_monero/api/structs/account_row.dart';
class Account {
Account({this.id, this.label});
@ -7,10 +5,6 @@ class Account {
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
this.label = (map['label'] ?? '') as String;
Account.fromRow(AccountRow row)
: this.id = row.getId(),
this.label = row.getLabel();
final int id;
final String label;
}
}

@ -0,0 +1,16 @@
import 'package:mobx/mobx.dart';
abstract class AccountList<T> {
ObservableList<T> get accounts;
void update();
List<T> getAll();
Future addAccount({String label});
Future setLabelAccount({int accountIndex, String label});
void refresh();
}

@ -23,7 +23,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
CryptoCurrency.usdt,
CryptoCurrency.usdterc20,
CryptoCurrency.xlm,
CryptoCurrency.xrp
CryptoCurrency.xrp,
CryptoCurrency.xhv
];
static const xmr = CryptoCurrency(title: 'XMR', raw: 0);
static const ada = CryptoCurrency(title: 'ADA', raw: 1);
@ -41,6 +42,21 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
static const usdterc20 = CryptoCurrency(title: 'USDTERC20', raw: 13);
static const xlm = CryptoCurrency(title: 'XLM', raw: 14);
static const xrp = CryptoCurrency(title: 'XRP', raw: 15);
static const xhv = CryptoCurrency(title: 'XHV', raw: 16);
static const xag = CryptoCurrency(title: 'XAG', raw: 17);
static const xau = CryptoCurrency(title: 'XAU', raw: 18);
static const xaud = CryptoCurrency(title: 'XAUD', raw: 19);
static const xbtc = CryptoCurrency(title: 'XBTC', raw: 20);
static const xcad = CryptoCurrency(title: 'XCAD', raw: 21);
static const xchf = CryptoCurrency(title: 'XCHF', raw: 22);
static const xcny = CryptoCurrency(title: 'XCNY', raw: 23);
static const xeur = CryptoCurrency(title: 'XEUR', raw: 24);
static const xgbp = CryptoCurrency(title: 'XGBP', raw: 25);
static const xjpy = CryptoCurrency(title: 'XJPY', raw: 26);
static const xnok = CryptoCurrency(title: 'XNOK', raw: 27);
static const xnzd = CryptoCurrency(title: 'XNZD', raw: 28);
static const xusd = CryptoCurrency(title: 'XUSD', raw: 29);
static CryptoCurrency deserialize({int raw}) {
switch (raw) {
@ -76,6 +92,34 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
return CryptoCurrency.xlm;
case 15:
return CryptoCurrency.xrp;
case 16:
return CryptoCurrency.xhv;
case 17:
return CryptoCurrency.xag;
case 18:
return CryptoCurrency.xau;
case 19:
return CryptoCurrency.xaud;
case 20:
return CryptoCurrency.xbtc;
case 21:
return CryptoCurrency.xcad;
case 22:
return CryptoCurrency.xchf;
case 23:
return CryptoCurrency.xcny;
case 24:
return CryptoCurrency.xeur;
case 25:
return CryptoCurrency.xgbp;
case 26:
return CryptoCurrency.xjpy;
case 27:
return CryptoCurrency.xnok;
case 28:
return CryptoCurrency.xnzd;
case 29:
return CryptoCurrency.xusd;
default:
return null;
}
@ -115,6 +159,34 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
return CryptoCurrency.xlm;
case 'xrp':
return CryptoCurrency.xrp;
case 'xhv':
return CryptoCurrency.xhv;
case 'xag':
return CryptoCurrency.xag;
case 'xau':
return CryptoCurrency.xau;
case 'xaud':
return CryptoCurrency.xaud;
case 'xbtc':
return CryptoCurrency.xbtc;
case 'xcad':
return CryptoCurrency.xcad;
case 'xchf':
return CryptoCurrency.xchf;
case 'xcny':
return CryptoCurrency.xcny;
case 'xeur':
return CryptoCurrency.xeur;
case 'xgbp':
return CryptoCurrency.xgbp;
case 'xjpy':
return CryptoCurrency.xjpy;
case 'xnok':
return CryptoCurrency.xnok;
case 'xnzd':
return CryptoCurrency.xnzd;
case 'xusd':
return CryptoCurrency.xusd;
default:
return null;
}

@ -9,6 +9,8 @@ CryptoCurrency currencyForWalletType(WalletType type) {
return CryptoCurrency.xmr;
case WalletType.litecoin:
return CryptoCurrency.ltc;
case WalletType.haven:
return CryptoCurrency.xhv;
default:
return null;
}

@ -8,7 +8,8 @@ final moneroAmountFormat = NumberFormat()
..minimumFractionDigits = 1;
String moneroAmountToString({int amount}) => moneroAmountFormat
.format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider));
.format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider))
.replaceAll(',', '');
double moneroAmountToDouble({int amount}) =>
cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);

@ -1,6 +1,6 @@
import 'package:cw_core/balance.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_monero/monero_amount_format.dart';
import 'package:cw_core/monero_amount_format.dart';
class MoneroBalance extends Balance {
MoneroBalance({@required this.fullBalance, @required this.unlockedBalance})

@ -60,6 +60,8 @@ class Node extends HiveObject with Keyable {
return createUriFromElectrumAddress(uriRaw);
case WalletType.litecoin:
return createUriFromElectrumAddress(uriRaw);
case WalletType.haven:
return Uri.http(uriRaw, '');
default:
return null;
}

@ -0,0 +1,12 @@
class Subaddress {
Subaddress({this.id, this.address, this.label});
Subaddress.fromMap(Map map)
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
this.address = (map['address'] ?? '') as String,
this.label = (map['label'] ?? '') as String;
final int id;
final String address;
final String label;
}

@ -0,0 +1,13 @@
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/account_list.dart';
import 'package:cw_core/wallet_info.dart';
abstract class WalletAddressesWithAccount<T> extends WalletAddresses {
WalletAddressesWithAccount(WalletInfo walletInfo) : super(walletInfo);
T get account;
set account(T account);
AccountList<T> get accountList;
}

@ -1,3 +1,4 @@
import 'package:mobx/mobx.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/transaction_priority.dart';
@ -35,7 +36,7 @@ abstract class WalletBase<
//set address(String address);
BalanceType get balance;
ObservableMap<CryptoCurrency, BalanceType> get balance;
SyncStatus get syncStatus;

@ -6,7 +6,8 @@ part 'wallet_type.g.dart';
const walletTypes = [
WalletType.monero,
WalletType.bitcoin,
WalletType.litecoin
WalletType.litecoin,
WalletType.haven
];
const walletTypeTypeId = 5;
@ -22,7 +23,10 @@ enum WalletType {
bitcoin,
@HiveField(3)
litecoin
litecoin,
@HiveField(4)
haven
}
int serializeToInt(WalletType type) {
@ -33,6 +37,8 @@ int serializeToInt(WalletType type) {
return 1;
case WalletType.litecoin:
return 2;
case WalletType.haven:
return 3;
default:
return -1;
}
@ -46,6 +52,8 @@ WalletType deserializeFromInt(int raw) {
return WalletType.bitcoin;
case 2:
return WalletType.litecoin;
case 3:
return WalletType.haven;
default:
return null;
}
@ -59,6 +67,8 @@ String walletTypeToString(WalletType type) {
return 'Bitcoin';
case WalletType.litecoin:
return 'Litecoin';
case WalletType.haven:
return 'Haven';
default:
return '';
}
@ -72,6 +82,8 @@ String walletTypeToDisplayName(WalletType type) {
return 'Bitcoin (Electrum)';
case WalletType.litecoin:
return 'Litecoin (Electrum)';
case WalletType.haven:
return 'Haven';
default:
return '';
}
@ -85,6 +97,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
return CryptoCurrency.btc;
case WalletType.litecoin:
return CryptoCurrency.ltc;
case WalletType.haven:
return CryptoCurrency.xhv;
default:
return null;
}

@ -0,0 +1,7 @@
.DS_Store
.dart_tool/
.packages
.pub/
build/

@ -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: 4d7946a68d26794349189cf21b3f68cc6fe61dcb
channel: stable
project_type: plugin

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

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

@ -0,0 +1,15 @@
# cw_haven
A new flutter plugin project.
## Getting Started
This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/developing-packages/),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

@ -0,0 +1,8 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures

@ -0,0 +1,220 @@
cmake_minimum_required(VERSION 3.4.1)
add_library( cw_haven
SHARED
../ios/Classes/haven_api.cpp)
find_library( log-lib log )
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../ios/External/android)
############
# libsodium
############
add_library(sodium STATIC IMPORTED)
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libsodium.a)
############
# OpenSSL
############
add_library(crypto STATIC IMPORTED)
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libcrypto.a)
add_library(ssl STATIC IMPORTED)
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libssl.a)
############
# Boost
############
add_library(boost_chrono STATIC IMPORTED)
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_chrono.a)
add_library(boost_date_time STATIC IMPORTED)
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_date_time.a)
add_library(boost_filesystem STATIC IMPORTED)
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_filesystem.a)
add_library(boost_program_options STATIC IMPORTED)
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_program_options.a)
add_library(boost_regex STATIC IMPORTED)
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_regex.a)
add_library(boost_serialization STATIC IMPORTED)
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_serialization.a)
add_library(boost_system STATIC IMPORTED)
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_system.a)
add_library(boost_thread STATIC IMPORTED)
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_thread.a)
add_library(boost_wserialization STATIC IMPORTED)
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_wserialization.a)
#############
# Haven
#############
add_library(wallet_api STATIC IMPORTED)
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet_api.a)
add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet.a)
add_library(cryptonote_core STATIC IMPORTED)
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcryptonote_core.a)
add_library(cryptonote_basic STATIC IMPORTED)
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcryptonote_basic.a)
add_library(mnemonics STATIC IMPORTED)
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libmnemonics.a)
add_library(common STATIC IMPORTED)
set_target_properties(common PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcommon.a)
add_library(cncrypto STATIC IMPORTED)
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcncrypto.a)
add_library(ringct STATIC IMPORTED)
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libringct.a)
add_library(ringct_basic STATIC IMPORTED)
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libringct_basic.a)
add_library(blockchain_db STATIC IMPORTED)
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libblockchain_db.a)
add_library(lmdb STATIC IMPORTED)
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/liblmdb.a)
add_library(easylogging STATIC IMPORTED)
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libeasylogging.a)
add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libunbound.a)
add_library(epee STATIC IMPORTED)
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libepee.a)
add_library(checkpoints STATIC IMPORTED)
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcheckpoints.a)
add_library(device STATIC IMPORTED)
set_target_properties(device PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libdevice.a)
add_library(device_trezor STATIC IMPORTED)
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libdevice_trezor.a)
add_library(multisig STATIC IMPORTED)
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libmultisig.a)
add_library(version STATIC IMPORTED)
set_target_properties(version PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libversion.a)
add_library(net STATIC IMPORTED)
set_target_properties(net PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libnet.a)
add_library(hardforks STATIC IMPORTED)
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libhardforks.a)
add_library(randomx STATIC IMPORTED)
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/librandomx.a)
add_library(offshore STATIC IMPORTED)
set_target_properties(offshore PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/liboffshore.a)
add_library(rpc_base STATIC IMPORTED)
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/librpc_base.a)
add_library(wallet-crypto STATIC IMPORTED)
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet-crypto.a)
include_directories( ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/include )
target_link_libraries( cw_haven
wallet_api
wallet
cryptonote_core
cryptonote_basic
mnemonics
ringct
ringct_basic
net
common
cncrypto
blockchain_db
lmdb
easylogging
unbound
epee
checkpoints
device
device_trezor
multisig
version
randomx
offshore
hardforks
rpc_base
boost_chrono
boost_date_time
boost_filesystem
boost_program_options
boost_regex
boost_serialization
boost_system
boost_thread
boost_wserialization
ssl
crypto
sodium
${log-lib} )

@ -0,0 +1,45 @@
group 'com.cakewallet.cw_haven'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
rootProject.allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
minSdkVersion 21
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

@ -0,0 +1 @@
rootProject.name = 'cw_haven'

@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cakewallet.cw_haven">
</manifest>

@ -0,0 +1,36 @@
package com.cakewallet.cw_haven
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
/** CwHavenPlugin */
class CwHavenPlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cw_haven")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}

@ -0,0 +1,37 @@
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/Generated.xcconfig
/Flutter/flutter_export_environment.sh

@ -0,0 +1,4 @@
#import <Flutter/Flutter.h>
@interface CwHavenPlugin : NSObject<FlutterPlugin>
@end

@ -0,0 +1,15 @@
#import "CwHavenPlugin.h"
#if __has_include(<cw_haven/cw_haven-Swift.h>)
#import <cw_haven/cw_haven-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "cw_haven-Swift.h"
#endif
@implementation CwHavenPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftCwHavenPlugin registerWithRegistrar:registrar];
}
@end

@ -0,0 +1,14 @@
import Flutter
import UIKit
public class SwiftCwHavenPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "cw_haven", binaryMessenger: registrar.messenger())
let instance = SwiftCwHavenPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
result("iOS " + UIDevice.current.systemVersion)
}
}

@ -0,0 +1,922 @@
#include <stdint.h>
#include "cstdlib"
#include <chrono>
#include <functional>
#include <iostream>
#include <unistd.h>
#include <mutex>
#include "thread"
#if __APPLE__
// Fix for randomx on ios
void __clear_cache(void* start, void* end) { }
#include "../External/ios/include/wallet2_api.h"
#else
#include "../External/android/x86/include/wallet2_api.h"
#endif
using namespace std::chrono_literals;
#ifdef __cplusplus
extern "C"
{
#endif
const uint64_t MONERO_BLOCK_SIZE = 1000;
struct Utf8Box
{
char *value;
Utf8Box(char *_value)
{
value = _value;
}
};
struct SubaddressRow
{
uint64_t id;
char *address;
char *label;
SubaddressRow(std::size_t _id, char *_address, char *_label)
{
id = static_cast<uint64_t>(_id);
address = _address;
label = _label;
}
};
struct AccountRow
{
uint64_t id;
char *label;
AccountRow(std::size_t _id, char *_label)
{
id = static_cast<uint64_t>(_id);
label = _label;
}
};
struct HavenBalance
{
uint64_t amount;
char *assetType;
HavenBalance(char *_assetType, uint64_t _amount)
{
amount = _amount;
assetType = _assetType;
}
};
struct HavenRate
{
uint64_t rate;
char *assetType;
HavenRate(char *_assetType, uint64_t _rate)
{
rate = _rate;
assetType = _assetType;
}
};
struct MoneroWalletListener : Monero::WalletListener
{
uint64_t m_height;
bool m_need_to_refresh;
bool m_new_transaction;
MoneroWalletListener()
{
m_height = 0;
m_need_to_refresh = false;
m_new_transaction = false;
}
void moneySpent(const std::string &txId, uint64_t amount, std::string assetType)
{
m_new_transaction = true;
}
void moneyReceived(const std::string &txId, uint64_t amount, std::string assetType)
{
m_new_transaction = true;
}
void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
{
m_new_transaction = true;
}
void newBlock(uint64_t height)
{
m_height = height;
}
void updated()
{
m_new_transaction = true;
}
void refreshed()
{
m_need_to_refresh = true;
}
void resetNeedToRefresh()
{
m_need_to_refresh = false;
}
bool isNeedToRefresh()
{
return m_need_to_refresh;
}
bool isNewTransactionExist()
{
return m_new_transaction;
}
void resetIsNewTransactionExist()
{
m_new_transaction = false;
}
uint64_t height()
{
return m_height;
}
};
struct TransactionInfoRow
{
uint64_t amount;
uint64_t fee;
uint64_t blockHeight;
uint64_t confirmations;
uint32_t subaddrAccount;
int8_t direction;
int8_t isPending;
uint32_t subaddrIndex;
char *hash;
char *paymentId;
char *assetType;
int64_t datetime;
TransactionInfoRow(Monero::TransactionInfo *transaction)
{
amount = transaction->amount();
fee = transaction->fee();
blockHeight = transaction->blockHeight();
subaddrAccount = transaction->subaddrAccount();
std::set<uint32_t>::iterator it = transaction->subaddrIndex().begin();
subaddrIndex = *it;
confirmations = transaction->confirmations();
datetime = static_cast<int64_t>(transaction->timestamp());
direction = transaction->direction();
isPending = static_cast<int8_t>(transaction->isPending());
std::string *hash_str = new std::string(transaction->hash());
hash = strdup(hash_str->c_str());
paymentId = strdup(transaction->paymentId().c_str());
assetType = strdup(transaction->assetType().c_str());
}
};
struct PendingTransactionRaw
{
uint64_t amount;
uint64_t fee;
char *hash;
Monero::PendingTransaction *transaction;
PendingTransactionRaw(Monero::PendingTransaction *_transaction)
{
transaction = _transaction;
amount = _transaction->amount();
fee = _transaction->fee();
hash = strdup(_transaction->txid()[0].c_str());
}
};
Monero::Wallet *m_wallet;
Monero::TransactionHistory *m_transaction_history;
MoneroWalletListener *m_listener;
Monero::Subaddress *m_subaddress;
Monero::SubaddressAccount *m_account;
uint64_t m_last_known_wallet_height;
uint64_t m_cached_syncing_blockchain_height = 0;
std::mutex store_lock;
bool is_storing = false;
void change_current_wallet(Monero::Wallet *wallet)
{
m_wallet = wallet;
m_listener = nullptr;
if (wallet != nullptr)
{
m_transaction_history = wallet->history();
}
else
{
m_transaction_history = nullptr;
}
if (wallet != nullptr)
{
m_account = wallet->subaddressAccount();
}
else
{
m_account = nullptr;
}
if (wallet != nullptr)
{
m_subaddress = wallet->subaddress();
}
else
{
m_subaddress = nullptr;
}
}
Monero::Wallet *get_current_wallet()
{
return m_wallet;
}
bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error)
{
Monero::WalletManagerFactory::setLogLevel(4);
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
Monero::Wallet *wallet = walletManager->createWallet(path, password, language, _networkType);
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
if (wallet->status() != Monero::Wallet::Status_Ok)
{
error = strdup(wallet->errorString().c_str());
return false;
}
change_current_wallet(wallet);
return true;
}
bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error)
{
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->recoveryWallet(
std::string(path),
std::string(password),
std::string(seed),
_networkType,
(uint64_t)restoreHeight);
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
if (status != Monero::Wallet::Status_Ok || !errorString.empty())
{
error = strdup(errorString.c_str());
return false;
}
change_current_wallet(wallet);
return true;
}
bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
{
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createWalletFromKeys(
std::string(path),
std::string(password),
std::string(language),
_networkType,
(uint64_t)restoreHeight,
std::string(address),
std::string(viewKey),
std::string(spendKey));
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
if (status != Monero::Wallet::Status_Ok || !errorString.empty())
{
error = strdup(errorString.c_str());
return false;
}
change_current_wallet(wallet);
return true;
}
bool load_wallet(char *path, char *password, int32_t nettype)
{
nice(19);
Monero::NetworkType networkType = static_cast<Monero::NetworkType>(nettype);
Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
Monero::Wallet *wallet = walletManager->openWallet(std::string(path), std::string(password), networkType);
int status;
std::string errorString;
wallet->statusWithErrorString(status, errorString);
change_current_wallet(wallet);
return !(status != Monero::Wallet::Status_Ok || !errorString.empty());
}
char *error_string() {
return strdup(get_current_wallet()->errorString().c_str());
}
bool is_wallet_exist(char *path)
{
return Monero::WalletManagerFactory::getWalletManager()->walletExists(std::string(path));
}
void close_current_wallet()
{
Monero::WalletManagerFactory::getWalletManager()->closeWallet(get_current_wallet());
change_current_wallet(nullptr);
}
char *get_filename()
{
return strdup(get_current_wallet()->filename().c_str());
}
char *secret_view_key()
{
return strdup(get_current_wallet()->secretViewKey().c_str());
}
char *public_view_key()
{
return strdup(get_current_wallet()->publicViewKey().c_str());
}
char *secret_spend_key()
{
return strdup(get_current_wallet()->secretSpendKey().c_str());
}
char *public_spend_key()
{
return strdup(get_current_wallet()->publicSpendKey().c_str());
}
char *get_address(uint32_t account_index, uint32_t address_index)
{
return strdup(get_current_wallet()->address(account_index, address_index).c_str());
}
const char *seed()
{
return strdup(get_current_wallet()->seed().c_str());
}
int64_t *get_full_balance(uint32_t account_index)
{
std::map<std::string, uint64_t> accountBalance;
std::map<uint32_t, std::map<std::string, uint64_t>> balanceSubaddresses = get_current_wallet()->balance(account_index);
std::vector<std::string> assetList = Monero::Assets::list();
//prefill balances
for (const auto &asset_type : assetList) {
accountBalance[asset_type] = 0;
}
// balances are mapped to their subaddress
// we compute total balances of account
for (auto const& balanceSubaddress : balanceSubaddresses)
{
std::map<std::string, uint64_t> balanceOfSubaddress = balanceSubaddress.second;
for (auto const& balance : balanceOfSubaddress)
{
const std::string &assetType = balance.first;
const uint64_t &amount = balance.second;
accountBalance[assetType] +=amount;
}
}
size_t size = accountBalance.size();
int64_t *balanceAddresses = (int64_t *)malloc(size * sizeof(int64_t));
int i = 0;
for (auto const& balance : accountBalance)
{
char *assetType = strdup(balance.first.c_str());
HavenBalance *hb = new HavenBalance(assetType, balance.second);
balanceAddresses[i] = reinterpret_cast<int64_t>(hb);
i++;
}
return balanceAddresses;
}
int64_t *get_unlocked_balance(uint32_t account_index)
{
std::map<std::string, uint64_t> accountBalance;
std::map<uint32_t, std::map<std::string, uint64_t>> balanceSubaddresses = get_current_wallet()->unlockedBalance(account_index);
std::vector<std::string> assetList = Monero::Assets::list();
//prefill balances
for (const auto &asset_type : assetList) {
accountBalance[asset_type] = 0;
}
// balances are mapped to their subaddress
// we compute total balances of account
for (auto const& balanceSubaddress : balanceSubaddresses)
{
std::map<std::string, uint64_t> balanceOfSubaddress = balanceSubaddress.second;
for (auto const& balance : balanceOfSubaddress)
{
const std::string &assetType = balance.first;
const uint64_t &amount = balance.second;
accountBalance[assetType] +=amount;
}
}
size_t size = accountBalance.size();
int64_t *balanceAddresses = (int64_t *)malloc(size * sizeof(int64_t));
int i = 0;
for (auto const& balance : accountBalance)
{
char *assetType = strdup(balance.first.c_str());
HavenBalance *hb = new HavenBalance(assetType, balance.second);
balanceAddresses[i] = reinterpret_cast<int64_t>(hb);
i++;
}
return balanceAddresses;
}
uint64_t get_current_height()
{
return get_current_wallet()->blockChainHeight();
}
uint64_t get_node_height()
{
return get_current_wallet()->daemonBlockChainHeight();
}
bool connect_to_node(char *error)
{
nice(19);
bool is_connected = get_current_wallet()->connectToDaemon();
if (!is_connected)
{
error = strdup(get_current_wallet()->errorString().c_str());
}
return is_connected;
}
bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error)
{
nice(19);
Monero::Wallet *wallet = get_current_wallet();
std::string _login = "";
std::string _password = "";
if (login != nullptr)
{
_login = std::string(login);
}
if (password != nullptr)
{
_password = std::string(password);
}
bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet);
if (!inited)
{
error = strdup(wallet->errorString().c_str());
} else if (!wallet->connectToDaemon()) {
error = strdup(wallet->errorString().c_str());
}
return inited;
}
bool is_connected()
{
return get_current_wallet()->connected();
}
void start_refresh()
{
get_current_wallet()->refreshAsync();
get_current_wallet()->startRefresh();
}
void set_refresh_from_block_height(uint64_t height)
{
get_current_wallet()->setRefreshFromBlockHeight(height);
}
void set_recovering_from_seed(bool is_recovery)
{
get_current_wallet()->setRecoveringFromSeed(is_recovery);
}
void store(char *path)
{
store_lock.lock();
if (is_storing) {
return;
}
is_storing = true;
get_current_wallet()->store(std::string(path));
is_storing = false;
store_lock.unlock();
}
bool transaction_create(char *address, char *asset_type, char *payment_id, char *amount,
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
{
nice(19);
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
std::string _payment_id;
Monero::PendingTransaction *transaction;
if (payment_id != nullptr)
{
_payment_id = std::string(payment_id);
}
if (amount != nullptr)
{
uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account, {});
}
else
{
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(),std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account, {});
}
int status = transaction->status();
if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
{
error = Utf8Box(strdup(transaction->errorString().c_str()));
return false;
}
if (m_listener != nullptr) {
m_listener->m_new_transaction = true;
}
pendingTransaction = PendingTransactionRaw(transaction);
return true;
}
bool transaction_create_mult_dest(char **addresses, char *asset_type, char *payment_id, char **amounts, uint32_t size,
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
{
nice(19);
std::vector<std::string> _addresses;
std::vector<uint64_t> _amounts;
for (int i = 0; i < size; i++) {
_addresses.push_back(std::string(*addresses));
_amounts.push_back(Monero::Wallet::amountFromString(std::string(*amounts)));
addresses++;
amounts++;
}
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
std::string _payment_id;
Monero::PendingTransaction *transaction;
if (payment_id != nullptr)
{
_payment_id = std::string(payment_id);
}
transaction = m_wallet->createTransactionMultDest(_addresses, _payment_id, _amounts,
std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account,{});
int status = transaction->status();
if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
{
error = Utf8Box(strdup(transaction->errorString().c_str()));
return false;
}
if (m_listener != nullptr) {
m_listener->m_new_transaction = true;
}
pendingTransaction = PendingTransactionRaw(transaction);
return true;
}
bool transaction_commit(PendingTransactionRaw *transaction, Utf8Box &error)
{
bool committed = transaction->transaction->commit();
if (!committed)
{
error = Utf8Box(strdup(transaction->transaction->errorString().c_str()));
} else if (m_listener != nullptr) {
m_listener->m_new_transaction = true;
}
return committed;
}
uint64_t get_node_height_or_update(uint64_t base_eight)
{
if (m_cached_syncing_blockchain_height < base_eight) {
m_cached_syncing_blockchain_height = base_eight;
}
return m_cached_syncing_blockchain_height;
}
uint64_t get_syncing_height()
{
if (m_listener == nullptr) {
return 0;
}
uint64_t height = m_listener->height();
if (height <= 1) {
return 0;
}
if (height != m_last_known_wallet_height)
{
m_last_known_wallet_height = height;
}
return height;
}
uint64_t is_needed_to_refresh()
{
if (m_listener == nullptr) {
return false;
}
bool should_refresh = m_listener->isNeedToRefresh();
if (should_refresh) {
m_listener->resetNeedToRefresh();
}
return should_refresh;
}
uint8_t is_new_transaction_exist()
{
if (m_listener == nullptr) {
return false;
}
bool is_new_transaction_exist = m_listener->isNewTransactionExist();
if (is_new_transaction_exist)
{
m_listener->resetIsNewTransactionExist();
}
return is_new_transaction_exist;
}
void set_listener()
{
m_last_known_wallet_height = 0;
if (m_listener != nullptr)
{
free(m_listener);
}
m_listener = new MoneroWalletListener();
get_current_wallet()->setListener(m_listener);
}
int64_t *subaddrress_get_all()
{
std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
size_t size = _subaddresses.size();
int64_t *subaddresses = (int64_t *)malloc(size * sizeof(int64_t));
for (int i = 0; i < size; i++)
{
Monero::SubaddressRow *row = _subaddresses[i];
SubaddressRow *_row = new SubaddressRow(row->getRowId(), strdup(row->getAddress().c_str()), strdup(row->getLabel().c_str()));
subaddresses[i] = reinterpret_cast<int64_t>(_row);
}
return subaddresses;
}
int32_t subaddrress_size()
{
std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
return _subaddresses.size();
}
void subaddress_add_row(uint32_t accountIndex, char *label)
{
m_subaddress->addRow(accountIndex, std::string(label));
}
void subaddress_set_label(uint32_t accountIndex, uint32_t addressIndex, char *label)
{
m_subaddress->setLabel(accountIndex, addressIndex, std::string(label));
}
void subaddress_refresh(uint32_t accountIndex)
{
m_subaddress->refresh(accountIndex);
}
int32_t account_size()
{
std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
return _accocunts.size();
}
int64_t *account_get_all()
{
std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
size_t size = _accocunts.size();
int64_t *accocunts = (int64_t *)malloc(size * sizeof(int64_t));
for (int i = 0; i < size; i++)
{
Monero::SubaddressAccountRow *row = _accocunts[i];
AccountRow *_row = new AccountRow(row->getRowId(), strdup(row->getLabel().c_str()));
accocunts[i] = reinterpret_cast<int64_t>(_row);
}
return accocunts;
}
void account_add_row(char *label)
{
m_account->addRow(std::string(label));
}
void account_set_label_row(uint32_t account_index, char *label)
{
m_account->setLabel(account_index, label);
}
void account_refresh()
{
m_account->refresh();
}
int64_t *transactions_get_all()
{
std::vector<Monero::TransactionInfo *> transactions = m_transaction_history->getAll();
size_t size = transactions.size();
int64_t *transactionAddresses = (int64_t *)malloc(size * sizeof(int64_t));
for (int i = 0; i < size; i++)
{
Monero::TransactionInfo *row = transactions[i];
TransactionInfoRow *tx = new TransactionInfoRow(row);
transactionAddresses[i] = reinterpret_cast<int64_t>(tx);
}
return transactionAddresses;
}
void transactions_refresh()
{
m_transaction_history->refresh();
}
int64_t transactions_count()
{
return m_transaction_history->count();
}
int LedgerExchange(
unsigned char *command,
unsigned int cmd_len,
unsigned char *response,
unsigned int max_resp_len)
{
return -1;
}
int LedgerFind(char *buffer, size_t len)
{
return -1;
}
void on_startup()
{
Monero::Utils::onStartup();
Monero::WalletManagerFactory::setLogLevel(4);
}
void rescan_blockchain()
{
m_wallet->rescanBlockchainAsync();
}
char * get_tx_key(char * txId)
{
return strdup(m_wallet->getTxKey(std::string(txId)).c_str());
}
int32_t asset_types_size()
{
return Monero::Assets::list().size();
}
char **asset_types()
{
size_t size = Monero::Assets::list().size();
std::vector<std::string> assetList = Monero::Assets::list();
char **assetTypesPts;
assetTypesPts = (char **) malloc( size * sizeof(char*));
for (int i = 0; i < size; i++)
{
std::string asset = assetList[i];
//assetTypes[i] = (char *)malloc( 5 * sizeof(char));
assetTypesPts[i] = strdup(asset.c_str());
}
return assetTypesPts;
}
std::map<std::string, uint64_t> rates;
void update_rate()
{
rates = get_current_wallet()->oracleRates();
}
int64_t *get_rate()
{
size_t size = rates.size();
int64_t *havenRates = (int64_t *)malloc(size * sizeof(int64_t));
int i = 0;
for (auto const& rate : rates)
{
char *assetType = strdup(rate.first.c_str());
HavenRate *havenRate = new HavenRate(assetType, rate.second);
havenRates[i] = reinterpret_cast<int64_t>(havenRate);
i++;
}
return havenRates;
}
int32_t size_of_rate()
{
return static_cast<int32_t>(rates.size());
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1,50 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint cw_haven.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'cw_haven'
s.version = '0.0.1'
s.summary = 'Cake Wallet Haven'
s.description = 'Cake Wallet wrapper over Haven project'
s.homepage = 'http://cakewallet.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Cake Wallet' => 'support@cakewallet.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h, Classes/*.h, ../shared_external/ios/libs/monero/include/src/**/*.h, ../shared_external/ios/libs/monero/include/contrib/**/*.h, ../shared_external/ios/libs/monero/include/../shared_external/ios/**/*.h'
s.dependency 'Flutter'
s.dependency 'cw_shared_external'
s.platform = :ios, '10.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
s.swift_version = '5.0'
s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/Classes/*.h" }
s.subspec 'OpenSSL' do |openssl|
openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
openssl.libraries = 'ssl', 'crypto'
openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Sodium' do |sodium|
sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libsodium.a'
sodium.libraries = 'sodium'
sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Boost' do |boost|
boost.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h',
boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libboost.a',
boost.libraries = 'boost'
boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Haven' do |haven|
haven.preserve_paths = 'External/ios/include/**/*.h'
haven.vendored_libraries = 'External/ios/lib/libhaven.a'
haven.libraries = 'haven'
haven.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
end
end

@ -0,0 +1,83 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/structs/account_row.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_haven/api/wallet.dart';
final accountSizeNative = havenApi
.lookup<NativeFunction<account_size>>('account_size')
.asFunction<SubaddressSize>();
final accountRefreshNative = havenApi
.lookup<NativeFunction<account_refresh>>('account_refresh')
.asFunction<AccountRefresh>();
final accountGetAllNative = havenApi
.lookup<NativeFunction<account_get_all>>('account_get_all')
.asFunction<AccountGetAll>();
final accountAddNewNative = havenApi
.lookup<NativeFunction<account_add_new>>('account_add_row')
.asFunction<AccountAddNew>();
final accountSetLabelNative = havenApi
.lookup<NativeFunction<account_set_label>>('account_set_label_row')
.asFunction<AccountSetLabel>();
bool isUpdating = false;
void refreshAccounts() {
try {
isUpdating = true;
accountRefreshNative();
isUpdating = false;
} catch (e) {
isUpdating = false;
rethrow;
}
}
List<AccountRow> getAllAccount() {
final size = accountSizeNative();
final accountAddressesPointer = accountGetAllNative();
final accountAddresses = accountAddressesPointer.asTypedList(size);
return accountAddresses
.map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
.toList();
}
void addAccountSync({String label}) {
final labelPointer = Utf8.toUtf8(label);
accountAddNewNative(labelPointer);
free(labelPointer);
}
void setLabelForAccountSync({int accountIndex, String label}) {
final labelPointer = Utf8.toUtf8(label);
accountSetLabelNative(accountIndex, labelPointer);
free(labelPointer);
}
void _addAccount(String label) => addAccountSync(label: label);
void _setLabelForAccount(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
setLabelForAccountSync(label: label, accountIndex: accountIndex);
}
Future<void> addAccount({String label}) async {
await compute(_addAccount, label);
await store();
}
Future<void> setLabelForAccount({int accountIndex, String label}) async {
await compute(
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
await store();
}

@ -0,0 +1,23 @@
import 'dart:ffi';
import 'package:cw_haven/api/convert_utf8_to_string.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:ffi/ffi.dart';
final assetTypesSizeNative = havenApi
.lookup<NativeFunction<account_size>>('asset_types_size')
.asFunction<SubaddressSize>();
final getAssetTypesNative = havenApi
.lookup<NativeFunction<asset_types>>('asset_types')
.asFunction<AssetTypes>();
List<String> getAssetTypes() {
List<String> assetTypes = [];
Pointer<Pointer<Utf8>> assetTypePointers = getAssetTypesNative();
Pointer<Utf8> assetpointer = assetTypePointers.elementAt(0)[0];
String asset = convertUTF8ToString(pointer: assetpointer);
return assetTypes;
}

@ -0,0 +1,58 @@
import 'dart:ffi';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/structs/haven_balance_row.dart';
import 'package:cw_haven/api/structs/haven_rate.dart';
import 'asset_types.dart';
List<HavenBalanceRow> getHavenFullBalance({int accountIndex = 0}) {
final size = assetTypesSizeNative();
final balanceAddressesPointer = getHavenFullBalanceNative(accountIndex);
final balanceAddresses = balanceAddressesPointer.asTypedList(size);
return balanceAddresses
.map((addr) => Pointer<HavenBalanceRow>.fromAddress(addr).ref)
.toList();
}
List<HavenBalanceRow> getHavenUnlockedBalance({int accountIndex = 0}) {
final size = assetTypesSizeNative();
final balanceAddressesPointer = getHavenUnlockedBalanceNative(accountIndex);
final balanceAddresses = balanceAddressesPointer.asTypedList(size);
return balanceAddresses
.map((addr) => Pointer<HavenBalanceRow>.fromAddress(addr).ref)
.toList();
}
List<HavenRate> getRate() {
updateRateNative();
final size = sizeOfRateNative();
final ratePointer = getRateNative();
final rate = ratePointer.asTypedList(size);
return rate
.map((addr) => Pointer<HavenRate>.fromAddress(addr).ref)
.toList();
}
final getHavenFullBalanceNative = havenApi
.lookup<NativeFunction<get_full_balance>>('get_full_balance')
.asFunction<GetHavenFullBalance>();
final getHavenUnlockedBalanceNative = havenApi
.lookup<NativeFunction<get_unlocked_balance>>('get_unlocked_balance')
.asFunction<GetHavenUnlockedBalance>();
final getRateNative = havenApi
.lookup<NativeFunction<get_rate>>('get_rate')
.asFunction<GetRate>();
final sizeOfRateNative = havenApi
.lookup<NativeFunction<size_of_rate>>('size_of_rate')
.asFunction<SizeOfRate>();
final updateRateNative = havenApi
.lookup<NativeFunction<update_rate>>('update_rate')
.asFunction<UpdateRate>();

@ -0,0 +1,8 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
String convertUTF8ToString({Pointer<Utf8> pointer}) {
final str = Utf8.fromUtf8(pointer);
free(pointer);
return str;
}

@ -0,0 +1,14 @@
import 'dart:async';
import 'package:flutter/services.dart';
class CwHaven {
static const MethodChannel _channel =
const MethodChannel('cw_haven');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
}

@ -0,0 +1,5 @@
class ConnectionToNodeException implements Exception {
ConnectionToNodeException({this.message});
final String message;
}

@ -0,0 +1,8 @@
class CreationTransactionException implements Exception {
CreationTransactionException({this.message});
final String message;
@override
String toString() => message;
}

@ -0,0 +1,5 @@
class SetupWalletException implements Exception {
SetupWalletException({this.message});
final String message;
}

@ -0,0 +1,8 @@
class WalletCreationException implements Exception {
WalletCreationException({this.message});
final String message;
@override
String toString() => message;
}

@ -0,0 +1,8 @@
class WalletOpeningException implements Exception {
WalletOpeningException({this.message});
final String message;
@override
String toString() => message;
}

@ -0,0 +1,5 @@
class WalletRestoreFromKeysException implements Exception {
WalletRestoreFromKeysException({this.message});
final String message;
}

@ -0,0 +1,5 @@
class WalletRestoreFromSeedException implements Exception {
WalletRestoreFromSeedException({this.message});
final String message;
}

@ -0,0 +1,6 @@
import 'dart:ffi';
import 'dart:io';
final DynamicLibrary havenApi = Platform.isAndroid
? DynamicLibrary.open("libcw_haven.so")
: DynamicLibrary.open("cw_haven.framework/cw_haven");

@ -0,0 +1,8 @@
import 'package:flutter/foundation.dart';
class MoneroOutput {
MoneroOutput({@required this.address, @required this.amount});
final String address;
final String amount;
}

@ -0,0 +1,138 @@
import 'dart:ffi';
import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:cw_haven/api/structs/ut8_box.dart';
import 'package:ffi/ffi.dart';
typedef create_wallet = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Pointer<Utf8>);
typedef restore_wallet_from_seed = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
typedef error_string = Pointer<Utf8> Function();
typedef get_filename = Pointer<Utf8> Function();
typedef get_seed = Pointer<Utf8> Function();
typedef get_address = Pointer<Utf8> Function(Int32, Int32);
typedef get_full_balance = Pointer<Int64> Function(Int32);
typedef get_unlocked_balance = Pointer<Int64> Function(Int32);
typedef get_full_balanace = Int64 Function(Int32);
typedef get_unlocked_balanace = Int64 Function(Int32);
typedef get_current_height = Int64 Function();
typedef get_node_height = Int64 Function();
typedef is_connected = Int8 Function();
typedef setup_node = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int8, Int8, Pointer<Utf8>);
typedef start_refresh = Void Function();
typedef connect_to_node = Int8 Function();
typedef set_refresh_from_block_height = Void Function(Int64);
typedef set_recovering_from_seed = Void Function(Int8);
typedef store_c = Void Function(Pointer<Utf8>);
typedef set_listener = Void Function();
typedef get_syncing_height = Int64 Function();
typedef is_needed_to_refresh = Int8 Function();
typedef is_new_transaction_exist = Int8 Function();
typedef subaddrress_size = Int32 Function();
typedef subaddrress_refresh = Void Function(Int32);
typedef subaddress_get_all = Pointer<Int64> Function();
typedef subaddress_add_new = Void Function(
Int32 accountIndex, Pointer<Utf8> label);
typedef subaddress_set_label = Void Function(
Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
typedef account_size = Int32 Function();
typedef account_refresh = Void Function();
typedef account_get_all = Pointer<Int64> Function();
typedef account_add_new = Void Function(Pointer<Utf8> label);
typedef account_set_label = Void Function(
Int32 accountIndex, Pointer<Utf8> label);
typedef transactions_refresh = Void Function();
typedef get_tx_key = Pointer<Utf8> Function(Pointer<Utf8> txId);
typedef transactions_count = Int64 Function();
typedef transactions_get_all = Pointer<Int64> Function();
typedef transaction_create = Int8 Function(
Pointer<Utf8> address,
Pointer<Utf8> assetType,
Pointer<Utf8> paymentId,
Pointer<Utf8> amount,
Int8 priorityRaw,
Int32 subaddrAccount,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef transaction_create_mult_dest = Int8 Function(
Pointer<Pointer<Utf8>> addresses,
Pointer<Utf8> assetType,
Pointer<Utf8> paymentId,
Pointer<Pointer<Utf8>> amounts,
Int32 size,
Int8 priorityRaw,
Int32 subaddrAccount,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef transaction_commit = Int8 Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
typedef secret_view_key = Pointer<Utf8> Function();
typedef public_view_key = Pointer<Utf8> Function();
typedef secret_spend_key = Pointer<Utf8> Function();
typedef public_spend_key = Pointer<Utf8> Function();
typedef close_current_wallet = Void Function();
typedef on_startup = Void Function();
typedef rescan_blockchain = Void Function();
typedef asset_types = Pointer<Pointer<Utf8>> Function();
typedef asset_types_size = Int32 Function();
typedef get_rate = Pointer<Int64> Function();
typedef size_of_rate = Int32 Function();
typedef update_rate = Void Function();

@ -0,0 +1,11 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class AccountRow extends Struct {
@Int64()
int id;
Pointer<Utf8> label;
String getLabel() => Utf8.fromUtf8(label);
int getId() => id;
}

@ -0,0 +1,11 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class HavenBalanceRow extends Struct {
@Int64()
int amount;
Pointer<Utf8> assetType;
int getAmount() => amount;
String getAssetType() => Utf8.fromUtf8(assetType);
}

@ -0,0 +1,11 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class HavenRate extends Struct {
@Int64()
int rate;
Pointer<Utf8> assetType;
int getRate() => rate;
String getAssetType() => Utf8.fromUtf8(assetType);
}

@ -0,0 +1,23 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class PendingTransactionRaw extends Struct {
@Int64()
int amount;
@Int64()
int fee;
Pointer<Utf8> hash;
String getHash() => Utf8.fromUtf8(hash);
}
class PendingTransactionDescription {
PendingTransactionDescription({this.amount, this.fee, this.hash, this.pointerAddress});
final int amount;
final int fee;
final String hash;
final int pointerAddress;
}

@ -0,0 +1,13 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class SubaddressRow extends Struct {
@Int64()
int id;
Pointer<Utf8> address;
Pointer<Utf8> label;
String getLabel() => Utf8.fromUtf8(label);
String getAddress() => Utf8.fromUtf8(address);
int getId() => id;
}

@ -0,0 +1,44 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class TransactionInfoRow extends Struct {
@Uint64()
int amount;
@Uint64()
int fee;
@Uint64()
int blockHeight;
@Uint64()
int confirmations;
@Uint32()
int subaddrAccount;
@Int8()
int direction;
@Int8()
int isPending;
@Uint32()
int subaddrIndex;
Pointer<Utf8> hash;
Pointer<Utf8> paymentId;
Pointer<Utf8> assetType;
@Int64()
int datetime;
int getDatetime() => datetime;
int getAmount() => amount >= 0 ? amount : amount * -1;
bool getIsPending() => isPending != 0;
String getHash() => Utf8.fromUtf8(hash);
String getPaymentId() => Utf8.fromUtf8(paymentId);
String getAssetType() => Utf8.fromUtf8(assetType);
}

@ -0,0 +1,8 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class Utf8Box extends Struct {
Pointer<Utf8> value;
String getValue() => Utf8.fromUtf8(value);
}

@ -0,0 +1,97 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/structs/subaddress_row.dart';
import 'package:cw_haven/api/wallet.dart';
final subaddressSizeNative = havenApi
.lookup<NativeFunction<subaddrress_size>>('subaddrress_size')
.asFunction<SubaddressSize>();
final subaddressRefreshNative = havenApi
.lookup<NativeFunction<subaddrress_refresh>>('subaddress_refresh')
.asFunction<SubaddressRefresh>();
final subaddrressGetAllNative = havenApi
.lookup<NativeFunction<subaddress_get_all>>('subaddrress_get_all')
.asFunction<SubaddressGetAll>();
final subaddrressAddNewNative = havenApi
.lookup<NativeFunction<subaddress_add_new>>('subaddress_add_row')
.asFunction<SubaddressAddNew>();
final subaddrressSetLabelNative = havenApi
.lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
.asFunction<SubaddressSetLabel>();
bool isUpdating = false;
void refreshSubaddresses({@required int accountIndex}) {
try {
isUpdating = true;
subaddressRefreshNative(accountIndex);
isUpdating = false;
} catch (e) {
isUpdating = false;
rethrow;
}
}
List<SubaddressRow> getAllSubaddresses() {
final size = subaddressSizeNative();
final subaddressAddressesPointer = subaddrressGetAllNative();
final subaddressAddresses = subaddressAddressesPointer.asTypedList(size);
return subaddressAddresses
.map((addr) => Pointer<SubaddressRow>.fromAddress(addr).ref)
.toList();
}
void addSubaddressSync({int accountIndex, String label}) {
final labelPointer = Utf8.toUtf8(label);
subaddrressAddNewNative(accountIndex, labelPointer);
free(labelPointer);
}
void setLabelForSubaddressSync(
{int accountIndex, int addressIndex, String label}) {
final labelPointer = Utf8.toUtf8(label);
subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
free(labelPointer);
}
void _addSubaddress(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
addSubaddressSync(accountIndex: accountIndex, label: label);
}
void _setLabelForSubaddress(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
final addressIndex = args['addressIndex'] as int;
setLabelForSubaddressSync(
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
}
Future addSubaddress({int accountIndex, String label}) async {
await compute<Map<String, Object>, void>(
_addSubaddress, {'accountIndex': accountIndex, 'label': label});
await store();
}
Future setLabelForSubaddress(
{int accountIndex, int addressIndex, String label}) async {
await compute<Map<String, Object>, void>(_setLabelForSubaddress, {
'accountIndex': accountIndex,
'addressIndex': addressIndex,
'label': label
});
await store();
}

@ -0,0 +1,246 @@
import 'dart:ffi';
import 'package:cw_haven/api/convert_utf8_to_string.dart';
import 'package:cw_haven/api/monero_output.dart';
import 'package:cw_haven/api/structs/ut8_box.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/structs/transaction_info_row.dart';
import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:cw_haven/api/exceptions/creation_transaction_exception.dart';
final transactionsRefreshNative = havenApi
.lookup<NativeFunction<transactions_refresh>>('transactions_refresh')
.asFunction<TransactionsRefresh>();
final transactionsCountNative = havenApi
.lookup<NativeFunction<transactions_count>>('transactions_count')
.asFunction<TransactionsCount>();
final transactionsGetAllNative = havenApi
.lookup<NativeFunction<transactions_get_all>>('transactions_get_all')
.asFunction<TransactionsGetAll>();
final transactionCreateNative = havenApi
.lookup<NativeFunction<transaction_create>>('transaction_create')
.asFunction<TransactionCreate>();
final transactionCreateMultDestNative = havenApi
.lookup<NativeFunction<transaction_create_mult_dest>>('transaction_create_mult_dest')
.asFunction<TransactionCreateMultDest>();
final transactionCommitNative = havenApi
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
.asFunction<TransactionCommit>();
final getTxKeyNative = havenApi
.lookup<NativeFunction<get_tx_key>>('get_tx_key')
.asFunction<GetTxKey>();
String getTxKey(String txId) {
final txIdPointer = Utf8.toUtf8(txId);
final keyPointer = getTxKeyNative(txIdPointer);
free(txIdPointer);
if (keyPointer != null) {
return convertUTF8ToString(pointer: keyPointer);
}
return null;
}
void refreshTransactions() => transactionsRefreshNative();
int countOfTransactions() => transactionsCountNative();
List<TransactionInfoRow> getAllTransations() {
final size = transactionsCountNative();
final transactionsPointer = transactionsGetAllNative();
final transactionsAddresses = transactionsPointer.asTypedList(size);
return transactionsAddresses
.map((addr) => Pointer<TransactionInfoRow>.fromAddress(addr).ref)
.toList();
}
PendingTransactionDescription createTransactionSync(
{String address,
String assetType,
String paymentId,
String amount,
int priorityRaw,
int accountIndex = 0}) {
final addressPointer = Utf8.toUtf8(address);
final assetTypePointer = Utf8.toUtf8(assetType);
final paymentIdPointer = Utf8.toUtf8(paymentId);
final amountPointer = amount != null ? Utf8.toUtf8(amount) : nullptr;
final errorMessagePointer = allocate<Utf8Box>();
final pendingTransactionRawPointer = allocate<PendingTransactionRaw>();
final created = transactionCreateNative(
addressPointer,
assetTypePointer,
paymentIdPointer,
amountPointer,
priorityRaw,
accountIndex,
errorMessagePointer,
pendingTransactionRawPointer) !=
0;
free(addressPointer);
free(assetTypePointer);
free(paymentIdPointer);
if (amountPointer != nullptr) {
free(amountPointer);
}
if (!created) {
final message = errorMessagePointer.ref.getValue();
free(errorMessagePointer);
throw CreationTransactionException(message: message);
}
return PendingTransactionDescription(
amount: pendingTransactionRawPointer.ref.amount,
fee: pendingTransactionRawPointer.ref.fee,
hash: pendingTransactionRawPointer.ref.getHash(),
pointerAddress: pendingTransactionRawPointer.address);
}
PendingTransactionDescription createTransactionMultDestSync(
{List<MoneroOutput> outputs,
String assetType,
String paymentId,
int priorityRaw,
int accountIndex = 0}) {
final int size = outputs.length;
final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
Utf8.toUtf8(output.address)).toList();
final Pointer<Pointer<Utf8>> addressesPointerPointer = allocate(count: size);
final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
Utf8.toUtf8(output.amount)).toList();
final Pointer<Pointer<Utf8>> amountsPointerPointer = allocate(count: size);
for (int i = 0; i < size; i++) {
addressesPointerPointer[i] = addressesPointers[i];
amountsPointerPointer[i] = amountsPointers[i];
}
final assetTypePointer = Utf8.toUtf8(assetType);
final paymentIdPointer = Utf8.toUtf8(paymentId);
final errorMessagePointer = allocate<Utf8Box>();
final pendingTransactionRawPointer = allocate<PendingTransactionRaw>();
final created = transactionCreateMultDestNative(
addressesPointerPointer,
assetTypePointer,
paymentIdPointer,
amountsPointerPointer,
size,
priorityRaw,
accountIndex,
errorMessagePointer,
pendingTransactionRawPointer) !=
0;
free(addressesPointerPointer);
free(assetTypePointer);
free(amountsPointerPointer);
addressesPointers.forEach((element) => free(element));
amountsPointers.forEach((element) => free(element));
free(paymentIdPointer);
if (!created) {
final message = errorMessagePointer.ref.getValue();
free(errorMessagePointer);
throw CreationTransactionException(message: message);
}
return PendingTransactionDescription(
amount: pendingTransactionRawPointer.ref.amount,
fee: pendingTransactionRawPointer.ref.fee,
hash: pendingTransactionRawPointer.ref.getHash(),
pointerAddress: pendingTransactionRawPointer.address);
}
void commitTransactionFromPointerAddress({int address}) => commitTransaction(
transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
void commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
final errorMessagePointer = allocate<Utf8Box>();
final isCommited =
transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
if (!isCommited) {
final message = errorMessagePointer.ref.getValue();
free(errorMessagePointer);
throw CreationTransactionException(message: message);
}
}
PendingTransactionDescription _createTransactionSync(Map args) {
final address = args['address'] as String;
final assetType = args['assetType'] as String;
final paymentId = args['paymentId'] as String;
final amount = args['amount'] as String;
final priorityRaw = args['priorityRaw'] as int;
final accountIndex = args['accountIndex'] as int;
return createTransactionSync(
address: address,
assetType: assetType,
paymentId: paymentId,
amount: amount,
priorityRaw: priorityRaw,
accountIndex: accountIndex);
}
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
final outputs = args['outputs'] as List<MoneroOutput>;
final assetType = args['assetType'] as String;
final paymentId = args['paymentId'] as String;
final priorityRaw = args['priorityRaw'] as int;
final accountIndex = args['accountIndex'] as int;
return createTransactionMultDestSync(
outputs: outputs,
assetType: assetType,
paymentId: paymentId,
priorityRaw: priorityRaw,
accountIndex: accountIndex);
}
Future<PendingTransactionDescription> createTransaction(
{String address,
String assetType,
String paymentId = '',
String amount,
int priorityRaw,
int accountIndex = 0}) =>
compute(_createTransactionSync, {
'address': address,
'assetType': assetType,
'paymentId': paymentId,
'amount': amount,
'priorityRaw': priorityRaw,
'accountIndex': accountIndex
});
Future<PendingTransactionDescription> createTransactionMultDest(
{List<MoneroOutput> outputs,
String assetType,
String paymentId = '',
int priorityRaw,
int accountIndex = 0}) =>
compute(_createTransactionMultDestSync, {
'outputs': outputs,
'assetType': assetType,
'paymentId': paymentId,
'priorityRaw': priorityRaw,
'accountIndex': accountIndex
});

@ -0,0 +1,136 @@
import 'dart:ffi';
import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:cw_haven/api/structs/ut8_box.dart';
import 'package:ffi/ffi.dart';
typedef CreateWallet = int Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, Pointer<Utf8>);
typedef RestoreWalletFromSeed = int Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
typedef RestoreWalletFromKeys = int Function(Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
typedef IsWalletExist = int Function(Pointer<Utf8>);
typedef LoadWallet = int Function(Pointer<Utf8>, Pointer<Utf8>, int);
typedef ErrorString = Pointer<Utf8> Function();
typedef GetFilename = Pointer<Utf8> Function();
typedef GetSeed = Pointer<Utf8> Function();
typedef GetAddress = Pointer<Utf8> Function(int, int);
typedef GetHavenFullBalance = Pointer<Int64> Function(int);
typedef GetHavenUnlockedBalance = Pointer<Int64> Function(int);
typedef GetFullBalance = int Function(int);
typedef GetUnlockedBalance = int Function(int);
typedef GetCurrentHeight = int Function();
typedef GetNodeHeight = int Function();
typedef IsConnected = int Function();
typedef SetupNode = int Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
typedef StartRefresh = void Function();
typedef ConnectToNode = int Function();
typedef SetRefreshFromBlockHeight = void Function(int);
typedef SetRecoveringFromSeed = void Function(int);
typedef Store = void Function(Pointer<Utf8>);
typedef SetListener = void Function();
typedef GetSyncingHeight = int Function();
typedef IsNeededToRefresh = int Function();
typedef IsNewTransactionExist = int Function();
typedef SubaddressSize = int Function();
typedef SubaddressRefresh = void Function(int);
typedef SubaddressGetAll = Pointer<Int64> Function();
typedef SubaddressAddNew = void Function(int accountIndex, Pointer<Utf8> label);
typedef SubaddressSetLabel = void Function(
int accountIndex, int addressIndex, Pointer<Utf8> label);
typedef AccountSize = int Function();
typedef AccountRefresh = void Function();
typedef AccountGetAll = Pointer<Int64> Function();
typedef AccountAddNew = void Function(Pointer<Utf8> label);
typedef AccountSetLabel = void Function(int accountIndex, Pointer<Utf8> label);
typedef TransactionsRefresh = void Function();
typedef GetTxKey = Pointer<Utf8> Function(Pointer<Utf8> txId);
typedef TransactionsCount = int Function();
typedef TransactionsGetAll = Pointer<Int64> Function();
typedef TransactionCreate = int Function(
Pointer<Utf8> address,
Pointer<Utf8> assetType,
Pointer<Utf8> paymentId,
Pointer<Utf8> amount,
int priorityRaw,
int subaddrAccount,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef TransactionCreateMultDest = int Function(
Pointer<Pointer<Utf8>> addresses,
Pointer<Utf8> assetType,
Pointer<Utf8> paymentId,
Pointer<Pointer<Utf8>> amounts,
int size,
int priorityRaw,
int subaddrAccount,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef TransactionCommit = int Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
typedef SecretViewKey = Pointer<Utf8> Function();
typedef PublicViewKey = Pointer<Utf8> Function();
typedef SecretSpendKey = Pointer<Utf8> Function();
typedef PublicSpendKey = Pointer<Utf8> Function();
typedef CloseCurrentWallet = void Function();
typedef OnStartup = void Function();
typedef RescanBlockchainAsync = void Function();
typedef AssetTypes = Pointer<Pointer<Utf8>> Function();
typedef AssetTypesSize = int Function();
typedef GetRate = Pointer<Int64> Function();
typedef SizeOfRate = int Function();
typedef UpdateRate = void Function();

@ -0,0 +1,329 @@
import 'dart:async';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:cw_haven/api/convert_utf8_to_string.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/exceptions/setup_wallet_exception.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
int _boolToInt(bool value) => value ? 1 : 0;
final getFileNameNative = havenApi
.lookup<NativeFunction<get_filename>>('get_filename')
.asFunction<GetFilename>();
final getSeedNative =
havenApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
final getAddressNative = havenApi
.lookup<NativeFunction<get_address>>('get_address')
.asFunction<GetAddress>();
final getFullBalanceNative = havenApi
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
.asFunction<GetFullBalance>();
final getUnlockedBalanceNative = havenApi
.lookup<NativeFunction<get_unlocked_balanace>>('get_unlocked_balance')
.asFunction<GetUnlockedBalance>();
final getCurrentHeightNative = havenApi
.lookup<NativeFunction<get_current_height>>('get_current_height')
.asFunction<GetCurrentHeight>();
final getNodeHeightNative = havenApi
.lookup<NativeFunction<get_node_height>>('get_node_height')
.asFunction<GetNodeHeight>();
final isConnectedNative = havenApi
.lookup<NativeFunction<is_connected>>('is_connected')
.asFunction<IsConnected>();
final setupNodeNative = havenApi
.lookup<NativeFunction<setup_node>>('setup_node')
.asFunction<SetupNode>();
final startRefreshNative = havenApi
.lookup<NativeFunction<start_refresh>>('start_refresh')
.asFunction<StartRefresh>();
final connecToNodeNative = havenApi
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
.asFunction<ConnectToNode>();
final setRefreshFromBlockHeightNative = havenApi
.lookup<NativeFunction<set_refresh_from_block_height>>(
'set_refresh_from_block_height')
.asFunction<SetRefreshFromBlockHeight>();
final setRecoveringFromSeedNative = havenApi
.lookup<NativeFunction<set_recovering_from_seed>>(
'set_recovering_from_seed')
.asFunction<SetRecoveringFromSeed>();
final storeNative =
havenApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
final setListenerNative = havenApi
.lookup<NativeFunction<set_listener>>('set_listener')
.asFunction<SetListener>();
final getSyncingHeightNative = havenApi
.lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
.asFunction<GetSyncingHeight>();
final isNeededToRefreshNative = havenApi
.lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
.asFunction<IsNeededToRefresh>();
final isNewTransactionExistNative = havenApi
.lookup<NativeFunction<is_new_transaction_exist>>(
'is_new_transaction_exist')
.asFunction<IsNewTransactionExist>();
final getSecretViewKeyNative = havenApi
.lookup<NativeFunction<secret_view_key>>('secret_view_key')
.asFunction<SecretViewKey>();
final getPublicViewKeyNative = havenApi
.lookup<NativeFunction<public_view_key>>('public_view_key')
.asFunction<PublicViewKey>();
final getSecretSpendKeyNative = havenApi
.lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
.asFunction<SecretSpendKey>();
final getPublicSpendKeyNative = havenApi
.lookup<NativeFunction<secret_view_key>>('public_spend_key')
.asFunction<PublicSpendKey>();
final closeCurrentWalletNative = havenApi
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
.asFunction<CloseCurrentWallet>();
final onStartupNative = havenApi
.lookup<NativeFunction<on_startup>>('on_startup')
.asFunction<OnStartup>();
final rescanBlockchainAsyncNative = havenApi
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
.asFunction<RescanBlockchainAsync>();
int getSyncingHeight() => getSyncingHeightNative();
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
String getSeed() => convertUTF8ToString(pointer: getSeedNative());
String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
int getFullBalance({int accountIndex = 0}) =>
getFullBalanceNative(accountIndex);
int getUnlockedBalance({int accountIndex = 0}) =>
getUnlockedBalanceNative(accountIndex);
int getCurrentHeight() => getCurrentHeightNative();
int getNodeHeightSync() => getNodeHeightNative();
bool isConnectedSync() => isConnectedNative() != 0;
bool setupNodeSync(
{String address,
String login,
String password,
bool useSSL = false,
bool isLightWallet = false}) {
final addressPointer = Utf8.toUtf8(address);
Pointer<Utf8> loginPointer;
Pointer<Utf8> passwordPointer;
if (login != null) {
loginPointer = Utf8.toUtf8(login);
}
if (password != null) {
passwordPointer = Utf8.toUtf8(password);
}
final errorMessagePointer = allocate<Utf8>();
final isSetupNode = setupNodeNative(
addressPointer,
loginPointer,
passwordPointer,
_boolToInt(useSSL),
_boolToInt(isLightWallet),
errorMessagePointer) !=
0;
free(addressPointer);
free(loginPointer);
free(passwordPointer);
if (!isSetupNode) {
throw SetupWalletException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
return isSetupNode;
}
void startRefreshSync() => startRefreshNative();
Future<bool> connectToNode() async => connecToNodeNative() != 0;
void setRefreshFromBlockHeight({int height}) =>
setRefreshFromBlockHeightNative(height);
void setRecoveringFromSeed({bool isRecovery}) =>
setRecoveringFromSeedNative(_boolToInt(isRecovery));
void storeSync() {
final pathPointer = Utf8.toUtf8('');
storeNative(pathPointer);
free(pathPointer);
}
void closeCurrentWallet() => closeCurrentWalletNative();
String getSecretViewKey() =>
convertUTF8ToString(pointer: getSecretViewKeyNative());
String getPublicViewKey() =>
convertUTF8ToString(pointer: getPublicViewKeyNative());
String getSecretSpendKey() =>
convertUTF8ToString(pointer: getSecretSpendKeyNative());
String getPublicSpendKey() =>
convertUTF8ToString(pointer: getPublicSpendKeyNative());
class SyncListener {
SyncListener(this.onNewBlock, this.onNewTransaction) {
_cachedBlockchainHeight = 0;
_lastKnownBlockHeight = 0;
_initialSyncHeight = 0;
}
void Function(int, int, double) onNewBlock;
void Function() onNewTransaction;
Timer _updateSyncInfoTimer;
int _cachedBlockchainHeight;
int _lastKnownBlockHeight;
int _initialSyncHeight;
Future<int> getNodeHeightOrUpdate(int baseHeight) async {
if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
_cachedBlockchainHeight = await getNodeHeight();
}
return _cachedBlockchainHeight;
}
void start() {
_cachedBlockchainHeight = 0;
_lastKnownBlockHeight = 0;
_initialSyncHeight = 0;
_updateSyncInfoTimer ??=
Timer.periodic(Duration(milliseconds: 1200), (_) async {
if (isNewTransactionExist()) {
onNewTransaction?.call();
}
var syncHeight = getSyncingHeight();
if (syncHeight <= 0) {
syncHeight = getCurrentHeight();
}
if (_initialSyncHeight <= 0) {
_initialSyncHeight = syncHeight;
}
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
if (_lastKnownBlockHeight == syncHeight || syncHeight == null) {
return;
}
_lastKnownBlockHeight = syncHeight;
final track = bchHeight - _initialSyncHeight;
final diff = track - (bchHeight - syncHeight);
final ptc = diff <= 0 ? 0.0 : diff / track;
final left = bchHeight - syncHeight;
if (syncHeight < 0 || left < 0) {
return;
}
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
onNewBlock?.call(syncHeight, left, ptc);
});
}
void stop() => _updateSyncInfoTimer?.cancel();
}
SyncListener setListeners(void Function(int, int, double) onNewBlock,
void Function() onNewTransaction) {
final listener = SyncListener(onNewBlock, onNewTransaction);
setListenerNative();
return listener;
}
void onStartup() => onStartupNative();
void _storeSync(Object _) => storeSync();
bool _setupNodeSync(Map args) {
final address = args['address'] as String;
final login = (args['login'] ?? '') as String;
final password = (args['password'] ?? '') as String;
final useSSL = args['useSSL'] as bool;
final isLightWallet = args['isLightWallet'] as bool;
return setupNodeSync(
address: address,
login: login,
password: password,
useSSL: useSSL,
isLightWallet: isLightWallet);
}
bool _isConnected(Object _) => isConnectedSync();
int _getNodeHeight(Object _) => getNodeHeightSync();
void startRefresh() => startRefreshSync();
Future setupNode(
{String address,
String login,
String password,
bool useSSL = false,
bool isLightWallet = false}) =>
compute<Map<String, Object>, void>(_setupNodeSync, {
'address': address,
'login': login,
'password': password,
'useSSL': useSSL,
'isLightWallet': isLightWallet
});
Future store() => compute<int, void>(_storeSync, 0);
Future<bool> isConnected() => compute(_isConnected, 0);
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();

@ -0,0 +1,248 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_haven/api/convert_utf8_to_string.dart';
import 'package:cw_haven/api/signatures.dart';
import 'package:cw_haven/api/types.dart';
import 'package:cw_haven/api/haven_api.dart';
import 'package:cw_haven/api/wallet.dart';
import 'package:cw_haven/api/exceptions/wallet_opening_exception.dart';
import 'package:cw_haven/api/exceptions/wallet_creation_exception.dart';
import 'package:cw_haven/api/exceptions/wallet_restore_from_keys_exception.dart';
import 'package:cw_haven/api/exceptions/wallet_restore_from_seed_exception.dart';
final createWalletNative = havenApi
.lookup<NativeFunction<create_wallet>>('create_wallet')
.asFunction<CreateWallet>();
final restoreWalletFromSeedNative = havenApi
.lookup<NativeFunction<restore_wallet_from_seed>>(
'restore_wallet_from_seed')
.asFunction<RestoreWalletFromSeed>();
final restoreWalletFromKeysNative = havenApi
.lookup<NativeFunction<restore_wallet_from_keys>>(
'restore_wallet_from_keys')
.asFunction<RestoreWalletFromKeys>();
final isWalletExistNative = havenApi
.lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
.asFunction<IsWalletExist>();
final loadWalletNative = havenApi
.lookup<NativeFunction<load_wallet>>('load_wallet')
.asFunction<LoadWallet>();
final errorStringNative = havenApi
.lookup<NativeFunction<error_string>>('error_string')
.asFunction<ErrorString>();
void createWalletSync(
{String path, String password, String language, int nettype = 0}) {
final pathPointer = Utf8.toUtf8(path);
final passwordPointer = Utf8.toUtf8(password);
final languagePointer = Utf8.toUtf8(language);
final errorMessagePointer = allocate<Utf8>();
final isWalletCreated = createWalletNative(pathPointer, passwordPointer,
languagePointer, nettype, errorMessagePointer) !=
0;
free(pathPointer);
free(passwordPointer);
free(languagePointer);
if (!isWalletCreated) {
throw WalletCreationException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
// setupNodeSync(address: "node.moneroworld.com:18089");
}
bool isWalletExistSync({String path}) {
final pathPointer = Utf8.toUtf8(path);
final isExist = isWalletExistNative(pathPointer) != 0;
free(pathPointer);
return isExist;
}
void restoreWalletFromSeedSync(
{String path,
String password,
String seed,
int nettype = 0,
int restoreHeight = 0}) {
final pathPointer = Utf8.toUtf8(path);
final passwordPointer = Utf8.toUtf8(password);
final seedPointer = Utf8.toUtf8(seed);
final errorMessagePointer = allocate<Utf8>();
final isWalletRestored = restoreWalletFromSeedNative(
pathPointer,
passwordPointer,
seedPointer,
nettype,
restoreHeight,
errorMessagePointer) !=
0;
free(pathPointer);
free(passwordPointer);
free(seedPointer);
if (!isWalletRestored) {
throw WalletRestoreFromSeedException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
}
void restoreWalletFromKeysSync(
{String path,
String password,
String language,
String address,
String viewKey,
String spendKey,
int nettype = 0,
int restoreHeight = 0}) {
final pathPointer = Utf8.toUtf8(path);
final passwordPointer = Utf8.toUtf8(password);
final languagePointer = Utf8.toUtf8(language);
final addressPointer = Utf8.toUtf8(address);
final viewKeyPointer = Utf8.toUtf8(viewKey);
final spendKeyPointer = Utf8.toUtf8(spendKey);
final errorMessagePointer = allocate<Utf8>();
final isWalletRestored = restoreWalletFromKeysNative(
pathPointer,
passwordPointer,
languagePointer,
addressPointer,
viewKeyPointer,
spendKeyPointer,
nettype,
restoreHeight,
errorMessagePointer) !=
0;
free(pathPointer);
free(passwordPointer);
free(languagePointer);
free(addressPointer);
free(viewKeyPointer);
free(spendKeyPointer);
if (!isWalletRestored) {
throw WalletRestoreFromKeysException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
}
void loadWallet({String path, String password, int nettype = 0}) {
final pathPointer = Utf8.toUtf8(path);
final passwordPointer = Utf8.toUtf8(password);
final loaded = loadWalletNative(pathPointer, passwordPointer, nettype) != 0;
free(pathPointer);
free(passwordPointer);
if (!loaded) {
throw WalletOpeningException(
message: convertUTF8ToString(pointer: errorStringNative()));
}
}
void _createWallet(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final language = args['language'] as String;
createWalletSync(path: path, password: password, language: language);
}
void _restoreFromSeed(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final seed = args['seed'] as String;
final restoreHeight = args['restoreHeight'] as int;
restoreWalletFromSeedSync(
path: path, password: password, seed: seed, restoreHeight: restoreHeight);
}
void _restoreFromKeys(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final language = args['language'] as String;
final restoreHeight = args['restoreHeight'] as int;
final address = args['address'] as String;
final viewKey = args['viewKey'] as String;
final spendKey = args['spendKey'] as String;
restoreWalletFromKeysSync(
path: path,
password: password,
language: language,
restoreHeight: restoreHeight,
address: address,
viewKey: viewKey,
spendKey: spendKey);
}
Future<void> _openWallet(Map<String, String> args) async =>
loadWallet(path: args['path'], password: args['password']);
bool _isWalletExist(String path) => isWalletExistSync(path: path);
void openWallet({String path, String password, int nettype = 0}) async =>
loadWallet(path: path, password: password, nettype: nettype);
Future<void> openWalletAsync(Map<String, String> args) async =>
compute(_openWallet, args);
Future<void> createWallet(
{String path,
String password,
String language,
int nettype = 0}) async =>
compute(_createWallet, {
'path': path,
'password': password,
'language': language,
'nettype': nettype
});
Future restoreFromSeed(
{String path,
String password,
String seed,
int nettype = 0,
int restoreHeight = 0}) async =>
compute<Map<String, Object>, void>(_restoreFromSeed, {
'path': path,
'password': password,
'seed': seed,
'nettype': nettype,
'restoreHeight': restoreHeight
});
Future restoreFromKeys(
{String path,
String password,
String language,
String address,
String viewKey,
String spendKey,
int nettype = 0,
int restoreHeight = 0}) async =>
compute<Map<String, Object>, void>(_restoreFromKeys, {
'path': path,
'password': password,
'language': language,
'address': address,
'viewKey': viewKey,
'spendKey': spendKey,
'nettype': nettype,
'restoreHeight': restoreHeight
});
Future<bool> isWalletExist({String path}) => compute(_isWalletExist, path);

@ -0,0 +1,84 @@
import 'package:mobx/mobx.dart';
import 'package:cw_core/account.dart';
import 'package:cw_core/account_list.dart';
import 'package:cw_haven/api/account_list.dart' as account_list;
part 'haven_account_list.g.dart';
class HavenAccountList = HavenAccountListBase with _$HavenAccountList;
abstract class HavenAccountListBase extends AccountList<Account> with Store {
HavenAccountListBase()
: accounts = ObservableList<Account>(),
_isRefreshing = false,
_isUpdating = false {
refresh();
}
@override
@observable
ObservableList<Account> accounts;
bool _isRefreshing;
bool _isUpdating;
@override
void update() async {
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
refresh();
final accounts = getAll();
if (accounts.isNotEmpty) {
this.accounts.clear();
this.accounts.addAll(accounts);
}
_isUpdating = false;
} catch (e) {
_isUpdating = false;
rethrow;
}
}
@override
List<Account> getAll() => account_list
.getAllAccount()
.map((accountRow) => Account(
id: accountRow.getId(),
label: accountRow.getLabel()))
.toList();
@override
Future addAccount({String label}) async {
await account_list.addAccount(label: label);
update();
}
@override
Future setLabelAccount({int accountIndex, String label}) async {
await account_list.setLabelForAccount(
accountIndex: accountIndex, label: label);
update();
}
@override
void refresh() {
if (_isRefreshing) {
return;
}
try {
_isRefreshing = true;
account_list.refreshAccounts();
_isRefreshing = false;
} catch (e) {
_isRefreshing = false;
print(e);
rethrow;
}
}
}

@ -0,0 +1,34 @@
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/monero_balance.dart';
import 'package:cw_haven/api/balance_list.dart';
import 'package:cw_haven/api/structs/haven_balance_row.dart';
const inactiveBalances = [
CryptoCurrency.xcad,
CryptoCurrency.xjpy,
CryptoCurrency.xnok,
CryptoCurrency.xnzd];
Map<CryptoCurrency, MoneroBalance> getHavenBalance({int accountIndex}) {
final fullBalances = getHavenFullBalance(accountIndex: accountIndex);
final unlockedBalances = getHavenUnlockedBalance(accountIndex: accountIndex);
final havenBalances = <CryptoCurrency, MoneroBalance>{};
final balancesLength = fullBalances.length;
for (int i = 0; i < balancesLength; i++) {
final assetType = fullBalances[i].getAssetType();
final fullBalance = fullBalances[i].getAmount();
final unlockedBalance = unlockedBalances[i].getAmount();
final moneroBalance = MoneroBalance(
fullBalance: fullBalance, unlockedBalance: unlockedBalance);
final currency = CryptoCurrency.fromString(assetType);
if (inactiveBalances.indexOf(currency) >= 0) {
continue;
}
havenBalances[currency] = moneroBalance;
}
return havenBalances;
}

@ -0,0 +1,87 @@
import 'package:cw_haven/api/structs/subaddress_row.dart';
import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_haven/api/subaddress_list.dart' as subaddress_list;
import 'package:cw_core/subaddress.dart';
part 'haven_subaddress_list.g.dart';
class HavenSubaddressList = HavenSubaddressListBase
with _$HavenSubaddressList;
abstract class HavenSubaddressListBase with Store {
HavenSubaddressListBase() {
_isRefreshing = false;
_isUpdating = false;
subaddresses = ObservableList<Subaddress>();
}
@observable
ObservableList<Subaddress> subaddresses;
bool _isRefreshing;
bool _isUpdating;
void update({int accountIndex}) {
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
refresh(accountIndex: accountIndex);
subaddresses.clear();
subaddresses.addAll(getAll());
_isUpdating = false;
} catch (e) {
_isUpdating = false;
rethrow;
}
}
List<Subaddress> getAll() {
var subaddresses = subaddress_list.getAllSubaddresses();
if (subaddresses.length > 2) {
final primary = subaddresses.first;
final rest = subaddresses.sublist(1).reversed;
subaddresses = [primary] + rest.toList();
}
return subaddresses
.map((subaddressRow) => Subaddress(
id: subaddressRow.getId(),
address: subaddressRow.getAddress(),
label: subaddressRow.getLabel()))
.toList();
}
Future addSubaddress({int accountIndex, String label}) async {
await subaddress_list.addSubaddress(
accountIndex: accountIndex, label: label);
update(accountIndex: accountIndex);
}
Future setLabelSubaddress(
{int accountIndex, int addressIndex, String label}) async {
await subaddress_list.setLabelForSubaddress(
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
update(accountIndex: accountIndex);
}
void refresh({int accountIndex}) {
if (_isRefreshing) {
return;
}
try {
_isRefreshing = true;
subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
_isRefreshing = false;
} on PlatformException catch (e) {
_isRefreshing = false;
print(e);
rethrow;
}
}
}

@ -0,0 +1,10 @@
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/output_info.dart';
class HavenTransactionCreationCredentials {
HavenTransactionCreationCredentials({this.outputs, this.priority, this.assetType});
final List<OutputInfo> outputs;
final MoneroTransactionPriority priority;
final String assetType;
}

@ -0,0 +1,8 @@
class HavenTransactionCreationException implements Exception {
HavenTransactionCreationException(this.message);
final String message;
@override
String toString() => message;
}

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

@ -0,0 +1,70 @@
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_haven/api/structs/transaction_info_row.dart';
import 'package:cw_core/parseBoolFromString.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_haven/api/transaction_history.dart';
class HavenTransactionInfo extends TransactionInfo {
HavenTransactionInfo(this.id, this.height, this.direction, this.date,
this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee);
HavenTransactionInfo.fromMap(Map map)
: id = (map['hash'] ?? '') as String,
height = (map['height'] ?? 0) as int,
direction =
parseTransactionDirectionFromNumber(map['direction'] as String) ??
TransactionDirection.incoming,
date = DateTime.fromMillisecondsSinceEpoch(
(int.parse(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;
HavenTransactionInfo.fromRow(TransactionInfoRow row)
: id = row.getHash(),
height = row.blockHeight,
direction = parseTransactionDirectionFromInt(row.direction) ??
TransactionDirection.incoming,
date = DateTime.fromMillisecondsSinceEpoch(row.getDatetime() * 1000),
isPending = row.isPending != 0,
amount = row.getAmount(),
accountIndex = row.subaddrAccount,
addressIndex = row.subaddrIndex,
key = null, //getTxKey(row.getHash()),
fee = row.fee,
assetType = row.getAssetType();
final String id;
final int height;
final TransactionDirection direction;
final DateTime date;
final int accountIndex;
final bool isPending;
final int amount;
final int fee;
final int addressIndex;
String recipientAddress;
String key;
String assetType;
String _fiatAmount;
@override
String amountFormatted() =>
'${formatAmount(moneroAmountToString(amount: amount))} $assetType';
@override
String fiatAmount() => _fiatAmount ?? '';
@override
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
@override
String feeFormatted() =>
'${formatAmount(moneroAmountToString(amount: fee))} $assetType';
}

@ -0,0 +1,388 @@
import 'dart:async';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_haven/haven_transaction_creation_credentials.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_haven/haven_transaction_creation_exception.dart';
import 'package:cw_haven/haven_transaction_info.dart';
import 'package:cw_haven/haven_wallet_addresses.dart';
import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_haven/api/transaction_history.dart'
as haven_transaction_history;
//import 'package:cw_haven/wallet.dart';
import 'package:cw_haven/api/wallet.dart' as haven_wallet;
import 'package:cw_haven/api/transaction_history.dart' as transaction_history;
import 'package:cw_haven/api/monero_output.dart';
import 'package:cw_haven/pending_haven_transaction.dart';
import 'package:cw_core/monero_wallet_keys.dart';
import 'package:cw_core/monero_balance.dart';
import 'package:cw_haven/haven_transaction_history.dart';
import 'package:cw_core/account.dart';
import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_haven/haven_balance.dart';
part 'haven_wallet.g.dart';
const moneroBlockSize = 1000;
class HavenWallet = HavenWalletBase with _$HavenWallet;
abstract class HavenWalletBase extends WalletBase<MoneroBalance,
HavenTransactionHistory, HavenTransactionInfo> with Store {
HavenWalletBase({WalletInfo walletInfo})
: super(walletInfo) {
transactionHistory = HavenTransactionHistory();
balance = ObservableMap.of(getHavenBalance(accountIndex: 0));
_isTransactionUpdating = false;
_hasSyncAfterStartup = false;
walletAddresses = HavenWalletAddresses(walletInfo);
_onAccountChangeReaction = reaction((_) => walletAddresses.account,
(Account account) {
balance.addAll(getHavenBalance(accountIndex: account.id));
walletAddresses.updateSubaddressList(accountIndex: account.id);
});
}
static const int _autoSaveInterval = 30;
@override
HavenWalletAddresses walletAddresses;
@override
@observable
SyncStatus syncStatus;
@override
@observable
ObservableMap<CryptoCurrency, MoneroBalance> balance;
@override
String get seed => haven_wallet.getSeed();
@override
MoneroWalletKeys get keys => MoneroWalletKeys(
privateSpendKey: haven_wallet.getSecretSpendKey(),
privateViewKey: haven_wallet.getSecretViewKey(),
publicSpendKey: haven_wallet.getPublicSpendKey(),
publicViewKey: haven_wallet.getPublicViewKey());
haven_wallet.SyncListener _listener;
ReactionDisposer _onAccountChangeReaction;
bool _isTransactionUpdating;
bool _hasSyncAfterStartup;
Timer _autoSaveTimer;
Future<void> init() async {
await walletAddresses.init();
balance.addAll(getHavenBalance(accountIndex: walletAddresses.account.id ?? 0));
_setListeners();
await updateTransactions();
if (walletInfo.isRecovery) {
haven_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
if (haven_wallet.getCurrentHeight() <= 1) {
haven_wallet.setRefreshFromBlockHeight(
height: walletInfo.restoreHeight);
}
}
_autoSaveTimer = Timer.periodic(
Duration(seconds: _autoSaveInterval),
(_) async => await save());
}
@override
void close() {
_listener?.stop();
_onAccountChangeReaction?.reaction?.dispose();
_autoSaveTimer?.cancel();
}
@override
Future<void> connectToNode({@required Node node}) async {
try {
syncStatus = ConnectingSyncStatus();
await haven_wallet.setupNode(
address: node.uriRaw,
login: node.login,
password: node.password,
useSSL: node.useSSL,
isLightWallet: false); // FIXME: hardcoded value
syncStatus = ConnectedSyncStatus();
} catch (e) {
syncStatus = FailedSyncStatus();
print(e);
}
}
@override
Future<void> startSync() async {
try {
_setInitialHeight();
} catch (_) {}
try {
syncStatus = StartingSyncStatus();
haven_wallet.startRefresh();
_setListeners();
_listener?.start();
} catch (e) {
syncStatus = FailedSyncStatus();
print(e);
rethrow;
}
}
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
final _credentials = credentials as HavenTransactionCreationCredentials;
final outputs = _credentials.outputs;
final hasMultiDestination = outputs.length > 1;
final assetType = CryptoCurrency.fromString(_credentials.assetType.toLowerCase());
final balances = getHavenBalance(accountIndex: walletAddresses.account.id);
final unlockedBalance = balances[assetType].unlockedBalance;
PendingTransactionDescription pendingTransactionDescription;
if (!(syncStatus is SyncedSyncStatus)) {
throw HavenTransactionCreationException('The wallet is not synced.');
}
if (hasMultiDestination) {
if (outputs.any((item) => item.sendAll
|| item.formattedCryptoAmount <= 0)) {
throw HavenTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
}
final int totalAmount = outputs.fold(0, (acc, value) =>
acc + value.formattedCryptoAmount);
if (unlockedBalance < totalAmount) {
throw HavenTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
}
final moneroOutputs = outputs.map((output) =>
MoneroOutput(
address: output.address,
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.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 HavenTransactionCreationException(
'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
}
pendingTransactionDescription =
await transaction_history.createTransaction(
address: address,
assetType: _credentials.assetType,
amount: amount,
priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account.id);
}
return PendingHavenTransaction(pendingTransactionDescription, assetType);
}
@override
int calculateEstimatedFee(TransactionPriority priority, int amount) {
// FIXME: hardcoded value;
if (priority is MoneroTransactionPriority) {
switch (priority) {
case MoneroTransactionPriority.slow:
return 24590000;
case MoneroTransactionPriority.regular:
return 123050000;
case MoneroTransactionPriority.medium:
return 245029999;
case MoneroTransactionPriority.fast:
return 614530000;
case MoneroTransactionPriority.fastest:
return 26021600000;
}
}
return 0;
}
@override
Future<void> save() async {
await walletAddresses.updateAddressesInBox();
await backupWalletFiles(name);
await haven_wallet.store();
}
Future<int> getNodeHeight() async => haven_wallet.getNodeHeight();
Future<bool> isConnected() async => haven_wallet.isConnected();
Future<void> setAsRecovered() async {
walletInfo.isRecovery = false;
await walletInfo.save();
}
@override
Future<void> rescan({int height}) async {
walletInfo.restoreHeight = height;
walletInfo.isRecovery = true;
haven_wallet.setRefreshFromBlockHeight(height: height);
haven_wallet.rescanBlockchainAsync();
await startSync();
_askForUpdateBalance();
walletAddresses.accountList.update();
await _askForUpdateTransactionHistory();
await save();
await walletInfo.save();
}
String getTransactionAddress(int accountIndex, int addressIndex) =>
haven_wallet.getAddress(
accountIndex: accountIndex,
addressIndex: addressIndex);
@override
Future<Map<String, HavenTransactionInfo>> fetchTransactions() async {
haven_transaction_history.refreshTransactions();
return _getAllTransactions(null).fold<Map<String, HavenTransactionInfo>>(
<String, HavenTransactionInfo>{},
(Map<String, HavenTransactionInfo> acc, HavenTransactionInfo tx) {
acc[tx.id] = tx;
return acc;
});
}
Future<void> updateTransactions() async {
try {
if (_isTransactionUpdating) {
return;
}
_isTransactionUpdating = true;
final transactions = await fetchTransactions();
transactionHistory.addMany(transactions);
await transactionHistory.save();
_isTransactionUpdating = false;
} catch (e) {
print(e);
_isTransactionUpdating = false;
}
}
List<HavenTransactionInfo> _getAllTransactions(dynamic _) => haven_transaction_history
.getAllTransations()
.map((row) => HavenTransactionInfo.fromRow(row))
.toList();
void _setListeners() {
_listener?.stop();
_listener = haven_wallet.setListeners(_onNewBlock, _onNewTransaction);
}
void _setInitialHeight() {
if (walletInfo.isRecovery) {
return;
}
final currentHeight = haven_wallet.getCurrentHeight();
if (currentHeight <= 1) {
final height = _getHeightByDate(walletInfo.date);
haven_wallet.setRecoveringFromSeed(isRecovery: true);
haven_wallet.setRefreshFromBlockHeight(height: height);
}
}
int _getHeightDistance(DateTime date) {
final distance =
DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
final daysTmp = (distance / 86400).round();
final days = daysTmp < 1 ? 1 : daysTmp;
return days * 1000;
}
int _getHeightByDate(DateTime date) {
final nodeHeight = haven_wallet.getNodeHeightSync();
final heightDistance = _getHeightDistance(date);
if (nodeHeight <= 0) {
return 0;
}
return nodeHeight - heightDistance;
}
void _askForUpdateBalance() =>
balance.addAll(getHavenBalance(accountIndex: walletAddresses.account.id));
Future<void> _askForUpdateTransactionHistory() async =>
await updateTransactions();
void _onNewBlock(int height, int blocksLeft, double ptc) async {
try {
if (walletInfo.isRecovery) {
await _askForUpdateTransactionHistory();
_askForUpdateBalance();
walletAddresses.accountList.update();
}
if (blocksLeft < 1000) {
await _askForUpdateTransactionHistory();
_askForUpdateBalance();
walletAddresses.accountList.update();
syncStatus = SyncedSyncStatus();
if (!_hasSyncAfterStartup) {
_hasSyncAfterStartup = true;
await save();
}
if (walletInfo.isRecovery) {
await setAsRecovered();
}
} else {
syncStatus = SyncingSyncStatus(blocksLeft, ptc);
}
} catch (e) {
print(e.toString());
}
}
void _onNewTransaction() async {
try {
await _askForUpdateTransactionHistory();
_askForUpdateBalance();
await Future<void>.delayed(Duration(seconds: 1));
} catch (e) {
print(e.toString());
}
}
}

@ -0,0 +1,86 @@
import 'package:cw_core/wallet_addresses_with_account.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/account.dart';
import 'package:cw_haven/haven_account_list.dart';
import 'package:cw_haven/haven_subaddress_list.dart';
import 'package:cw_core/subaddress.dart';
import 'package:mobx/mobx.dart';
part 'haven_wallet_addresses.g.dart';
class HavenWalletAddresses = HavenWalletAddressesBase
with _$HavenWalletAddresses;
abstract class HavenWalletAddressesBase extends WalletAddressesWithAccount<Account> with Store {
HavenWalletAddressesBase(WalletInfo walletInfo) : super(walletInfo) {
accountList = HavenAccountList();
subaddressList = HavenSubaddressList();
}
@override
@observable
String address;
@override
@observable
Account account;
@observable
Subaddress subaddress;
HavenSubaddressList subaddressList;
HavenAccountList accountList;
@override
Future<void> init() async {
accountList.update();
account = accountList.accounts.first;
updateSubaddressList(accountIndex: account.id ?? 0);
await updateAddressesInBox();
}
@override
Future<void> updateAddressesInBox() async {
try {
final _subaddressList = HavenSubaddressList();
addressesMap.clear();
accountList.accounts.forEach((account) {
_subaddressList.update(accountIndex: account.id);
_subaddressList.subaddresses.forEach((subaddress) {
addressesMap[subaddress.address] = subaddress.label;
});
});
await saveAddressesInBox();
} catch (e) {
print(e.toString());
}
}
bool validate() {
accountList.update();
final accountListLength = accountList.accounts?.length ?? 0;
if (accountListLength <= 0) {
return false;
}
subaddressList.update(accountIndex: accountList.accounts.first.id);
final subaddressListLength = subaddressList.subaddresses?.length ?? 0;
if (subaddressListLength <= 0) {
return false;
}
return true;
}
void updateSubaddressList({int accountIndex}) {
subaddressList.update(accountIndex: accountIndex);
subaddress = subaddressList.subaddresses.first;
address = subaddress.address;
}
}

@ -0,0 +1,228 @@
import 'dart:io';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/monero_wallet_utils.dart';
import 'package:hive/hive.dart';
import 'package:cw_haven/api/wallet_manager.dart' as haven_wallet_manager;
import 'package:cw_haven/api/wallet.dart' as haven_wallet;
import 'package:cw_haven/api/exceptions/wallet_opening_exception.dart';
import 'package:cw_haven/haven_wallet.dart';
import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
class HavenNewWalletCredentials extends WalletCredentials {
HavenNewWalletCredentials({String name, String password, this.language})
: super(name: name, password: password);
final String language;
}
class HavenRestoreWalletFromSeedCredentials extends WalletCredentials {
HavenRestoreWalletFromSeedCredentials(
{String name, String password, int height, this.mnemonic})
: super(name: name, password: password, height: height);
final String mnemonic;
}
class HavenWalletLoadingException implements Exception {
@override
String toString() => 'Failure to load the wallet.';
}
class HavenRestoreWalletFromKeysCredentials extends WalletCredentials {
HavenRestoreWalletFromKeysCredentials(
{String name,
String password,
this.language,
this.address,
this.viewKey,
this.spendKey,
int height})
: super(name: name, password: password, height: height);
final String language;
final String address;
final String viewKey;
final String spendKey;
}
class HavenWalletService extends WalletService<
HavenNewWalletCredentials,
HavenRestoreWalletFromSeedCredentials,
HavenRestoreWalletFromKeysCredentials> {
HavenWalletService(this.walletInfoSource);
final Box<WalletInfo> walletInfoSource;
static bool walletFilesExist(String path) =>
!File(path).existsSync() && !File('$path.keys').existsSync();
@override
WalletType getType() => WalletType.haven;
@override
Future<HavenWallet> create(HavenNewWalletCredentials credentials) async {
try {
final path = await pathForWallet(name: credentials.name, type: getType());
await haven_wallet_manager.createWallet(
path: path,
password: credentials.password,
language: credentials.language);
final wallet = HavenWallet(walletInfo: credentials.walletInfo);
await wallet.init();
return wallet;
} catch (e) {
// TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: ${e.toString()}');
rethrow;
}
}
@override
Future<bool> isWalletExit(String name) async {
try {
final path = await pathForWallet(name: name, type: getType());
return haven_wallet_manager.isWalletExist(path: path);
} catch (e) {
// TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: $e');
rethrow;
}
}
@override
Future<HavenWallet> openWallet(String name, String password) async {
try {
final path = await pathForWallet(name: name, type: getType());
if (walletFilesExist(path)) {
await repairOldAndroidWallet(name);
}
await haven_wallet_manager
.openWalletAsync({'path': path, 'password': password});
final walletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(name, getType()),
orElse: () => null);
final wallet = HavenWallet(walletInfo: walletInfo);
final isValid = wallet.walletAddresses.validate();
if (!isValid) {
await restoreOrResetWalletFiles(name);
wallet.close();
return openWallet(name, password);
}
await wallet.init();
return wallet;
} catch (e) {
// TODO: Implement Exception for wallet list service.
if ((e.toString().contains('bad_alloc') ||
(e is WalletOpeningException &&
(e.message == 'std::bad_alloc' ||
e.message.contains('bad_alloc')))) ||
(e.toString().contains('does not correspond') ||
(e is WalletOpeningException &&
e.message.contains('does not correspond')))) {
await restoreOrResetWalletFiles(name);
return openWallet(name, password);
}
rethrow;
}
}
@override
Future<void> remove(String wallet) async {
final path = await pathForWalletDir(name: wallet, type: getType());
final file = Directory(path);
final isExist = file.existsSync();
if (isExist) {
await file.delete(recursive: true);
}
}
@override
Future<HavenWallet> restoreFromKeys(
HavenRestoreWalletFromKeysCredentials credentials) async {
try {
final path = await pathForWallet(name: credentials.name, type: getType());
await haven_wallet_manager.restoreFromKeys(
path: path,
password: credentials.password,
language: credentials.language,
restoreHeight: credentials.height,
address: credentials.address,
viewKey: credentials.viewKey,
spendKey: credentials.spendKey);
final wallet = HavenWallet(walletInfo: credentials.walletInfo);
await wallet.init();
return wallet;
} catch (e) {
// TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: $e');
rethrow;
}
}
@override
Future<HavenWallet> restoreFromSeed(
HavenRestoreWalletFromSeedCredentials credentials) async {
try {
final path = await pathForWallet(name: credentials.name, type: getType());
await haven_wallet_manager.restoreFromSeed(
path: path,
password: credentials.password,
seed: credentials.mnemonic,
restoreHeight: credentials.height);
final wallet = HavenWallet(walletInfo: credentials.walletInfo);
await wallet.init();
return wallet;
} catch (e) {
// TODO: Implement Exception for wallet list service.
print('HavenWalletsManager Error: $e');
rethrow;
}
}
Future<void> repairOldAndroidWallet(String name) async {
try {
if (!Platform.isAndroid) {
return;
}
final oldAndroidWalletDirPath =
await outdatedAndroidPathForWalletDir(name: name);
final dir = Directory(oldAndroidWalletDirPath);
if (!dir.existsSync()) {
return;
}
final newWalletDirPath =
await pathForWalletDir(name: name, type: getType());
dir.listSync().forEach((f) {
final file = File(f.path);
final name = f.path.split('/').last;
final newPath = newWalletDirPath + '/$name';
final newFile = File(newPath);
if (!newFile.existsSync()) {
newFile.createSync();
}
newFile.writeAsBytesSync(file.readAsBytesSync());
});
} catch (e) {
print(e.toString());
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,48 @@
import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:cw_haven/api/transaction_history.dart'
as haven_transaction_history;
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/core/amount_converter.dart';
import 'package:cw_core/pending_transaction.dart';
class DoubleSpendException implements Exception {
DoubleSpendException();
@override
String toString() =>
'This transaction cannot be committed. This can be due to many reasons including the wallet not being synced, there is not enough XMR in your available balance, or previous transactions are not yet fully processed.';
}
class PendingHavenTransaction with PendingTransaction {
PendingHavenTransaction(this.pendingTransactionDescription, this.cryptoCurrency);
final PendingTransactionDescription pendingTransactionDescription;
final CryptoCurrency cryptoCurrency;
@override
String get id => pendingTransactionDescription.hash;
@override
String get amountFormatted => AmountConverter.amountIntToString(
cryptoCurrency, pendingTransactionDescription.amount);
@override
String get feeFormatted => AmountConverter.amountIntToString(
cryptoCurrency, pendingTransactionDescription.fee);
@override
Future<void> commit() async {
try {
haven_transaction_history.commitTransactionFromPointerAddress(
address: pendingTransactionDescription.pointerAddress);
} catch (e) {
final message = e.toString();
if (message.contains('Reason: double spend')) {
throw DoubleSpendException();
}
rethrow;
}
}
}

@ -0,0 +1,15 @@
//import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_haven/balance_list.dart';
//Future<void> updateHavenRate(FiatConversionStore fiatConversionStore) async {
// final rate = getRate();
// final base = rate.firstWhere((row) => row.getAssetType() == 'XUSD', orElse: () => null);
// rate.forEach((row) {
// final cur = CryptoCurrency.fromString(row.getAssetType());
// final baseRate = moneroAmountToDouble(amount: base.getRate());
// final rowRate = moneroAmountToDouble(amount: row.getRate());
// fiatConversionStore.prices[cur] = baseRate * rowRate;
// });
//}

@ -0,0 +1,609 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "14.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.41.2"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.1"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
build:
dependency: transitive
description:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.2"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.6"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.10"
build_resolvers:
dependency: "direct dev"
description:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.3"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.5"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.10"
built_collection:
dependency: transitive
description:
name: built_collection
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.1"
built_value:
dependency: transitive
description:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.4"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "3.7.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
cw_core:
dependency: "direct main"
description:
path: "../cw_core"
relative: true
source: path
version: "0.0.1"
cw_monero:
dependency: "direct main"
description:
path: "../cw_monero"
relative: true
source: path
version: "0.0.1"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.12"
dartx:
dependency: transitive
description:
name: dartx
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.0"
encrypt:
dependency: transitive
description:
name: encrypt
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
ffi:
dependency: "direct main"
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_mobx:
dependency: "direct main"
description:
name: flutter_mobx
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0+2"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
hive:
dependency: transitive
description:
name: hive
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.4+1"
hive_generator:
dependency: "direct dev"
description:
name: hive_generator
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.2"
http:
dependency: "direct main"
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.2"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
intl:
dependency: "direct main"
description:
name: intl
url: "https://pub.dartlang.org"
source: hosted
version: "0.17.0"
io:
dependency: transitive
description:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.1"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
mobx:
dependency: "direct main"
description:
name: mobx
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1+4"
mobx_codegen:
dependency: "direct dev"
description:
name: mobx_codegen
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
path_provider:
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.28"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+2"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+8"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+3"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.1"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
pointycastle:
dependency: transitive
description:
name: pointycastle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.3"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.8"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.9"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.4+1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.10+3"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.19"
time:
dependency: transitive
description:
name: time
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.1"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+3"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.4+1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.12.0 <3.0.0"
flutter: ">=1.20.0"

@ -0,0 +1,78 @@
name: cw_haven
description: A new flutter plugin project.
version: 0.0.1
publish_to: none
author: Cake Wallet
homepage: https://cakewallet.com
environment:
sdk: ">=2.7.0 <3.0.0"
flutter: ">=1.20.0"
dependencies:
flutter:
sdk: flutter
ffi: ^0.1.3
path_provider: ^1.4.0
http: ^0.12.0+2
mobx: ^1.2.1+2
flutter_mobx: ^1.1.0+2
intl: ^0.17.0
cw_core:
path: ../cw_core
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.10.3
build_resolvers: ^1.3.10
mobx_codegen: ^1.1.0+1
hive_generator: ^0.8.1
# 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.
flutter:
# This section identifies this Flutter project as a plugin project.
# The 'pluginClass' and Android 'package' identifiers should not ordinarily
# be modified. They are used by the tooling to maintain consistency when
# adding or updating assets for this project.
plugin:
platforms:
android:
package: com.cakewallet.cw_haven
pluginClass: CwHavenPlugin
ios:
pluginClass: CwHavenPlugin
# To add assets to your plugin 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 plugin 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

@ -7,8 +7,6 @@ add_library( cw_monero
find_library( log-lib log )
set(CMAKE_BUILD_TYPE Debug)
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../ios/External/android)
############

@ -38,12 +38,10 @@ android {
disable 'InvalidPackage'
}
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "CMakeLists.txt"
cmake {
path "CMakeLists.txt"
}
}
}
}
dependencies {

@ -12,43 +12,44 @@ Pod::Spec.new do |s|
s.author = { 'CakeWallet' => 'support@cakewallet.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h, Classes/*.h, External/ios/libs/monero/include/src/**/*.h, External/ios/libs/monero/include/contrib/**/*.h, External/ios/libs/monero/include/External/ios/**/*.h'
s.public_header_files = 'Classes/**/*.h, Classes/*.h, External/ios/libs/monero/include/External/ios/**/*.h'
s.dependency 'Flutter'
s.dependency 'cw_shared_external'
s.platform = :ios, '10.0'
s.swift_version = '4.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/Classes/*.h" }
s.subspec 'OpenSSL' do |openssl|
openssl.preserve_paths = 'External/ios/include/*.h'
openssl.vendored_libraries = 'External/ios/lib/libcrypto.a', 'External/ios/lib/libssl.a'
openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
openssl.libraries = 'ssl', 'crypto'
openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Monero' do |monero|
monero.preserve_paths = 'External/ios/include/**/*.h'
monero.vendored_libraries = 'External/ios/lib/libeasylogging.a', 'External/ios/lib/libepee.a', 'External/ios/lib/liblmdb.a', 'External/ios/lib/librandomx.a', 'External/ios/lib/libunbound.a', 'External/ios/lib/libwallet_merged.a', 'libcryptonote_basic.a', 'libcryptonote_format_utils_basic.a'
monero.libraries = 'easylogging', 'epee', 'unbound', 'wallet_merged', 'lmdb', 'randomx', 'cryptonote_basic', 'cryptonote_format_utils_basic'
monero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
s.subspec 'Sodium' do |sodium|
sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libsodium.a'
sodium.libraries = 'sodium'
sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Boost' do |boost|
boost.preserve_paths = 'External/ios/include/**/*.h', 'External/ios/include/**/*.h'
boost.vendored_libraries = 'External/ios/lib/libboost_chrono.a', 'External/ios/lib/libboost_date_time.a', 'External/ios/lib/libboost_filesystem.a', 'External/ios/lib/libboost_graph.a', 'External/ios/lib/libboost_locale.a', 'External/ios/lib/libboost_program_options.a', 'External/ios/lib/libboost_random.a', 'External/ios/lib/libboost_regex.a', 'External/ios/lib/libboost_serialization.a', 'External/ios/lib/libboost_system.a', 'External/ios/lib/libboost_thread.a', 'External/ios/lib/libboost_wserialization.a'
boost.libraries = 'boost_wserialization', 'boost_thread', 'boost_system', 'boost_serialization', 'boost_regex', 'boost_random', 'boost_program_options', 'boost_locale', 'boost_graph', 'boost_filesystem', 'boost_date_time', 'boost_chrono'
boost.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h',
boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libboost.a',
boost.libraries = 'boost'
boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Sodium' do |sodium|
sodium.preserve_paths = 'External/ios/include/**/*.h'
sodium.vendored_libraries = 'External/ios/lib/libsodium.a'
sodium.libraries = 'sodium'
sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
s.subspec 'Monero' do |monero|
monero.preserve_paths = 'External/ios/include/**/*.h'
monero.vendored_libraries = 'External/ios/lib/libmonero.a'
monero.libraries = 'monero'
monero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
end
s.subspec 'lmdb' do |lmdb|
lmdb.vendored_libraries = 'External/ios/lib/liblmdb.a'
lmdb.libraries = 'lmdb'
end
# s.subspec 'lmdb' do |lmdb|
# lmdb.vendored_libraries = 'External/ios/lib/liblmdb.a'
# lmdb.libraries = 'lmdb'
# end
end

@ -1,5 +1,5 @@
import 'package:mobx/mobx.dart';
import 'package:cw_monero/account.dart';
import 'package:cw_core/account.dart';
import 'package:cw_monero/api/account_list.dart' as account_list;
part 'monero_account_list.g.dart';
@ -44,7 +44,9 @@ abstract class MoneroAccountListBase with Store {
List<Account> getAll() => account_list
.getAllAccount()
.map((accountRow) => Account.fromRow(accountRow))
.map((accountRow) => Account(
id: accountRow.getId(),
label: accountRow.getLabel()))
.toList();
Future addAccount({String label}) async {

@ -2,7 +2,7 @@ import 'package:cw_monero/api/structs/subaddress_row.dart';
import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
import 'package:cw_monero/subaddress.dart';
import 'package:cw_core/subaddress.dart';
part 'monero_subaddress_list.g.dart';
@ -49,7 +49,13 @@ abstract class MoneroSubaddressListBase with Store {
}
return subaddresses
.map((subaddressRow) => Subaddress.fromRow(subaddressRow))
.map((subaddressRow) => Subaddress(
id: subaddressRow.getId(),
address: subaddressRow.getAddress(),
label: subaddressRow.getId() == 0 &&
subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase()
? 'Primary address'
: subaddressRow.getLabel()))
.toList();
}

@ -1,6 +1,4 @@
//import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
import 'package:cw_monero/monero_transaction_priority.dart';
//import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/output_info.dart';
class MoneroTransactionCreationCredentials {

@ -1,5 +1,5 @@
import 'package:cw_core/transaction_info.dart';
import 'package:cw_monero/monero_amount_format.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_monero/api/structs/transaction_info_row.dart';
import 'package:cw_core/parseBoolFromString.dart';
import 'package:cw_core/transaction_direction.dart';

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save