@novastera-oss/nitro-metamask 0.3.3 → 0.4.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/README.md +45 -1
- package/android/src/main/java/com/margelo/nitro/nitrometamask/HybridNitroMetamask.kt +349 -175
- package/app.plugin.js +121 -0
- package/ios/HybridNitroMetamask.swift +71 -110
- package/lib/typescript/src/specs/nitro-metamask.nitro.d.ts +31 -6
- package/lib/typescript/src/specs/nitro-metamask.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/NitroMetamask+autolinking.cmake +2 -0
- package/nitrogen/generated/android/c++/JConnectResult.hpp +3 -3
- package/nitrogen/generated/android/c++/JConnectSignResult.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridNitroMetamaskSpec.cpp +48 -7
- package/nitrogen/generated/android/c++/JHybridNitroMetamaskSpec.hpp +4 -2
- package/nitrogen/generated/android/c++/JVariant_NullType_Long.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_Long.hpp +69 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_String.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_String.hpp +70 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrometamask/ConnectResult.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrometamask/ConnectSignResult.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrometamask/HybridNitroMetamaskSpec.kt +11 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrometamask/Variant_NullType_Long.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrometamask/Variant_NullType_String.kt +59 -0
- package/nitrogen/generated/ios/NitroMetamask-Swift-Cxx-Bridge.cpp +24 -0
- package/nitrogen/generated/ios/NitroMetamask-Swift-Cxx-Bridge.hpp +192 -0
- package/nitrogen/generated/ios/NitroMetamask-Swift-Cxx-Umbrella.hpp +5 -0
- package/nitrogen/generated/ios/c++/HybridNitroMetamaskSpecSwift.hpp +24 -3
- package/nitrogen/generated/ios/swift/ConnectResult.swift +2 -2
- package/nitrogen/generated/ios/swift/ConnectSignResult.swift +40 -0
- package/nitrogen/generated/ios/swift/Func_void_ConnectSignResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__int64_t_.swift +59 -0
- package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__std__string_.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridNitroMetamaskSpec.swift +4 -2
- package/nitrogen/generated/ios/swift/HybridNitroMetamaskSpec_cxx.swift +67 -8
- package/nitrogen/generated/ios/swift/Variant_NullType_Int64.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_String.swift +18 -0
- package/nitrogen/generated/shared/c++/ConnectResult.hpp +5 -5
- package/nitrogen/generated/shared/c++/ConnectSignResult.hpp +91 -0
- package/nitrogen/generated/shared/c++/HybridNitroMetamaskSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridNitroMetamaskSpec.hpp +9 -2
- package/package.json +3 -2
- package/src/specs/nitro-metamask.nitro.ts +32 -6
package/app.plugin.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const { withAppDelegate } = require('@expo/config-plugins');
|
|
2
|
+
|
|
3
|
+
const withMetamaskAppDelegate = (config) => {
|
|
4
|
+
return withAppDelegate(config, (config) => {
|
|
5
|
+
const { modResults } = config;
|
|
6
|
+
|
|
7
|
+
// Check if AppDelegate is Swift
|
|
8
|
+
if (modResults.language === 'swift') {
|
|
9
|
+
// Check if the method already exists
|
|
10
|
+
if (modResults.contents.includes('MetaMaskSDK.shared.handleUrl')) {
|
|
11
|
+
return config;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Add import if not present
|
|
15
|
+
if (!modResults.contents.includes('import MetaMaskSDK')) {
|
|
16
|
+
// Find the last import statement and add after it
|
|
17
|
+
const importRegex = /^import\s+.*$/gm;
|
|
18
|
+
const imports = modResults.contents.match(importRegex);
|
|
19
|
+
if (imports && imports.length > 0) {
|
|
20
|
+
const lastImport = imports[imports.length - 1];
|
|
21
|
+
const lastImportIndex = modResults.contents.lastIndexOf(lastImport);
|
|
22
|
+
modResults.contents =
|
|
23
|
+
modResults.contents.slice(0, lastImportIndex + lastImport.length) +
|
|
24
|
+
'\nimport MetaMaskSDK' +
|
|
25
|
+
modResults.contents.slice(lastImportIndex + lastImport.length);
|
|
26
|
+
} else {
|
|
27
|
+
// No imports found, add at the top after the first line
|
|
28
|
+
const firstLineIndex = modResults.contents.indexOf('\n');
|
|
29
|
+
modResults.contents =
|
|
30
|
+
modResults.contents.slice(0, firstLineIndex + 1) +
|
|
31
|
+
'import MetaMaskSDK\n' +
|
|
32
|
+
modResults.contents.slice(firstLineIndex + 1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Add the deep link handler method
|
|
37
|
+
const deepLinkHandler = `
|
|
38
|
+
// Handle deep links from MetaMask wallet
|
|
39
|
+
// MetaMask returns to the app via deep link after signing/connecting
|
|
40
|
+
// Added by @novastera-oss/nitro-metamask config plugin
|
|
41
|
+
func application(
|
|
42
|
+
_ app: UIApplication,
|
|
43
|
+
open url: URL,
|
|
44
|
+
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
|
|
45
|
+
) -> Bool {
|
|
46
|
+
// Check if this is a MetaMask deep link (host="mmsdk")
|
|
47
|
+
if let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
|
|
48
|
+
components.host == "mmsdk" {
|
|
49
|
+
// Handle MetaMask deep link return
|
|
50
|
+
MetaMaskSDK.shared.handleUrl(url)
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Handle other deep links (e.g., React Native Linking)
|
|
55
|
+
return false
|
|
56
|
+
}`;
|
|
57
|
+
|
|
58
|
+
// Insert before the last closing brace of the AppDelegate class
|
|
59
|
+
// Try to find the closing brace of the class before @end or end of file
|
|
60
|
+
const classEndPattern = /(\s+)\}(?=\s*(?:@end|$))/;
|
|
61
|
+
const match = modResults.contents.match(classEndPattern);
|
|
62
|
+
if (match) {
|
|
63
|
+
const indent = match[1];
|
|
64
|
+
const insertIndex = match.index;
|
|
65
|
+
modResults.contents =
|
|
66
|
+
modResults.contents.slice(0, insertIndex) +
|
|
67
|
+
deepLinkHandler.replace(/^ /gm, indent) +
|
|
68
|
+
'\n' + indent + '}' +
|
|
69
|
+
modResults.contents.slice(insertIndex + match[0].length);
|
|
70
|
+
} else {
|
|
71
|
+
// Fallback: append before @end
|
|
72
|
+
modResults.contents = modResults.contents.replace(
|
|
73
|
+
/^(@end|}$)/m,
|
|
74
|
+
deepLinkHandler + '\n$1'
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
} else if (modResults.language === 'objc') {
|
|
78
|
+
// Handle Objective-C AppDelegate
|
|
79
|
+
if (modResults.contents.includes('MetaMaskSDK')) {
|
|
80
|
+
return config;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Add import
|
|
84
|
+
if (!modResults.contents.includes('#import <MetaMaskSDK/MetaMaskSDK.h>')) {
|
|
85
|
+
const importRegex = /^#import\s+.*$/gm;
|
|
86
|
+
const imports = modResults.contents.match(importRegex);
|
|
87
|
+
if (imports && imports.length > 0) {
|
|
88
|
+
const lastImport = imports[imports.length - 1];
|
|
89
|
+
const lastImportIndex = modResults.contents.lastIndexOf(lastImport);
|
|
90
|
+
modResults.contents =
|
|
91
|
+
modResults.contents.slice(0, lastImportIndex + lastImport.length) +
|
|
92
|
+
'\n#import <MetaMaskSDK/MetaMaskSDK.h>' +
|
|
93
|
+
modResults.contents.slice(lastImportIndex + lastImport.length);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const objcHandler = `
|
|
98
|
+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
|
99
|
+
// Check if this is a MetaMask deep link (host="mmsdk")
|
|
100
|
+
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
|
|
101
|
+
if ([components.host isEqualToString:@"mmsdk"]) {
|
|
102
|
+
// Handle MetaMask deep link return
|
|
103
|
+
[[MetaMaskSDK sharedInstance] handleUrl:url];
|
|
104
|
+
return YES;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Handle other deep links
|
|
108
|
+
return NO;
|
|
109
|
+
}`;
|
|
110
|
+
|
|
111
|
+
modResults.contents = modResults.contents.replace(
|
|
112
|
+
/^(@end|}$)/m,
|
|
113
|
+
objcHandler + '\n$1'
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return config;
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
module.exports = withMetamaskAppDelegate;
|
|
@@ -9,9 +9,10 @@ final class HybridNitroMetamask: HybridNitroMetamaskSpec {
|
|
|
9
9
|
// iOS SDK handles deep linking automatically via Info.plist
|
|
10
10
|
private var dappUrl: String? = nil
|
|
11
11
|
|
|
12
|
-
func configure(dappUrl: String?) {
|
|
12
|
+
func configure(dappUrl: String?, deepLinkScheme: String?) {
|
|
13
13
|
// iOS SDK handles deep linking automatically via Info.plist
|
|
14
14
|
// Store the URL for consistency with Android implementation
|
|
15
|
+
// deepLinkScheme is ignored on iOS as it's handled automatically
|
|
15
16
|
self.dappUrl = dappUrl
|
|
16
17
|
NSLog("NitroMetamask: configure: Dapp URL set to \(dappUrl ?? "default"). Deep link handled automatically via Info.plist")
|
|
17
18
|
}
|
|
@@ -53,7 +54,7 @@ final class HybridNitroMetamask: HybridNitroMetamaskSpec {
|
|
|
53
54
|
|
|
54
55
|
return ConnectResult(
|
|
55
56
|
address: address,
|
|
56
|
-
chainId:
|
|
57
|
+
chainId: Int64(chainIdInt)
|
|
57
58
|
)
|
|
58
59
|
|
|
59
60
|
case .failure(let error):
|
|
@@ -105,136 +106,96 @@ final class HybridNitroMetamask: HybridNitroMetamaskSpec {
|
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
func connectSign(nonce: String, exp: Int64) -> Promise<
|
|
109
|
+
func connectSign(nonce: String, exp: Int64) -> Promise<ConnectSignResult> {
|
|
109
110
|
// Use Promise.async with Swift async/await for best practice in Nitro modules
|
|
110
111
|
// Reference: https://nitro.margelo.com/docs/types/promises
|
|
111
|
-
// Based on MetaMask iOS SDK:
|
|
112
|
+
// Based on MetaMask iOS SDK: connectAndSign(message:) convenience method
|
|
112
113
|
// Reference: https://github.com/MetaMask/metamask-ios-sdk
|
|
113
114
|
return Promise.async {
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
// Construct JSON message with only nonce and exp
|
|
116
|
+
// We don't include address or chainID - just encrypt nonce and exp
|
|
117
|
+
let messageDict: [String: Any] = [
|
|
118
|
+
"nonce": nonce,
|
|
119
|
+
"exp": exp
|
|
120
|
+
]
|
|
117
121
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
domain: "MetamaskConnector",
|
|
139
|
-
code: -1,
|
|
140
|
-
userInfo: [NSLocalizedDescriptionKey: "Invalid chainId format"]
|
|
141
|
-
)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Construct JSON message
|
|
145
|
-
let messageDict: [String: Any] = [
|
|
146
|
-
"address": account,
|
|
147
|
-
"chainID": chainIdInt,
|
|
148
|
-
"nonce": nonce,
|
|
149
|
-
"exp": exp
|
|
150
|
-
]
|
|
151
|
-
|
|
152
|
-
guard let jsonData = try? JSONSerialization.data(withJSONObject: messageDict),
|
|
153
|
-
let message = String(data: jsonData, encoding: .utf8) else {
|
|
154
|
-
throw NSError(
|
|
155
|
-
domain: "MetamaskConnector",
|
|
156
|
-
code: -1,
|
|
157
|
-
userInfo: [NSLocalizedDescriptionKey: "Failed to create JSON message"]
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Create EthereumRequest for personal_sign
|
|
162
|
-
let params: [String] = [account, message]
|
|
163
|
-
let request = EthereumRequest(
|
|
164
|
-
method: .personalSign,
|
|
165
|
-
params: params
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
// Make the request using the SDK's async request method
|
|
169
|
-
let result = try await self.sdk.request(request)
|
|
170
|
-
|
|
171
|
-
// Extract signature from response
|
|
172
|
-
if let signature = result as? String {
|
|
173
|
-
return signature
|
|
174
|
-
} else if let dict = result as? [String: Any], let sig = dict["signature"] as? String ?? dict["result"] as? String {
|
|
175
|
-
return sig
|
|
176
|
-
} else {
|
|
177
|
-
throw NSError(
|
|
178
|
-
domain: "MetamaskConnector",
|
|
179
|
-
code: -1,
|
|
180
|
-
userInfo: [NSLocalizedDescriptionKey: "Invalid signature response format"]
|
|
181
|
-
)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
case .failure(let error):
|
|
185
|
-
throw error
|
|
186
|
-
}
|
|
187
|
-
} else {
|
|
188
|
-
// Already connected, construct message and sign
|
|
189
|
-
guard let account = address, !account.isEmpty,
|
|
190
|
-
let chainId = chainIdHex, !chainId.isEmpty,
|
|
191
|
-
let chainIdInt = Int(chainId.replacingOccurrences(of: "0x", with: ""), radix: 16) else {
|
|
122
|
+
guard let jsonData = try? JSONSerialization.data(withJSONObject: messageDict),
|
|
123
|
+
let message = String(data: jsonData, encoding: .utf8) else {
|
|
124
|
+
throw NSError(
|
|
125
|
+
domain: "MetamaskConnector",
|
|
126
|
+
code: -1,
|
|
127
|
+
userInfo: [NSLocalizedDescriptionKey: "Failed to create JSON message"]
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
NSLog("NitroMetamask: connectSign: Constructed message with nonce and exp: \(message)")
|
|
132
|
+
|
|
133
|
+
// Use the SDK's connectAndSign convenience method - it will connect if needed and sign the message
|
|
134
|
+
// This is the recommended approach per MetaMask iOS SDK documentation
|
|
135
|
+
// Reference: https://github.com/MetaMask/metamask-ios-sdk
|
|
136
|
+
let connectSignResult = try await self.sdk.connectAndSign(message: message)
|
|
137
|
+
|
|
138
|
+
switch connectSignResult {
|
|
139
|
+
case .success(let signature):
|
|
140
|
+
// After connectSign completes, get the address and chainId from the SDK
|
|
141
|
+
guard let address = self.sdk.account, !address.isEmpty else {
|
|
192
142
|
throw NSError(
|
|
193
143
|
domain: "MetamaskConnector",
|
|
194
144
|
code: -1,
|
|
195
|
-
userInfo: [NSLocalizedDescriptionKey: "
|
|
145
|
+
userInfo: [NSLocalizedDescriptionKey: "Failed to retrieve address after connectSign"]
|
|
196
146
|
)
|
|
197
147
|
}
|
|
198
148
|
|
|
199
|
-
|
|
200
|
-
let messageDict: [String: Any] = [
|
|
201
|
-
"address": account,
|
|
202
|
-
"chainID": chainIdInt,
|
|
203
|
-
"nonce": nonce,
|
|
204
|
-
"exp": Int64(exp)
|
|
205
|
-
]
|
|
206
|
-
|
|
207
|
-
guard let jsonData = try? JSONSerialization.data(withJSONObject: messageDict),
|
|
208
|
-
let message = String(data: jsonData, encoding: .utf8) else {
|
|
149
|
+
guard let chainIdHex = self.sdk.chainId, !chainIdHex.isEmpty else {
|
|
209
150
|
throw NSError(
|
|
210
151
|
domain: "MetamaskConnector",
|
|
211
152
|
code: -1,
|
|
212
|
-
userInfo: [NSLocalizedDescriptionKey: "Failed to
|
|
153
|
+
userInfo: [NSLocalizedDescriptionKey: "Failed to retrieve chainId after connectSign"]
|
|
213
154
|
)
|
|
214
155
|
}
|
|
215
156
|
|
|
216
|
-
//
|
|
217
|
-
let
|
|
218
|
-
let request = EthereumRequest(
|
|
219
|
-
method: .personalSign,
|
|
220
|
-
params: params
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
// Make the request using the SDK's async request method
|
|
224
|
-
let result = try await self.sdk.request(request)
|
|
225
|
-
|
|
226
|
-
// Extract signature from response
|
|
227
|
-
if let signature = result as? String {
|
|
228
|
-
return signature
|
|
229
|
-
} else if let dict = result as? [String: Any], let sig = dict["signature"] as? String ?? dict["result"] as? String {
|
|
230
|
-
return sig
|
|
231
|
-
} else {
|
|
157
|
+
// Parse chainId from hex string (e.g., "0x1") to Int64
|
|
158
|
+
guard let chainId = Int64(chainIdHex.replacingOccurrences(of: "0x", with: ""), radix: 16) else {
|
|
232
159
|
throw NSError(
|
|
233
160
|
domain: "MetamaskConnector",
|
|
234
161
|
code: -1,
|
|
235
|
-
userInfo: [NSLocalizedDescriptionKey: "Invalid
|
|
162
|
+
userInfo: [NSLocalizedDescriptionKey: "Invalid chainId format: \(chainIdHex)"]
|
|
236
163
|
)
|
|
237
164
|
}
|
|
165
|
+
|
|
166
|
+
NSLog("NitroMetamask: connectSign: Signature received successfully, address=\(address), chainId=\(chainId)")
|
|
167
|
+
|
|
168
|
+
// Return ConnectSignResult with signature, address, and chainId
|
|
169
|
+
return ConnectSignResult(signature: signature, address: address, chainId: chainId)
|
|
170
|
+
|
|
171
|
+
case .failure(let error):
|
|
172
|
+
throw error
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
func getAddress() -> Promise<Variant_NullType_String> {
|
|
178
|
+
return Promise.async {
|
|
179
|
+
if let account = self.sdk.account, !account.isEmpty {
|
|
180
|
+
return Variant_NullType_String.second(account)
|
|
181
|
+
} else {
|
|
182
|
+
return Variant_NullType_String.first(NullType())
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
func getChainId() -> Promise<Variant_NullType_Int64> {
|
|
188
|
+
return Promise.async {
|
|
189
|
+
guard let chainIdHex = self.sdk.chainId, !chainIdHex.isEmpty else {
|
|
190
|
+
return Variant_NullType_Int64.first(NullType())
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Parse chainId from hex string (e.g., "0x1") to Int64 (bigint maps to Int64 in Swift)
|
|
194
|
+
if let chainIdInt = Int64(chainIdHex.replacingOccurrences(of: "0x", with: ""), radix: 16) {
|
|
195
|
+
return Variant_NullType_Int64.second(chainIdInt)
|
|
196
|
+
} else {
|
|
197
|
+
NSLog("NitroMetamask: Invalid chainId format: \(chainIdHex)")
|
|
198
|
+
return Variant_NullType_Int64.first(NullType())
|
|
238
199
|
}
|
|
239
200
|
}
|
|
240
201
|
}
|
|
@@ -1,23 +1,48 @@
|
|
|
1
1
|
import { type HybridObject } from 'react-native-nitro-modules';
|
|
2
2
|
export interface ConnectResult {
|
|
3
3
|
address: string;
|
|
4
|
-
chainId:
|
|
4
|
+
chainId: bigint;
|
|
5
|
+
}
|
|
6
|
+
export interface ConnectSignResult {
|
|
7
|
+
signature: string;
|
|
8
|
+
address: string;
|
|
9
|
+
chainId: bigint;
|
|
5
10
|
}
|
|
6
11
|
export interface NitroMetamask extends HybridObject<{
|
|
7
12
|
ios: 'swift';
|
|
8
13
|
android: 'kotlin';
|
|
9
14
|
}> {
|
|
10
15
|
/**
|
|
11
|
-
* Configure the dapp URL for MetaMask SDK
|
|
12
|
-
* This URL is only used for SDK validation - the deep link return is handled automatically via AndroidManifest.xml.
|
|
16
|
+
* Configure the dapp URL and deep link scheme for MetaMask SDK.
|
|
13
17
|
*
|
|
14
18
|
* @param dappUrl - A valid HTTP/HTTPS URL (e.g., "https://yourdomain.com").
|
|
15
19
|
* If not provided, defaults to "https://novastera.com".
|
|
16
|
-
* This is
|
|
20
|
+
* This is used for SDK validation.
|
|
21
|
+
* @param deepLinkScheme - The deep link scheme from your AndroidManifest.xml (e.g., "nitrometamask").
|
|
22
|
+
* If not provided, the library will attempt to auto-detect it.
|
|
23
|
+
* This is used to return to your app after MetaMask operations.
|
|
17
24
|
*/
|
|
18
|
-
configure(dappUrl?: string): void;
|
|
25
|
+
configure(dappUrl?: string, deepLinkScheme?: string): void;
|
|
19
26
|
connect(): Promise<ConnectResult>;
|
|
20
27
|
signMessage(message: string): Promise<string>;
|
|
21
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Connect to MetaMask (if not already connected) and sign a message containing nonce and expiration.
|
|
30
|
+
* Returns the signature along with the address and chainId that were used to sign.
|
|
31
|
+
*
|
|
32
|
+
* @param nonce - A unique nonce for this signing request
|
|
33
|
+
* @param exp - Expiration timestamp (as bigint)
|
|
34
|
+
* @returns Promise resolving to ConnectSignResult containing signature, address, and chainId
|
|
35
|
+
*/
|
|
36
|
+
connectSign(nonce: string, exp: bigint): Promise<ConnectSignResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Get the currently connected wallet address.
|
|
39
|
+
* Returns null if not connected.
|
|
40
|
+
*/
|
|
41
|
+
getAddress(): Promise<string | null>;
|
|
42
|
+
/**
|
|
43
|
+
* Get the current chain ID.
|
|
44
|
+
* Returns null if not connected.
|
|
45
|
+
*/
|
|
46
|
+
getChainId(): Promise<bigint | null>;
|
|
22
47
|
}
|
|
23
48
|
//# sourceMappingURL=nitro-metamask.nitro.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nitro-metamask.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/nitro-metamask.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IACtF
|
|
1
|
+
{"version":3,"file":"nitro-metamask.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/nitro-metamask.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IACtF;;;;;;;;;OASG;IACH,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1D,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC,CAAA;IACjC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7C;;;;;;;OAOG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACnE;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACpC;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CACrC"}
|
|
@@ -36,6 +36,8 @@ target_sources(
|
|
|
36
36
|
../nitrogen/generated/shared/c++/HybridNitroMetamaskSpec.cpp
|
|
37
37
|
# Android-specific Nitrogen C++ sources
|
|
38
38
|
../nitrogen/generated/android/c++/JHybridNitroMetamaskSpec.cpp
|
|
39
|
+
../nitrogen/generated/android/c++/JVariant_NullType_String.cpp
|
|
40
|
+
../nitrogen/generated/android/c++/JVariant_NullType_Long.cpp
|
|
39
41
|
)
|
|
40
42
|
|
|
41
43
|
# From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
|
|
@@ -33,8 +33,8 @@ namespace margelo::nitro::nitrometamask {
|
|
|
33
33
|
static const auto clazz = javaClassStatic();
|
|
34
34
|
static const auto fieldAddress = clazz->getField<jni::JString>("address");
|
|
35
35
|
jni::local_ref<jni::JString> address = this->getFieldValue(fieldAddress);
|
|
36
|
-
static const auto fieldChainId = clazz->getField<
|
|
37
|
-
|
|
36
|
+
static const auto fieldChainId = clazz->getField<int64_t>("chainId");
|
|
37
|
+
int64_t chainId = this->getFieldValue(fieldChainId);
|
|
38
38
|
return ConnectResult(
|
|
39
39
|
address->toStdString(),
|
|
40
40
|
chainId
|
|
@@ -47,7 +47,7 @@ namespace margelo::nitro::nitrometamask {
|
|
|
47
47
|
*/
|
|
48
48
|
[[maybe_unused]]
|
|
49
49
|
static jni::local_ref<JConnectResult::javaobject> fromCpp(const ConnectResult& value) {
|
|
50
|
-
using JSignature = JConnectResult(jni::alias_ref<jni::JString>,
|
|
50
|
+
using JSignature = JConnectResult(jni::alias_ref<jni::JString>, int64_t);
|
|
51
51
|
static const auto clazz = javaClassStatic();
|
|
52
52
|
static const auto create = clazz->getStaticMethod<JSignature>("fromCpp");
|
|
53
53
|
return create(
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// JConnectSignResult.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <fbjni/fbjni.h>
|
|
11
|
+
#include "ConnectSignResult.hpp"
|
|
12
|
+
|
|
13
|
+
#include <string>
|
|
14
|
+
|
|
15
|
+
namespace margelo::nitro::nitrometamask {
|
|
16
|
+
|
|
17
|
+
using namespace facebook;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The C++ JNI bridge between the C++ struct "ConnectSignResult" and the the Kotlin data class "ConnectSignResult".
|
|
21
|
+
*/
|
|
22
|
+
struct JConnectSignResult final: public jni::JavaClass<JConnectSignResult> {
|
|
23
|
+
public:
|
|
24
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/nitrometamask/ConnectSignResult;";
|
|
25
|
+
|
|
26
|
+
public:
|
|
27
|
+
/**
|
|
28
|
+
* Convert this Java/Kotlin-based struct to the C++ struct ConnectSignResult by copying all values to C++.
|
|
29
|
+
*/
|
|
30
|
+
[[maybe_unused]]
|
|
31
|
+
[[nodiscard]]
|
|
32
|
+
ConnectSignResult toCpp() const {
|
|
33
|
+
static const auto clazz = javaClassStatic();
|
|
34
|
+
static const auto fieldSignature = clazz->getField<jni::JString>("signature");
|
|
35
|
+
jni::local_ref<jni::JString> signature = this->getFieldValue(fieldSignature);
|
|
36
|
+
static const auto fieldAddress = clazz->getField<jni::JString>("address");
|
|
37
|
+
jni::local_ref<jni::JString> address = this->getFieldValue(fieldAddress);
|
|
38
|
+
static const auto fieldChainId = clazz->getField<int64_t>("chainId");
|
|
39
|
+
int64_t chainId = this->getFieldValue(fieldChainId);
|
|
40
|
+
return ConnectSignResult(
|
|
41
|
+
signature->toStdString(),
|
|
42
|
+
address->toStdString(),
|
|
43
|
+
chainId
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public:
|
|
48
|
+
/**
|
|
49
|
+
* Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java.
|
|
50
|
+
*/
|
|
51
|
+
[[maybe_unused]]
|
|
52
|
+
static jni::local_ref<JConnectSignResult::javaobject> fromCpp(const ConnectSignResult& value) {
|
|
53
|
+
using JSignature = JConnectSignResult(jni::alias_ref<jni::JString>, jni::alias_ref<jni::JString>, int64_t);
|
|
54
|
+
static const auto clazz = javaClassStatic();
|
|
55
|
+
static const auto create = clazz->getStaticMethod<JSignature>("fromCpp");
|
|
56
|
+
return create(
|
|
57
|
+
clazz,
|
|
58
|
+
jni::make_jstring(value.signature),
|
|
59
|
+
jni::make_jstring(value.address),
|
|
60
|
+
value.chainId
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
} // namespace margelo::nitro::nitrometamask
|
|
@@ -9,12 +9,21 @@
|
|
|
9
9
|
|
|
10
10
|
// Forward declaration of `ConnectResult` to properly resolve imports.
|
|
11
11
|
namespace margelo::nitro::nitrometamask { struct ConnectResult; }
|
|
12
|
+
// Forward declaration of `ConnectSignResult` to properly resolve imports.
|
|
13
|
+
namespace margelo::nitro::nitrometamask { struct ConnectSignResult; }
|
|
12
14
|
|
|
13
15
|
#include "ConnectResult.hpp"
|
|
14
16
|
#include <NitroModules/Promise.hpp>
|
|
15
17
|
#include <NitroModules/JPromise.hpp>
|
|
16
18
|
#include "JConnectResult.hpp"
|
|
17
19
|
#include <string>
|
|
20
|
+
#include "ConnectSignResult.hpp"
|
|
21
|
+
#include "JConnectSignResult.hpp"
|
|
22
|
+
#include <NitroModules/Null.hpp>
|
|
23
|
+
#include <variant>
|
|
24
|
+
#include "JVariant_NullType_String.hpp"
|
|
25
|
+
#include <NitroModules/JNull.hpp>
|
|
26
|
+
#include "JVariant_NullType_Long.hpp"
|
|
18
27
|
#include <optional>
|
|
19
28
|
|
|
20
29
|
namespace margelo::nitro::nitrometamask {
|
|
@@ -49,9 +58,9 @@ namespace margelo::nitro::nitrometamask {
|
|
|
49
58
|
|
|
50
59
|
|
|
51
60
|
// Methods
|
|
52
|
-
void JHybridNitroMetamaskSpec::configure(const std::optional<std::string>& dappUrl) {
|
|
53
|
-
static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* dappUrl */)>("configure");
|
|
54
|
-
method(_javaPart, dappUrl.has_value() ? jni::make_jstring(dappUrl.value()) : nullptr);
|
|
61
|
+
void JHybridNitroMetamaskSpec::configure(const std::optional<std::string>& dappUrl, const std::optional<std::string>& deepLinkScheme) {
|
|
62
|
+
static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* dappUrl */, jni::alias_ref<jni::JString> /* deepLinkScheme */)>("configure");
|
|
63
|
+
method(_javaPart, dappUrl.has_value() ? jni::make_jstring(dappUrl.value()) : nullptr, deepLinkScheme.has_value() ? jni::make_jstring(deepLinkScheme.value()) : nullptr);
|
|
55
64
|
}
|
|
56
65
|
std::shared_ptr<Promise<ConnectResult>> JHybridNitroMetamaskSpec::connect() {
|
|
57
66
|
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("connect");
|
|
@@ -85,14 +94,46 @@ namespace margelo::nitro::nitrometamask {
|
|
|
85
94
|
return __promise;
|
|
86
95
|
}();
|
|
87
96
|
}
|
|
88
|
-
std::shared_ptr<Promise<
|
|
97
|
+
std::shared_ptr<Promise<ConnectSignResult>> JHybridNitroMetamaskSpec::connectSign(const std::string& nonce, int64_t exp) {
|
|
89
98
|
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JString> /* nonce */, int64_t /* exp */)>("connectSign");
|
|
90
99
|
auto __result = method(_javaPart, jni::make_jstring(nonce), exp);
|
|
91
100
|
return [&]() {
|
|
92
|
-
auto __promise = Promise<
|
|
101
|
+
auto __promise = Promise<ConnectSignResult>::create();
|
|
93
102
|
__result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
|
|
94
|
-
auto __result = jni::static_ref_cast<
|
|
95
|
-
__promise->resolve(__result->
|
|
103
|
+
auto __result = jni::static_ref_cast<JConnectSignResult>(__boxedResult);
|
|
104
|
+
__promise->resolve(__result->toCpp());
|
|
105
|
+
});
|
|
106
|
+
__result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
|
|
107
|
+
jni::JniException __jniError(__throwable);
|
|
108
|
+
__promise->reject(std::make_exception_ptr(__jniError));
|
|
109
|
+
});
|
|
110
|
+
return __promise;
|
|
111
|
+
}();
|
|
112
|
+
}
|
|
113
|
+
std::shared_ptr<Promise<std::variant<nitro::NullType, std::string>>> JHybridNitroMetamaskSpec::getAddress() {
|
|
114
|
+
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getAddress");
|
|
115
|
+
auto __result = method(_javaPart);
|
|
116
|
+
return [&]() {
|
|
117
|
+
auto __promise = Promise<std::variant<nitro::NullType, std::string>>::create();
|
|
118
|
+
__result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
|
|
119
|
+
auto __result = jni::static_ref_cast<JVariant_NullType_String>(__boxedResult);
|
|
120
|
+
__promise->resolve(__result->toCpp());
|
|
121
|
+
});
|
|
122
|
+
__result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
|
|
123
|
+
jni::JniException __jniError(__throwable);
|
|
124
|
+
__promise->reject(std::make_exception_ptr(__jniError));
|
|
125
|
+
});
|
|
126
|
+
return __promise;
|
|
127
|
+
}();
|
|
128
|
+
}
|
|
129
|
+
std::shared_ptr<Promise<std::variant<nitro::NullType, int64_t>>> JHybridNitroMetamaskSpec::getChainId() {
|
|
130
|
+
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getChainId");
|
|
131
|
+
auto __result = method(_javaPart);
|
|
132
|
+
return [&]() {
|
|
133
|
+
auto __promise = Promise<std::variant<nitro::NullType, int64_t>>::create();
|
|
134
|
+
__result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
|
|
135
|
+
auto __result = jni::static_ref_cast<JVariant_NullType_Long>(__boxedResult);
|
|
136
|
+
__promise->resolve(__result->toCpp());
|
|
96
137
|
});
|
|
97
138
|
__result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
|
|
98
139
|
jni::JniException __jniError(__throwable);
|
|
@@ -54,10 +54,12 @@ namespace margelo::nitro::nitrometamask {
|
|
|
54
54
|
|
|
55
55
|
public:
|
|
56
56
|
// Methods
|
|
57
|
-
void configure(const std::optional<std::string>& dappUrl) override;
|
|
57
|
+
void configure(const std::optional<std::string>& dappUrl, const std::optional<std::string>& deepLinkScheme) override;
|
|
58
58
|
std::shared_ptr<Promise<ConnectResult>> connect() override;
|
|
59
59
|
std::shared_ptr<Promise<std::string>> signMessage(const std::string& message) override;
|
|
60
|
-
std::shared_ptr<Promise<
|
|
60
|
+
std::shared_ptr<Promise<ConnectSignResult>> connectSign(const std::string& nonce, int64_t exp) override;
|
|
61
|
+
std::shared_ptr<Promise<std::variant<nitro::NullType, std::string>>> getAddress() override;
|
|
62
|
+
std::shared_ptr<Promise<std::variant<nitro::NullType, int64_t>>> getChainId() override;
|
|
61
63
|
|
|
62
64
|
private:
|
|
63
65
|
friend HybridBase;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// JVariant_NullType_Long.cpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#include "JVariant_NullType_Long.hpp"
|
|
9
|
+
|
|
10
|
+
namespace margelo::nitro::nitrometamask {
|
|
11
|
+
/**
|
|
12
|
+
* Converts JVariant_NullType_Long to std::variant<nitro::NullType, int64_t>
|
|
13
|
+
*/
|
|
14
|
+
std::variant<nitro::NullType, int64_t> JVariant_NullType_Long::toCpp() const {
|
|
15
|
+
if (isInstanceOf(JVariant_NullType_Long_impl::First::javaClassStatic())) {
|
|
16
|
+
// It's a `nitro::NullType`
|
|
17
|
+
auto jniValue = static_cast<const JVariant_NullType_Long_impl::First*>(this)->getValue();
|
|
18
|
+
return nitro::null;
|
|
19
|
+
} else if (isInstanceOf(JVariant_NullType_Long_impl::Second::javaClassStatic())) {
|
|
20
|
+
// It's a `int64_t`
|
|
21
|
+
auto jniValue = static_cast<const JVariant_NullType_Long_impl::Second*>(this)->getValue();
|
|
22
|
+
return jniValue;
|
|
23
|
+
}
|
|
24
|
+
throw std::invalid_argument("Variant is unknown Kotlin instance!");
|
|
25
|
+
}
|
|
26
|
+
} // namespace margelo::nitro::nitrometamask
|