monero-native 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/LICENSE +38 -0
- package/README.md +26 -0
- package/android/build.gradle +40 -0
- package/android/src/main/java/app/edge/rnmonero/RnMoneroModule.java +93 -0
- package/android/src/main/java/app/edge/rnmonero/RnMoneroPackage.java +21 -0
- package/android/src/main/jniLibs/arm64-v8a/librnmonero.so +0 -0
- package/ios/MoneroModule.h +5 -0
- package/ios/MoneroModule.mm +143 -0
- package/ios/MoneroModule.xcframework/Info.plist +43 -0
- package/ios/MoneroModule.xcframework/ios-arm64/libmonero-module.a +0 -0
- package/ios/MoneroModule.xcframework/ios-arm64-simulator/libmonero-module.a +0 -0
- package/lib/src/CppBridge.d.ts +181 -0
- package/lib/src/CppBridge.js +296 -0
- package/lib/src/index.d.ts +4 -0
- package/lib/src/index.js +27 -0
- package/lib/src/load-addon.d.ts +6 -0
- package/lib/src/load-addon.js +49 -0
- package/lib/src/node.d.ts +12 -0
- package/lib/src/node.js +23 -0
- package/lib/src/types.d.ts +120 -0
- package/lib/src/types.js +11 -0
- package/monero-native.podspec +28 -0
- package/node.d.ts +5 -0
- package/node.js +2 -0
- package/package.json +94 -0
- package/prebuilds/darwin-arm64/monero.node +0 -0
- package/src/monero-wrapper/monero-methods.hpp +25 -0
- package/src/node/monero-napi.cpp +248 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# monero-native
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.5.0 (2026-08-14)
|
|
6
|
+
|
|
7
|
+
- changed: (Breaking) `broadcastTransaction` returns a `BroadcastResult` with the transaction secret key (`txKey`) instead of the string `"success"`. The key is the sender's only proof of payment and the broadcast is the send path's only chance to hand it to the caller, since it cannot be derived from the seed. A key the wallet cannot report never fails an already-broadcast payment: the result simply carries no `txKey`.
|
|
8
|
+
|
|
9
|
+
## 0.4.2 (2026-07-17)
|
|
10
|
+
|
|
11
|
+
- changed: Bump vtnerd/lwsf to da8e2617958312f10fe4406808c2a951c5cf0a09
|
|
12
|
+
|
|
13
|
+
## 0.4.1 (2026-07-14)
|
|
14
|
+
|
|
15
|
+
- fixed: iOS no longer crashes with EXC_BAD_INSTRUCTION (SIGILL) in `CRYPTO_atomic_load` on A11 and older devices (iPhone X, 8, 7, 6s) the moment a wallet opens. OpenSSL's `ios64-xcrun` build target stopped passing a deployment-target flag, so clang targeted the SDK version and raised the CPU baseline to apple-a12, emitting ARMv8.3 `ldapr` (and ARMv8.1 LSE) instructions those chips lack; the first SSL client construction (`getWalletManager` → `boost::asio::ssl::context` → `ERR_clear_error`) executed one and crash-looped the app on login. The OpenSSL build now pins `-miphoneos-version-min`/`-mios-simulator-version-min` to the platform minimum, restoring the ARMv8.0 baseline (`ldar`).
|
|
16
|
+
|
|
17
|
+
## 0.4.0 (2026-07-06)
|
|
18
|
+
|
|
19
|
+
- added: `getWalletStatus` reports a `refreshed` flag, true once the wallet has completed its first server refresh (and so knows its real balance and spendable outputs). LWS wallets report seed heights that look synced before then, so treat a wallet as synced only when `refreshed` is true.
|
|
20
|
+
- fixed: LWS wallets can spend and receive over the Nym mixnet. The lwsf RPC timeout of 5 seconds was too short for a mixnet round-trip, so single-shot spend and receive calls failed; the Nym path now uses a 120-second budget.
|
|
21
|
+
|
|
22
|
+
## 0.3.0 (2026-07-03)
|
|
23
|
+
|
|
24
|
+
- added: `getPendingTransactions`, a paged view of the not-yet-mined transactions. `getAllTransactions` sorts pending entries behind all confirmed ones, so a cursor-based scan of confirmed history never reaches them; this exposes the pending set directly.
|
|
25
|
+
- fixed: LWS wallets sync again. The 0.2.0 https change passed `use_ssl=true` to `wallet->init` for https daemons; wallet2 (monerod) ignores that flag, but lwsf honors it and switches from tolerant `ssl_support_autodetect` to `ssl_support_enabled`, whose certificate verification always fails on iOS/Android (no OpenSSL system CA store in the app sandbox). Every LWS connection was silently dropped at the TLS handshake, so LWS wallets polled forever at height 0 with no transactions or balance. Revert to `use_ssl=false` (TLS still autodetected from the `https://` scheme); the Nym scheme fix is unaffected since it derives https from the port inside NymHttpClient.
|
|
26
|
+
- fixed: Monero Full Node (monerod) sends no longer fail with "Failed to load transaction from file". `createTransaction` now retains the signed transaction natively and `broadcastTransaction` commits it directly, instead of saving it to a file and reloading it: on the full-node (wallet2) backend `save_tx` writes an unsigned tx set while `submitTransaction`'s `load_tx` requires a signed one, so the file round-trip always failed. Retained transactions are capped at 50 per wallet (oldest disposed first) and cleared when the wallet closes. Method signatures are unchanged, but the semantics narrow: `signedTxHex` is now an opaque token (the txid) identifying the retained transaction rather than serialized bytes, a signed transaction can no longer be broadcast after its wallet closes or the app restarts (`broadcastTransaction` reports that it must be recreated), and payments the wallet would split into multiple on-chain transactions are rejected at creation so a broadcast is atomic.
|
|
27
|
+
|
|
28
|
+
## 0.2.0 (2026-06-29)
|
|
29
|
+
|
|
30
|
+
- changed: Switch the package manager from yarn to npm (package-lock.json + `.npmrc` legacy-peer-deps), matching the other Edge currency repos.
|
|
31
|
+
- fixed: Monero Full Node (monerod) wallets now sync, calculate max, and send when the Nym mixnet is enabled. The Nym HTTP client rebuilt request URLs from an unreliable SSL flag and emitted `http://` on port 443, so every monerod RPC failed under Nym while the same wallet worked with Nym off. Derive the scheme from the daemon address (and treat port 443 as https).
|
|
32
|
+
- fixed: `getWalletStatus` now reads the live wallet balance on every call instead of only recomputing it when the synced block height changes, so a pending incoming transaction (or pending change after a send) is reflected immediately rather than after the next block.
|
|
33
|
+
|
|
34
|
+
## 0.1.0 (2026-06-15)
|
|
35
|
+
|
|
36
|
+
- Initial release
|
package/LICENSE
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Airbitz, Inc.
|
|
4
|
+
Copyright (c) 2014-2024, The Monero Project
|
|
5
|
+
|
|
6
|
+
All rights reserved.
|
|
7
|
+
|
|
8
|
+
Redistribution and use in source and binary forms, with or without
|
|
9
|
+
modification, are permitted provided that the following conditions are met:
|
|
10
|
+
|
|
11
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
12
|
+
list of conditions and the following disclaimer.
|
|
13
|
+
|
|
14
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
15
|
+
this list of conditions and the following disclaimer in the documentation
|
|
16
|
+
and/or other materials provided with the distribution.
|
|
17
|
+
|
|
18
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
19
|
+
may be used to endorse or promote products derived from this software
|
|
20
|
+
without specific prior written permission.
|
|
21
|
+
|
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
23
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
24
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
25
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
26
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
27
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
28
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
29
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
30
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
31
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
This package wraps the Monero Project, which is BSD-3-Clause, and ships
|
|
36
|
+
binaries compiled from it. The wrapper carries the same license so the package
|
|
37
|
+
and what it distributes agree. Boost, OpenSSL, libsodium, libunbound, libexpat
|
|
38
|
+
and libzmq are also compiled in and remain under their own licenses.
|
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# monero-native
|
|
2
|
+
|
|
3
|
+
Native Monero wallet library (LWSF) for React Native and Node.js.
|
|
4
|
+
|
|
5
|
+
The compiled C++ lives in this package. React Native and Node are hosts.
|
|
6
|
+
|
|
7
|
+
- GitHub: [EdgeApp/monero-native](https://github.com/EdgeApp/monero-native)
|
|
8
|
+
- npm: `monero-native`
|
|
9
|
+
|
|
10
|
+
## React Native
|
|
11
|
+
|
|
12
|
+
Add the package and run `pod install` as needed.
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import { makeMonero } from 'monero-native'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Mobile binaries: `npm run build-native` (Android + iOS). That script fetches third-party C++ and is not run on `npm install`.
|
|
19
|
+
|
|
20
|
+
## Node (CLI)
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
import { makeNodeMoneroModule } from 'monero-native/node'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Host addon: `npm run build-native-host` (explicit; `prepare` / `prepack` compile JavaScript only).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
repositories {
|
|
3
|
+
mavenCentral()
|
|
4
|
+
google()
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
dependencies {
|
|
8
|
+
classpath 'com.android.tools.build:gradle:7.3.1'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
apply plugin: 'com.android.library'
|
|
13
|
+
|
|
14
|
+
def safeExtGet(prop, fallback) {
|
|
15
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
android {
|
|
19
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 32)
|
|
20
|
+
defaultConfig {
|
|
21
|
+
minSdkVersion safeExtGet('minSdkVersion', 23)
|
|
22
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 32)
|
|
23
|
+
}
|
|
24
|
+
lintOptions {
|
|
25
|
+
abortOnError false
|
|
26
|
+
}
|
|
27
|
+
namespace 'app.edge.rnmonero'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
repositories {
|
|
31
|
+
maven {
|
|
32
|
+
url('../node_modules/react-native/android')
|
|
33
|
+
}
|
|
34
|
+
google()
|
|
35
|
+
mavenCentral()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
dependencies {
|
|
39
|
+
implementation 'com.facebook.react:react-native:+'
|
|
40
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
package app.edge.rnmonero;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments;
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
5
|
+
import com.facebook.react.bridge.Promise;
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
7
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
8
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
9
|
+
import com.facebook.react.bridge.WritableMap;
|
|
10
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
11
|
+
import java.util.HashMap;
|
|
12
|
+
import java.util.Map;
|
|
13
|
+
import java.util.concurrent.ExecutorService;
|
|
14
|
+
import java.util.concurrent.Executors;
|
|
15
|
+
|
|
16
|
+
public class RnMoneroModule extends ReactContextBaseJavaModule {
|
|
17
|
+
private native String callMoneroJNI(String method, String[] arguments);
|
|
18
|
+
|
|
19
|
+
private native String[] getMethodNames();
|
|
20
|
+
|
|
21
|
+
// Sets the C++ callback so WalletListener events route through onWalletEvent
|
|
22
|
+
private native void initEventCallback();
|
|
23
|
+
|
|
24
|
+
private final ExecutorService moneroExecutor = Executors.newSingleThreadExecutor();
|
|
25
|
+
private final ExecutorService nymCompletionExecutor = Executors.newSingleThreadExecutor();
|
|
26
|
+
|
|
27
|
+
static {
|
|
28
|
+
System.loadLibrary("rnmonero");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public RnMoneroModule(ReactApplicationContext reactContext) {
|
|
32
|
+
super(reactContext);
|
|
33
|
+
initEventCallback();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Override
|
|
37
|
+
public Map<String, Object> getConstants() {
|
|
38
|
+
final Map<String, Object> constants = new HashMap<>();
|
|
39
|
+
constants.put("methodNames", getMethodNames());
|
|
40
|
+
constants.put("documentDirectory", getReactApplicationContext().getFilesDir().getAbsolutePath());
|
|
41
|
+
return constants;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Override
|
|
45
|
+
public String getName() {
|
|
46
|
+
return "MoneroLwsfModule";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@ReactMethod
|
|
50
|
+
public void callMonero(String method, ReadableArray arguments, Promise promise) {
|
|
51
|
+
// Re-package the arguments:
|
|
52
|
+
String[] strings = new String[arguments.size()];
|
|
53
|
+
for (int i = 0; i < arguments.size(); ++i) {
|
|
54
|
+
strings[i] = arguments.getString(i);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ExecutorService executor =
|
|
58
|
+
isNymCompletionMethod(method) ? nymCompletionExecutor : moneroExecutor;
|
|
59
|
+
executor.execute(() -> {
|
|
60
|
+
try {
|
|
61
|
+
promise.resolve(callMoneroJNI(method, strings));
|
|
62
|
+
} catch (Exception e) {
|
|
63
|
+
promise.reject("MoneroError", e);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private static boolean isNymCompletionMethod(String method) {
|
|
69
|
+
return "resolveFetch".equals(method) || "rejectFetch".equals(method);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Required by React Native NativeEventEmitter on Android
|
|
73
|
+
@ReactMethod
|
|
74
|
+
public void addListener(String eventName) {}
|
|
75
|
+
|
|
76
|
+
@ReactMethod
|
|
77
|
+
public void removeListeners(int count) {}
|
|
78
|
+
|
|
79
|
+
// Called from C++ WalletListener via JNI on the SDK refresh thread.
|
|
80
|
+
// Forwards the event to JS through RCTDeviceEventEmitter.
|
|
81
|
+
public void onWalletEvent(String walletId, String eventName, String jsonPayload) {
|
|
82
|
+
ReactApplicationContext ctx = getReactApplicationContext();
|
|
83
|
+
if (ctx == null || !ctx.hasActiveReactInstance()) return;
|
|
84
|
+
|
|
85
|
+
WritableMap params = Arguments.createMap();
|
|
86
|
+
params.putString("walletId", walletId);
|
|
87
|
+
params.putString("eventName", eventName);
|
|
88
|
+
params.putString("data", jsonPayload);
|
|
89
|
+
|
|
90
|
+
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
91
|
+
.emit("MoneroWalletEvent", params);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
package app.edge.rnmonero;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage;
|
|
4
|
+
import com.facebook.react.bridge.NativeModule;
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager;
|
|
7
|
+
import java.util.Arrays;
|
|
8
|
+
import java.util.Collections;
|
|
9
|
+
import java.util.List;
|
|
10
|
+
|
|
11
|
+
public class RnMoneroPackage implements ReactPackage {
|
|
12
|
+
@Override
|
|
13
|
+
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
|
14
|
+
return Arrays.<NativeModule>asList(new RnMoneroModule(reactContext));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@Override
|
|
18
|
+
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
|
19
|
+
return Collections.emptyList();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#import "MoneroModule.h"
|
|
2
|
+
#include "monero-methods.hpp"
|
|
3
|
+
|
|
4
|
+
@interface MoneroModule () {
|
|
5
|
+
dispatch_queue_t _moneroQueue;
|
|
6
|
+
dispatch_queue_t _nymCompletionQueue;
|
|
7
|
+
}
|
|
8
|
+
@end
|
|
9
|
+
|
|
10
|
+
static bool isNymCompletionMethod(const std::string& method) {
|
|
11
|
+
return method == "resolveFetch" || method == "rejectFetch";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Global pointer so the C++ callback can reach the ObjC module instance
|
|
15
|
+
static __weak MoneroModule* g_module = nil;
|
|
16
|
+
|
|
17
|
+
@implementation MoneroModule
|
|
18
|
+
|
|
19
|
+
RCT_EXPORT_MODULE(MoneroLwsfModule);
|
|
20
|
+
|
|
21
|
+
+ (BOOL)requiresMainQueueSetup { return NO; }
|
|
22
|
+
|
|
23
|
+
- (instancetype)init {
|
|
24
|
+
self = [super init];
|
|
25
|
+
if (self) {
|
|
26
|
+
g_module = self;
|
|
27
|
+
_moneroQueue = dispatch_queue_create(
|
|
28
|
+
"app.edge.rnmonero.monero", DISPATCH_QUEUE_SERIAL);
|
|
29
|
+
_nymCompletionQueue = dispatch_queue_create(
|
|
30
|
+
"app.edge.rnmonero.nymCompletion", DISPATCH_QUEUE_SERIAL);
|
|
31
|
+
|
|
32
|
+
// Wire the C++ wallet-event callback to this module's event emitter
|
|
33
|
+
moneroSetEventCallback([](const std::string& walletId,
|
|
34
|
+
const std::string& eventName,
|
|
35
|
+
const std::string& jsonPayload) {
|
|
36
|
+
MoneroModule* module = g_module;
|
|
37
|
+
if (module == nil) return;
|
|
38
|
+
|
|
39
|
+
NSString *nsWalletId = [NSString stringWithUTF8String:walletId.c_str()];
|
|
40
|
+
NSString *nsEventName = [NSString stringWithUTF8String:eventName.c_str()];
|
|
41
|
+
NSString *nsPayload = [NSString stringWithUTF8String:jsonPayload.c_str()];
|
|
42
|
+
|
|
43
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
44
|
+
[module sendEventWithName:@"MoneroWalletEvent" body:@{
|
|
45
|
+
@"walletId": nsWalletId,
|
|
46
|
+
@"eventName": nsEventName,
|
|
47
|
+
@"data": nsPayload
|
|
48
|
+
}];
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return self;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
- (NSArray<NSString *> *)supportedEvents {
|
|
56
|
+
return @[@"MoneroWalletEvent"];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (void)startObserving {}
|
|
60
|
+
- (void)stopObserving {}
|
|
61
|
+
|
|
62
|
+
RCT_REMAP_METHOD(
|
|
63
|
+
callMonero,
|
|
64
|
+
callMoneroMethod:(NSString *)method
|
|
65
|
+
arguments:(NSArray *)arguments
|
|
66
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
67
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
68
|
+
) {
|
|
69
|
+
const std::string methodString = [method UTF8String];
|
|
70
|
+
|
|
71
|
+
// Re-package the arguments:
|
|
72
|
+
NSUInteger length = [arguments count];
|
|
73
|
+
std::vector<std::string> strings;
|
|
74
|
+
strings.reserve(length);
|
|
75
|
+
for (NSUInteger i = 0; i < length; ++i) {
|
|
76
|
+
NSString *string = [arguments objectAtIndex:i];
|
|
77
|
+
strings.push_back([string UTF8String]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Find the named method:
|
|
81
|
+
for (int i = 0; i < moneroMethodCount; ++i) {
|
|
82
|
+
if (moneroMethods[i].name != methodString) continue;
|
|
83
|
+
|
|
84
|
+
// Validate the argument count:
|
|
85
|
+
if (moneroMethods[i].argc != strings.size()) {
|
|
86
|
+
reject(@"Error", @"monero incorrect C++ argument count", nil);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const MoneroMethod methodInfo = moneroMethods[i];
|
|
91
|
+
dispatch_queue_t queue =
|
|
92
|
+
isNymCompletionMethod(methodString) ? _nymCompletionQueue : _moneroQueue;
|
|
93
|
+
dispatch_async(queue, ^{
|
|
94
|
+
// Call the method, with error handling:
|
|
95
|
+
try {
|
|
96
|
+
const std::string out = methodInfo.method(strings);
|
|
97
|
+
resolve(
|
|
98
|
+
[NSString stringWithCString:out.c_str() encoding:NSUTF8StringEncoding]
|
|
99
|
+
);
|
|
100
|
+
} catch (std::exception &e) {
|
|
101
|
+
reject(
|
|
102
|
+
@"Error",
|
|
103
|
+
[NSString stringWithCString:e.what() encoding:NSUTF8StringEncoding],
|
|
104
|
+
nil
|
|
105
|
+
);
|
|
106
|
+
} catch (...) {
|
|
107
|
+
reject(@"Error", @"monero threw a C++ exception", nil);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
reject(
|
|
114
|
+
@"TypeError",
|
|
115
|
+
[NSString stringWithFormat:@"No monero C++ method %@", method],
|
|
116
|
+
nil
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
- (NSDictionary *)constantsToExport
|
|
121
|
+
{
|
|
122
|
+
NSMutableArray *out = [NSMutableArray arrayWithCapacity:moneroMethodCount];
|
|
123
|
+
for (int i = 0; i < moneroMethodCount; ++i) {
|
|
124
|
+
NSString *name = [NSString stringWithCString:moneroMethods[i].name
|
|
125
|
+
encoding:NSUTF8StringEncoding];
|
|
126
|
+
out[i] = name;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
130
|
+
NSURL *docsDir = [fileManager URLForDirectory:NSDocumentDirectory
|
|
131
|
+
inDomain:NSUserDomainMask
|
|
132
|
+
appropriateForURL:nil
|
|
133
|
+
create:YES
|
|
134
|
+
error:nil];
|
|
135
|
+
NSString *docsPath = [docsDir path];
|
|
136
|
+
|
|
137
|
+
return @{
|
|
138
|
+
@"methodNames": out,
|
|
139
|
+
@"documentDirectory": docsPath
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>AvailableLibraries</key>
|
|
6
|
+
<array>
|
|
7
|
+
<dict>
|
|
8
|
+
<key>BinaryPath</key>
|
|
9
|
+
<string>libmonero-module.a</string>
|
|
10
|
+
<key>LibraryIdentifier</key>
|
|
11
|
+
<string>ios-arm64</string>
|
|
12
|
+
<key>LibraryPath</key>
|
|
13
|
+
<string>libmonero-module.a</string>
|
|
14
|
+
<key>SupportedArchitectures</key>
|
|
15
|
+
<array>
|
|
16
|
+
<string>arm64</string>
|
|
17
|
+
</array>
|
|
18
|
+
<key>SupportedPlatform</key>
|
|
19
|
+
<string>ios</string>
|
|
20
|
+
</dict>
|
|
21
|
+
<dict>
|
|
22
|
+
<key>BinaryPath</key>
|
|
23
|
+
<string>libmonero-module.a</string>
|
|
24
|
+
<key>LibraryIdentifier</key>
|
|
25
|
+
<string>ios-arm64-simulator</string>
|
|
26
|
+
<key>LibraryPath</key>
|
|
27
|
+
<string>libmonero-module.a</string>
|
|
28
|
+
<key>SupportedArchitectures</key>
|
|
29
|
+
<array>
|
|
30
|
+
<string>arm64</string>
|
|
31
|
+
</array>
|
|
32
|
+
<key>SupportedPlatform</key>
|
|
33
|
+
<string>ios</string>
|
|
34
|
+
<key>SupportedPlatformVariant</key>
|
|
35
|
+
<string>simulator</string>
|
|
36
|
+
</dict>
|
|
37
|
+
</array>
|
|
38
|
+
<key>CFBundlePackageType</key>
|
|
39
|
+
<string>XFWK</string>
|
|
40
|
+
<key>XCFrameworkFormatVersion</key>
|
|
41
|
+
<string>1.0</string>
|
|
42
|
+
</dict>
|
|
43
|
+
</plist>
|
|
Binary file
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { BroadcastResult, DerivedKeys, EncodeUriParams, GeneratedWallet, NetworkType, ParsedUri, Recipient, SignedTransaction, TransactionPriority, TransactionsPage, WalletBackend, WalletStatus } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* The shape of the native C++ module exposed to React Native.
|
|
4
|
+
*
|
|
5
|
+
* You do not normally need this, but it is accessible as
|
|
6
|
+
* `require('react-native').NativeModules.MoneroLwsfModule`.
|
|
7
|
+
*
|
|
8
|
+
* Pass this object to the `CppBridge` constructor to re-assemble the API.
|
|
9
|
+
*/
|
|
10
|
+
export interface NativeMoneroLwsfModule {
|
|
11
|
+
readonly callMonero: (name: string, jsonArguments: string[]) => Promise<string>;
|
|
12
|
+
readonly methodNames: string[];
|
|
13
|
+
readonly documentDirectory: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class CppBridge {
|
|
16
|
+
private readonly module;
|
|
17
|
+
constructor(moneroLwsfModule: NativeMoneroLwsfModule);
|
|
18
|
+
/**
|
|
19
|
+
* Generate a new wallet's keys in memory (no disk I/O).
|
|
20
|
+
* @param nettype - Network type (0=mainnet, 1=testnet, 2=stagenet)
|
|
21
|
+
* @param language - Mnemonic language (e.g., "English")
|
|
22
|
+
* @returns Generated wallet with mnemonic and spend keys
|
|
23
|
+
*/
|
|
24
|
+
generateWallet(nettype: NetworkType, language?: string): Promise<GeneratedWallet>;
|
|
25
|
+
/**
|
|
26
|
+
* Derive all keys from a mnemonic (no disk I/O).
|
|
27
|
+
* @param mnemonic - The 25-word mnemonic seed
|
|
28
|
+
* @param nettype - Network type (0=mainnet, 1=testnet, 2=stagenet)
|
|
29
|
+
* @returns All four keys (view and spend, public and secret)
|
|
30
|
+
*/
|
|
31
|
+
seedAndKeysFromMnemonic(mnemonic: string, nettype: NetworkType): Promise<DerivedKeys>;
|
|
32
|
+
/**
|
|
33
|
+
* Get the current network blockchain height from a daemon.
|
|
34
|
+
* @param backend - Backend type ('lws' or 'monerod')
|
|
35
|
+
* @param nettype - Network type (0=mainnet, 1=testnet, 2=stagenet)
|
|
36
|
+
* @param daemonAddress - Daemon address to query
|
|
37
|
+
* @returns Current blockchain height
|
|
38
|
+
*/
|
|
39
|
+
getNetworkBlockHeight(backend: WalletBackend, nettype: NetworkType, daemonAddress: string): Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* Validate a Monero address.
|
|
42
|
+
* @param address - The address to validate
|
|
43
|
+
* @param nettype - Network type (0=mainnet, 1=testnet, 2=stagenet)
|
|
44
|
+
* @returns true if valid, false otherwise
|
|
45
|
+
*/
|
|
46
|
+
isValidAddress(address: string, nettype: NetworkType): Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Open or create a wallet. If already open, returns current status.
|
|
49
|
+
* If wallet exists on disk, opens it. Otherwise creates from mnemonic.
|
|
50
|
+
* @param walletId - Unique identifier for the wallet
|
|
51
|
+
* @param backend - Backend type ("lws" or "monerod")
|
|
52
|
+
* @param mnemonic - The 25-word mnemonic seed
|
|
53
|
+
* @param nettype - Network type (0=mainnet, 1=testnet, 2=stagenet)
|
|
54
|
+
* @param restoreHeight - Block height to restore from
|
|
55
|
+
* @param daemonAddress - Daemon address to connect to
|
|
56
|
+
* @returns Current wallet status (heights and balances)
|
|
57
|
+
*/
|
|
58
|
+
openWallet(walletId: string, backend: WalletBackend, mnemonic: string, password: string, nettype: NetworkType, restoreHeight: number, daemonAddress: string): Promise<WalletStatus>;
|
|
59
|
+
/**
|
|
60
|
+
* Get the current status of an open wallet.
|
|
61
|
+
* @param walletId - Unique identifier for the wallet
|
|
62
|
+
* @returns Current wallet status (heights and balances)
|
|
63
|
+
*/
|
|
64
|
+
getWalletStatus(walletId: string): Promise<WalletStatus>;
|
|
65
|
+
/**
|
|
66
|
+
* Close an open wallet.
|
|
67
|
+
* @param walletId - Unique identifier for the wallet to close
|
|
68
|
+
*/
|
|
69
|
+
closeWallet(walletId: string): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Delete a wallet's files from disk. Closes the wallet first if it's open.
|
|
72
|
+
* @param walletId - Unique identifier for the wallet
|
|
73
|
+
* @param backend - Backend type ('lws' or 'monerod')
|
|
74
|
+
*/
|
|
75
|
+
deleteWallet(walletId: string, backend: WalletBackend): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Get all transactions with pagination.
|
|
78
|
+
* @param walletId - Unique identifier for the wallet
|
|
79
|
+
* @param page - Page number (0-indexed)
|
|
80
|
+
* @param pageSize - Number of transactions per page
|
|
81
|
+
* @param sort - Sort order: 'asc' (oldest first) or 'desc' (newest first), pending always at end
|
|
82
|
+
* @returns Paginated transactions with metadata
|
|
83
|
+
*/
|
|
84
|
+
getAllTransactions(walletId: string, page: number, pageSize: number, sort?: 'asc' | 'desc'): Promise<TransactionsPage>;
|
|
85
|
+
/**
|
|
86
|
+
* Get not-yet-mined transactions with pagination. Same shape as
|
|
87
|
+
* getAllTransactions, filtered to pending entries. Pending transactions sort
|
|
88
|
+
* behind all confirmed ones in getAllTransactions, so a cursor-based scan of
|
|
89
|
+
* confirmed history never reaches them; use this to read the pending set
|
|
90
|
+
* directly. The set can include entries the backend reports as permanently
|
|
91
|
+
* failed (isFailed: true); callers decide how to label those.
|
|
92
|
+
* @param walletId - Unique identifier for the wallet
|
|
93
|
+
* @param page - Page number (0-indexed)
|
|
94
|
+
* @param pageSize - Number of transactions per page
|
|
95
|
+
* @returns Paginated pending transactions with metadata
|
|
96
|
+
*/
|
|
97
|
+
getPendingTransactions(walletId: string, page: number, pageSize: number): Promise<TransactionsPage>;
|
|
98
|
+
/**
|
|
99
|
+
* Create a transaction (supports multiple recipients).
|
|
100
|
+
* The transaction is created and signed but not broadcast yet: it is retained
|
|
101
|
+
* natively for a later broadcastTransaction call. At most 50 transactions are
|
|
102
|
+
* retained per wallet (oldest disposed first; broadcasting an evicted one
|
|
103
|
+
* reports that it must be recreated), and all are released when the wallet
|
|
104
|
+
* closes. Payments the wallet would split into multiple on-chain
|
|
105
|
+
* transactions are rejected, so a later broadcast is atomic.
|
|
106
|
+
* @param walletId - Unique identifier for the wallet
|
|
107
|
+
* @param recipients - Array of recipients with addresses and amounts (atomic units)
|
|
108
|
+
* @param priority - Transaction priority (0=Default, 1=Low, 2=Medium, 3=High)
|
|
109
|
+
* @returns SignedTransaction with txid, signedTxHex, and fee (atomic units)
|
|
110
|
+
*/
|
|
111
|
+
createTransaction(walletId: string, recipients: Recipient[], priority: TransactionPriority): Promise<SignedTransaction>;
|
|
112
|
+
/**
|
|
113
|
+
* Broadcast a previously created transaction. `signedTx` identifies the
|
|
114
|
+
* natively retained transaction to broadcast.
|
|
115
|
+
* @param walletId - Unique identifier for the wallet
|
|
116
|
+
* @param signedTx - The signedTxHex returned by createTransaction
|
|
117
|
+
* @returns BroadcastResult with the transaction secret key, when the wallet
|
|
118
|
+
* can report it. This is the only chance to read the key on the send path:
|
|
119
|
+
* it is not derivable from the seed, so a caller that drops it here can
|
|
120
|
+
* only recover it from this wallet's local cache later.
|
|
121
|
+
* @throws Error if the transaction is no longer retained (evicted, or the
|
|
122
|
+
* wallet was closed since creation) or the broadcast fails
|
|
123
|
+
*/
|
|
124
|
+
broadcastTransaction(walletId: string, signedTx: string): Promise<BroadcastResult>;
|
|
125
|
+
/**
|
|
126
|
+
* Parse a monero: URI into its components.
|
|
127
|
+
* @param uri - The monero: URI to parse
|
|
128
|
+
* @param nettype - Network type (0=mainnet, 1=testnet, 2=stagenet)
|
|
129
|
+
* @returns Parsed URI components
|
|
130
|
+
* @throws Error if URI is invalid
|
|
131
|
+
*/
|
|
132
|
+
parseUri(uri: string, nettype: NetworkType): Promise<ParsedUri>;
|
|
133
|
+
/**
|
|
134
|
+
* Encode a monero: URI from components.
|
|
135
|
+
* @param params - URI components (address, amount, etc.)
|
|
136
|
+
* @param nettype - Network type (0=mainnet, 1=testnet, 2=stagenet)
|
|
137
|
+
* @returns The encoded monero: URI
|
|
138
|
+
* @throws Error if parameters are invalid
|
|
139
|
+
*/
|
|
140
|
+
encodeUri(params: EncodeUriParams, nettype: NetworkType): Promise<string>;
|
|
141
|
+
/**
|
|
142
|
+
* Set the API key for LWS (Light Wallet Server) requests.
|
|
143
|
+
* Once set, the key will be included in all subsequent LWS HTTP POST requests
|
|
144
|
+
* as an "api_key" field in the JSON body.
|
|
145
|
+
* @param apiKey - The API key to include in LWS requests
|
|
146
|
+
*/
|
|
147
|
+
setLwsApiKey(apiKey: string): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Enable or disable the Nym fetch interceptor.
|
|
150
|
+
*
|
|
151
|
+
* When enabled, all LWSF HTTP POST requests that the C++ wallet code
|
|
152
|
+
* would have issued are redirected through the native event bridge. The
|
|
153
|
+
* consumer must register a handler via `NativeEventEmitter` on the
|
|
154
|
+
* "MoneroWalletEvent" event with `eventName === 'nymFetchRequest'` and
|
|
155
|
+
* call `resolveFetch` / `rejectFetch` to complete the request.
|
|
156
|
+
*
|
|
157
|
+
* @param enabled - Whether to route HTTP through the JS fetch bridge
|
|
158
|
+
* @param baseUrl - scheme://host[:port] of the LWSF server (must match
|
|
159
|
+
* the daemon address used at openWallet time). Empty
|
|
160
|
+
* when disabling.
|
|
161
|
+
*/
|
|
162
|
+
setNymEnabled(enabled: boolean, baseUrl: string): Promise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* Resolve a pending nym fetch request that was emitted as a
|
|
165
|
+
* `nymFetchRequest` wallet event. Must be called with the same
|
|
166
|
+
* `requestId` carried on the incoming event.
|
|
167
|
+
*
|
|
168
|
+
* @param requestId - id forwarded via the native event
|
|
169
|
+
* @param status - HTTP status code returned from fetch
|
|
170
|
+
* @param bodyBase64 - response body encoded as base64
|
|
171
|
+
*/
|
|
172
|
+
resolveFetch(requestId: string, status: number, bodyBase64: string): Promise<void>;
|
|
173
|
+
/**
|
|
174
|
+
* Reject a pending nym fetch request. The blocked C++ caller will
|
|
175
|
+
* receive a runtime_error bubbled as an RPC failure.
|
|
176
|
+
*
|
|
177
|
+
* @param requestId - id forwarded via the native event
|
|
178
|
+
* @param errorMessage - human-readable error description
|
|
179
|
+
*/
|
|
180
|
+
rejectFetch(requestId: string, errorMessage: string): Promise<void>;
|
|
181
|
+
}
|