Compare commits
10 Commits
b95af3a649
...
fd50aa9db5
Author | SHA1 | Date |
---|---|---|
dsc | fd50aa9db5 | 5 months ago |
Omar Hatem | d756b367d3 | 6 months ago |
Matthew Fosse | 2ff81df9e7 | 6 months ago |
Serhii | 049e4def27 | 6 months ago |
Serhii | faf151a4dc | 6 months ago |
Adegoke David | ef7762eaca | 6 months ago |
Matthew Fosse | 7ce387c130 | 6 months ago |
Konstantin Ullrich | 72777fbf2c | 6 months ago |
Serhii | 2138c35e38 | 6 months ago |
Matthew Fosse | d370c754c5 | 6 months ago |
@ -0,0 +1,11 @@
|
|||||||
|
package com.cakewallet.wownero;
|
||||||
|
|
||||||
|
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.wownero;
|
||||||
|
|
||||||
|
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(""));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 49 KiB |
@ -1,6 +1,6 @@
|
|||||||
|
-
|
||||||
|
uri: polygon-rpc.com
|
||||||
-
|
-
|
||||||
uri: polygon-bor.publicnode.com
|
uri: polygon-bor.publicnode.com
|
||||||
-
|
-
|
||||||
uri: polygon-rpc.com
|
|
||||||
-
|
|
||||||
uri: polygon.llamarpc.com
|
uri: polygon.llamarpc.com
|
@ -0,0 +1,16 @@
|
|||||||
|
-
|
||||||
|
uri: nyc.muchwow.lol:34568
|
||||||
|
is_default: true
|
||||||
|
useSSL: false
|
||||||
|
-
|
||||||
|
uri: amsterdam.muchwow.lol:34568
|
||||||
|
is_default: false
|
||||||
|
useSSL: false
|
||||||
|
-
|
||||||
|
uri: singapore.muchwow.lol:34568
|
||||||
|
is_default: false
|
||||||
|
useSSL: false
|
||||||
|
-
|
||||||
|
uri: suchwow.xyz:34568
|
||||||
|
is_default: false
|
||||||
|
useSSL: false
|
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:cw_core/crypto_amount_format.dart';
|
||||||
|
|
||||||
|
const wowneroAmountLength = 12;
|
||||||
|
const wowneroAmountDivider = 100000000000;
|
||||||
|
final wowneroAmountFormat = NumberFormat()
|
||||||
|
..maximumFractionDigits = wowneroAmountLength
|
||||||
|
..minimumFractionDigits = 1;
|
||||||
|
|
||||||
|
String wowneroAmountToString({required int amount}) => wowneroAmountFormat
|
||||||
|
.format(cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider))
|
||||||
|
.replaceAll(',', '');
|
||||||
|
|
||||||
|
double wowneroAmountToDouble({required int amount}) =>
|
||||||
|
cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider);
|
||||||
|
|
||||||
|
int wowneroParseAmount({required String amount}) =>
|
||||||
|
(double.parse(amount) * wowneroAmountDivider).round();
|
@ -0,0 +1,38 @@
|
|||||||
|
import 'package:cw_core/balance.dart';
|
||||||
|
import 'package:cw_core/wownero_amount_format.dart';
|
||||||
|
|
||||||
|
class WowneroBalance extends Balance {
|
||||||
|
WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||||
|
: formattedFullBalance = wowneroAmountToString(amount: fullBalance),
|
||||||
|
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
|
||||||
|
formattedLockedBalance =
|
||||||
|
wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
|
||||||
|
super(unlockedBalance, fullBalance);
|
||||||
|
|
||||||
|
WowneroBalance.fromString(
|
||||||
|
{required this.formattedFullBalance,
|
||||||
|
required this.formattedUnlockedBalance,
|
||||||
|
this.formattedLockedBalance = '0.0'})
|
||||||
|
: fullBalance = wowneroParseAmount(amount: formattedFullBalance),
|
||||||
|
unlockedBalance = wowneroParseAmount(amount: formattedUnlockedBalance),
|
||||||
|
frozenBalance = wowneroParseAmount(amount: formattedLockedBalance),
|
||||||
|
super(wowneroParseAmount(amount: formattedUnlockedBalance),
|
||||||
|
wowneroParseAmount(amount: formattedFullBalance));
|
||||||
|
|
||||||
|
final int fullBalance;
|
||||||
|
final int unlockedBalance;
|
||||||
|
final int frozenBalance;
|
||||||
|
final String formattedFullBalance;
|
||||||
|
final String formattedUnlockedBalance;
|
||||||
|
final String formattedLockedBalance;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedUnAvailableBalance =>
|
||||||
|
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedAdditionalBalance => formattedFullBalance;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
class WowneroWalletKeys {
|
||||||
|
const WowneroWalletKeys(
|
||||||
|
{required this.privateSpendKey,
|
||||||
|
required this.privateViewKey,
|
||||||
|
required this.publicSpendKey,
|
||||||
|
required this.publicViewKey});
|
||||||
|
|
||||||
|
final String publicViewKey;
|
||||||
|
final String privateViewKey;
|
||||||
|
final String publicSpendKey;
|
||||||
|
final String privateSpendKey;
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
String backupFileName(String originalPath) {
|
||||||
|
final pathParts = originalPath.split('/');
|
||||||
|
final newName = '#_${pathParts.last}';
|
||||||
|
pathParts.removeLast();
|
||||||
|
pathParts.add(newName);
|
||||||
|
return pathParts.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> backupWalletFiles(String name) async {
|
||||||
|
final path = await pathForWallet(name: name, type: WalletType.wownero);
|
||||||
|
final cacheFile = File(path);
|
||||||
|
final keysFile = File('$path.keys');
|
||||||
|
final addressListFile = File('$path.address.txt');
|
||||||
|
final newCacheFilePath = backupFileName(cacheFile.path);
|
||||||
|
final newKeysFilePath = backupFileName(keysFile.path);
|
||||||
|
final newAddressListFilePath = backupFileName(addressListFile.path);
|
||||||
|
|
||||||
|
if (cacheFile.existsSync()) {
|
||||||
|
await cacheFile.copy(newCacheFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keysFile.existsSync()) {
|
||||||
|
await keysFile.copy(newKeysFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addressListFile.existsSync()) {
|
||||||
|
await addressListFile.copy(newAddressListFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> restoreWalletFiles(String name) async {
|
||||||
|
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.wownero);
|
||||||
|
final cacheFilePath = '$walletDirPath/$name';
|
||||||
|
final keysFilePath = '$walletDirPath/$name.keys';
|
||||||
|
final addressListFilePath = '$walletDirPath/$name.address.txt';
|
||||||
|
final backupCacheFile = File(backupFileName(cacheFilePath));
|
||||||
|
final backupKeysFile = File(backupFileName(keysFilePath));
|
||||||
|
final backupAddressListFile = File(backupFileName(addressListFilePath));
|
||||||
|
|
||||||
|
if (backupCacheFile.existsSync()) {
|
||||||
|
await backupCacheFile.copy(cacheFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupKeysFile.existsSync()) {
|
||||||
|
await backupKeysFile.copy(keysFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupAddressListFile.existsSync()) {
|
||||||
|
await backupAddressListFile.copy(addressListFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> backupWalletFilesExists(String name) async {
|
||||||
|
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.wownero);
|
||||||
|
final cacheFilePath = '$walletDirPath/$name';
|
||||||
|
final keysFilePath = '$walletDirPath/$name.keys';
|
||||||
|
final addressListFilePath = '$walletDirPath/$name.address.txt';
|
||||||
|
final backupCacheFile = File(backupFileName(cacheFilePath));
|
||||||
|
final backupKeysFile = File(backupFileName(keysFilePath));
|
||||||
|
final backupAddressListFile = File(backupFileName(addressListFilePath));
|
||||||
|
|
||||||
|
return backupCacheFile.existsSync()
|
||||||
|
&& backupKeysFile.existsSync()
|
||||||
|
&& backupAddressListFile.existsSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeCache(String name) async {
|
||||||
|
final path = await pathForWallet(name: name, type: WalletType.wownero);
|
||||||
|
final cacheFile = File(path);
|
||||||
|
|
||||||
|
if (cacheFile.existsSync()) {
|
||||||
|
cacheFile.deleteSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> restoreOrResetWalletFiles(String name) async {
|
||||||
|
final backupsExists = await backupWalletFilesExists(name);
|
||||||
|
|
||||||
|
if (backupsExists) {
|
||||||
|
await restoreWalletFiles(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCache(name);
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
.DS_Store
|
||||||
|
.dart_tool/
|
||||||
|
|
||||||
|
.packages
|
||||||
|
.pub/
|
||||||
|
|
||||||
|
build/
|
||||||
|
|
||||||
|
ios/External/
|
||||||
|
android/.externalNativeBuild/
|
||||||
|
android/.cxx/
|
@ -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: 398e4272a2e43d7daab75f225a13422e384ee0cd
|
||||||
|
channel: dev
|
||||||
|
|
||||||
|
project_type: plugin
|
@ -0,0 +1,3 @@
|
|||||||
|
## 0.0.1
|
||||||
|
|
||||||
|
* TODO: wow.
|
@ -0,0 +1 @@
|
|||||||
|
TODO: Add your license here.
|
@ -0,0 +1,5 @@
|
|||||||
|
# cw_wownero
|
||||||
|
|
||||||
|
This project is part of Cake Wallet app.
|
||||||
|
|
||||||
|
Copyright (c) 2022 Cake Technologies LLC.
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||||
|
<classpathentry kind="output" path="bin/default"/>
|
||||||
|
</classpath>
|
@ -0,0 +1,8 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>cw_wownero</name>
|
||||||
|
<comment>Project android created by Buildship.</comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
@ -0,0 +1,13 @@
|
|||||||
|
arguments=
|
||||||
|
auto.sync=false
|
||||||
|
build.scans.enabled=false
|
||||||
|
connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.0-20191016123526+0000))
|
||||||
|
connection.project.dir=../../android
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
gradle.user.home=
|
||||||
|
java.home=
|
||||||
|
jvm.arguments=
|
||||||
|
offline.mode=false
|
||||||
|
override.workspace.settings=true
|
||||||
|
show.console.view=true
|
||||||
|
show.executions.view=true
|
@ -0,0 +1,232 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.4.1)
|
||||||
|
|
||||||
|
add_library( cw_wownero
|
||||||
|
SHARED
|
||||||
|
./jni/wownero_jni.cpp
|
||||||
|
../ios/Classes/wownero_api.cpp)
|
||||||
|
|
||||||
|
find_library( log-lib log )
|
||||||
|
|
||||||
|
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../../cw_shared_external/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)
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Wownero
|
||||||
|
#############
|
||||||
|
|
||||||
|
add_library(wallet_api STATIC IMPORTED)
|
||||||
|
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libwallet_api.a)
|
||||||
|
|
||||||
|
add_library(wallet STATIC IMPORTED)
|
||||||
|
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libwallet.a)
|
||||||
|
|
||||||
|
add_library(cryptonote_core STATIC IMPORTED)
|
||||||
|
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcryptonote_core.a)
|
||||||
|
|
||||||
|
add_library(cryptonote_basic STATIC IMPORTED)
|
||||||
|
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcryptonote_basic.a)
|
||||||
|
|
||||||
|
add_library(cryptonote_format_utils_basic STATIC IMPORTED)
|
||||||
|
set_target_properties(cryptonote_format_utils_basic PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcryptonote_format_utils_basic.a)
|
||||||
|
|
||||||
|
add_library(mnemonics STATIC IMPORTED)
|
||||||
|
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libmnemonics.a)
|
||||||
|
|
||||||
|
add_library(common STATIC IMPORTED)
|
||||||
|
set_target_properties(common PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcommon.a)
|
||||||
|
|
||||||
|
add_library(cncrypto STATIC IMPORTED)
|
||||||
|
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcncrypto.a)
|
||||||
|
|
||||||
|
add_library(ringct STATIC IMPORTED)
|
||||||
|
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libringct.a)
|
||||||
|
|
||||||
|
add_library(ringct_basic STATIC IMPORTED)
|
||||||
|
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libringct_basic.a)
|
||||||
|
|
||||||
|
add_library(blockchain_db STATIC IMPORTED)
|
||||||
|
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libblockchain_db.a)
|
||||||
|
|
||||||
|
add_library(lmdb STATIC IMPORTED)
|
||||||
|
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/liblmdb.a)
|
||||||
|
|
||||||
|
add_library(easylogging STATIC IMPORTED)
|
||||||
|
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libeasylogging.a)
|
||||||
|
|
||||||
|
add_library(unbound STATIC IMPORTED)
|
||||||
|
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libunbound.a)
|
||||||
|
|
||||||
|
add_library(epee STATIC IMPORTED)
|
||||||
|
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libepee.a)
|
||||||
|
|
||||||
|
add_library(blocks STATIC IMPORTED)
|
||||||
|
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libblocks.a)
|
||||||
|
|
||||||
|
add_library(checkpoints STATIC IMPORTED)
|
||||||
|
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcheckpoints.a)
|
||||||
|
|
||||||
|
add_library(device STATIC IMPORTED)
|
||||||
|
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libdevice.a)
|
||||||
|
|
||||||
|
add_library(device_trezor STATIC IMPORTED)
|
||||||
|
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libdevice_trezor.a)
|
||||||
|
|
||||||
|
add_library(multisig STATIC IMPORTED)
|
||||||
|
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libmultisig.a)
|
||||||
|
|
||||||
|
add_library(version STATIC IMPORTED)
|
||||||
|
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libversion.a)
|
||||||
|
|
||||||
|
add_library(net STATIC IMPORTED)
|
||||||
|
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libnet.a)
|
||||||
|
|
||||||
|
add_library(hardforks STATIC IMPORTED)
|
||||||
|
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libhardforks.a)
|
||||||
|
|
||||||
|
add_library(randomx STATIC IMPORTED)
|
||||||
|
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/librandomx.a)
|
||||||
|
|
||||||
|
add_library(rpc_base STATIC IMPORTED)
|
||||||
|
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/librpc_base.a)
|
||||||
|
|
||||||
|
add_library(wallet-crypto STATIC IMPORTED)
|
||||||
|
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libwallet-crypto.a)
|
||||||
|
|
||||||
|
set(WALLET_CRYPTO "")
|
||||||
|
|
||||||
|
if(${ANDROID_ABI} STREQUAL "x86_64")
|
||||||
|
set(WALLET_CRYPTO "wallet-crypto")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories( ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/include )
|
||||||
|
|
||||||
|
target_link_libraries( cw_wownero
|
||||||
|
|
||||||
|
wallet_api
|
||||||
|
wallet
|
||||||
|
cryptonote_core
|
||||||
|
cryptonote_basic
|
||||||
|
cryptonote_format_utils_basic
|
||||||
|
mnemonics
|
||||||
|
ringct
|
||||||
|
ringct_basic
|
||||||
|
net
|
||||||
|
common
|
||||||
|
cncrypto
|
||||||
|
blockchain_db
|
||||||
|
lmdb
|
||||||
|
easylogging
|
||||||
|
unbound
|
||||||
|
epee
|
||||||
|
blocks
|
||||||
|
checkpoints
|
||||||
|
device
|
||||||
|
device_trezor
|
||||||
|
multisig
|
||||||
|
version
|
||||||
|
randomx
|
||||||
|
hardforks
|
||||||
|
rpc_base
|
||||||
|
${WALLET_CRYPTO}
|
||||||
|
|
||||||
|
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,49 @@
|
|||||||
|
group 'com.cakewallet.wownero'
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.7.10'
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:7.3.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
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
}
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path "CMakeLists.txt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
android.enableR8=true
|
||||||
|
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-4.10.2-all.zip
|
@ -0,0 +1,74 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <jni.h>
|
||||||
|
#include "../../ios/Classes/wownero_api.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_cakewallet_wownero_WowneroApi_setNodeAddressJNI(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject inst,
|
||||||
|
jstring uri,
|
||||||
|
jstring login,
|
||||||
|
jstring password,
|
||||||
|
jboolean use_ssl,
|
||||||
|
jboolean is_light_wallet) {
|
||||||
|
const char *_uri = env->GetStringUTFChars(uri, 0);
|
||||||
|
const char *_login = "";
|
||||||
|
const char *_password = "";
|
||||||
|
char *error;
|
||||||
|
|
||||||
|
if (login != NULL) {
|
||||||
|
_login = env->GetStringUTFChars(login, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password != NULL) {
|
||||||
|
_password = env->GetStringUTFChars(password, 0);
|
||||||
|
}
|
||||||
|
char *__uri = (char*) _uri;
|
||||||
|
char *__login = (char*) _login;
|
||||||
|
char *__password = (char*) _password;
|
||||||
|
bool inited = setup_node(__uri, __login, __password, false, false, error);
|
||||||
|
|
||||||
|
if (!inited) {
|
||||||
|
env->ThrowNew(env->FindClass("java/lang/Exception"), error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_cakewallet_wownero_WowneroApi_connectToNodeJNI(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject inst) {
|
||||||
|
char *error;
|
||||||
|
bool is_connected = connect_to_node(error);
|
||||||
|
|
||||||
|
if (!is_connected) {
|
||||||
|
env->ThrowNew(env->FindClass("java/lang/Exception"), error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_cakewallet_wownero_WowneroApi_startSyncJNI(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject inst) {
|
||||||
|
start_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_cakewallet_wownero_WowneroApi_loadWalletJNI(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject inst,
|
||||||
|
jstring path,
|
||||||
|
jstring password) {
|
||||||
|
char *_path = (char *) env->GetStringUTFChars(path, 0);
|
||||||
|
char *_password = (char *) env->GetStringUTFChars(password, 0);
|
||||||
|
|
||||||
|
load_wallet(_path, _password, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'cw_wownero'
|
@ -0,0 +1,4 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.cakewallet.wownero">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.cakewallet.cw_wownero
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.AsyncTask
|
||||||
|
import android.os.Looper
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Process
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
class doAsync(val handler: () -> Unit) : AsyncTask<Void, Void, Void>() {
|
||||||
|
override fun doInBackground(vararg params: Void?): Void? {
|
||||||
|
Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
|
||||||
|
handler()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CwWowneroPlugin: MethodCallHandler {
|
||||||
|
companion object {
|
||||||
|
// val wowneroApi = WowneroApi()
|
||||||
|
val main = Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
init {
|
||||||
|
System.loadLibrary("cw_wownero")
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun registerWith(registrar: Registrar) {
|
||||||
|
val channel = MethodChannel(registrar.messenger(), "cw_wownero")
|
||||||
|
channel.setMethodCallHandler(CwWowneroPlugin())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMethodCall(call: MethodCall, result: Result) {
|
||||||
|
if (call.method == "setupNode") {
|
||||||
|
val uri = call.argument("address") ?: ""
|
||||||
|
val login = call.argument("login") ?: ""
|
||||||
|
val password = call.argument("password") ?: ""
|
||||||
|
val useSSL = false
|
||||||
|
val isLightWallet = false
|
||||||
|
// doAsync {
|
||||||
|
// try {
|
||||||
|
// wowneroApi.setNodeAddressJNI(uri, login, password, useSSL, isLightWallet)
|
||||||
|
// main.post({
|
||||||
|
// result.success(true)
|
||||||
|
// });
|
||||||
|
// } catch(e: Throwable) {
|
||||||
|
// main.post({
|
||||||
|
// result.error("CONNECTION_ERROR", e.message, null)
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }.execute()
|
||||||
|
}
|
||||||
|
if (call.method == "startSync") {
|
||||||
|
// doAsync {
|
||||||
|
// wowneroApi.startSyncJNI()
|
||||||
|
// main.post({
|
||||||
|
// result.success(true)
|
||||||
|
// });
|
||||||
|
// }.execute()
|
||||||
|
}
|
||||||
|
if (call.method == "loadWallet") {
|
||||||
|
val path = call.argument("path") ?: ""
|
||||||
|
val password = call.argument("password") ?: ""
|
||||||
|
// wowneroApi.loadWalletJNI(path, password)
|
||||||
|
result.success(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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,23 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct CWWowneroWalletListener;
|
||||||
|
|
||||||
|
typedef int8_t (*on_new_block_callback)(uint64_t height);
|
||||||
|
typedef int8_t (*on_need_to_refresh_callback)();
|
||||||
|
|
||||||
|
typedef struct CWWowneroWalletListener
|
||||||
|
{
|
||||||
|
// on_money_spent_callback *on_money_spent;
|
||||||
|
// on_money_received_callback *on_money_received;
|
||||||
|
// on_unconfirmed_money_received_callback *on_unconfirmed_money_received;
|
||||||
|
// on_new_block_callback *on_new_block;
|
||||||
|
// on_updated_callback *on_updated;
|
||||||
|
// on_refreshed_callback *on_refreshed;
|
||||||
|
|
||||||
|
on_new_block_callback on_new_block;
|
||||||
|
} CWWowneroWalletListener;
|
||||||
|
|
||||||
|
struct TestListener {
|
||||||
|
// int8_t x;
|
||||||
|
on_new_block_callback on_new_block;
|
||||||
|
};
|
@ -0,0 +1,4 @@
|
|||||||
|
#import <Flutter/Flutter.h>
|
||||||
|
|
||||||
|
@interface CwWowneroPlugin : NSObject<FlutterPlugin>
|
||||||
|
@end
|
@ -0,0 +1,8 @@
|
|||||||
|
#import "CwWowneroPlugin.h"
|
||||||
|
#import <cw_wownero/cw_wownero-Swift.h>
|
||||||
|
|
||||||
|
@implementation CwWowneroPlugin
|
||||||
|
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||||
|
[SwiftCwWowneroPlugin registerWithRegistrar:registrar];
|
||||||
|
}
|
||||||
|
@end
|
@ -0,0 +1,14 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public class SwiftCwWowneroPlugin: NSObject, FlutterPlugin {
|
||||||
|
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||||
|
let channel = FlutterMethodChannel(name: "cw_wownero", binaryMessenger: registrar.messenger())
|
||||||
|
let instance = SwiftCwWowneroPlugin()
|
||||||
|
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||||
|
result("iOS " + UIDevice.current.systemVersion)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,39 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "CwWalletListener.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error);
|
||||||
|
bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error);
|
||||||
|
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);
|
||||||
|
void load_wallet(char *path, char *password, int32_t nettype);
|
||||||
|
bool is_wallet_exist(char *path);
|
||||||
|
|
||||||
|
char *get_filename();
|
||||||
|
const char *seed();
|
||||||
|
char *get_address(uint32_t account_index, uint32_t address_index);
|
||||||
|
uint64_t get_full_balance(uint32_t account_index);
|
||||||
|
uint64_t get_unlocked_balance(uint32_t account_index);
|
||||||
|
uint64_t get_current_height();
|
||||||
|
uint64_t get_node_height();
|
||||||
|
|
||||||
|
bool is_connected();
|
||||||
|
|
||||||
|
bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error);
|
||||||
|
bool connect_to_node(char *error);
|
||||||
|
void start_refresh();
|
||||||
|
void set_refresh_from_block_height(uint64_t height);
|
||||||
|
void set_recovering_from_seed(bool is_recovery);
|
||||||
|
void store(char *path);
|
||||||
|
|
||||||
|
void set_trusted_daemon(bool arg);
|
||||||
|
bool trusted_daemon();
|
||||||
|
char *sign_message(char *message, char *address);
|
||||||
|
|
||||||
|
#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_wownero.podspec' to validate before publishing.
|
||||||
|
#
|
||||||
|
Pod::Spec.new do |s|
|
||||||
|
s.name = 'cw_wownero'
|
||||||
|
s.version = '0.0.2'
|
||||||
|
s.summary = 'Cake Wallet Wownero'
|
||||||
|
s.description = 'Cake Wallet wrapper over Wownero project'
|
||||||
|
s.homepage = 'http://cakewallet.com'
|
||||||
|
s.license = { :file => '../LICENSE' }
|
||||||
|
s.author = { 'CakeWallet' => '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.swift_version = '5.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 = '../../../../../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 'Wownero' do |wownero|
|
||||||
|
wownero.preserve_paths = 'External/ios/include/**/*.h'
|
||||||
|
wownero.vendored_libraries = 'External/ios/lib/libwownero.a'
|
||||||
|
wownero.libraries = 'wownero'
|
||||||
|
wownero.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_wownero/api/signatures.dart';
|
||||||
|
import 'package:cw_wownero/api/types.dart';
|
||||||
|
import 'package:cw_wownero/api/wownero_api.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/account_row.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:cw_wownero/api/wallet.dart';
|
||||||
|
|
||||||
|
final accountSizeNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<account_size>>('account_size')
|
||||||
|
.asFunction<SubaddressSize>();
|
||||||
|
|
||||||
|
final accountRefreshNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<account_refresh>>('account_refresh')
|
||||||
|
.asFunction<AccountRefresh>();
|
||||||
|
|
||||||
|
final accountGetAllNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<account_get_all>>('account_get_all')
|
||||||
|
.asFunction<AccountGetAll>();
|
||||||
|
|
||||||
|
final accountAddNewNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<account_add_new>>('account_add_row')
|
||||||
|
.asFunction<AccountAddNew>();
|
||||||
|
|
||||||
|
final accountSetLabelNative = wowneroApi
|
||||||
|
.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({required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
accountAddNewNative(labelPointer);
|
||||||
|
calloc.free(labelPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabelForAccountSync({required int accountIndex, required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
accountSetLabelNative(accountIndex, labelPointer);
|
||||||
|
calloc.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({required String label}) async {
|
||||||
|
await compute(_addAccount, label);
|
||||||
|
await store();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
|
||||||
|
await compute(
|
||||||
|
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
|
||||||
|
await store();
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_wownero/api/signatures.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/coins_info_row.dart';
|
||||||
|
import 'package:cw_wownero/api/types.dart';
|
||||||
|
import 'package:cw_wownero/api/wownero_api.dart';
|
||||||
|
|
||||||
|
final refreshCoinsNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<refresh_coins>>('refresh_coins')
|
||||||
|
.asFunction<RefreshCoins>();
|
||||||
|
|
||||||
|
final coinsCountNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<coins_count>>('coins_count')
|
||||||
|
.asFunction<CoinsCount>();
|
||||||
|
|
||||||
|
final coinNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<coin>>('coin')
|
||||||
|
.asFunction<GetCoin>();
|
||||||
|
|
||||||
|
final freezeCoinNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<freeze_coin>>('freeze_coin')
|
||||||
|
.asFunction<FreezeCoin>();
|
||||||
|
|
||||||
|
final thawCoinNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<thaw_coin>>('thaw_coin')
|
||||||
|
.asFunction<ThawCoin>();
|
||||||
|
|
||||||
|
void refreshCoins(int accountIndex) => refreshCoinsNative(accountIndex);
|
||||||
|
|
||||||
|
int countOfCoins() => coinsCountNative();
|
||||||
|
|
||||||
|
CoinsInfoRow getCoin(int index) => coinNative(index).ref;
|
||||||
|
|
||||||
|
void freezeCoin(int index) => freezeCoinNative(index);
|
||||||
|
|
||||||
|
void thawCoin(int index) => thawCoinNative(index);
|
@ -0,0 +1,8 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
String convertUTF8ToString({required Pointer<Utf8> pointer}) {
|
||||||
|
final str = pointer.toDartString();
|
||||||
|
calloc.free(pointer);
|
||||||
|
return str;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
class ConnectionToNodeException implements Exception {
|
||||||
|
ConnectionToNodeException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
class CreationTransactionException implements Exception {
|
||||||
|
CreationTransactionException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
class SetupWalletException implements Exception {
|
||||||
|
SetupWalletException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
class WalletCreationException implements Exception {
|
||||||
|
WalletCreationException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
class WalletOpeningException implements Exception {
|
||||||
|
WalletOpeningException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
class WalletRestoreFromKeysException implements Exception {
|
||||||
|
WalletRestoreFromKeysException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
class WalletRestoreFromSeedException implements Exception {
|
||||||
|
WalletRestoreFromSeedException({required this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_wownero/api/structs/coins_info_row.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/pending_transaction.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/transaction_info_row.dart';
|
||||||
|
import 'package:cw_wownero/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 restore_wallet_from_spend_key = Int8 Function(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_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>?, 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_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||||
|
|
||||||
|
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_transaction = Pointer<TransactionInfoRow> Function(Pointer<Utf8> txId);
|
||||||
|
|
||||||
|
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> paymentId,
|
||||||
|
Pointer<Utf8> amount,
|
||||||
|
Int8 priorityRaw,
|
||||||
|
Int32 subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
Int32 preferredInputsSize,
|
||||||
|
Pointer<Utf8Box> error,
|
||||||
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
typedef transaction_create_mult_dest = Int8 Function(
|
||||||
|
Pointer<Pointer<Utf8>> addresses,
|
||||||
|
Pointer<Utf8> paymentId,
|
||||||
|
Pointer<Pointer<Utf8>> amounts,
|
||||||
|
Int32 size,
|
||||||
|
Int8 priorityRaw,
|
||||||
|
Int32 subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
Int32 preferredInputsSize,
|
||||||
|
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 get_subaddress_label = Pointer<Utf8> Function(Int32 accountIndex, Int32 addressIndex);
|
||||||
|
|
||||||
|
typedef set_trusted_daemon = Void Function(Int8 trusted);
|
||||||
|
|
||||||
|
typedef trusted_daemon = Int8 Function();
|
||||||
|
|
||||||
|
typedef refresh_coins = Void Function(Int32 accountIndex);
|
||||||
|
|
||||||
|
typedef coins_count = Int64 Function();
|
||||||
|
|
||||||
|
// typedef coins_from_txid = Pointer<CoinsInfoRow> Function(Pointer<Utf8> txid);
|
||||||
|
|
||||||
|
typedef coin = Pointer<CoinsInfoRow> Function(Int32 index);
|
||||||
|
|
||||||
|
typedef freeze_coin = Void Function(Int32 index);
|
||||||
|
|
||||||
|
typedef thaw_coin = Void Function(Int32 index);
|
||||||
|
|
||||||
|
typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);
|
@ -0,0 +1,11 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class AccountRow extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int id;
|
||||||
|
external Pointer<Utf8> label;
|
||||||
|
|
||||||
|
String getLabel() => label.toDartString();
|
||||||
|
int getId() => id;
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class CoinsInfoRow extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int blockHeight;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hash;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int internalOutputIndex;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int globalOutputIndex;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int spent;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int frozen;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int spentHeight;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int amount;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int rct;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int keyImageKnown;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int pkIndex;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrIndex;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrAccount;
|
||||||
|
|
||||||
|
external Pointer<Utf8> address;
|
||||||
|
|
||||||
|
external Pointer<Utf8> addressLabel;
|
||||||
|
|
||||||
|
external Pointer<Utf8> keyImage;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int unlockTime;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int unlocked;
|
||||||
|
|
||||||
|
external Pointer<Utf8> pubKey;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int coinbase;
|
||||||
|
|
||||||
|
external Pointer<Utf8> description;
|
||||||
|
|
||||||
|
String getHash() => hash.toDartString();
|
||||||
|
|
||||||
|
String getAddress() => address.toDartString();
|
||||||
|
|
||||||
|
String getAddressLabel() => addressLabel.toDartString();
|
||||||
|
|
||||||
|
String getKeyImage() => keyImage.toDartString();
|
||||||
|
|
||||||
|
String getPubKey() => pubKey.toDartString();
|
||||||
|
|
||||||
|
String getDescription() => description.toDartString();
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class PendingTransactionRaw extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int amount;
|
||||||
|
|
||||||
|
@Int64()
|
||||||
|
external int fee;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hash;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hex;
|
||||||
|
|
||||||
|
external Pointer<Utf8> txKey;
|
||||||
|
|
||||||
|
String getHash() => hash.toDartString();
|
||||||
|
|
||||||
|
String getHex() => hex.toDartString();
|
||||||
|
|
||||||
|
String getKey() => txKey.toDartString();
|
||||||
|
}
|
||||||
|
|
||||||
|
class PendingTransactionDescription {
|
||||||
|
PendingTransactionDescription({
|
||||||
|
required this.amount,
|
||||||
|
required this.fee,
|
||||||
|
required this.hash,
|
||||||
|
required this.hex,
|
||||||
|
required this.txKey,
|
||||||
|
required this.pointerAddress});
|
||||||
|
|
||||||
|
final int amount;
|
||||||
|
final int fee;
|
||||||
|
final String hash;
|
||||||
|
final String hex;
|
||||||
|
final String txKey;
|
||||||
|
final int pointerAddress;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class SubaddressRow extends Struct {
|
||||||
|
@Int64()
|
||||||
|
external int id;
|
||||||
|
external Pointer<Utf8> address;
|
||||||
|
external Pointer<Utf8> label;
|
||||||
|
|
||||||
|
String getLabel() => label.toDartString();
|
||||||
|
String getAddress() => address.toDartString();
|
||||||
|
int getId() => id;
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class TransactionInfoRow extends Struct {
|
||||||
|
@Uint64()
|
||||||
|
external int amount;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int fee;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int blockHeight;
|
||||||
|
|
||||||
|
@Uint64()
|
||||||
|
external int confirmations;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrAccount;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int direction;
|
||||||
|
|
||||||
|
@Int8()
|
||||||
|
external int isPending;
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int subaddrIndex;
|
||||||
|
|
||||||
|
external Pointer<Utf8> hash;
|
||||||
|
|
||||||
|
external Pointer<Utf8> paymentId;
|
||||||
|
|
||||||
|
@Int64()
|
||||||
|
external int datetime;
|
||||||
|
|
||||||
|
int getDatetime() => datetime;
|
||||||
|
int getAmount() => amount >= 0 ? amount : amount * -1;
|
||||||
|
bool getIsPending() => isPending != 0;
|
||||||
|
String getHash() => hash.toDartString();
|
||||||
|
String getPaymentId() => paymentId.toDartString();
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
class Utf8Box extends Struct {
|
||||||
|
external Pointer<Utf8> value;
|
||||||
|
|
||||||
|
String getValue() => value.toDartString();
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:cw_wownero/api/signatures.dart';
|
||||||
|
import 'package:cw_wownero/api/types.dart';
|
||||||
|
import 'package:cw_wownero/api/wownero_api.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/subaddress_row.dart';
|
||||||
|
import 'package:cw_wownero/api/wallet.dart';
|
||||||
|
|
||||||
|
final subaddressSizeNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<subaddrress_size>>('subaddrress_size')
|
||||||
|
.asFunction<SubaddressSize>();
|
||||||
|
|
||||||
|
final subaddressRefreshNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<subaddrress_refresh>>('subaddress_refresh')
|
||||||
|
.asFunction<SubaddressRefresh>();
|
||||||
|
|
||||||
|
final subaddrressGetAllNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<subaddress_get_all>>('subaddrress_get_all')
|
||||||
|
.asFunction<SubaddressGetAll>();
|
||||||
|
|
||||||
|
final subaddrressAddNewNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<subaddress_add_new>>('subaddress_add_row')
|
||||||
|
.asFunction<SubaddressAddNew>();
|
||||||
|
|
||||||
|
final subaddrressSetLabelNative = wowneroApi
|
||||||
|
.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({required int accountIndex, required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
subaddrressAddNewNative(accountIndex, labelPointer);
|
||||||
|
calloc.free(labelPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabelForSubaddressSync(
|
||||||
|
{required int accountIndex, required int addressIndex, required String label}) {
|
||||||
|
final labelPointer = label.toNativeUtf8();
|
||||||
|
subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
|
||||||
|
calloc.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({required int accountIndex, required String label}) async {
|
||||||
|
await compute<Map<String, Object>, void>(
|
||||||
|
_addSubaddress, {'accountIndex': accountIndex, 'label': label});
|
||||||
|
await store();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future setLabelForSubaddress(
|
||||||
|
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||||
|
await compute<Map<String, Object>, void>(_setLabelForSubaddress, {
|
||||||
|
'accountIndex': accountIndex,
|
||||||
|
'addressIndex': addressIndex,
|
||||||
|
'label': label
|
||||||
|
});
|
||||||
|
await store();
|
||||||
|
}
|
@ -0,0 +1,281 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:cw_wownero/api/convert_utf8_to_string.dart';
|
||||||
|
import 'package:cw_wownero/api/exceptions/creation_transaction_exception.dart';
|
||||||
|
import 'package:cw_wownero/api/wownero_api.dart';
|
||||||
|
import 'package:cw_wownero/api/wownero_output.dart';
|
||||||
|
import 'package:cw_wownero/api/signatures.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/pending_transaction.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/transaction_info_row.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/ut8_box.dart';
|
||||||
|
import 'package:cw_wownero/api/types.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
final transactionsRefreshNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<transactions_refresh>>('transactions_refresh')
|
||||||
|
.asFunction<TransactionsRefresh>();
|
||||||
|
|
||||||
|
final transactionsCountNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<transactions_count>>('transactions_count')
|
||||||
|
.asFunction<TransactionsCount>();
|
||||||
|
|
||||||
|
final transactionsGetAllNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<transactions_get_all>>('transactions_get_all')
|
||||||
|
.asFunction<TransactionsGetAll>();
|
||||||
|
|
||||||
|
final transactionCreateNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<transaction_create>>('transaction_create')
|
||||||
|
.asFunction<TransactionCreate>();
|
||||||
|
|
||||||
|
final transactionCreateMultDestNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<transaction_create_mult_dest>>('transaction_create_mult_dest')
|
||||||
|
.asFunction<TransactionCreateMultDest>();
|
||||||
|
|
||||||
|
final transactionCommitNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
|
||||||
|
.asFunction<TransactionCommit>();
|
||||||
|
|
||||||
|
final getTxKeyNative =
|
||||||
|
wowneroApi.lookup<NativeFunction<get_tx_key>>('get_tx_key').asFunction<GetTxKey>();
|
||||||
|
|
||||||
|
final getTransactionNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_transaction>>('get_transaction')
|
||||||
|
.asFunction<GetTransaction>();
|
||||||
|
|
||||||
|
String getTxKey(String txId) {
|
||||||
|
final txIdPointer = txId.toNativeUtf8();
|
||||||
|
final keyPointer = getTxKeyNative(txIdPointer);
|
||||||
|
|
||||||
|
calloc.free(txIdPointer);
|
||||||
|
|
||||||
|
if (keyPointer != null) {
|
||||||
|
return convertUTF8ToString(pointer: keyPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshTransactions() => transactionsRefreshNative();
|
||||||
|
|
||||||
|
int countOfTransactions() => transactionsCountNative();
|
||||||
|
|
||||||
|
List<TransactionInfoRow> getAllTransactions() {
|
||||||
|
final size = transactionsCountNative();
|
||||||
|
final transactionsPointer = transactionsGetAllNative();
|
||||||
|
final transactionsAddresses = transactionsPointer.asTypedList(size);
|
||||||
|
|
||||||
|
return transactionsAddresses
|
||||||
|
.map((addr) => Pointer<TransactionInfoRow>.fromAddress(addr).ref)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionInfoRow getTransaction(String txId) {
|
||||||
|
final txIdPointer = txId.toNativeUtf8();
|
||||||
|
return getTransactionNative(txIdPointer).ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription createTransactionSync(
|
||||||
|
{required String address,
|
||||||
|
required String paymentId,
|
||||||
|
required int priorityRaw,
|
||||||
|
String? amount,
|
||||||
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) {
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||||
|
final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
|
||||||
|
|
||||||
|
final int preferredInputsSize = preferredInputs.length;
|
||||||
|
final List<Pointer<Utf8>> preferredInputsPointers =
|
||||||
|
preferredInputs.map((output) => output.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < preferredInputsSize; i++) {
|
||||||
|
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||||
|
final created = transactionCreateNative(
|
||||||
|
addressPointer,
|
||||||
|
paymentIdPointer,
|
||||||
|
amountPointer,
|
||||||
|
priorityRaw,
|
||||||
|
accountIndex,
|
||||||
|
preferredInputsPointerPointer,
|
||||||
|
preferredInputsSize,
|
||||||
|
errorMessagePointer,
|
||||||
|
pendingTransactionRawPointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(preferredInputsPointerPointer);
|
||||||
|
|
||||||
|
preferredInputsPointers.forEach((element) => calloc.free(element));
|
||||||
|
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
calloc.free(paymentIdPointer);
|
||||||
|
|
||||||
|
if (amountPointer != nullptr) {
|
||||||
|
calloc.free(amountPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!created) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw CreationTransactionException(message: message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PendingTransactionDescription(
|
||||||
|
amount: pendingTransactionRawPointer.ref.amount,
|
||||||
|
fee: pendingTransactionRawPointer.ref.fee,
|
||||||
|
hash: pendingTransactionRawPointer.ref.getHash(),
|
||||||
|
hex: pendingTransactionRawPointer.ref.getHex(),
|
||||||
|
txKey: pendingTransactionRawPointer.ref.getKey(),
|
||||||
|
pointerAddress: pendingTransactionRawPointer.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription createTransactionMultDestSync(
|
||||||
|
{required List<MoneroOutput> outputs,
|
||||||
|
required String paymentId,
|
||||||
|
required int priorityRaw,
|
||||||
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) {
|
||||||
|
final int size = outputs.length;
|
||||||
|
final List<Pointer<Utf8>> addressesPointers =
|
||||||
|
outputs.map((output) => output.address.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> addressesPointerPointer = calloc(size);
|
||||||
|
final List<Pointer<Utf8>> amountsPointers =
|
||||||
|
outputs.map((output) => output.amount.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> amountsPointerPointer = calloc(size);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
addressesPointerPointer[i] = addressesPointers[i];
|
||||||
|
amountsPointerPointer[i] = amountsPointers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
final int preferredInputsSize = preferredInputs.length;
|
||||||
|
final List<Pointer<Utf8>> preferredInputsPointers =
|
||||||
|
preferredInputs.map((output) => output.toNativeUtf8()).toList();
|
||||||
|
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < preferredInputsSize; i++) {
|
||||||
|
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||||
|
final created = transactionCreateMultDestNative(
|
||||||
|
addressesPointerPointer,
|
||||||
|
paymentIdPointer,
|
||||||
|
amountsPointerPointer,
|
||||||
|
size,
|
||||||
|
priorityRaw,
|
||||||
|
accountIndex,
|
||||||
|
preferredInputsPointerPointer,
|
||||||
|
preferredInputsSize,
|
||||||
|
errorMessagePointer,
|
||||||
|
pendingTransactionRawPointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(addressesPointerPointer);
|
||||||
|
calloc.free(amountsPointerPointer);
|
||||||
|
calloc.free(preferredInputsPointerPointer);
|
||||||
|
|
||||||
|
addressesPointers.forEach((element) => calloc.free(element));
|
||||||
|
amountsPointers.forEach((element) => calloc.free(element));
|
||||||
|
preferredInputsPointers.forEach((element) => calloc.free(element));
|
||||||
|
|
||||||
|
calloc.free(paymentIdPointer);
|
||||||
|
|
||||||
|
if (!created) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw CreationTransactionException(message: message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PendingTransactionDescription(
|
||||||
|
amount: pendingTransactionRawPointer.ref.amount,
|
||||||
|
fee: pendingTransactionRawPointer.ref.fee,
|
||||||
|
hash: pendingTransactionRawPointer.ref.getHash(),
|
||||||
|
hex: pendingTransactionRawPointer.ref.getHex(),
|
||||||
|
txKey: pendingTransactionRawPointer.ref.getKey(),
|
||||||
|
pointerAddress: pendingTransactionRawPointer.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void commitTransactionFromPointerAddress({required int address}) =>
|
||||||
|
commitTransaction(transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
||||||
|
|
||||||
|
void commitTransaction({required Pointer<PendingTransactionRaw> transactionPointer}) {
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final isCommited = transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
||||||
|
|
||||||
|
if (!isCommited) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw CreationTransactionException(message: message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription _createTransactionSync(Map args) {
|
||||||
|
final address = args['address'] 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;
|
||||||
|
final preferredInputs = args['preferredInputs'] as List<String>;
|
||||||
|
|
||||||
|
return createTransactionSync(
|
||||||
|
address: address,
|
||||||
|
paymentId: paymentId,
|
||||||
|
amount: amount,
|
||||||
|
priorityRaw: priorityRaw,
|
||||||
|
accountIndex: accountIndex,
|
||||||
|
preferredInputs: preferredInputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
|
||||||
|
final outputs = args['outputs'] as List<MoneroOutput>;
|
||||||
|
final paymentId = args['paymentId'] as String;
|
||||||
|
final priorityRaw = args['priorityRaw'] as int;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
final preferredInputs = args['preferredInputs'] as List<String>;
|
||||||
|
|
||||||
|
return createTransactionMultDestSync(
|
||||||
|
outputs: outputs,
|
||||||
|
paymentId: paymentId,
|
||||||
|
priorityRaw: priorityRaw,
|
||||||
|
accountIndex: accountIndex,
|
||||||
|
preferredInputs: preferredInputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PendingTransactionDescription> createTransaction(
|
||||||
|
{required String address,
|
||||||
|
required int priorityRaw,
|
||||||
|
String? amount,
|
||||||
|
String paymentId = '',
|
||||||
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) =>
|
||||||
|
compute(_createTransactionSync, {
|
||||||
|
'address': address,
|
||||||
|
'paymentId': paymentId,
|
||||||
|
'amount': amount,
|
||||||
|
'priorityRaw': priorityRaw,
|
||||||
|
'accountIndex': accountIndex,
|
||||||
|
'preferredInputs': preferredInputs
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<PendingTransactionDescription> createTransactionMultDest(
|
||||||
|
{required List<MoneroOutput> outputs,
|
||||||
|
required int priorityRaw,
|
||||||
|
String paymentId = '',
|
||||||
|
int accountIndex = 0,
|
||||||
|
List<String> preferredInputs = const []}) =>
|
||||||
|
compute(_createTransactionMultDestSync, {
|
||||||
|
'outputs': outputs,
|
||||||
|
'paymentId': paymentId,
|
||||||
|
'priorityRaw': priorityRaw,
|
||||||
|
'accountIndex': accountIndex,
|
||||||
|
'preferredInputs': preferredInputs
|
||||||
|
});
|
@ -0,0 +1,153 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:cw_wownero/api/structs/coins_info_row.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/pending_transaction.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/transaction_info_row.dart';
|
||||||
|
import 'package:cw_wownero/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 RestoreWalletFromSpendKey = int Function(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 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>?, 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 SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||||
|
|
||||||
|
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 GetTransaction = Pointer<TransactionInfoRow> Function(Pointer<Utf8> txId);
|
||||||
|
|
||||||
|
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> paymentId,
|
||||||
|
Pointer<Utf8> amount,
|
||||||
|
int priorityRaw,
|
||||||
|
int subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
int preferredInputsSize,
|
||||||
|
Pointer<Utf8Box> error,
|
||||||
|
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||||
|
|
||||||
|
typedef TransactionCreateMultDest = int Function(
|
||||||
|
Pointer<Pointer<Utf8>> addresses,
|
||||||
|
Pointer<Utf8> paymentId,
|
||||||
|
Pointer<Pointer<Utf8>> amounts,
|
||||||
|
int size,
|
||||||
|
int priorityRaw,
|
||||||
|
int subaddrAccount,
|
||||||
|
Pointer<Pointer<Utf8>> preferredInputs,
|
||||||
|
int preferredInputsSize,
|
||||||
|
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 GetSubaddressLabel = Pointer<Utf8> Function(
|
||||||
|
int accountIndex,
|
||||||
|
int addressIndex);
|
||||||
|
|
||||||
|
typedef SetTrustedDaemon = void Function(int);
|
||||||
|
|
||||||
|
typedef TrustedDaemon = int Function();
|
||||||
|
|
||||||
|
typedef RefreshCoins = void Function(int);
|
||||||
|
|
||||||
|
typedef CoinsCount = int Function();
|
||||||
|
|
||||||
|
typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
|
||||||
|
|
||||||
|
typedef FreezeCoin = void Function(int);
|
||||||
|
|
||||||
|
typedef ThawCoin = void Function(int);
|
||||||
|
|
||||||
|
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);
|
@ -0,0 +1,399 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:cw_wownero/api/structs/ut8_box.dart';
|
||||||
|
import 'package:cw_wownero/api/convert_utf8_to_string.dart';
|
||||||
|
import 'package:cw_wownero/api/signatures.dart';
|
||||||
|
import 'package:cw_wownero/api/types.dart';
|
||||||
|
import 'package:cw_wownero/api/wownero_api.dart';
|
||||||
|
import 'package:cw_wownero/api/exceptions/setup_wallet_exception.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
int _boolToInt(bool value) => value ? 1 : 0;
|
||||||
|
|
||||||
|
final getFileNameNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_filename>>('get_filename')
|
||||||
|
.asFunction<GetFilename>();
|
||||||
|
|
||||||
|
final getSeedNative =
|
||||||
|
wowneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
|
||||||
|
|
||||||
|
final getAddressNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_address>>('get_address')
|
||||||
|
.asFunction<GetAddress>();
|
||||||
|
|
||||||
|
final getFullBalanceNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
|
||||||
|
.asFunction<GetFullBalance>();
|
||||||
|
|
||||||
|
final getUnlockedBalanceNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_unlocked_balanace>>('get_unlocked_balance')
|
||||||
|
.asFunction<GetUnlockedBalance>();
|
||||||
|
|
||||||
|
final getCurrentHeightNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_current_height>>('get_current_height')
|
||||||
|
.asFunction<GetCurrentHeight>();
|
||||||
|
|
||||||
|
final getNodeHeightNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_node_height>>('get_node_height')
|
||||||
|
.asFunction<GetNodeHeight>();
|
||||||
|
|
||||||
|
final isConnectedNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<is_connected>>('is_connected')
|
||||||
|
.asFunction<IsConnected>();
|
||||||
|
|
||||||
|
final setupNodeNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<setup_node>>('setup_node')
|
||||||
|
.asFunction<SetupNode>();
|
||||||
|
|
||||||
|
final startRefreshNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<start_refresh>>('start_refresh')
|
||||||
|
.asFunction<StartRefresh>();
|
||||||
|
|
||||||
|
final connecToNodeNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
|
||||||
|
.asFunction<ConnectToNode>();
|
||||||
|
|
||||||
|
final setRefreshFromBlockHeightNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<set_refresh_from_block_height>>(
|
||||||
|
'set_refresh_from_block_height')
|
||||||
|
.asFunction<SetRefreshFromBlockHeight>();
|
||||||
|
|
||||||
|
final setRecoveringFromSeedNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<set_recovering_from_seed>>(
|
||||||
|
'set_recovering_from_seed')
|
||||||
|
.asFunction<SetRecoveringFromSeed>();
|
||||||
|
|
||||||
|
final storeNative =
|
||||||
|
wowneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
||||||
|
|
||||||
|
final setPasswordNative =
|
||||||
|
wowneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
|
||||||
|
|
||||||
|
final setListenerNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<set_listener>>('set_listener')
|
||||||
|
.asFunction<SetListener>();
|
||||||
|
|
||||||
|
final getSyncingHeightNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
|
||||||
|
.asFunction<GetSyncingHeight>();
|
||||||
|
|
||||||
|
final isNeededToRefreshNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
|
||||||
|
.asFunction<IsNeededToRefresh>();
|
||||||
|
|
||||||
|
final isNewTransactionExistNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<is_new_transaction_exist>>(
|
||||||
|
'is_new_transaction_exist')
|
||||||
|
.asFunction<IsNewTransactionExist>();
|
||||||
|
|
||||||
|
final getSecretViewKeyNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<secret_view_key>>('secret_view_key')
|
||||||
|
.asFunction<SecretViewKey>();
|
||||||
|
|
||||||
|
final getPublicViewKeyNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<public_view_key>>('public_view_key')
|
||||||
|
.asFunction<PublicViewKey>();
|
||||||
|
|
||||||
|
final getSecretSpendKeyNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
|
||||||
|
.asFunction<SecretSpendKey>();
|
||||||
|
|
||||||
|
final getPublicSpendKeyNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<secret_view_key>>('public_spend_key')
|
||||||
|
.asFunction<PublicSpendKey>();
|
||||||
|
|
||||||
|
final closeCurrentWalletNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
|
||||||
|
.asFunction<CloseCurrentWallet>();
|
||||||
|
|
||||||
|
final onStartupNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<on_startup>>('on_startup')
|
||||||
|
.asFunction<OnStartup>();
|
||||||
|
|
||||||
|
final rescanBlockchainAsyncNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
|
||||||
|
.asFunction<RescanBlockchainAsync>();
|
||||||
|
|
||||||
|
final getSubaddressLabelNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label')
|
||||||
|
.asFunction<GetSubaddressLabel>();
|
||||||
|
|
||||||
|
final setTrustedDaemonNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
|
||||||
|
.asFunction<SetTrustedDaemon>();
|
||||||
|
|
||||||
|
final trustedDaemonNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
||||||
|
.asFunction<TrustedDaemon>();
|
||||||
|
|
||||||
|
final signMessageNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<sign_message>>('sign_message')
|
||||||
|
.asFunction<SignMessage>();
|
||||||
|
|
||||||
|
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(
|
||||||
|
{required String address,
|
||||||
|
String? login,
|
||||||
|
String? password,
|
||||||
|
bool useSSL = false,
|
||||||
|
bool isLightWallet = false,
|
||||||
|
String? socksProxyAddress}) {
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
Pointer<Utf8>? loginPointer;
|
||||||
|
Pointer<Utf8>? socksProxyAddressPointer;
|
||||||
|
Pointer<Utf8>? passwordPointer;
|
||||||
|
|
||||||
|
if (login != null) {
|
||||||
|
loginPointer = login.toNativeUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password != null) {
|
||||||
|
passwordPointer = password.toNativeUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socksProxyAddress != null) {
|
||||||
|
socksProxyAddressPointer = socksProxyAddress.toNativeUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isSetupNode = setupNodeNative(
|
||||||
|
addressPointer,
|
||||||
|
loginPointer,
|
||||||
|
passwordPointer,
|
||||||
|
_boolToInt(useSSL),
|
||||||
|
_boolToInt(isLightWallet),
|
||||||
|
socksProxyAddressPointer,
|
||||||
|
errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
|
||||||
|
if (loginPointer != null) {
|
||||||
|
calloc.free(loginPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passwordPointer != null) {
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSetupNode) {
|
||||||
|
throw SetupWalletException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSetupNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startRefreshSync() => startRefreshNative();
|
||||||
|
|
||||||
|
Future<bool> connectToNode() async => connecToNodeNative() != 0;
|
||||||
|
|
||||||
|
void setRefreshFromBlockHeight({required int height}) =>
|
||||||
|
setRefreshFromBlockHeightNative(height);
|
||||||
|
|
||||||
|
void setRecoveringFromSeed({required bool isRecovery}) =>
|
||||||
|
setRecoveringFromSeedNative(_boolToInt(isRecovery));
|
||||||
|
|
||||||
|
void storeSync() {
|
||||||
|
final pathPointer = ''.toNativeUtf8();
|
||||||
|
storeNative(pathPointer);
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPasswordSync(String password) {
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final errorMessagePointer = calloc<Utf8Box>();
|
||||||
|
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
final message = errorMessagePointer.ref.getValue();
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
throw Exception(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
calloc.free(errorMessagePointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
var syncHeight = getSyncingHeight();
|
||||||
|
|
||||||
|
if (syncHeight <= 0) {
|
||||||
|
syncHeight = getCurrentHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_initialSyncHeight <= 0) {
|
||||||
|
_initialSyncHeight = syncHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
|
||||||
|
|
||||||
|
if (_lastKnownBlockHeight == syncHeight) {
|
||||||
|
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<String, Object?> 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;
|
||||||
|
final socksProxyAddress = (args['socksProxyAddress'] ?? '') as String;
|
||||||
|
|
||||||
|
return setupNodeSync(
|
||||||
|
address: address,
|
||||||
|
login: login,
|
||||||
|
password: password,
|
||||||
|
useSSL: useSSL,
|
||||||
|
isLightWallet: isLightWallet,
|
||||||
|
socksProxyAddress: socksProxyAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isConnected(Object _) => isConnectedSync();
|
||||||
|
|
||||||
|
int _getNodeHeight(Object _) => getNodeHeightSync();
|
||||||
|
|
||||||
|
void startRefresh() => startRefreshSync();
|
||||||
|
|
||||||
|
Future<void> setupNode(
|
||||||
|
{required String address,
|
||||||
|
String? login,
|
||||||
|
String? password,
|
||||||
|
bool useSSL = false,
|
||||||
|
String? socksProxyAddress,
|
||||||
|
bool isLightWallet = false}) =>
|
||||||
|
compute<Map<String, Object?>, void>(_setupNodeSync, {
|
||||||
|
'address': address,
|
||||||
|
'login': login ,
|
||||||
|
'password': password,
|
||||||
|
'useSSL': useSSL,
|
||||||
|
'isLightWallet': isLightWallet,
|
||||||
|
'socksProxyAddress': socksProxyAddress
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> store() => compute<int, void>(_storeSync, 0);
|
||||||
|
|
||||||
|
Future<bool> isConnected() => compute(_isConnected, 0);
|
||||||
|
|
||||||
|
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
|
||||||
|
|
||||||
|
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
|
||||||
|
|
||||||
|
String getSubaddressLabel(int accountIndex, int addressIndex) {
|
||||||
|
return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
|
||||||
|
|
||||||
|
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
|
||||||
|
|
||||||
|
String signMessage(String message, {String address = ""}) {
|
||||||
|
final messagePointer = message.toNativeUtf8();
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
|
||||||
|
final signature = convertUTF8ToString(pointer: signMessageNative(messagePointer, addressPointer));
|
||||||
|
calloc.free(messagePointer);
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
@ -0,0 +1,333 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:cw_wownero/api/convert_utf8_to_string.dart';
|
||||||
|
import 'package:cw_wownero/api/exceptions/wallet_creation_exception.dart';
|
||||||
|
import 'package:cw_wownero/api/exceptions/wallet_opening_exception.dart';
|
||||||
|
import 'package:cw_wownero/api/exceptions/wallet_restore_from_keys_exception.dart';
|
||||||
|
import 'package:cw_wownero/api/exceptions/wallet_restore_from_seed_exception.dart';
|
||||||
|
import 'package:cw_wownero/api/wownero_api.dart';
|
||||||
|
import 'package:cw_wownero/api/signatures.dart';
|
||||||
|
import 'package:cw_wownero/api/types.dart';
|
||||||
|
import 'package:cw_wownero/api/wallet.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
final createWalletNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<create_wallet>>('create_wallet')
|
||||||
|
.asFunction<CreateWallet>();
|
||||||
|
|
||||||
|
final restoreWalletFromSeedNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<restore_wallet_from_seed>>(
|
||||||
|
'restore_wallet_from_seed')
|
||||||
|
.asFunction<RestoreWalletFromSeed>();
|
||||||
|
|
||||||
|
final restoreWalletFromKeysNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<restore_wallet_from_keys>>(
|
||||||
|
'restore_wallet_from_keys')
|
||||||
|
.asFunction<RestoreWalletFromKeys>();
|
||||||
|
|
||||||
|
final restoreWalletFromSpendKeyNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<restore_wallet_from_spend_key>>(
|
||||||
|
'restore_wallet_from_spend_key')
|
||||||
|
.asFunction<RestoreWalletFromSpendKey>();
|
||||||
|
|
||||||
|
final isWalletExistNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
|
||||||
|
.asFunction<IsWalletExist>();
|
||||||
|
|
||||||
|
final loadWalletNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<load_wallet>>('load_wallet')
|
||||||
|
.asFunction<LoadWallet>();
|
||||||
|
|
||||||
|
final errorStringNative = wowneroApi
|
||||||
|
.lookup<NativeFunction<error_string>>('error_string')
|
||||||
|
.asFunction<ErrorString>();
|
||||||
|
|
||||||
|
void createWalletSync(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
int nettype = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final languagePointer = language.toNativeUtf8();
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isWalletCreated = createWalletNative(pathPointer, passwordPointer,
|
||||||
|
languagePointer, nettype, errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
calloc.free(languagePointer);
|
||||||
|
|
||||||
|
if (!isWalletCreated) {
|
||||||
|
throw WalletCreationException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupNodeSync(address: "node.wowneroworld.com:18089");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isWalletExistSync({required String path}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final isExist = isWalletExistNative(pathPointer) != 0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
|
||||||
|
return isExist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreWalletFromSeedSync(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String seed,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final seedPointer = seed.toNativeUtf8();
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isWalletRestored = restoreWalletFromSeedNative(
|
||||||
|
pathPointer,
|
||||||
|
passwordPointer,
|
||||||
|
seedPointer,
|
||||||
|
nettype,
|
||||||
|
restoreHeight,
|
||||||
|
errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
calloc.free(seedPointer);
|
||||||
|
|
||||||
|
if (!isWalletRestored) {
|
||||||
|
throw WalletRestoreFromSeedException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreWalletFromKeysSync(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
required String address,
|
||||||
|
required String viewKey,
|
||||||
|
required String spendKey,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final languagePointer = language.toNativeUtf8();
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
final viewKeyPointer = viewKey.toNativeUtf8();
|
||||||
|
final spendKeyPointer = spendKey.toNativeUtf8();
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isWalletRestored = restoreWalletFromKeysNative(
|
||||||
|
pathPointer,
|
||||||
|
passwordPointer,
|
||||||
|
languagePointer,
|
||||||
|
addressPointer,
|
||||||
|
viewKeyPointer,
|
||||||
|
spendKeyPointer,
|
||||||
|
nettype,
|
||||||
|
restoreHeight,
|
||||||
|
errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
calloc.free(languagePointer);
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
calloc.free(viewKeyPointer);
|
||||||
|
calloc.free(spendKeyPointer);
|
||||||
|
|
||||||
|
if (!isWalletRestored) {
|
||||||
|
throw WalletRestoreFromKeysException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreWalletFromSpendKeySync(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String seed,
|
||||||
|
required String language,
|
||||||
|
required String spendKey,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final seedPointer = seed.toNativeUtf8();
|
||||||
|
final languagePointer = language.toNativeUtf8();
|
||||||
|
final spendKeyPointer = spendKey.toNativeUtf8();
|
||||||
|
final errorMessagePointer = ''.toNativeUtf8();
|
||||||
|
final isWalletRestored = restoreWalletFromSpendKeyNative(
|
||||||
|
pathPointer,
|
||||||
|
passwordPointer,
|
||||||
|
seedPointer,
|
||||||
|
languagePointer,
|
||||||
|
spendKeyPointer,
|
||||||
|
nettype,
|
||||||
|
restoreHeight,
|
||||||
|
errorMessagePointer) !=
|
||||||
|
0;
|
||||||
|
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.free(passwordPointer);
|
||||||
|
calloc.free(languagePointer);
|
||||||
|
calloc.free(spendKeyPointer);
|
||||||
|
|
||||||
|
storeSync();
|
||||||
|
|
||||||
|
if (!isWalletRestored) {
|
||||||
|
throw WalletRestoreFromKeysException(
|
||||||
|
message: convertUTF8ToString(pointer: errorMessagePointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadWallet({
|
||||||
|
required String path,
|
||||||
|
required String password,
|
||||||
|
int nettype = 0}) {
|
||||||
|
final pathPointer = path.toNativeUtf8();
|
||||||
|
final passwordPointer = password.toNativeUtf8();
|
||||||
|
final loaded = loadWalletNative(pathPointer, passwordPointer, nettype) != 0;
|
||||||
|
calloc.free(pathPointer);
|
||||||
|
calloc.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _restoreFromSpendKey(Map<String, dynamic> args) {
|
||||||
|
final path = args['path'] as String;
|
||||||
|
final password = args['password'] as String;
|
||||||
|
final seed = args['seed'] as String;
|
||||||
|
final language = args['language'] as String;
|
||||||
|
final spendKey = args['spendKey'] as String;
|
||||||
|
final restoreHeight = args['restoreHeight'] as int;
|
||||||
|
|
||||||
|
restoreWalletFromSpendKeySync(
|
||||||
|
path: path,
|
||||||
|
password: password,
|
||||||
|
seed: seed,
|
||||||
|
language: language,
|
||||||
|
restoreHeight: restoreHeight,
|
||||||
|
spendKey: spendKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _openWallet(Map<String, String> args) async =>
|
||||||
|
loadWallet(path: args['path'] as String, password: args['password'] as String);
|
||||||
|
|
||||||
|
bool _isWalletExist(String path) => isWalletExistSync(path: path);
|
||||||
|
|
||||||
|
void openWallet({required String path, required 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(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
int nettype = 0}) async =>
|
||||||
|
compute(_createWallet, {
|
||||||
|
'path': path,
|
||||||
|
'password': password,
|
||||||
|
'language': language,
|
||||||
|
'nettype': nettype
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> restoreFromSeed(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required 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<void> restoreFromKeys(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String language,
|
||||||
|
required String address,
|
||||||
|
required String viewKey,
|
||||||
|
required 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<void> restoreFromSpendKey(
|
||||||
|
{required String path,
|
||||||
|
required String password,
|
||||||
|
required String seed,
|
||||||
|
required String language,
|
||||||
|
required String spendKey,
|
||||||
|
int nettype = 0,
|
||||||
|
int restoreHeight = 0}) async =>
|
||||||
|
compute<Map<String, Object>, void>(_restoreFromSpendKey, {
|
||||||
|
'path': path,
|
||||||
|
'password': password,
|
||||||
|
'seed': seed,
|
||||||
|
'language': language,
|
||||||
|
'spendKey': spendKey,
|
||||||
|
'nettype': nettype,
|
||||||
|
'restoreHeight': restoreHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<bool> isWalletExist({required String path}) => compute(_isWalletExist, path);
|
@ -0,0 +1,6 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
final DynamicLibrary wowneroApi = Platform.isAndroid
|
||||||
|
? DynamicLibrary.open("libcw_wownero.so")
|
||||||
|
: DynamicLibrary.open("cw_wownero.framework/cw_wownero");
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue