mirror of
https://github.com/MAGICGrants/flutter_libsparkmobile.git
synced 2026-01-06 19:53:57 -05:00
migrate to ffi plugin
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -28,10 +28,6 @@ doc/api/
|
||||
|
||||
.idea/
|
||||
|
||||
lib/git_versions.dart
|
||||
|
||||
# Ignore build artifacts.
|
||||
scripts/*/cache/
|
||||
scripts/*/sparkmobile
|
||||
scripts/*/CMakeLists/sparkmobile/CMakeLists.txt
|
||||
scripts/*/CMakeLists/secp256k1/CMakeLists.txt
|
||||
src/build
|
||||
src/deps/sparkmobile
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "sparkmobile"]
|
||||
path = sparkmobile
|
||||
url = https://github.com/firoorg/sparkmobile
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
// The Android Gradle Plugin builds the native code with the Android NDK.
|
||||
|
||||
group 'com.cypherstack.flutter_libsparkmobile'
|
||||
version '1.0-SNAPSHOT'
|
||||
version '1.0'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// The Android Gradle Plugin knows how to build native code with the NDK.
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
rootProject.allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
@@ -22,43 +23,37 @@ allprojects {
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
// Bumping the plugin compileSdkVersion requires all clients of this plugin
|
||||
// to bump the version in their app.
|
||||
compileSdkVersion 31
|
||||
|
||||
// Bumping the plugin ndkVersion requires all clients of this plugin to bump
|
||||
// the version in their app and to download a newer version of the NDK.
|
||||
ndkVersion "23.1.7779620"
|
||||
|
||||
// Invoke the shared CMake build with the Android Gradle Plugin.
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "../src/CMakeLists.txt"
|
||||
|
||||
// The default CMake version for the Android Gradle Plugin is 3.10.2.
|
||||
// https://developer.android.com/studio/projects/install-ndk#vanilla_cmake
|
||||
//
|
||||
// The Flutter tooling requires that developers have CMake 3.10 or later
|
||||
// installed. You should not increase this version, as doing so will cause
|
||||
// the plugin to fail to compile for some customers of the plugin.
|
||||
// version "3.10.2"
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
test.java.srcDirs += 'src/test/kotlin'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'org.jetbrains.kotlin:kotlin-test'
|
||||
testImplementation 'org.mockito:mockito-core:5.0.0'
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests.all {
|
||||
useJUnitPlatform()
|
||||
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed", "standardOut", "standardError"
|
||||
outputs.upToDateWhen {false}
|
||||
showStandardStreams = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.cypherstack.flutter_libsparkmobile
|
||||
|
||||
import androidx.annotation.NonNull
|
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
import io.flutter.plugin.common.MethodChannel.Result
|
||||
|
||||
/** FlutterLibsparkmobilePlugin */
|
||||
class FlutterLibsparkmobilePlugin: FlutterPlugin, MethodCallHandler {
|
||||
/// The MethodChannel that will the communication between Flutter and native Android
|
||||
///
|
||||
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
|
||||
/// when the Flutter Engine is detached from the Activity
|
||||
private lateinit var channel : MethodChannel
|
||||
|
||||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_libsparkmobile")
|
||||
channel.setMethodCallHandler(this)
|
||||
}
|
||||
|
||||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||
if (call.method == "getPlatformVersion") {
|
||||
result.success("Android ${android.os.Build.VERSION.RELEASE}")
|
||||
} else {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
channel.setMethodCallHandler(null)
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.cypherstack.flutter_libsparkmobile
|
||||
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import kotlin.test.Test
|
||||
import org.mockito.Mockito
|
||||
|
||||
/*
|
||||
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
|
||||
*
|
||||
* Once you have built the plugin's example app, you can run these tests from the command
|
||||
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
|
||||
* you can run them directly from IDEs that support JUnit such as Android Studio.
|
||||
*/
|
||||
|
||||
internal class FlutterLibsparkmobilePluginTest {
|
||||
@Test
|
||||
fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
|
||||
val plugin = FlutterLibsparkmobilePlugin()
|
||||
|
||||
val call = MethodCall("getPlatformVersion", null)
|
||||
val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
|
||||
plugin.onMethodCall(call, mockResult)
|
||||
|
||||
Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,11 @@ import Flutter
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
@testable import flutter_libsparkmobile
|
||||
|
||||
// This demonstrates a simple unit test of the Swift portion of this plugin's implementation.
|
||||
//
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testGetPlatformVersion() {
|
||||
let plugin = FlutterLibsparkmobilePlugin()
|
||||
|
||||
let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: [])
|
||||
|
||||
let resultExpectation = expectation(description: "result block must be called.")
|
||||
plugin.handle(call) { result in
|
||||
XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion)
|
||||
resultExpectation.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1)
|
||||
func testExample() {
|
||||
// If you add code to the Runner application, consider adding tests here.
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,8 +86,6 @@ set_target_properties(${BINARY_NAME}
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||
)
|
||||
|
||||
# Enable the test target.
|
||||
set(include_flutter_libsparkmobile_tests TRUE)
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
# them to the application.
|
||||
@@ -119,10 +117,6 @@ install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}
|
||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/linux/build/libsparkmobile.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
# Must have ran build script(s) in order for this library to exist.
|
||||
|
||||
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||
install(FILES "${bundled_library}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <flutter_libsparkmobile/flutter_libsparkmobile_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) flutter_libsparkmobile_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterLibsparkmobilePlugin");
|
||||
flutter_libsparkmobile_plugin_register_with_registrar(flutter_libsparkmobile_registrar);
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_libsparkmobile
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
coinlib_flutter
|
||||
flutter_libsparkmobile
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import flutter_libsparkmobile
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FlutterLibsparkmobilePlugin.register(with: registry.registrar(forPlugin: "FlutterLibsparkmobilePlugin"))
|
||||
}
|
||||
|
||||
@@ -2,26 +2,11 @@ import FlutterMacOS
|
||||
import Cocoa
|
||||
import XCTest
|
||||
|
||||
@testable import flutter_libsparkmobile
|
||||
|
||||
// This demonstrates a simple unit test of the Swift portion of this plugin's implementation.
|
||||
//
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testGetPlatformVersion() {
|
||||
let plugin = FlutterLibsparkmobilePlugin()
|
||||
|
||||
let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: [])
|
||||
|
||||
let resultExpectation = expectation(description: "result block must be called.")
|
||||
plugin.handle(call) { result in
|
||||
XCTAssertEqual(result as! String,
|
||||
"macOS " + ProcessInfo.processInfo.operatingSystemVersionString)
|
||||
resultExpectation.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1)
|
||||
func testExample() {
|
||||
// If you add code to the Runner application, consider adding tests here.
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,20 @@ description: Demonstrates how to use the flutter_libsparkmobile plugin.
|
||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
|
||||
# The following defines the version and build number for your application.
|
||||
# A version number is three numbers separated by dots, like 1.2.43
|
||||
# followed by an optional build number separated by a +.
|
||||
# Both the version and the builder number may be overridden in flutter
|
||||
# build by specifying --build-name and --build-number, respectively.
|
||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.6 <4.0.0'
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||
# Application build; see runner/CMakeLists.txt.
|
||||
add_subdirectory("runner")
|
||||
|
||||
# Enable the test target.
|
||||
set(include_flutter_libsparkmobile_tests TRUE)
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
# them to the application.
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FlutterLibsparkmobilePluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterLibsparkmobilePluginCApi"));
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_libsparkmobile
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
flutter_libsparkmobile
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
19
ffigen.yaml
Normal file
19
ffigen.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
# Run with `flutter pub run ffigen --config ffigen.yaml`.
|
||||
name: FlutterLibsparkmobileBindings
|
||||
description: |
|
||||
Bindings for `src/flutter_libsparkmobile.h`.
|
||||
|
||||
Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`.
|
||||
output: 'lib/flutter_libsparkmobile_bindings_generated.dart'
|
||||
headers:
|
||||
entry-points:
|
||||
- 'src/flutter_libsparkmobile.h'
|
||||
include-directives:
|
||||
- 'src/flutter_libsparkmobile.h'
|
||||
preamble: |
|
||||
// ignore_for_file: always_specify_types
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
comments:
|
||||
style: any
|
||||
length: full
|
||||
@@ -3,7 +3,7 @@
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
|
||||
|
||||
38
ios/.gitignore
vendored
38
ios/.gitignore
vendored
@@ -1,38 +0,0 @@
|
||||
.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/ephemeral/
|
||||
/Flutter/flutter_export_environment.sh
|
||||
@@ -1,19 +0,0 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
public class FlutterLibsparkmobilePlugin: NSObject, FlutterPlugin {
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "flutter_libsparkmobile", binaryMessenger: registrar.messenger())
|
||||
let instance = FlutterLibsparkmobilePlugin()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
}
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "getPlatformVersion":
|
||||
result("iOS " + UIDevice.current.systemVersion)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
3
ios/Classes/flutter_libsparkmobile.c
Normal file
3
ios/Classes/flutter_libsparkmobile.c
Normal file
@@ -0,0 +1,3 @@
|
||||
// Relative import to be able to reuse the C sources.
|
||||
// See the comment in ../{projectName}}.podspec for more information.
|
||||
#include flutter_libsparkmobile.cpp
|
||||
@@ -5,13 +5,18 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'flutter_libsparkmobile'
|
||||
s.version = '0.0.1'
|
||||
s.summary = 'A new Flutter plugin project.'
|
||||
s.summary = 'A new Flutter project.'
|
||||
s.description = <<-DESC
|
||||
A new Flutter plugin project.
|
||||
A new Flutter project.
|
||||
DESC
|
||||
s.homepage = 'http://example.com'
|
||||
s.license = { :file => '../LICENSE' }
|
||||
s.author = { 'Your Company' => 'email@example.com' }
|
||||
|
||||
# This will ensure the source files in Classes/ are included in the native
|
||||
# builds of apps using this FFI plugin. Podspec does not support relative
|
||||
# paths, so Classes contains a forwarder C file that relatively imports
|
||||
# `../src/*` so that the C sources can be shared among all target platforms.
|
||||
s.source = { :path => '.' }
|
||||
s.source_files = 'Classes/**/*'
|
||||
s.dependency 'Flutter'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
@@ -5,46 +6,67 @@ import 'dart:typed_data';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:flutter_libsparkmobile/extensions.dart';
|
||||
|
||||
import 'flutter_libsparkmobile_bindings.dart';
|
||||
import 'flutter_libsparkmobile_bindings_generated.dart';
|
||||
|
||||
const kSparkChain = 6;
|
||||
const kSparkBaseDerivationPath = "m/44'/136'/0'/$kSparkChain/";
|
||||
|
||||
const String _kLibName = 'flutter_libsparkmobile';
|
||||
|
||||
/// The dynamic library in which the symbols for [FlutterLibsparkmobileBindings] can be found.
|
||||
final DynamicLibrary _dylib = () {
|
||||
if (Platform.isMacOS || Platform.isIOS) {
|
||||
return DynamicLibrary.open('$_kLibName.framework/$_kLibName');
|
||||
}
|
||||
if (Platform.isAndroid || Platform.isLinux) {
|
||||
return DynamicLibrary.open('lib$_kLibName.so');
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
return DynamicLibrary.open('$_kLibName.dll');
|
||||
}
|
||||
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
|
||||
}();
|
||||
|
||||
/// The bindings to the native functions in [_dylib].
|
||||
final FlutterLibsparkmobileBindings _bindings =
|
||||
FlutterLibsparkmobileBindings(_dylib);
|
||||
|
||||
abstract final class LibSpark {
|
||||
static SparkMobileBindings? _bindings;
|
||||
|
||||
static void _checkLoaded() {
|
||||
_bindings ??= SparkMobileBindings(_loadLibrary());
|
||||
}
|
||||
|
||||
static DynamicLibrary _loadLibrary() {
|
||||
// hack in prefix for test env
|
||||
String testPrefix = "";
|
||||
if (Platform.environment.containsKey('FLUTTER_TEST')) {
|
||||
if (Platform.isLinux) {
|
||||
testPrefix = 'scripts/linux/build/';
|
||||
} else if (Platform.isMacOS) {
|
||||
testPrefix = 'scripts/macos/build/';
|
||||
} else if (Platform.isWindows) {
|
||||
testPrefix = 'scripts/windows/build/';
|
||||
} else {
|
||||
throw UnsupportedError('This platform is not supported');
|
||||
}
|
||||
}
|
||||
|
||||
if (Platform.isLinux) {
|
||||
return DynamicLibrary.open('${testPrefix}libsparkmobile.so');
|
||||
} else if (Platform.isAndroid) {
|
||||
// return DynamicLibrary.open('${testPrefix}libsparkmobile.so');
|
||||
} else if (Platform.isIOS) {
|
||||
// return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib');
|
||||
} else if (Platform.isMacOS) {
|
||||
// return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib');
|
||||
} else if (Platform.isWindows) {
|
||||
// return DynamicLibrary.open('${testPrefix}sparkmobile.dll');
|
||||
}
|
||||
throw UnsupportedError('This platform is not supported');
|
||||
}
|
||||
static final FlutterLibsparkmobileBindings _bindings =
|
||||
FlutterLibsparkmobileBindings(_dylib);
|
||||
//
|
||||
// static void _checkLoaded() {
|
||||
// _bindings ??= SparkMobileBindings(_loadLibrary());
|
||||
// }
|
||||
//
|
||||
// static DynamicLibrary _loadLibrary() {
|
||||
// // hack in prefix for test env
|
||||
// String testPrefix = "";
|
||||
// if (Platform.environment.containsKey('FLUTTER_TEST')) {
|
||||
// if (Platform.isLinux) {
|
||||
// testPrefix = 'scripts/linux/build/';
|
||||
// } else if (Platform.isMacOS) {
|
||||
// testPrefix = 'scripts/macos/build/';
|
||||
// } else if (Platform.isWindows) {
|
||||
// testPrefix = 'scripts/windows/build/';
|
||||
// } else {
|
||||
// throw UnsupportedError('This platform is not supported');
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (Platform.isLinux) {
|
||||
// return DynamicLibrary.open('${testPrefix}libsparkmobile.so');
|
||||
// } else if (Platform.isAndroid) {
|
||||
// // return DynamicLibrary.open('${testPrefix}libsparkmobile.so');
|
||||
// } else if (Platform.isIOS) {
|
||||
// // return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib');
|
||||
// } else if (Platform.isMacOS) {
|
||||
// // return DynamicLibrary.open('${testPrefix}libsparkmobile.dylib');
|
||||
// } else if (Platform.isWindows) {
|
||||
// // return DynamicLibrary.open('${testPrefix}sparkmobile.dll');
|
||||
// }
|
||||
// throw UnsupportedError('This platform is not supported');
|
||||
// }
|
||||
|
||||
// SparkMobileBindings methods:
|
||||
|
||||
@@ -55,7 +77,7 @@ abstract final class LibSpark {
|
||||
required int diversifier,
|
||||
bool isTestNet = false,
|
||||
}) async {
|
||||
_checkLoaded();
|
||||
// _checkLoaded();
|
||||
|
||||
if (index < 0) {
|
||||
throw Exception("Index must not be negative.");
|
||||
@@ -75,7 +97,7 @@ abstract final class LibSpark {
|
||||
final keyDataPointer = privateKey.toHexString().toNativeUtf8().cast<Char>();
|
||||
|
||||
// Call the native method with the pointer.
|
||||
final addressPointer = _bindings!.getAddress(
|
||||
final addressPointer = _bindings.getAddress(
|
||||
keyDataPointer,
|
||||
index,
|
||||
diversifier,
|
||||
@@ -92,3 +114,128 @@ abstract final class LibSpark {
|
||||
return addressString;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// /// A very short-lived native function.
|
||||
// ///
|
||||
// /// For very short-lived functions, it is fine to call them on the main isolate.
|
||||
// /// They will block the Dart execution while running the native function, so
|
||||
// /// only do this for native functions which are guaranteed to be short-lived.
|
||||
// int sum(int a, int b) => _bindings.sum(a, b);
|
||||
//
|
||||
// /// A longer lived native function, which occupies the thread calling it.
|
||||
// ///
|
||||
// /// Do not call these kind of native functions in the main isolate. They will
|
||||
// /// block Dart execution. This will cause dropped frames in Flutter applications.
|
||||
// /// Instead, call these native functions on a separate isolate.
|
||||
// ///
|
||||
// /// Modify this to suit your own use case. Example use cases:
|
||||
// ///
|
||||
// /// 1. Reuse a single isolate for various different kinds of requests.
|
||||
// /// 2. Use multiple helper isolates for parallel execution.
|
||||
// Future<int> sumAsync(int a, int b) async {
|
||||
// final SendPort helperIsolateSendPort = await _helperIsolateSendPort;
|
||||
// final int requestId = _nextSumRequestId++;
|
||||
// final _SumRequest request = _SumRequest(requestId, a, b);
|
||||
// final Completer<int> completer = Completer<int>();
|
||||
// _sumRequests[requestId] = completer;
|
||||
// helperIsolateSendPort.send(request);
|
||||
// return completer.future;
|
||||
// }
|
||||
//
|
||||
// const String _libName = 'flutter_libsparkmobile';
|
||||
//
|
||||
// /// The dynamic library in which the symbols for [FlutterLibsparkmobileBindings] can be found.
|
||||
// final DynamicLibrary _dylib = () {
|
||||
// if (Platform.isMacOS || Platform.isIOS) {
|
||||
// return DynamicLibrary.open('$_libName.framework/$_libName');
|
||||
// }
|
||||
// if (Platform.isAndroid || Platform.isLinux) {
|
||||
// return DynamicLibrary.open('lib$_libName.so');
|
||||
// }
|
||||
// if (Platform.isWindows) {
|
||||
// return DynamicLibrary.open('$_libName.dll');
|
||||
// }
|
||||
// throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
|
||||
// }();
|
||||
//
|
||||
// /// The bindings to the native functions in [_dylib].
|
||||
// final FlutterLibsparkmobileBindings _bindings = FlutterLibsparkmobileBindings(_dylib);
|
||||
|
||||
//
|
||||
// /// A request to compute `sum`.
|
||||
// ///
|
||||
// /// Typically sent from one isolate to another.
|
||||
// class _SumRequest {
|
||||
// final int id;
|
||||
// final int a;
|
||||
// final int b;
|
||||
//
|
||||
// const _SumRequest(this.id, this.a, this.b);
|
||||
// }
|
||||
//
|
||||
// /// A response with the result of `sum`.
|
||||
// ///
|
||||
// /// Typically sent from one isolate to another.
|
||||
// class _SumResponse {
|
||||
// final int id;
|
||||
// final int result;
|
||||
//
|
||||
// const _SumResponse(this.id, this.result);
|
||||
// }
|
||||
//
|
||||
// /// Counter to identify [_SumRequest]s and [_SumResponse]s.
|
||||
// int _nextSumRequestId = 0;
|
||||
//
|
||||
// /// Mapping from [_SumRequest] `id`s to the completers corresponding to the correct future of the pending request.
|
||||
// final Map<int, Completer<int>> _sumRequests = <int, Completer<int>>{};
|
||||
//
|
||||
// /// The SendPort belonging to the helper isolate.
|
||||
// Future<SendPort> _helperIsolateSendPort = () async {
|
||||
// // The helper isolate is going to send us back a SendPort, which we want to
|
||||
// // wait for.
|
||||
// final Completer<SendPort> completer = Completer<SendPort>();
|
||||
//
|
||||
// // Receive port on the main isolate to receive messages from the helper.
|
||||
// // We receive two types of messages:
|
||||
// // 1. A port to send messages on.
|
||||
// // 2. Responses to requests we sent.
|
||||
// final ReceivePort receivePort = ReceivePort()
|
||||
// ..listen((dynamic data) {
|
||||
// if (data is SendPort) {
|
||||
// // The helper isolate sent us the port on which we can sent it requests.
|
||||
// completer.complete(data);
|
||||
// return;
|
||||
// }
|
||||
// if (data is _SumResponse) {
|
||||
// // The helper isolate sent us a response to a request we sent.
|
||||
// final Completer<int> completer = _sumRequests[data.id]!;
|
||||
// _sumRequests.remove(data.id);
|
||||
// completer.complete(data.result);
|
||||
// return;
|
||||
// }
|
||||
// throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
|
||||
// });
|
||||
//
|
||||
// // Start the helper isolate.
|
||||
// await Isolate.spawn((SendPort sendPort) async {
|
||||
// final ReceivePort helperReceivePort = ReceivePort()
|
||||
// ..listen((dynamic data) {
|
||||
// // On the helper isolate listen to requests and respond to them.
|
||||
// if (data is _SumRequest) {
|
||||
// final int result = _bindings.sum_long_running(data.a, data.b);
|
||||
// final _SumResponse response = _SumResponse(data.id, result);
|
||||
// sendPort.send(response);
|
||||
// return;
|
||||
// }
|
||||
// throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
|
||||
// });
|
||||
//
|
||||
// // Send the port to the main isolate on which we can receive requests.
|
||||
// sendPort.send(helperReceivePort.sendPort);
|
||||
// }, receivePort.sendPort);
|
||||
//
|
||||
// // Wait until the helper isolate has sent us back the SendPort on which we
|
||||
// // can start sending requests.
|
||||
// return completer.future;
|
||||
// }();
|
||||
|
||||
@@ -1,439 +0,0 @@
|
||||
// ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_api
|
||||
|
||||
// AUTO GENERATED FILE, DO NOT EDIT.
|
||||
//
|
||||
// Generated by `package:ffigen`.
|
||||
// ignore_for_file: type=lint
|
||||
import 'dart:ffi' as ffi;
|
||||
|
||||
/// Bindings for sparkmobile.
|
||||
class SparkMobileBindings {
|
||||
/// Holds the symbol lookup function.
|
||||
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
_lookup;
|
||||
|
||||
/// The symbols are looked up in [dynamicLibrary].
|
||||
SparkMobileBindings(ffi.DynamicLibrary dynamicLibrary)
|
||||
: _lookup = dynamicLibrary.lookup;
|
||||
|
||||
/// The symbols are looked up with [lookup].
|
||||
SparkMobileBindings.fromLookup(
|
||||
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
lookup)
|
||||
: _lookup = lookup;
|
||||
|
||||
ffi.Pointer<ffi.Char> getAddress(
|
||||
ffi.Pointer<ffi.Char> keyDataHex,
|
||||
int index,
|
||||
int diversifier,
|
||||
int isTestNet,
|
||||
) {
|
||||
return _getAddress(
|
||||
keyDataHex,
|
||||
index,
|
||||
diversifier,
|
||||
isTestNet,
|
||||
);
|
||||
}
|
||||
|
||||
late final _getAddressPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<ffi.Char> Function(
|
||||
ffi.Pointer<ffi.Char>, ffi.Int, ffi.Int, ffi.Int)>>('getAddress');
|
||||
late final _getAddress = _getAddressPtr.asFunction<
|
||||
ffi.Pointer<ffi.Char> Function(ffi.Pointer<ffi.Char>, int, int, int)>();
|
||||
|
||||
CIdentifiedCoinData identifyCoin(
|
||||
CCoin c_struct,
|
||||
ffi.Pointer<ffi.Char> keyDataHex,
|
||||
int index,
|
||||
) {
|
||||
return _identifyCoin(
|
||||
c_struct,
|
||||
keyDataHex,
|
||||
index,
|
||||
);
|
||||
}
|
||||
|
||||
late final _identifyCoinPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
CIdentifiedCoinData Function(
|
||||
CCoin, ffi.Pointer<ffi.Char>, ffi.Int)>>('identifyCoin');
|
||||
late final _identifyCoin = _identifyCoinPtr.asFunction<
|
||||
CIdentifiedCoinData Function(CCoin, ffi.Pointer<ffi.Char>, int)>();
|
||||
|
||||
ffi.Pointer<CCRecipient> createSparkMintRecipients(
|
||||
int numRecipients,
|
||||
ffi.Pointer<PubKeyScript> pubKeyScripts,
|
||||
ffi.Pointer<ffi.Uint64> amounts,
|
||||
ffi.Pointer<ffi.Char> memo,
|
||||
int subtractFee,
|
||||
) {
|
||||
return _createSparkMintRecipients(
|
||||
numRecipients,
|
||||
pubKeyScripts,
|
||||
amounts,
|
||||
memo,
|
||||
subtractFee,
|
||||
);
|
||||
}
|
||||
|
||||
late final _createSparkMintRecipientsPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<CCRecipient> Function(
|
||||
ffi.Int,
|
||||
ffi.Pointer<PubKeyScript>,
|
||||
ffi.Pointer<ffi.Uint64>,
|
||||
ffi.Pointer<ffi.Char>,
|
||||
ffi.Int)>>('createSparkMintRecipients');
|
||||
late final _createSparkMintRecipients =
|
||||
_createSparkMintRecipientsPtr.asFunction<
|
||||
ffi.Pointer<CCRecipient> Function(int, ffi.Pointer<PubKeyScript>,
|
||||
ffi.Pointer<ffi.Uint64>, ffi.Pointer<ffi.Char>, int)>();
|
||||
}
|
||||
|
||||
final class __fsid_t extends ffi.Struct {
|
||||
@ffi.Array.multi([2])
|
||||
external ffi.Array<ffi.Int> __val;
|
||||
}
|
||||
|
||||
final class CCoin extends ffi.Struct {
|
||||
@ffi.Char()
|
||||
external int type;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> k;
|
||||
|
||||
@ffi.Int()
|
||||
external int kLength;
|
||||
|
||||
external ffi.Pointer<ffi.Char> address;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int v;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> memo;
|
||||
|
||||
@ffi.Int()
|
||||
external int memoLength;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> serial_context;
|
||||
|
||||
@ffi.Int()
|
||||
external int serial_contextLength;
|
||||
}
|
||||
|
||||
final class CIdentifiedCoinData extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int i;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> d;
|
||||
|
||||
@ffi.Int()
|
||||
external int dLength;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int v;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> k;
|
||||
|
||||
@ffi.Int()
|
||||
external int kLength;
|
||||
|
||||
external ffi.Pointer<ffi.Char> memo;
|
||||
|
||||
@ffi.Int()
|
||||
external int memoLength;
|
||||
}
|
||||
|
||||
final class CCRecipient extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.UnsignedChar> pubKey;
|
||||
|
||||
@ffi.Int()
|
||||
external int pubKeyLength;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int cAmount;
|
||||
|
||||
@ffi.Int()
|
||||
external int subtractFee;
|
||||
}
|
||||
|
||||
final class CMintedCoinData extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Char> address;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int value;
|
||||
|
||||
external ffi.Pointer<ffi.Char> memo;
|
||||
}
|
||||
|
||||
final class PubKeyScript extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.UnsignedChar> bytes;
|
||||
|
||||
@ffi.Int()
|
||||
external int length;
|
||||
}
|
||||
|
||||
final class COutputCoinData extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Char> address;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int value;
|
||||
|
||||
external ffi.Pointer<ffi.Char> memo;
|
||||
}
|
||||
|
||||
final class CCSparkMintMeta extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int height;
|
||||
|
||||
external ffi.Pointer<ffi.Char> id;
|
||||
|
||||
@ffi.Int()
|
||||
external int isUsed;
|
||||
|
||||
external ffi.Pointer<ffi.Char> txid;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int i;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> d;
|
||||
|
||||
@ffi.Int()
|
||||
external int dLength;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int v;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> k;
|
||||
|
||||
@ffi.Int()
|
||||
external int kLength;
|
||||
|
||||
external ffi.Pointer<ffi.Char> memo;
|
||||
|
||||
@ffi.Int()
|
||||
external int memoLength;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> serial_context;
|
||||
|
||||
@ffi.Int()
|
||||
external int serial_contextLength;
|
||||
|
||||
@ffi.Char()
|
||||
external int type;
|
||||
|
||||
external CCoin coin;
|
||||
}
|
||||
|
||||
const int _STDINT_H = 1;
|
||||
|
||||
const int _FEATURES_H = 1;
|
||||
|
||||
const int _DEFAULT_SOURCE = 1;
|
||||
|
||||
const int __GLIBC_USE_ISOC2X = 1;
|
||||
|
||||
const int __USE_ISOC11 = 1;
|
||||
|
||||
const int __USE_ISOC99 = 1;
|
||||
|
||||
const int __USE_ISOC95 = 1;
|
||||
|
||||
const int _POSIX_SOURCE = 1;
|
||||
|
||||
const int _POSIX_C_SOURCE = 200809;
|
||||
|
||||
const int __USE_POSIX = 1;
|
||||
|
||||
const int __USE_POSIX2 = 1;
|
||||
|
||||
const int __USE_POSIX199309 = 1;
|
||||
|
||||
const int __USE_POSIX199506 = 1;
|
||||
|
||||
const int __USE_XOPEN2K = 1;
|
||||
|
||||
const int __USE_XOPEN2K8 = 1;
|
||||
|
||||
const int _ATFILE_SOURCE = 1;
|
||||
|
||||
const int __USE_MISC = 1;
|
||||
|
||||
const int __USE_ATFILE = 1;
|
||||
|
||||
const int __USE_FORTIFY_LEVEL = 0;
|
||||
|
||||
const int __GLIBC_USE_DEPRECATED_GETS = 0;
|
||||
|
||||
const int __GLIBC_USE_DEPRECATED_SCANF = 0;
|
||||
|
||||
const int _STDC_PREDEF_H = 1;
|
||||
|
||||
const int __STDC_IEC_559__ = 1;
|
||||
|
||||
const int __STDC_IEC_559_COMPLEX__ = 1;
|
||||
|
||||
const int __STDC_ISO_10646__ = 201706;
|
||||
|
||||
const int __GNU_LIBRARY__ = 6;
|
||||
|
||||
const int __GLIBC__ = 2;
|
||||
|
||||
const int __GLIBC_MINOR__ = 31;
|
||||
|
||||
const int _SYS_CDEFS_H = 1;
|
||||
|
||||
const int __glibc_c99_flexarr_available = 1;
|
||||
|
||||
const int __WORDSIZE = 64;
|
||||
|
||||
const int __WORDSIZE_TIME64_COMPAT32 = 1;
|
||||
|
||||
const int __SYSCALL_WORDSIZE = 64;
|
||||
|
||||
const int __LONG_DOUBLE_USES_FLOAT128 = 0;
|
||||
|
||||
const int __HAVE_GENERIC_SELECTION = 0;
|
||||
|
||||
const int __GLIBC_USE_LIB_EXT2 = 1;
|
||||
|
||||
const int __GLIBC_USE_IEC_60559_BFP_EXT = 1;
|
||||
|
||||
const int __GLIBC_USE_IEC_60559_BFP_EXT_C2X = 1;
|
||||
|
||||
const int __GLIBC_USE_IEC_60559_FUNCS_EXT = 1;
|
||||
|
||||
const int __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X = 1;
|
||||
|
||||
const int __GLIBC_USE_IEC_60559_TYPES_EXT = 1;
|
||||
|
||||
const int _BITS_TYPES_H = 1;
|
||||
|
||||
const int __TIMESIZE = 64;
|
||||
|
||||
const int _BITS_TYPESIZES_H = 1;
|
||||
|
||||
const int __OFF_T_MATCHES_OFF64_T = 1;
|
||||
|
||||
const int __INO_T_MATCHES_INO64_T = 1;
|
||||
|
||||
const int __RLIM_T_MATCHES_RLIM64_T = 1;
|
||||
|
||||
const int __STATFS_MATCHES_STATFS64 = 1;
|
||||
|
||||
const int __FD_SETSIZE = 1024;
|
||||
|
||||
const int _BITS_TIME64_H = 1;
|
||||
|
||||
const int _BITS_WCHAR_H = 1;
|
||||
|
||||
const int __WCHAR_MAX = 2147483647;
|
||||
|
||||
const int __WCHAR_MIN = -2147483648;
|
||||
|
||||
const int _BITS_STDINT_INTN_H = 1;
|
||||
|
||||
const int _BITS_STDINT_UINTN_H = 1;
|
||||
|
||||
const int INT8_MIN = -128;
|
||||
|
||||
const int INT16_MIN = -32768;
|
||||
|
||||
const int INT32_MIN = -2147483648;
|
||||
|
||||
const int INT64_MIN = -9223372036854775808;
|
||||
|
||||
const int INT8_MAX = 127;
|
||||
|
||||
const int INT16_MAX = 32767;
|
||||
|
||||
const int INT32_MAX = 2147483647;
|
||||
|
||||
const int INT64_MAX = 9223372036854775807;
|
||||
|
||||
const int UINT8_MAX = 255;
|
||||
|
||||
const int UINT16_MAX = 65535;
|
||||
|
||||
const int UINT32_MAX = 4294967295;
|
||||
|
||||
const int UINT64_MAX = -1;
|
||||
|
||||
const int INT_LEAST8_MIN = -128;
|
||||
|
||||
const int INT_LEAST16_MIN = -32768;
|
||||
|
||||
const int INT_LEAST32_MIN = -2147483648;
|
||||
|
||||
const int INT_LEAST64_MIN = -9223372036854775808;
|
||||
|
||||
const int INT_LEAST8_MAX = 127;
|
||||
|
||||
const int INT_LEAST16_MAX = 32767;
|
||||
|
||||
const int INT_LEAST32_MAX = 2147483647;
|
||||
|
||||
const int INT_LEAST64_MAX = 9223372036854775807;
|
||||
|
||||
const int UINT_LEAST8_MAX = 255;
|
||||
|
||||
const int UINT_LEAST16_MAX = 65535;
|
||||
|
||||
const int UINT_LEAST32_MAX = 4294967295;
|
||||
|
||||
const int UINT_LEAST64_MAX = -1;
|
||||
|
||||
const int INT_FAST8_MIN = -128;
|
||||
|
||||
const int INT_FAST16_MIN = -9223372036854775808;
|
||||
|
||||
const int INT_FAST32_MIN = -9223372036854775808;
|
||||
|
||||
const int INT_FAST64_MIN = -9223372036854775808;
|
||||
|
||||
const int INT_FAST8_MAX = 127;
|
||||
|
||||
const int INT_FAST16_MAX = 9223372036854775807;
|
||||
|
||||
const int INT_FAST32_MAX = 9223372036854775807;
|
||||
|
||||
const int INT_FAST64_MAX = 9223372036854775807;
|
||||
|
||||
const int UINT_FAST8_MAX = 255;
|
||||
|
||||
const int UINT_FAST16_MAX = -1;
|
||||
|
||||
const int UINT_FAST32_MAX = -1;
|
||||
|
||||
const int UINT_FAST64_MAX = -1;
|
||||
|
||||
const int INTPTR_MIN = -9223372036854775808;
|
||||
|
||||
const int INTPTR_MAX = 9223372036854775807;
|
||||
|
||||
const int UINTPTR_MAX = -1;
|
||||
|
||||
const int INTMAX_MIN = -9223372036854775808;
|
||||
|
||||
const int INTMAX_MAX = 9223372036854775807;
|
||||
|
||||
const int UINTMAX_MAX = -1;
|
||||
|
||||
const int PTRDIFF_MIN = -9223372036854775808;
|
||||
|
||||
const int PTRDIFF_MAX = 9223372036854775807;
|
||||
|
||||
const int SIG_ATOMIC_MIN = -2147483648;
|
||||
|
||||
const int SIG_ATOMIC_MAX = 2147483647;
|
||||
|
||||
const int SIZE_MAX = -1;
|
||||
|
||||
const int WCHAR_MIN = -2147483648;
|
||||
|
||||
const int WCHAR_MAX = 2147483647;
|
||||
|
||||
const int WINT_MIN = 0;
|
||||
|
||||
const int WINT_MAX = 4294967295;
|
||||
198
lib/flutter_libsparkmobile_bindings_generated.dart
Normal file
198
lib/flutter_libsparkmobile_bindings_generated.dart
Normal file
@@ -0,0 +1,198 @@
|
||||
// ignore_for_file: always_specify_types
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
|
||||
// AUTO GENERATED FILE, DO NOT EDIT.
|
||||
//
|
||||
// Generated by `package:ffigen`.
|
||||
import 'dart:ffi' as ffi;
|
||||
|
||||
/// Bindings for `src/flutter_libsparkmobile.h`.
|
||||
///
|
||||
/// Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`.
|
||||
///
|
||||
class FlutterLibsparkmobileBindings {
|
||||
/// Holds the symbol lookup function.
|
||||
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
_lookup;
|
||||
|
||||
/// The symbols are looked up in [dynamicLibrary].
|
||||
FlutterLibsparkmobileBindings(ffi.DynamicLibrary dynamicLibrary)
|
||||
: _lookup = dynamicLibrary.lookup;
|
||||
|
||||
/// The symbols are looked up with [lookup].
|
||||
FlutterLibsparkmobileBindings.fromLookup(
|
||||
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
lookup)
|
||||
: _lookup = lookup;
|
||||
|
||||
/// FFI-friendly wrapper for spark::getAddress.
|
||||
ffi.Pointer<ffi.Char> getAddress(
|
||||
ffi.Pointer<ffi.Char> keyDataHex,
|
||||
int index,
|
||||
int diversifier,
|
||||
int isTestNet,
|
||||
) {
|
||||
return _getAddress(
|
||||
keyDataHex,
|
||||
index,
|
||||
diversifier,
|
||||
isTestNet,
|
||||
);
|
||||
}
|
||||
|
||||
late final _getAddressPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<ffi.Char> Function(
|
||||
ffi.Pointer<ffi.Char>, ffi.Int, ffi.Int, ffi.Int)>>('getAddress');
|
||||
late final _getAddress = _getAddressPtr.asFunction<
|
||||
ffi.Pointer<ffi.Char> Function(ffi.Pointer<ffi.Char>, int, int, int)>();
|
||||
|
||||
/// FFI-friendly wrapper for spark::identifyCoin.
|
||||
CIdentifiedCoinData identifyCoin(
|
||||
CCoin c_struct,
|
||||
ffi.Pointer<ffi.Char> keyDataHex,
|
||||
int index,
|
||||
) {
|
||||
return _identifyCoin(
|
||||
c_struct,
|
||||
keyDataHex,
|
||||
index,
|
||||
);
|
||||
}
|
||||
|
||||
late final _identifyCoinPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
CIdentifiedCoinData Function(
|
||||
CCoin, ffi.Pointer<ffi.Char>, ffi.Int)>>('identifyCoin');
|
||||
late final _identifyCoin = _identifyCoinPtr.asFunction<
|
||||
CIdentifiedCoinData Function(CCoin, ffi.Pointer<ffi.Char>, int)>();
|
||||
|
||||
/// FFI-friendly wrapper for spark::createSparkMintRecipients.
|
||||
ffi.Pointer<CCRecipient> createSparkMintRecipients(
|
||||
int numRecipients,
|
||||
ffi.Pointer<PubKeyScript> pubKeyScripts,
|
||||
ffi.Pointer<ffi.Uint64> amounts,
|
||||
ffi.Pointer<ffi.Char> memo,
|
||||
int subtractFee,
|
||||
) {
|
||||
return _createSparkMintRecipients(
|
||||
numRecipients,
|
||||
pubKeyScripts,
|
||||
amounts,
|
||||
memo,
|
||||
subtractFee,
|
||||
);
|
||||
}
|
||||
|
||||
late final _createSparkMintRecipientsPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<CCRecipient> Function(
|
||||
ffi.Int,
|
||||
ffi.Pointer<PubKeyScript>,
|
||||
ffi.Pointer<ffi.Uint64>,
|
||||
ffi.Pointer<ffi.Char>,
|
||||
ffi.Int)>>('createSparkMintRecipients');
|
||||
late final _createSparkMintRecipients =
|
||||
_createSparkMintRecipientsPtr.asFunction<
|
||||
ffi.Pointer<CCRecipient> Function(int, ffi.Pointer<PubKeyScript>,
|
||||
ffi.Pointer<ffi.Uint64>, ffi.Pointer<ffi.Char>, int)>();
|
||||
}
|
||||
|
||||
/// FFI-friendly wrapper for a spark::Coin.
|
||||
///
|
||||
/// A Coin is a type, a key, an index, a value, a memo, and a serial context. We accept these params
|
||||
/// as a C struct, deriving the key from the keyData and index.
|
||||
final class CCoin extends ffi.Struct {
|
||||
@ffi.Char()
|
||||
external int type;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> k;
|
||||
|
||||
@ffi.Int()
|
||||
external int kLength;
|
||||
|
||||
external ffi.Pointer<ffi.Char> keyData;
|
||||
|
||||
@ffi.Int()
|
||||
external int index;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int v;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> memo;
|
||||
|
||||
@ffi.Int()
|
||||
external int memoLength;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> serial_context;
|
||||
|
||||
@ffi.Int()
|
||||
external int serial_contextLength;
|
||||
}
|
||||
|
||||
/// FFI-friendly wrapper for a spark::IdentifiedCoinData.
|
||||
///
|
||||
/// An IdentifiedCoinData is a diversifier, encrypted diversifier, value, nonce, and memo. We accept
|
||||
/// these params as a C struct.
|
||||
final class CIdentifiedCoinData extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int i;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> d;
|
||||
|
||||
@ffi.Int()
|
||||
external int dLength;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int v;
|
||||
|
||||
external ffi.Pointer<ffi.UnsignedChar> k;
|
||||
|
||||
@ffi.Int()
|
||||
external int kLength;
|
||||
|
||||
external ffi.Pointer<ffi.Char> memo;
|
||||
|
||||
@ffi.Int()
|
||||
external int memoLength;
|
||||
}
|
||||
|
||||
/// FFI-friendly wrapper for a spark::CRecipient.
|
||||
///
|
||||
/// A CRecipient is a CScript, CAmount, and a bool. We accept a C-style, FFI-friendly CCRecipient
|
||||
/// struct in order to construct a C++ CRecipient. A CScript is constructed from a hex string, a
|
||||
/// CAmount is just a uint64_t, and the bool will be an int.
|
||||
final class CCRecipient extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.UnsignedChar> pubKey;
|
||||
|
||||
@ffi.Int()
|
||||
external int pubKeyLength;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int cAmount;
|
||||
|
||||
@ffi.Int()
|
||||
external int subtractFee;
|
||||
}
|
||||
|
||||
/// FFI-friendly wrapper for a spark::MintedCoinData.
|
||||
///
|
||||
/// A MintedCoinData is a struct that contains an Address, a uint64_t value, and a string memo. We
|
||||
/// accept these as a CMintedCoinData from the Dart interface, and convert them to a MintedCoinData
|
||||
/// struct.
|
||||
final class CMintedCoinData extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Char> address;
|
||||
|
||||
@ffi.Uint64()
|
||||
external int value;
|
||||
|
||||
external ffi.Pointer<ffi.Char> memo;
|
||||
}
|
||||
|
||||
final class PubKeyScript extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.UnsignedChar> bytes;
|
||||
|
||||
@ffi.Int()
|
||||
external int length;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'flutter_libsparkmobile_platform_interface.dart';
|
||||
|
||||
/// An implementation of [FlutterLibsparkmobilePlatform] that uses method channels.
|
||||
class MethodChannelFlutterLibsparkmobile extends FlutterLibsparkmobilePlatform {
|
||||
/// The method channel used to interact with the native platform.
|
||||
@visibleForTesting
|
||||
final methodChannel = const MethodChannel('flutter_libsparkmobile');
|
||||
|
||||
@override
|
||||
Future<String?> getPlatformVersion() async {
|
||||
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
|
||||
return version;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
|
||||
import 'flutter_libsparkmobile_method_channel.dart';
|
||||
|
||||
abstract class FlutterLibsparkmobilePlatform extends PlatformInterface {
|
||||
/// Constructs a FlutterLibsparkmobilePlatform.
|
||||
FlutterLibsparkmobilePlatform() : super(token: _token);
|
||||
|
||||
static final Object _token = Object();
|
||||
|
||||
static FlutterLibsparkmobilePlatform _instance = MethodChannelFlutterLibsparkmobile();
|
||||
|
||||
/// The default instance of [FlutterLibsparkmobilePlatform] to use.
|
||||
///
|
||||
/// Defaults to [MethodChannelFlutterLibsparkmobile].
|
||||
static FlutterLibsparkmobilePlatform get instance => _instance;
|
||||
|
||||
/// Platform-specific implementations should set this with their own
|
||||
/// platform-specific class that extends [FlutterLibsparkmobilePlatform] when
|
||||
/// they register themselves.
|
||||
static set instance(FlutterLibsparkmobilePlatform instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
Future<String?> getPlatformVersion() {
|
||||
throw UnimplementedError('platformVersion() has not been implemented.');
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
/*ANDROID_VERSION*/ const ANDROID_VERSION = "";
|
||||
/*IOS_VERSION*/ const IOS_VERSION = "";
|
||||
/*MACOS_VERSION*/ const MACOS_VERSION = "";
|
||||
/*LINUX_VERSION*/ const LINUX_VERSION = "";
|
||||
/*WINDOWS_VERSION*/ const WINDOWS_VERSION = "";
|
||||
|
||||
String getPluginVersion() {
|
||||
if (Platform.isAndroid) {
|
||||
return ANDROID_VERSION;
|
||||
} else if (Platform.isIOS) {
|
||||
return IOS_VERSION;
|
||||
} else if (Platform.isMacOS) {
|
||||
return MACOS_VERSION;
|
||||
} else if (Platform.isLinux) {
|
||||
return LINUX_VERSION;
|
||||
} else if (Platform.isWindows) {
|
||||
return WINDOWS_VERSION;
|
||||
} else {
|
||||
return "Unknown version";
|
||||
}
|
||||
}
|
||||
@@ -5,90 +5,20 @@ cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Project-level configuration.
|
||||
set(PROJECT_NAME "flutter_libsparkmobile")
|
||||
set(PROJECT_SYSTEM_NAME "linux")
|
||||
|
||||
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||
|
||||
# This value is used when generating builds using this plugin, so it must
|
||||
# not be changed.
|
||||
set(PLUGIN_NAME "flutter_libsparkmobile_plugin")
|
||||
|
||||
# Any new source files that you add to the plugin should be added here.
|
||||
list(APPEND PLUGIN_SOURCES
|
||||
"flutter_libsparkmobile_plugin.cc"
|
||||
)
|
||||
|
||||
# Define the plugin library target. Its name must not be changed (see comment
|
||||
# on PLUGIN_NAME above).
|
||||
add_library(${PLUGIN_NAME} SHARED
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
|
||||
# Apply a standard set of build settings that are configured in the
|
||||
# application-level CMakeLists.txt. This can be removed for plugins that want
|
||||
# full control over build settings.
|
||||
apply_standard_settings(${PLUGIN_NAME})
|
||||
|
||||
# Symbols are hidden by default to reduce the chance of accidental conflicts
|
||||
# between plugins. This should not be removed; any symbols that should be
|
||||
# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro.
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||
|
||||
# Source include directories and library dependencies. Add any plugin-specific
|
||||
# dependencies here.
|
||||
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)
|
||||
# Invoke the build for native code shared with the other target platforms.
|
||||
# This can be changed to accommodate different builds.
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared")
|
||||
|
||||
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||
# This list could contain prebuilt libraries, or libraries created by an
|
||||
# external build triggered from this build file.
|
||||
set(flutter_libsparkmobile_bundled_libraries
|
||||
""
|
||||
# Defined in ../src/CMakeLists.txt.
|
||||
# This can be changed to accommodate different builds.
|
||||
$<TARGET_FILE:flutter_libsparkmobile>
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
# === Tests ===
|
||||
# These unit tests can be run from a terminal after building the example.
|
||||
|
||||
# Only enable test builds when building the example (which sets this variable)
|
||||
# so that plugin clients aren't building the tests.
|
||||
if (${include_${PROJECT_NAME}_tests})
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
|
||||
message("Unit tests require CMake 3.11.0 or later")
|
||||
else()
|
||||
set(TEST_RUNNER "${PROJECT_NAME}_test")
|
||||
enable_testing()
|
||||
|
||||
# Add the Google Test dependency.
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/release-1.11.0.zip
|
||||
)
|
||||
# Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
# Disable install commands for gtest so it doesn't end up in the bundle.
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
# The plugin's exported API is not very useful for unit testing, so build the
|
||||
# sources directly into the test binary rather than using the shared library.
|
||||
add_executable(${TEST_RUNNER}
|
||||
test/flutter_libsparkmobile_plugin_test.cc
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
apply_standard_settings(${TEST_RUNNER})
|
||||
target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE flutter)
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK)
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock)
|
||||
|
||||
# Enable automatic test discovery.
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(${TEST_RUNNER})
|
||||
|
||||
endif() # CMake version check
|
||||
endif() # include_${PROJECT_NAME}_tests
|
||||
@@ -1,76 +0,0 @@
|
||||
#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h"
|
||||
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "flutter_libsparkmobile_plugin_private.h"
|
||||
|
||||
#define FLUTTER_LIBSPARKMOBILE_PLUGIN(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), flutter_libsparkmobile_plugin_get_type(), \
|
||||
FlutterLibsparkmobilePlugin))
|
||||
|
||||
struct _FlutterLibsparkmobilePlugin {
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FlutterLibsparkmobilePlugin, flutter_libsparkmobile_plugin, g_object_get_type())
|
||||
|
||||
// Called when a method call is received from Flutter.
|
||||
static void flutter_libsparkmobile_plugin_handle_method_call(
|
||||
FlutterLibsparkmobilePlugin* self,
|
||||
FlMethodCall* method_call) {
|
||||
g_autoptr(FlMethodResponse) response = nullptr;
|
||||
|
||||
const gchar* method = fl_method_call_get_name(method_call);
|
||||
|
||||
if (strcmp(method, "getPlatformVersion") == 0) {
|
||||
response = get_platform_version();
|
||||
} else {
|
||||
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
|
||||
}
|
||||
|
||||
fl_method_call_respond(method_call, response, nullptr);
|
||||
}
|
||||
|
||||
FlMethodResponse* get_platform_version() {
|
||||
struct utsname uname_data = {};
|
||||
uname(&uname_data);
|
||||
g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version);
|
||||
g_autoptr(FlValue) result = fl_value_new_string(version);
|
||||
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
|
||||
}
|
||||
|
||||
static void flutter_libsparkmobile_plugin_dispose(GObject* object) {
|
||||
G_OBJECT_CLASS(flutter_libsparkmobile_plugin_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void flutter_libsparkmobile_plugin_class_init(FlutterLibsparkmobilePluginClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = flutter_libsparkmobile_plugin_dispose;
|
||||
}
|
||||
|
||||
static void flutter_libsparkmobile_plugin_init(FlutterLibsparkmobilePlugin* self) {}
|
||||
|
||||
static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call,
|
||||
gpointer user_data) {
|
||||
FlutterLibsparkmobilePlugin* plugin = FLUTTER_LIBSPARKMOBILE_PLUGIN(user_data);
|
||||
flutter_libsparkmobile_plugin_handle_method_call(plugin, method_call);
|
||||
}
|
||||
|
||||
void flutter_libsparkmobile_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
|
||||
FlutterLibsparkmobilePlugin* plugin = FLUTTER_LIBSPARKMOBILE_PLUGIN(
|
||||
g_object_new(flutter_libsparkmobile_plugin_get_type(), nullptr));
|
||||
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
g_autoptr(FlMethodChannel) channel =
|
||||
fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
|
||||
"flutter_libsparkmobile",
|
||||
FL_METHOD_CODEC(codec));
|
||||
fl_method_channel_set_method_call_handler(channel, method_call_cb,
|
||||
g_object_ref(plugin),
|
||||
g_object_unref);
|
||||
|
||||
g_object_unref(plugin);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
|
||||
#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h"
|
||||
|
||||
// This file exposes some plugin internals for unit testing. See
|
||||
// https://github.com/flutter/flutter/issues/88724 for current limitations
|
||||
// in the unit-testable API.
|
||||
|
||||
// Handles the getPlatformVersion method call.
|
||||
FlMethodResponse *get_platform_version();
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_
|
||||
#define FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_
|
||||
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef FLUTTER_PLUGIN_IMPL
|
||||
#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define FLUTTER_PLUGIN_EXPORT
|
||||
#endif
|
||||
|
||||
typedef struct _FlutterLibsparkmobilePlugin FlutterLibsparkmobilePlugin;
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
} FlutterLibsparkmobilePluginClass;
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT GType flutter_libsparkmobile_plugin_get_type();
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void flutter_libsparkmobile_plugin_register_with_registrar(
|
||||
FlPluginRegistrar* registrar);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif // FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_
|
||||
@@ -1,31 +0,0 @@
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin.h"
|
||||
#include "flutter_libsparkmobile_plugin_private.h"
|
||||
|
||||
// This demonstrates a simple unit test of the C portion of this plugin's
|
||||
// implementation.
|
||||
//
|
||||
// Once you have built the plugin's example app, you can run these tests
|
||||
// from the command line. For instance, for a plugin called my_plugin
|
||||
// built for x64 debug, run:
|
||||
// $ build/linux/x64/debug/plugins/my_plugin/my_plugin_test
|
||||
|
||||
namespace flutter_libsparkmobile {
|
||||
namespace test {
|
||||
|
||||
TEST(FlutterLibsparkmobilePlugin, GetPlatformVersion) {
|
||||
g_autoptr(FlMethodResponse) response = get_platform_version();
|
||||
ASSERT_NE(response, nullptr);
|
||||
ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
|
||||
FlValue* result = fl_method_success_response_get_result(
|
||||
FL_METHOD_SUCCESS_RESPONSE(response));
|
||||
ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING);
|
||||
// The full string varies, so just validate that it has the right format.
|
||||
EXPECT_THAT(fl_value_get_string(result), testing::StartsWith("Linux "));
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace flutter_libsparkmobile
|
||||
@@ -1,19 +0,0 @@
|
||||
import Cocoa
|
||||
import FlutterMacOS
|
||||
|
||||
public class FlutterLibsparkmobilePlugin: NSObject, FlutterPlugin {
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "flutter_libsparkmobile", binaryMessenger: registrar.messenger)
|
||||
let instance = FlutterLibsparkmobilePlugin()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
}
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "getPlatformVersion":
|
||||
result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
3
macos/Classes/flutter_libsparkmobile.c
Normal file
3
macos/Classes/flutter_libsparkmobile.c
Normal file
@@ -0,0 +1,3 @@
|
||||
// Relative import to be able to reuse the C sources.
|
||||
// See the comment in ../{projectName}}.podspec for more information.
|
||||
#include flutter_libsparkmobile.cpp
|
||||
@@ -5,14 +5,18 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'flutter_libsparkmobile'
|
||||
s.version = '0.0.1'
|
||||
s.summary = 'A new Flutter plugin project.'
|
||||
s.summary = 'A new Flutter project.'
|
||||
s.description = <<-DESC
|
||||
A new Flutter plugin project.
|
||||
A new Flutter project.
|
||||
DESC
|
||||
s.homepage = 'http://example.com'
|
||||
s.license = { :file => '../LICENSE' }
|
||||
s.author = { 'Your Company' => 'email@example.com' }
|
||||
|
||||
# This will ensure the source files in Classes/ are included in the native
|
||||
# builds of apps using this FFI plugin. Podspec does not support relative
|
||||
# paths, so Classes contains a forwarder C file that relatively imports
|
||||
# `../src/*` so that the C sources can be shared among all target platforms.
|
||||
s.source = { :path => '.' }
|
||||
s.source_files = 'Classes/**/*'
|
||||
s.dependency 'FlutterMacOS'
|
||||
|
||||
31
pubspec.yaml
31
pubspec.yaml
@@ -1,5 +1,5 @@
|
||||
name: flutter_libsparkmobile
|
||||
description: A new Flutter plugin project.
|
||||
description: Flutter Sparkmobile ffi wrapper
|
||||
version: 0.0.1
|
||||
homepage:
|
||||
|
||||
@@ -12,14 +12,12 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.0.2
|
||||
test: ^1.24.1
|
||||
typed_data: ^1.3.2
|
||||
|
||||
dev_dependencies:
|
||||
ffigen: ^6.1.2
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
ffigen: ^9.0.1
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
@@ -36,19 +34,20 @@ flutter:
|
||||
# This is required for using `dart:ffi`.
|
||||
# All these are used by the tooling to maintain consistency when
|
||||
# adding or updating assets for this project.
|
||||
#
|
||||
# Please refer to README.md for a detailed explanation.
|
||||
plugin:
|
||||
platforms:
|
||||
android:
|
||||
package: com.cypherstack.flutter_libsparkmobile
|
||||
pluginClass: FlutterLibsparkmobilePlugin
|
||||
ffiPlugin: true
|
||||
ios:
|
||||
pluginClass: FlutterLibsparkmobilePlugin
|
||||
ffiPlugin: true
|
||||
linux:
|
||||
pluginClass: FlutterLibsparkmobilePlugin
|
||||
ffiPlugin: true
|
||||
macos:
|
||||
pluginClass: FlutterLibsparkmobilePlugin
|
||||
ffiPlugin: true
|
||||
windows:
|
||||
pluginClass: FlutterLibsparkmobilePluginCApi
|
||||
ffiPlugin: true
|
||||
|
||||
# To add assets to your plugin package, add an assets section, like this:
|
||||
# assets:
|
||||
@@ -80,15 +79,3 @@ flutter:
|
||||
#
|
||||
# For details regarding fonts in packages, see
|
||||
# https://flutter.dev/custom-fonts/#from-packages
|
||||
|
||||
ffigen:
|
||||
name: SparkMobileBindings
|
||||
description: Bindings for sparkmobile.
|
||||
language: c
|
||||
output: 'lib/flutter_libsparkmobile_bindings.dart'
|
||||
headers:
|
||||
entry-points:
|
||||
- 'sparkmobile/src/dart_interface.h'
|
||||
# copyCMakeLists.sh creates this header, see build_all.sh.
|
||||
preamble: |
|
||||
// ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_api
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
set -e
|
||||
|
||||
./build_openssl.sh
|
||||
./build_sharedfile.sh
|
||||
|
||||
|
||||
|
||||
@@ -2,67 +2,66 @@
|
||||
|
||||
set -e
|
||||
|
||||
export WORKDIR="$(pwd)/../../src/build/linux"
|
||||
export ORIGINAL_PATH=$PATH
|
||||
export THREADS=16
|
||||
export TYPES_OF_BUILD="x86_64"
|
||||
|
||||
if [ -z "$IS_ARM" ]; then
|
||||
TYPES_OF_BUILD="x86_64"
|
||||
export TYPES_OF_BUILD="x86_64"
|
||||
else
|
||||
TYPES_OF_BUILD="aarch64"
|
||||
export TYPES_OF_BUILD="aarch64"
|
||||
fi
|
||||
THREADS=16
|
||||
|
||||
WORKDIR="$(pwd)/"build
|
||||
CACHEDIR="$(pwd)/"cache
|
||||
mkdir -p $CACHEDIR
|
||||
if [ ! -d "$WORKDIR" ] ; then
|
||||
mkdir -p "$WORKDIR"
|
||||
fi
|
||||
|
||||
OPENSSL_FILENAME=openssl-1.1.1k.tar.gz
|
||||
OPENSSL_FILE_PATH=$CACHEDIR/$OPENSSL_FILENAME
|
||||
OPENSSL_SRC_DIR=$WORKDIR/openssl-1.1.1k
|
||||
|
||||
OPENSSL_FILENAME="openssl-1.1.1k.tar.gz"
|
||||
OPENSSL_FILE_PATH="$WORKDIR/$OPENSSL_FILENAME"
|
||||
OPENSSL_SRC_DIR="$WORKDIR/openssl-1.1.1k"
|
||||
OPENSSL_SHA256="892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5"
|
||||
|
||||
ZLIB_DIR=$WORKDIR/zlib
|
||||
ZLIB_TAG=v1.2.11
|
||||
ZLIB_DIR="$WORKDIR/zlib"
|
||||
ZLIB_TAG="v1.2.11"
|
||||
ZLIB_COMMIT_HASH="cacf7f1d4e3d44d871b605da3b647f07d718623f"
|
||||
|
||||
# If a zlib dir exists, we assume that it's already been built.
|
||||
# TODO make a better zlib-validity check.
|
||||
|
||||
if [ ! -d "$ZLIB_DIR" ] ; then
|
||||
git clone -b $ZLIB_TAG --depth 1 https://github.com/madler/zlib $ZLIB_DIR
|
||||
cd $ZLIB_DIR
|
||||
git reset --hard $ZLIB_COMMIT_HASH
|
||||
./configure --static
|
||||
make
|
||||
fi
|
||||
cd $ZLIB_DIR
|
||||
git reset --hard $ZLIB_COMMIT_HASH
|
||||
./configure --static
|
||||
make
|
||||
|
||||
# Download openssl if it doesn't exist.
|
||||
curl https://www.openssl.org/source/$OPENSSL_FILENAME -o $OPENSSL_FILE_PATH
|
||||
|
||||
# Validate checksum.
|
||||
echo $OPENSSL_SHA256 $OPENSSL_FILE_PATH | sha256sum -c - || exit 1
|
||||
|
||||
# Build openssl for each arch.
|
||||
for arch in $TYPES_OF_BUILD
|
||||
do
|
||||
echo "Building $TYPES_OF_BUILD"
|
||||
PREFIX=$WORKDIR/prefix_${arch}
|
||||
echo "Building $TYPES_OF_BUILD"
|
||||
PREFIX=$WORKDIR/prefix_${arch}
|
||||
|
||||
case $arch in
|
||||
"x86_64") X_ARCH="linux-x86_64";;
|
||||
"aarch64") X_ARCH="linux-aarch64";;
|
||||
*) X_ARCH="linux-x86_64";;
|
||||
esac
|
||||
case $arch in
|
||||
"x86_64") X_ARCH="linux-x86_64";;
|
||||
"aarch64") X_ARCH="linux-aarch64";;
|
||||
*) X_ARCH="linux-x86_64";;
|
||||
esac
|
||||
|
||||
cd $WORKDIR
|
||||
# Don't delete the openssl source dir. We don't need clean builds every time.
|
||||
# rm -rf $OPENSSL_SRC_DIR
|
||||
tar -xzf $OPENSSL_FILE_PATH -C $WORKDIR
|
||||
cd $OPENSSL_SRC_DIR
|
||||
cd $WORKDIR
|
||||
rm -rf $OPENSSL_SRC_DIR
|
||||
tar -xzf $OPENSSL_FILE_PATH -C $WORKDIR
|
||||
cd $OPENSSL_SRC_DIR
|
||||
|
||||
./Configure ${X_ARCH} \
|
||||
no-asm no-shared \
|
||||
--with-zlib-include=${PREFIX}/include \
|
||||
--with-zlib-lib=${PREFIX}/lib \
|
||||
--prefix=${PREFIX} \
|
||||
--openssldir=${PREFIX}
|
||||
make -j$THREADS
|
||||
make -j$THREADS install_sw
|
||||
|
||||
#sed -i -e "s/mandroid/target\ ${TARGET}\-linux\-android/" Configure
|
||||
./Configure ${X_ARCH} \
|
||||
no-asm no-shared \
|
||||
--with-zlib-include=${PREFIX}/include \
|
||||
--with-zlib-lib=${PREFIX}/lib \
|
||||
--prefix=${PREFIX} \
|
||||
--openssldir=${PREFIX}
|
||||
make -j$THREADS
|
||||
make -j$THREADS install_sw
|
||||
done
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copy the sparkmobile submodule to the build directory for interfacing to Dart.
|
||||
#
|
||||
# We copy the fresh and unmodified sparkmobile submodule to the build directory in order to graft
|
||||
# an additional Dart interface onto the sparkmobile library.
|
||||
cp -r ../../sparkmobile .
|
||||
|
||||
WORKDIR="$(pwd)/build"
|
||||
SEDWORKDIR=$(echo $WORKDIR | sed 's/\//\\\//g')
|
||||
|
||||
# Create new CMakelists.txt files for the sparkmobile and secp256k1 directories.
|
||||
#
|
||||
# Copy the template CMakelists.txt files to the working sparkmobile directory and replace the
|
||||
# distribution_DIR variable with the working directory.
|
||||
sed "s/SET(distribution_DIR \/opt\/android)/SET(distribution_DIR $SEDWORKDIR)/g" ./CMakeLists/sparkmobile/template_CMakeLists.txt > ./CMakeLists/sparkmobile/CMakeLists.txt
|
||||
sed "s/SET(distribution_DIR \/opt\/android)/SET(distribution_DIR $SEDWORKDIR)/g" ./CMakeLists/secp256k1/template_CMakeLists.txt > ./CMakeLists/secp256k1/CMakeLists.txt
|
||||
|
||||
# Copy the sparkmobile and secp256k1 CMakeLists.txts.
|
||||
cp CMakeLists/sparkmobile/CMakeLists.txt sparkmobile/
|
||||
cp CMakeLists/secp256k1/CMakeLists.txt sparkmobile/secp256k1/
|
||||
|
||||
# Git versioning.
|
||||
echo ''$(git log -1 --pretty=format:"%H")' '$(date) >> build/git_commit_version.txt
|
||||
VERSIONS_FILE=../../lib/git_versions.dart
|
||||
EXAMPLE_VERSIONS_FILE=../../lib/git_versions_example.dart
|
||||
if [ ! -f "$VERSIONS_FILE" ]; then
|
||||
cp $EXAMPLE_VERSIONS_FILE $VERSIONS_FILE
|
||||
fi
|
||||
COMMIT=$(git log -1 --pretty=format:"%H")
|
||||
OS="LINUX"
|
||||
|
||||
# Write the commit hash to the versions file.
|
||||
sed -i "/\/\*${OS}_VERSION/c\\/\*${OS}_VERSION\*\/ const ${OS}_VERSION = \"$COMMIT\";" $VERSIONS_FILE
|
||||
|
||||
# Build the shared library.
|
||||
cd build
|
||||
cmake ../sparkmobile
|
||||
make -j$(nproc)
|
||||
17
scripts/prebuild.sh
Executable file
17
scripts/prebuild.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd ../src/deps
|
||||
|
||||
if [ -d sparkmobile ]; then
|
||||
rm -rf sparkmobile
|
||||
fi
|
||||
|
||||
git clone https://github.com/firoorg/sparkmobile.git
|
||||
cd sparkmobile
|
||||
git checkout ef2e39aae18ecc49e0ddc63a3183e9764b96012e
|
||||
|
||||
cd ..
|
||||
cp CMakeLists/sparkmobile/CMakeLists.txt sparkmobile/
|
||||
cp CMakeLists/secp256k1/CMakeLists.txt sparkmobile/secp256k1/
|
||||
Submodule sparkmobile deleted from fe2148f01b
26
src/CMakeLists.txt
Normal file
26
src/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
# The Flutter tooling requires that developers have CMake 3.10 or later
|
||||
# installed. You should not increase this version, as doing so will cause
|
||||
# the plugin to fail to compile for some customers of the plugin.
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(flutter_libsparkmobile_library VERSION 0.0.1)
|
||||
|
||||
SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
|
||||
|
||||
|
||||
|
||||
add_library(flutter_libsparkmobile SHARED
|
||||
"flutter_libsparkmobile.cpp"
|
||||
"utils.cpp"
|
||||
)
|
||||
|
||||
add_subdirectory("deps/sparkmobile")
|
||||
|
||||
set_target_properties(flutter_libsparkmobile PROPERTIES
|
||||
PUBLIC_HEADER flutter_libsparkmobile.h
|
||||
OUTPUT_NAME "flutter_libsparkmobile"
|
||||
)
|
||||
|
||||
target_link_libraries(flutter_libsparkmobile sparkmobile)
|
||||
|
||||
target_compile_definitions(flutter_libsparkmobile PUBLIC DART_SHARED_LIB)
|
||||
7
src/cmake/FindGMP.cmake
Normal file
7
src/cmake/FindGMP.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
find_path(GMP_INCLUDE_DIRS NAMES gmp.h)
|
||||
find_library(GMP_LIBRARY NAMES gmp libgmp)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GMP DEFAULT_MSG
|
||||
GMP_INCLUDE_DIRS
|
||||
GMP_LIBRARY)
|
||||
mark_as_advanced(GMP_INCLUDE_DIRS GMP_LIBRARY)
|
||||
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) 2017 The Bitcoin developers
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(secp256k1)
|
||||
project(secp256k1_spark)
|
||||
|
||||
SET(distribution_DIR /opt/android)
|
||||
SET(distribution_DIR "../../../build/${BUILD_FOR_SYSTEM_NAME}")
|
||||
SET(OPENSSL_ROOT_DIR ${distribution_DIR}/prefix_${ANDROID_ABI})
|
||||
|
||||
SET(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
||||
@@ -22,14 +22,14 @@ LINK_DIRECTORIES(${OPENSSL_LIBRARIES_DIR})
|
||||
# TODO: change this to include when possible
|
||||
include_directories(. include src/modules/ecdh src)
|
||||
|
||||
add_library(secp256k1 src/secp256k1.c src/cpp/GroupElement.cpp src/cpp/MultiExponent.cpp src/cpp/Scalar.cpp src/modules/ecdh/main_impl.h include/secp256k1_ecdh.h src/scratch_impl.h src/scratch.h)
|
||||
add_library(secp256k1_spark src/secp256k1.c src/cpp/GroupElement.cpp src/cpp/MultiExponent.cpp src/cpp/Scalar.cpp src/modules/ecdh/main_impl.h include/secp256k1_ecdh.h src/scratch_impl.h src/scratch.h)
|
||||
|
||||
# We need to link in GMP
|
||||
find_package(GMP)
|
||||
if(GMP_INCLUDE_DIR AND GMP_LIBRARIES)
|
||||
target_include_directories(secp256k1 PUBLIC ${GMP_INCLUDE_DIR})
|
||||
target_link_libraries(secp256k1 ${GMP_LIBRARIES})
|
||||
target_compile_definitions(secp256k1
|
||||
target_link_libraries(secp256k1_spark ${GMP_LIBRARIES})
|
||||
target_compile_definitions(secp256k1_spark
|
||||
PUBLIC
|
||||
HAVE_LIBGMP
|
||||
USE_NUM_GMP
|
||||
@@ -37,7 +37,7 @@ if(GMP_INCLUDE_DIR AND GMP_LIBRARIES)
|
||||
USE_SCALAR_INV_BUILTIN
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(secp256k1
|
||||
target_compile_definitions(secp256k1_spark
|
||||
PUBLIC
|
||||
USE_NUM_NONE
|
||||
USE_FIELD_INV_BUILTIN
|
||||
@@ -49,7 +49,7 @@ endif()
|
||||
include(CheckTypeSize)
|
||||
check_type_size(__int128 SIZEOF___INT128)
|
||||
if(SIZEOF___INT128 EQUAL 16)
|
||||
target_compile_definitions(secp256k1 PUBLIC HAVE___INT128)
|
||||
target_compile_definitions(secp256k1_spark PUBLIC HAVE___INT128)
|
||||
else()
|
||||
# If we do not support __int128, we should be falling back
|
||||
# on 32bits implementations for field and scalar.
|
||||
@@ -64,17 +64,17 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message(SEND_ERROR "Compiler does not support __int128")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(secp256k1 PUBLIC USE_SCALAR_4X64)
|
||||
target_compile_definitions(secp256k1 PUBLIC USE_FIELD_5X52)
|
||||
target_compile_definitions(secp256k1_spark PUBLIC USE_SCALAR_4X64)
|
||||
target_compile_definitions(secp256k1_spark PUBLIC USE_FIELD_5X52)
|
||||
else()
|
||||
target_compile_definitions(secp256k1 PUBLIC USE_SCALAR_8X32)
|
||||
target_compile_definitions(secp256k1 PUBLIC USE_FIELD_10X26)
|
||||
target_compile_definitions(secp256k1_spark PUBLIC USE_SCALAR_8X32)
|
||||
target_compile_definitions(secp256k1_spark PUBLIC USE_FIELD_10X26)
|
||||
endif()
|
||||
|
||||
|
||||
# TODO: emult static precomputation
|
||||
# TODO: ecdh module
|
||||
# TODO: RECOVERY module
|
||||
TARGET_INCLUDE_DIRECTORIES(secp256k1 PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
TARGET_LINK_LIBRARIES(secp256k1 ${OPENSSL_LIBRARIES})
|
||||
#target_link_libraries(secp256k1 ${OPENSSL_LIBRARIES})
|
||||
TARGET_INCLUDE_DIRECTORIES(secp256k1_spark PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
TARGET_LINK_LIBRARIES(secp256k1_spark ${OPENSSL_LIBRARIES})
|
||||
#target_link_libraries(secp256k1_spark ${OPENSSL_LIBRARIES})
|
||||
@@ -4,7 +4,7 @@ project(sparkmobile)
|
||||
|
||||
set(OPENSSL_USE_STATIC_LIBS OFF CACHE BOOL "" FORCE)
|
||||
|
||||
SET(distribution_DIR /opt/android)
|
||||
SET(distribution_DIR "../../build/${BUILD_FOR_SYSTEM_NAME}")
|
||||
SET(OPENSSL_ROOT_DIR ${distribution_DIR}/prefix_${ANDROID_ABI})
|
||||
|
||||
SET(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
||||
@@ -42,9 +42,7 @@ set_property(SOURCE src/spark.cpp
|
||||
src/schnorr.cpp
|
||||
src/spend_transaction.cpp
|
||||
src/transcript.cpp
|
||||
src/util.cpp
|
||||
src/utils.cpp
|
||||
src/dart_interface.cpp
|
||||
src/util.cpp
|
||||
PROPERTY COMPILE_FLAGS "-std=c++17" )
|
||||
|
||||
add_library(sparkmobile SHARED
|
||||
@@ -75,12 +73,10 @@ add_library(sparkmobile SHARED
|
||||
src/schnorr.cpp
|
||||
src/spend_transaction.cpp
|
||||
src/transcript.cpp
|
||||
src/util.cpp
|
||||
src/utils.cpp
|
||||
src/dart_interface.cpp)
|
||||
src/util.cpp)
|
||||
|
||||
target_link_libraries(sparkmobile ${OPENSSL_LIBRARIES} secp256k1)
|
||||
target_link_libraries(sparkmobile ${OPENSSL_LIBRARIES} secp256k1_spark)
|
||||
|
||||
add_dependencies(sparkmobile secp256k1)
|
||||
add_dependencies(sparkmobile secp256k1_spark)
|
||||
|
||||
target_include_directories(sparkmobile PUBLIC secp256k1 ${OPENSSL_INCLUDE_DIR})
|
||||
target_include_directories(sparkmobile PUBLIC secp256k1_spark ${OPENSSL_INCLUDE_DIR})
|
||||
111
src/flutter_libsparkmobile.cpp
Normal file
111
src/flutter_libsparkmobile.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "flutter_libsparkmobile.h"
|
||||
#include "utils.h"
|
||||
#include "deps/sparkmobile/include/spark.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream> // Just for printing.
|
||||
|
||||
using namespace spark;
|
||||
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for spark::getAddress.
|
||||
*/
|
||||
FFI_PLUGIN_EXPORT
|
||||
const char* getAddress(const char* keyDataHex, int index, int diversifier, int isTestNet) {
|
||||
try {
|
||||
// Use the hex string directly to create the SpendKey.
|
||||
spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index);
|
||||
|
||||
spark::FullViewKey fullViewKey(spendKey);
|
||||
spark::IncomingViewKey incomingViewKey(fullViewKey);
|
||||
spark::Address address(incomingViewKey, static_cast<uint64_t>(diversifier));
|
||||
|
||||
// Encode the Address object into a string using the appropriate network.
|
||||
std::string encodedAddress = address.encode(isTestNet ? spark::ADDRESS_NETWORK_TESTNET : spark::ADDRESS_NETWORK_MAINNET);
|
||||
|
||||
// Allocate memory for the C-style string.
|
||||
char* cstr = new char[encodedAddress.length() + 1];
|
||||
std::strcpy(cstr, encodedAddress.c_str());
|
||||
|
||||
return cstr;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for spark:identifyCoin.
|
||||
*
|
||||
* Uses the utility functions spark::Coin fromFFI(const CCoin& c_struct) to pass parameters to the
|
||||
* C++ function spark::identifyCoin(const Coin& coin), then uses the utility function
|
||||
* CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct) to convert the result back
|
||||
* to a C struct.
|
||||
*
|
||||
* We also need the incoming view key or we need to derive it, so accept keyDataHex and index.
|
||||
*/
|
||||
FFI_PLUGIN_EXPORT
|
||||
struct CIdentifiedCoinData identifyCoin(struct CCoin c_struct, const char* keyDataHex, int index) {
|
||||
try {
|
||||
spark::Coin coin = fromFFI(c_struct);
|
||||
|
||||
// Derive the incoming view key from the key data and index.
|
||||
spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index);
|
||||
spark::FullViewKey fullViewKey(spendKey);
|
||||
spark::IncomingViewKey incomingViewKey(fullViewKey);
|
||||
|
||||
spark::IdentifiedCoinData identifiedCoinData = coin.identify(incomingViewKey);
|
||||
return toFFI(identifiedCoinData);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return CIdentifiedCoinData();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for spark::createSparkMintRecipients.
|
||||
*/
|
||||
FFI_PLUGIN_EXPORT
|
||||
struct CCRecipient* createSparkMintRecipients(
|
||||
int numRecipients,
|
||||
struct PubKeyScript* pubKeyScripts,
|
||||
uint64_t* amounts,
|
||||
const char* memo,
|
||||
int subtractFee)
|
||||
{
|
||||
try {
|
||||
std::vector<CRecipient> recipients;
|
||||
|
||||
for (int i = 0; i < numRecipients; i++) {
|
||||
CScript scriptPubKey = createCScriptFromBytes(
|
||||
pubKeyScripts[i].bytes,
|
||||
pubKeyScripts[i].length
|
||||
);
|
||||
|
||||
CRecipient recipient;
|
||||
recipient.pubKey = scriptPubKey;
|
||||
|
||||
recipient.amount = amounts[i];
|
||||
|
||||
recipient.subtractFeeFromAmount = (bool)subtractFee;
|
||||
|
||||
recipients.push_back(recipient);
|
||||
}
|
||||
|
||||
std::vector<CCRecipient> ccRecipients;
|
||||
|
||||
for (const CRecipient& recipient : recipients) {
|
||||
CCRecipient ccRecipient = toFFI(recipient);
|
||||
ccRecipients.push_back(ccRecipient);
|
||||
}
|
||||
|
||||
CCRecipient* result = new CCRecipient[numRecipients];
|
||||
std::copy(ccRecipients.begin(), ccRecipients.end(), result);
|
||||
|
||||
return result;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
118
src/flutter_libsparkmobile.h
Normal file
118
src/flutter_libsparkmobile.h
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
#ifndef ORG_FIRO_SPARK_DART_INTERFACE_H
|
||||
#define ORG_FIRO_SPARK_DART_INTERFACE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef FFI_PLUGIN_EXPORT
|
||||
#ifdef __cplusplus
|
||||
#define FFI_PLUGIN_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used))
|
||||
#else
|
||||
#define FFI_PLUGIN_EXPORT __attribute__((visibility("default"))) __attribute__((used))
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#define FFI_PLUGIN_EXPORT __declspec(dllexport)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for spark::getAddress.
|
||||
*/
|
||||
FFI_PLUGIN_EXPORT
|
||||
const char* getAddress(const char* keyDataHex, int index, int diversifier, int isTestNet);
|
||||
|
||||
/*
|
||||
FFI_PLUGIN_EXPORT
|
||||
const char *createFullViewKey(const char* keyData, int index);
|
||||
|
||||
FFI_PLUGIN_EXPORT
|
||||
const char* createIncomingViewKey(const char* keyData, int index);
|
||||
*/
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for a spark::Coin.
|
||||
*
|
||||
* A Coin is a type, a key, an index, a value, a memo, and a serial context. We accept these params
|
||||
* as a C struct, deriving the key from the keyData and index.
|
||||
*/
|
||||
struct CCoin {
|
||||
char type;
|
||||
const unsigned char* k;
|
||||
int kLength;
|
||||
const char* keyData;
|
||||
int index;
|
||||
uint64_t v;
|
||||
const unsigned char* memo;
|
||||
int memoLength;
|
||||
const unsigned char* serial_context;
|
||||
int serial_contextLength;
|
||||
};
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for a spark::IdentifiedCoinData.
|
||||
*
|
||||
* An IdentifiedCoinData is a diversifier, encrypted diversifier, value, nonce, and memo. We accept
|
||||
* these params as a C struct.
|
||||
*/
|
||||
struct CIdentifiedCoinData {
|
||||
uint64_t i;
|
||||
const unsigned char* d;
|
||||
int dLength;
|
||||
uint64_t v;
|
||||
const unsigned char* k;
|
||||
int kLength;
|
||||
const char* memo;
|
||||
int memoLength;
|
||||
};
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for spark::identifyCoin.
|
||||
*/
|
||||
FFI_PLUGIN_EXPORT
|
||||
struct CIdentifiedCoinData identifyCoin(struct CCoin c_struct, const char* keyDataHex, int index);
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for a spark::CRecipient.
|
||||
*
|
||||
* A CRecipient is a CScript, CAmount, and a bool. We accept a C-style, FFI-friendly CCRecipient
|
||||
* struct in order to construct a C++ CRecipient. A CScript is constructed from a hex string, a
|
||||
* CAmount is just a uint64_t, and the bool will be an int.
|
||||
*/
|
||||
struct CCRecipient {
|
||||
const unsigned char* pubKey;
|
||||
int pubKeyLength;
|
||||
uint64_t cAmount;
|
||||
int subtractFee;
|
||||
};
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for a spark::MintedCoinData.
|
||||
*
|
||||
* A MintedCoinData is a struct that contains an Address, a uint64_t value, and a string memo. We
|
||||
* accept these as a CMintedCoinData from the Dart interface, and convert them to a MintedCoinData
|
||||
* struct.
|
||||
*/
|
||||
struct CMintedCoinData {
|
||||
const char* address;
|
||||
uint64_t value;
|
||||
const char* memo;
|
||||
};
|
||||
|
||||
struct PubKeyScript {
|
||||
unsigned char* bytes;
|
||||
int length;
|
||||
};
|
||||
|
||||
/*
|
||||
* FFI-friendly wrapper for spark::createSparkMintRecipients.
|
||||
*/
|
||||
FFI_PLUGIN_EXPORT
|
||||
struct CCRecipient* createSparkMintRecipients(
|
||||
int numRecipients,
|
||||
struct PubKeyScript* pubKeyScripts,
|
||||
uint64_t* amounts,
|
||||
const char* memo,
|
||||
int subtractFee);
|
||||
|
||||
#endif //ORG_FIRO_SPARK_DART_INTERFACE_H
|
||||
318
src/utils.cpp
Normal file
318
src/utils.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
#include "utils.h"
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
#include "flutter_libsparkmobile.h"
|
||||
#include "deps/sparkmobile/src/coin.h"
|
||||
#include "deps/sparkmobile/src/keys.h"
|
||||
#include "deps/sparkmobile//bitcoin/script.h" // For CScript.
|
||||
|
||||
/*
|
||||
* Utility function to generate an address from keyData, index, and a diversifier.
|
||||
*/
|
||||
const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier) {
|
||||
try {
|
||||
spark::SpendKey spendKey = createSpendKeyFromData(keyData, index);
|
||||
spark::FullViewKey fullViewKey(spendKey);
|
||||
spark::IncomingViewKey incomingViewKey(fullViewKey);
|
||||
spark::Address address(incomingViewKey, diversifier);
|
||||
|
||||
// Encode the Address object into a string.
|
||||
std::string encodedAddress = address.encode(spark::ADDRESS_NETWORK_TESTNET);
|
||||
|
||||
// Allocate memory for the C-style string and return it.
|
||||
char* result = new char[encodedAddress.size() + 1];
|
||||
std::copy(encodedAddress.begin(), encodedAddress.end(), result);
|
||||
result[encodedAddress.size()] = '\0'; // Null-terminate the C string.
|
||||
|
||||
return result;
|
||||
} catch (const std::exception& e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to generate SpendKey from keyData and index.
|
||||
*/
|
||||
spark::SpendKey createSpendKeyFromData(const char *keyData, int index) {
|
||||
try {
|
||||
// Convert the keyData from hex string to binary
|
||||
unsigned char* key_data_bin = hexToBytes(keyData);
|
||||
|
||||
const SpendKeyData *data = new SpendKeyData(key_data_bin, index);
|
||||
|
||||
return createSpendKey(*data);
|
||||
} catch (const std::exception& e) {
|
||||
// We can't return here, so just throw the exception again.
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CCoin factory.
|
||||
*
|
||||
* TODO manage the memory allocated by this function.
|
||||
*/
|
||||
struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* keyData, int index, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength) {
|
||||
CCoin coin;
|
||||
coin.type = type;
|
||||
coin.k = copyBytes(k, kLength);
|
||||
coin.kLength = kLength;
|
||||
coin.keyData = strdup(keyData);
|
||||
coin.index = index;
|
||||
coin.v = v;
|
||||
coin.memo = copyBytes(memo, memoLength);
|
||||
coin.memoLength = memoLength;
|
||||
coin.serial_context = copyBytes(serial_context, serial_contextLength);
|
||||
coin.serial_contextLength = serial_contextLength;
|
||||
return coin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert an FFI-friendly C CCoin struct to a C++ Coin struct.
|
||||
*/
|
||||
spark::Coin fromFFI(const CCoin& c_struct) {
|
||||
spark::Coin cpp_struct(
|
||||
// The test params are only used for unit tests.
|
||||
spark::Params::get_default(),
|
||||
c_struct.type,
|
||||
spark::Scalar(c_struct.k),
|
||||
spark::Address(spark::IncomingViewKey(spark::FullViewKey(createSpendKeyFromData(c_struct.keyData, c_struct.index))), c_struct.index),
|
||||
c_struct.v,
|
||||
std::string(reinterpret_cast<const char*>(c_struct.memo), c_struct.memoLength),
|
||||
std::vector<unsigned char>(c_struct.serial_context, c_struct.serial_context + c_struct.serial_contextLength)
|
||||
);
|
||||
|
||||
return cpp_struct;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert a C++ IdentifiedCoinData struct to an FFI-friendly struct.
|
||||
*/
|
||||
CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct) {
|
||||
CIdentifiedCoinData c_struct;
|
||||
|
||||
c_struct.i = cpp_struct.i;
|
||||
c_struct.d = copyBytes(cpp_struct.d.data(), cpp_struct.d.size());
|
||||
c_struct.dLength = cpp_struct.d.size();
|
||||
c_struct.v = cpp_struct.v;
|
||||
|
||||
// Serialize and copy the Scalar k.
|
||||
std::vector<unsigned char> scalarBytes(32);
|
||||
cpp_struct.k.serialize(scalarBytes.data());
|
||||
c_struct.k = copyBytes(scalarBytes.data(), scalarBytes.size());
|
||||
c_struct.kLength = scalarBytes.size();
|
||||
|
||||
// Copy the memo.
|
||||
c_struct.memo = strdup(cpp_struct.memo.c_str());
|
||||
c_struct.memoLength = cpp_struct.memo.size();
|
||||
|
||||
return c_struct;
|
||||
}
|
||||
|
||||
/*
|
||||
* Factory function to create a CScript from a byte array.
|
||||
*/
|
||||
CScript createCScriptFromBytes(const unsigned char* bytes, int length) {
|
||||
// Construct a CScript object
|
||||
CScript script;
|
||||
|
||||
// Check if bytes is not nullptr and length is positive
|
||||
if (bytes != nullptr && length > 0) {
|
||||
// Append each byte to the script
|
||||
for (int i = 0; i < length; ++i) {
|
||||
script << bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert a C++ CScript to a byte array.
|
||||
*/
|
||||
std::vector<unsigned char> serializeCScript(const CScript& script) {
|
||||
return std::vector<unsigned char>(script.begin(), script.end());
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert an FFI-friendly C CCRecipient struct to a C++ CRecipient struct.
|
||||
*/
|
||||
CRecipient fromFFI(const CCRecipient& c_struct) {
|
||||
// Use the factory function to create a CScript object.
|
||||
CScript script = createCScriptFromBytes(c_struct.pubKey, c_struct.pubKeyLength);
|
||||
|
||||
CRecipient cpp_struct = createCRecipient(
|
||||
script,
|
||||
c_struct.cAmount,
|
||||
static_cast<bool>(c_struct.subtractFee)
|
||||
);
|
||||
|
||||
return cpp_struct;
|
||||
}
|
||||
|
||||
/*
|
||||
* CCRecipient factory.
|
||||
*
|
||||
* TODO manage the memory allocated by this function.
|
||||
*/
|
||||
struct CCRecipient createCCRecipient(const unsigned char* pubKey, uint64_t amount, int subtractFee) {
|
||||
CCRecipient recipient;
|
||||
recipient.pubKey = copyBytes(pubKey, 32);
|
||||
recipient.cAmount = amount;
|
||||
recipient.subtractFee = subtractFee;
|
||||
return recipient;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert a C++ CRecipient struct to an FFI-friendly struct.
|
||||
*/
|
||||
CCRecipient toFFI(const CRecipient& cpp_struct) {
|
||||
CCRecipient c_struct;
|
||||
|
||||
// Serialize CScript and copy.
|
||||
std::vector<unsigned char> scriptBytes = serializeCScript(cpp_struct.pubKey);
|
||||
if (!scriptBytes.empty()) {
|
||||
c_struct.pubKey = copyBytes(scriptBytes.data(), scriptBytes.size());
|
||||
c_struct.pubKeyLength = static_cast<int>(scriptBytes.size());
|
||||
} else {
|
||||
c_struct.pubKey = nullptr;
|
||||
c_struct.pubKeyLength = 0;
|
||||
}
|
||||
|
||||
c_struct.cAmount = cpp_struct.amount;
|
||||
c_struct.subtractFee = static_cast<int>(cpp_struct.subtractFeeFromAmount);
|
||||
|
||||
return c_struct;
|
||||
}
|
||||
|
||||
/*
|
||||
* CRecipient factory.
|
||||
*
|
||||
* TODO manage the memory allocated by this function.
|
||||
*/
|
||||
CRecipient createCRecipient(const CScript& script, CAmount amount, bool subtractFee) {
|
||||
CRecipient recipient;
|
||||
recipient.pubKey = script;
|
||||
recipient.amount = amount;
|
||||
recipient.subtractFeeFromAmount = subtractFee;
|
||||
return recipient;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to decode an Address from a string.
|
||||
*/
|
||||
spark::Address decodeAddress(const std::string& str) {
|
||||
spark::Address address;
|
||||
address.decode(str);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
/*
|
||||
* MintedCoinData factory.
|
||||
*/
|
||||
spark::MintedCoinData createMintedCoinData(const char* address, uint64_t v, const char* memo) {
|
||||
return {
|
||||
decodeAddress(address),
|
||||
v,
|
||||
memo
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert an FFI-friendly C CMintedCoinData struct to a C++ MintedCoinData.
|
||||
*/
|
||||
spark::MintedCoinData fromFFI(const CMintedCoinData& c_struct) {
|
||||
return createMintedCoinData(
|
||||
c_struct.address,
|
||||
c_struct.value,
|
||||
c_struct.memo
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* CMintedCoinData factory.
|
||||
*/
|
||||
CMintedCoinData createCMintedCoinData(const char* address, uint64_t value, const char* memo) {
|
||||
CMintedCoinData c_struct;
|
||||
c_struct.address = strdup(address);
|
||||
c_struct.value = value;
|
||||
c_struct.memo = strdup(memo);
|
||||
return c_struct;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert a C++ MintedCoinData struct to an FFI-friendly CMintedCoinData.
|
||||
*/
|
||||
CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct) {
|
||||
return createCMintedCoinData(
|
||||
cpp_struct.address.encode(true).c_str(),
|
||||
cpp_struct.v,
|
||||
cpp_struct.memo.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function for deep copying byte arrays.
|
||||
*
|
||||
* Used by createCCoin.
|
||||
*/
|
||||
unsigned char* copyBytes(const unsigned char* source, int length) {
|
||||
if (source == nullptr || length <= 0) return nullptr;
|
||||
|
||||
unsigned char* dest = new unsigned char[length];
|
||||
std::memcpy(dest, source, length);
|
||||
return dest;
|
||||
}
|
||||
|
||||
unsigned char *hexToBytes(const char *hexstr) {
|
||||
size_t length = strlen(hexstr) / 2;
|
||||
auto *chrs = (unsigned char *) malloc((length + 1) * sizeof(unsigned char));
|
||||
for (size_t i = 0, j = 0; j < length; i += 2, j++) {
|
||||
chrs[j] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25;
|
||||
}
|
||||
chrs[length] = '\0';
|
||||
return chrs;
|
||||
}
|
||||
|
||||
const char *bytesToHex(const unsigned char *bytes, int size) {
|
||||
std::string str;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
const unsigned char ch = bytes[i];
|
||||
str.append(&hexArray[(ch & 0xF0) >> 4], 1);
|
||||
str.append(&hexArray[ch & 0xF], 1);
|
||||
}
|
||||
char *new_str = new char[std::strlen(str.c_str()) + 1];
|
||||
std::strcpy(new_str, str.c_str());
|
||||
return new_str;
|
||||
}
|
||||
|
||||
const char *bytesToHex(const char *bytes, int size) {
|
||||
std::string str;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
const unsigned char ch = (const unsigned char) bytes[i];
|
||||
str.append(&hexArray[(ch & 0xF0) >> 4], 1);
|
||||
str.append(&hexArray[ch & 0xF], 1);
|
||||
}
|
||||
char *new_str = new char[std::strlen(str.c_str()) + 1];
|
||||
std::strcpy(new_str, str.c_str());
|
||||
return new_str;
|
||||
}
|
||||
|
||||
const char *bytesToHex(std::vector<unsigned char> bytes, int size) {
|
||||
std::string str;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
const unsigned char ch = bytes[i];
|
||||
str.append(&hexArray[(ch & 0xF0) >> 4], 1);
|
||||
str.append(&hexArray[ch & 0xF], 1);
|
||||
}
|
||||
char *new_str = new char[std::strlen(str.c_str()) + 1];
|
||||
std::strcpy(new_str, str.c_str());
|
||||
return new_str;
|
||||
}
|
||||
62
src/utils.h
Normal file
62
src/utils.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef ORG_FIRO_SPARK_UTILS_H
|
||||
#define ORG_FIRO_SPARK_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "flutter_libsparkmobile.h"
|
||||
#include "deps/sparkmobile/include/spark.h"
|
||||
|
||||
const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier);
|
||||
|
||||
spark::SpendKey createSpendKeyFromData(const char *keyData, int index);
|
||||
|
||||
spark::Coin fromFFI(const CCoin& c_struct);
|
||||
|
||||
CCoin toFFI(const spark::Coin& cpp_struct);
|
||||
|
||||
struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* keyData, int index, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength);
|
||||
|
||||
spark::IdentifiedCoinData fromFFI(const CIdentifiedCoinData& c_struct);
|
||||
|
||||
CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct);
|
||||
|
||||
CScript createCScriptFromBytes(const unsigned char* bytes, int length);
|
||||
|
||||
std::vector<unsigned char> serializeCScript(const CScript& script);
|
||||
|
||||
CRecipient createCRecipient(const CScript& script, CAmount amount, bool subtractFee);
|
||||
|
||||
CRecipient fromFFI(const CCRecipient& c_struct);
|
||||
|
||||
struct CCRecipient createCCRecipient(const unsigned char* pubKey, uint64_t amount, int subtractFee);
|
||||
|
||||
CCRecipient toFFI(const CRecipient& cpp_struct);
|
||||
|
||||
spark::Address decodeAddress(const std::string& str);
|
||||
|
||||
spark::MintedCoinData createMintedCoinData(const char* address, uint64_t v, const char* memo);
|
||||
|
||||
spark::MintedCoinData fromFFI(const CMintedCoinData& c_struct);
|
||||
|
||||
CMintedCoinData createCMintedCoinData(const char* address, uint64_t value, const char* memo);
|
||||
|
||||
CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct);
|
||||
|
||||
char const hexArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
|
||||
'e', 'f'};
|
||||
|
||||
unsigned char* copyBytes(const unsigned char* source, int length);
|
||||
|
||||
unsigned char *hexToBytes(const char *str);
|
||||
|
||||
const char *bytesToHex(const unsigned char *bytes, int size);
|
||||
|
||||
const char *bytesToHex(const char *bytes, int size);
|
||||
|
||||
const char *bytesToHex(std::vector<unsigned char> bytes, int size);
|
||||
|
||||
|
||||
#endif //ORG_FIRO_SPARK_UTILS_H
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_libsparkmobile/flutter_libsparkmobile_method_channel.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
MethodChannelFlutterLibsparkmobile platform = MethodChannelFlutterLibsparkmobile();
|
||||
const MethodChannel channel = MethodChannel('flutter_libsparkmobile');
|
||||
|
||||
setUp(() {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||
channel,
|
||||
(MethodCall methodCall) async {
|
||||
return '42';
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null);
|
||||
});
|
||||
|
||||
test('getPlatformVersion', () async {
|
||||
expect(await platform.getPlatformVersion(), '42');
|
||||
});
|
||||
}
|
||||
@@ -8,89 +8,16 @@ cmake_minimum_required(VERSION 3.14)
|
||||
set(PROJECT_NAME "flutter_libsparkmobile")
|
||||
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||
|
||||
# This value is used when generating builds using this plugin, so it must
|
||||
# not be changed
|
||||
set(PLUGIN_NAME "flutter_libsparkmobile_plugin")
|
||||
|
||||
# Any new source files that you add to the plugin should be added here.
|
||||
list(APPEND PLUGIN_SOURCES
|
||||
"flutter_libsparkmobile_plugin.cpp"
|
||||
"flutter_libsparkmobile_plugin.h"
|
||||
)
|
||||
|
||||
# Define the plugin library target. Its name must not be changed (see comment
|
||||
# on PLUGIN_NAME above).
|
||||
add_library(${PLUGIN_NAME} SHARED
|
||||
"include/flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h"
|
||||
"flutter_libsparkmobile_plugin_c_api.cpp"
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
|
||||
# Apply a standard set of build settings that are configured in the
|
||||
# application-level CMakeLists.txt. This can be removed for plugins that want
|
||||
# full control over build settings.
|
||||
apply_standard_settings(${PLUGIN_NAME})
|
||||
|
||||
# Symbols are hidden by default to reduce the chance of accidental conflicts
|
||||
# between plugins. This should not be removed; any symbols that should be
|
||||
# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro.
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||
|
||||
# Source include directories and library dependencies. Add any plugin-specific
|
||||
# dependencies here.
|
||||
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin)
|
||||
# Invoke the build for native code shared with the other target platforms.
|
||||
# This can be changed to accommodate different builds.
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared")
|
||||
|
||||
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||
# This list could contain prebuilt libraries, or libraries created by an
|
||||
# external build triggered from this build file.
|
||||
set(flutter_libsparkmobile_bundled_libraries
|
||||
""
|
||||
# Defined in ../src/CMakeLists.txt.
|
||||
# This can be changed to accommodate different builds.
|
||||
$<TARGET_FILE:flutter_libsparkmobile>
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
# === Tests ===
|
||||
# These unit tests can be run from a terminal after building the example, or
|
||||
# from Visual Studio after opening the generated solution file.
|
||||
|
||||
# Only enable test builds when building the example (which sets this variable)
|
||||
# so that plugin clients aren't building the tests.
|
||||
if (${include_${PROJECT_NAME}_tests})
|
||||
set(TEST_RUNNER "${PROJECT_NAME}_test")
|
||||
enable_testing()
|
||||
|
||||
# Add the Google Test dependency.
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/release-1.11.0.zip
|
||||
)
|
||||
# Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
# Disable install commands for gtest so it doesn't end up in the bundle.
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
# The plugin's C API is not very useful for unit testing, so build the sources
|
||||
# directly into the test binary rather than using the DLL.
|
||||
add_executable(${TEST_RUNNER}
|
||||
test/flutter_libsparkmobile_plugin_test.cpp
|
||||
${PLUGIN_SOURCES}
|
||||
)
|
||||
apply_standard_settings(${TEST_RUNNER})
|
||||
target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin)
|
||||
target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock)
|
||||
# flutter_wrapper_plugin has link dependencies on the Flutter DLL.
|
||||
add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${FLUTTER_LIBRARY}" $<TARGET_FILE_DIR:${TEST_RUNNER}>
|
||||
)
|
||||
|
||||
# Enable automatic test discovery.
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(${TEST_RUNNER})
|
||||
endif()
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
#include "flutter_libsparkmobile_plugin.h"
|
||||
|
||||
// This must be included before many other Windows headers.
|
||||
#include <windows.h>
|
||||
|
||||
// For getPlatformVersion; remove unless needed for your plugin implementation.
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
namespace flutter_libsparkmobile {
|
||||
|
||||
// static
|
||||
void FlutterLibsparkmobilePlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarWindows *registrar) {
|
||||
auto channel =
|
||||
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
||||
registrar->messenger(), "flutter_libsparkmobile",
|
||||
&flutter::StandardMethodCodec::GetInstance());
|
||||
|
||||
auto plugin = std::make_unique<FlutterLibsparkmobilePlugin>();
|
||||
|
||||
channel->SetMethodCallHandler(
|
||||
[plugin_pointer = plugin.get()](const auto &call, auto result) {
|
||||
plugin_pointer->HandleMethodCall(call, std::move(result));
|
||||
});
|
||||
|
||||
registrar->AddPlugin(std::move(plugin));
|
||||
}
|
||||
|
||||
FlutterLibsparkmobilePlugin::FlutterLibsparkmobilePlugin() {}
|
||||
|
||||
FlutterLibsparkmobilePlugin::~FlutterLibsparkmobilePlugin() {}
|
||||
|
||||
void FlutterLibsparkmobilePlugin::HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
if (method_call.method_name().compare("getPlatformVersion") == 0) {
|
||||
std::ostringstream version_stream;
|
||||
version_stream << "Windows ";
|
||||
if (IsWindows10OrGreater()) {
|
||||
version_stream << "10+";
|
||||
} else if (IsWindows8OrGreater()) {
|
||||
version_stream << "8";
|
||||
} else if (IsWindows7OrGreater()) {
|
||||
version_stream << "7";
|
||||
}
|
||||
result->Success(flutter::EncodableValue(version_stream.str()));
|
||||
} else {
|
||||
result->NotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flutter_libsparkmobile
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_
|
||||
#define FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace flutter_libsparkmobile {
|
||||
|
||||
class FlutterLibsparkmobilePlugin : public flutter::Plugin {
|
||||
public:
|
||||
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
|
||||
|
||||
FlutterLibsparkmobilePlugin();
|
||||
|
||||
virtual ~FlutterLibsparkmobilePlugin();
|
||||
|
||||
// Disallow copy and assign.
|
||||
FlutterLibsparkmobilePlugin(const FlutterLibsparkmobilePlugin&) = delete;
|
||||
FlutterLibsparkmobilePlugin& operator=(const FlutterLibsparkmobilePlugin&) = delete;
|
||||
|
||||
// Called when a method is called on this plugin's channel from Dart.
|
||||
void HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
};
|
||||
|
||||
} // namespace flutter_libsparkmobile
|
||||
|
||||
#endif // FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_H_
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "include/flutter_libsparkmobile/flutter_libsparkmobile_plugin_c_api.h"
|
||||
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include "flutter_libsparkmobile_plugin.h"
|
||||
|
||||
void FlutterLibsparkmobilePluginCApiRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar) {
|
||||
flutter_libsparkmobile::FlutterLibsparkmobilePlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarManager::GetInstance()
|
||||
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_C_API_H_
|
||||
#define FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_C_API_H_
|
||||
|
||||
#include <flutter_plugin_registrar.h>
|
||||
|
||||
#ifdef FLUTTER_PLUGIN_IMPL
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void FlutterLibsparkmobilePluginCApiRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // FLUTTER_PLUGIN_FLUTTER_LIBSPARKMOBILE_PLUGIN_C_API_H_
|
||||
@@ -1,43 +0,0 @@
|
||||
#include <flutter/method_call.h>
|
||||
#include <flutter/method_result_functions.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "flutter_libsparkmobile_plugin.h"
|
||||
|
||||
namespace flutter_libsparkmobile {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
using flutter::EncodableMap;
|
||||
using flutter::EncodableValue;
|
||||
using flutter::MethodCall;
|
||||
using flutter::MethodResultFunctions;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FlutterLibsparkmobilePlugin, GetPlatformVersion) {
|
||||
FlutterLibsparkmobilePlugin plugin;
|
||||
// Save the reply value from the success callback.
|
||||
std::string result_string;
|
||||
plugin.HandleMethodCall(
|
||||
MethodCall("getPlatformVersion", std::make_unique<EncodableValue>()),
|
||||
std::make_unique<MethodResultFunctions<>>(
|
||||
[&result_string](const EncodableValue* result) {
|
||||
result_string = std::get<std::string>(*result);
|
||||
},
|
||||
nullptr, nullptr));
|
||||
|
||||
// Since the exact string varies by host, just ensure that it's a string
|
||||
// with the expected format.
|
||||
EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace flutter_libsparkmobile
|
||||
Reference in New Issue
Block a user