From aae968b1c217b84a33e58b48905b68b9bf0d14c0 Mon Sep 17 00:00:00 2001 From: MoCipher Date: Fri, 20 Feb 2026 10:10:41 +0100 Subject: [PATCH] new file: core/uniffi/bindings/android/Cryptec.java new file: core/uniffi/bindings/ios/Cryptec.h new file: mobile/__tests__/nativeModuleIntegration.test.ts new file: mobile/android/src/main/java/com/cryptec/CryptecModule.java new file: mobile/android/src/main/java/com/cryptec/CryptecPackage.java new file: mobile/ios/CryptecModule.m --- core/uniffi/bindings/android/Cryptec.java | 10 +++++ core/uniffi/bindings/ios/Cryptec.h | 15 +++++++ .../__tests__/nativeModuleIntegration.test.ts | 35 +++++++++++++++++ .../main/java/com/cryptec/CryptecModule.java | 39 +++++++++++++++++++ .../main/java/com/cryptec/CryptecPackage.java | 24 ++++++++++++ mobile/ios/CryptecModule.m | 10 +++++ 6 files changed, 133 insertions(+) create mode 100644 core/uniffi/bindings/android/Cryptec.java create mode 100644 core/uniffi/bindings/ios/Cryptec.h create mode 100644 mobile/__tests__/nativeModuleIntegration.test.ts create mode 100644 mobile/android/src/main/java/com/cryptec/CryptecModule.java create mode 100644 mobile/android/src/main/java/com/cryptec/CryptecPackage.java create mode 100644 mobile/ios/CryptecModule.m diff --git a/core/uniffi/bindings/android/Cryptec.java b/core/uniffi/bindings/android/Cryptec.java new file mode 100644 index 0000000..feed854 --- /dev/null +++ b/core/uniffi/bindings/android/Cryptec.java @@ -0,0 +1,10 @@ +// UniFFI-generated placeholder for Android (stub). +// The real generated class will provide JNI hooks to the Rust library. +package org.cryptec.uniffi.bindings; + +public final class Cryptec { + public static String generate_mnemonic(int strength) { return ""; } + public static String first_receive_address(String mnemonic) { return ""; } + public static String create_psbt(String mnemonic, String to, long sats) { return ""; } + public static String sign_psbt(String mnemonic, String psbt_b64) { return ""; } +} diff --git a/core/uniffi/bindings/ios/Cryptec.h b/core/uniffi/bindings/ios/Cryptec.h new file mode 100644 index 0000000..5a91a6c --- /dev/null +++ b/core/uniffi/bindings/ios/Cryptec.h @@ -0,0 +1,15 @@ +// UniFFI placeholder header (iOS) - generated bindings will provide concrete implementations +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface Cryptec : NSObject + ++ (NSString*)generate_mnemonic:(uint32_t)strength; ++ (NSString*)first_receive_address:(NSString*)mnemonic; ++ (NSString*)create_psbt:(NSString*)mnemonic to:(NSString*)to sats:(uint64_t)sats; ++ (NSString*)sign_psbt:(NSString*)mnemonic psbt:(NSString*)psbt_b64; + +@end + +NS_ASSUME_NONNULL_END diff --git a/mobile/__tests__/nativeModuleIntegration.test.ts b/mobile/__tests__/nativeModuleIntegration.test.ts new file mode 100644 index 0000000..af177f2 --- /dev/null +++ b/mobile/__tests__/nativeModuleIntegration.test.ts @@ -0,0 +1,35 @@ +import { NativeModules } from 'react-native'; +import nativeBridge from '../src/nativeBridge'; + +describe('native module integration (shim)', () => { + afterEach(() => { + jest.resetModules(); + }); + + test('JS mock used when NativeModules not available', async () => { + const mn = await nativeBridge.generateMnemonic(128); + expect(typeof mn).toBe('string'); + const addr = nativeBridge.firstReceiveAddressFromMnemonic(mn); + expect(typeof addr).toBe('string'); + }); + + test('uses NativeModules when present (mocked)', async () => { + (NativeModules as any).Cryptec = { + generate_mnemonic: (s: number) => 'abandon abandon abandon ...', + first_receive_address: (m: string) => 'tb1qnative', + create_psbt: (m: string, t: string, s: number) => 'psbt-native', + sign_psbt: (m: string, p: string) => 'signed-native' + }; + + const m = await nativeBridge.generateMnemonic(128); + expect(m).toContain('abandon'); + const addr = nativeBridge.firstReceiveAddressFromMnemonic('x'); + expect(addr).toBe('tb1qnative'); + + const psbt = await nativeBridge.createPsbtMock('x', 'tb1qnative', 1000); + expect(psbt).toBe('psbt-native'); + + const signed = await nativeBridge.signPsbtMock('x', 'psbt-native'); + expect(signed).toBe('signed-native'); + }); +}); diff --git a/mobile/android/src/main/java/com/cryptec/CryptecModule.java b/mobile/android/src/main/java/com/cryptec/CryptecModule.java new file mode 100644 index 0000000..04bf34c --- /dev/null +++ b/mobile/android/src/main/java/com/cryptec/CryptecModule.java @@ -0,0 +1,39 @@ +package com.cryptec; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.Promise; + +public class CryptecModule extends ReactContextBaseJavaModule { + public CryptecModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public String getName() { + return "Cryptec"; + } + + @ReactMethod + public void generate_mnemonic(int strength, Promise p) { + // Native implementation should call into UniFFI-generated JNI bridge. + // Fallback: return an error so JS fallback can be used in dev/CI. + p.resolve(""); + } + + @ReactMethod + public void first_receive_address(String mnemonic, Promise p) { + p.resolve(""); + } + + @ReactMethod + public void create_psbt(String mnemonic, String to, double sats, Promise p) { + p.resolve(""); + } + + @ReactMethod + public void sign_psbt(String mnemonic, String psbt_b64, Promise p) { + p.resolve(""); + } +} diff --git a/mobile/android/src/main/java/com/cryptec/CryptecPackage.java b/mobile/android/src/main/java/com/cryptec/CryptecPackage.java new file mode 100644 index 0000000..6fcbeba --- /dev/null +++ b/mobile/android/src/main/java/com/cryptec/CryptecPackage.java @@ -0,0 +1,24 @@ +package com.cryptec; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class CryptecPackage implements ReactPackage { + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + modules.add(new CryptecModule(reactContext)); + return modules; + } +} diff --git a/mobile/ios/CryptecModule.m b/mobile/ios/CryptecModule.m new file mode 100644 index 0000000..a34dfdc --- /dev/null +++ b/mobile/ios/CryptecModule.m @@ -0,0 +1,10 @@ +#import + +@interface RCT_EXTERN_MODULE(Cryptec, NSObject) + +RCT_EXTERN_METHOD(generate_mnemonic:(NSInteger)strength resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(first_receive_address:(NSString*)mnemonic resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(create_psbt:(NSString*)mnemonic to:(NSString*)to sats:(nonnull NSNumber*)sats resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(sign_psbt:(NSString*)mnemonic psbt:(NSString*)psbt resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) + +@end