react-native-zcash 0.0.2 → 0.2.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 +14 -0
- package/android/build.gradle +43 -5
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt +317 -0
- package/android/src/main/java/app/edge/rnzcash/RNZcashPackage.kt +18 -0
- package/ios/RNZcash-Bridging-Header.h +6 -0
- package/ios/RNZcash.m +89 -43
- package/ios/RNZcash.swift +528 -0
- package/lib/rnzcash.rn.js +305 -85
- package/lib/rnzcash.rn.js.map +1 -1
- package/lib/src/react-native.d.ts +30 -3
- package/lib/src/types.d.ts +84 -5
- package/package.json +10 -7
- package/react-native-zcash.podspec +6 -3
- package/src/react-native.ts +203 -78
- package/src/types.ts +95 -6
- package/android/src/main/java/com/reactlibrary/RNZcashModule.java +0 -94
- package/android/src/main/java/com/reactlibrary/RNZcashPackage.java +0 -21
- package/ios/RNZcash.h +0 -5
- package/lib/rnzcash.cjs.js +0 -3
- package/lib/rnzcash.cjs.js.flow +0 -3
- package/lib/rnzcash.cjs.js.map +0 -1
- package/lib/rnzcash.js +0 -2
- package/lib/rnzcash.js.flow +0 -3
- package/lib/rnzcash.js.map +0 -1
- package/lib/rnzcash.web.js +0 -3
- package/lib/rnzcash.web.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# React Native Zcash
|
|
2
2
|
|
|
3
|
+
## 0.2.1 (2022-03-16)
|
|
4
|
+
|
|
5
|
+
- Update the ZcashLightClientKit dependency
|
|
6
|
+
- Remove unused build scripts
|
|
7
|
+
|
|
8
|
+
## 0.2.0 (2022-01-10)
|
|
9
|
+
|
|
10
|
+
- Add iOS support
|
|
11
|
+
- Android: Cleanup unused methods
|
|
12
|
+
|
|
13
|
+
## 0.1.0 (2021-11-09)
|
|
14
|
+
|
|
15
|
+
- Initial release
|
|
16
|
+
|
|
3
17
|
## 0.0.2
|
|
4
18
|
|
|
5
19
|
- Add stubs for deriveViewKey and getShieldedBalance
|
package/android/build.gradle
CHANGED
|
@@ -1,19 +1,34 @@
|
|
|
1
1
|
buildscript {
|
|
2
|
+
ext.versions = [
|
|
3
|
+
'kotlin': '1.5.0',
|
|
4
|
+
'zcash': '1.3.0-beta18',
|
|
5
|
+
'room': '2.3.0'
|
|
6
|
+
]
|
|
2
7
|
repositories {
|
|
8
|
+
mavenLocal()
|
|
3
9
|
google()
|
|
10
|
+
mavenCentral()
|
|
4
11
|
jcenter()
|
|
12
|
+
maven {
|
|
13
|
+
url 'https://jitpack.io'
|
|
14
|
+
}
|
|
15
|
+
maven {
|
|
16
|
+
url "https://plugins.gradle.org/m2/"
|
|
17
|
+
}
|
|
5
18
|
}
|
|
6
19
|
|
|
7
20
|
dependencies {
|
|
8
|
-
classpath 'com.android.tools.build:gradle:
|
|
21
|
+
classpath 'com.android.tools.build:gradle:4.0.2'
|
|
22
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
|
|
9
23
|
}
|
|
10
24
|
}
|
|
11
25
|
|
|
12
26
|
apply plugin: 'com.android.library'
|
|
13
|
-
apply plugin: '
|
|
27
|
+
apply plugin: 'kotlin-android'
|
|
28
|
+
apply plugin: 'kotlin-kapt'
|
|
14
29
|
|
|
15
30
|
def safeExtGet(prop, fallback) {
|
|
16
|
-
|
|
31
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
def DEFAULT_COMPILE_SDK_VERSION = 28
|
|
@@ -24,7 +39,13 @@ def DEFAULT_TARGET_SDK_VERSION = 27
|
|
|
24
39
|
android {
|
|
25
40
|
compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
|
|
26
41
|
buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION)
|
|
27
|
-
|
|
42
|
+
compileOptions {
|
|
43
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
44
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
45
|
+
}
|
|
46
|
+
kotlinOptions {
|
|
47
|
+
jvmTarget = JavaVersion.VERSION_1_8
|
|
48
|
+
}
|
|
28
49
|
defaultConfig {
|
|
29
50
|
minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
|
|
30
51
|
targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
|
|
@@ -37,9 +58,26 @@ android {
|
|
|
37
58
|
}
|
|
38
59
|
|
|
39
60
|
repositories {
|
|
40
|
-
|
|
61
|
+
mavenLocal()
|
|
62
|
+
google()
|
|
63
|
+
jcenter()
|
|
64
|
+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
65
|
+
maven {
|
|
66
|
+
url("../node_modules/react-native/android")
|
|
67
|
+
}
|
|
41
68
|
}
|
|
42
69
|
|
|
43
70
|
dependencies {
|
|
71
|
+
// React-Native
|
|
44
72
|
implementation 'com.facebook.react:react-native:+'
|
|
73
|
+
|
|
74
|
+
// Zcash
|
|
75
|
+
implementation "cash.z.ecc.android:zcash-android-sdk:${versions.zcash}"
|
|
76
|
+
|
|
77
|
+
// Process Room annotations
|
|
78
|
+
kapt "androidx.room:room-compiler:${versions.room}"
|
|
79
|
+
|
|
80
|
+
implementation "androidx.paging:paging-runtime-ktx:2.1.2"
|
|
81
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
|
|
82
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
|
|
45
83
|
}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
package app.edge.rnzcash;
|
|
2
|
+
|
|
3
|
+
import androidx.paging.PagedList
|
|
4
|
+
import cash.z.ecc.android.sdk.Initializer
|
|
5
|
+
import cash.z.ecc.android.sdk.SdkSynchronizer
|
|
6
|
+
import cash.z.ecc.android.sdk.Synchronizer
|
|
7
|
+
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCED
|
|
8
|
+
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
|
9
|
+
import cash.z.ecc.android.sdk.db.entity.*
|
|
10
|
+
import cash.z.ecc.android.sdk.ext.*
|
|
11
|
+
import cash.z.ecc.android.sdk.transaction.*
|
|
12
|
+
import cash.z.ecc.android.sdk.type.*
|
|
13
|
+
import cash.z.ecc.android.sdk.tool.DerivationTool
|
|
14
|
+
import com.facebook.react.bridge.*
|
|
15
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
|
|
16
|
+
import kotlinx.coroutines.CoroutineScope
|
|
17
|
+
import kotlinx.coroutines.cancel
|
|
18
|
+
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
19
|
+
import kotlinx.coroutines.flow.filter
|
|
20
|
+
import kotlinx.coroutines.launch
|
|
21
|
+
import java.nio.charset.StandardCharsets
|
|
22
|
+
import kotlin.coroutines.EmptyCoroutineContext
|
|
23
|
+
|
|
24
|
+
class WalletSynchronizer constructor(val initializer: Initializer) {
|
|
25
|
+
|
|
26
|
+
val synchronizer: SdkSynchronizer = Synchronizer(
|
|
27
|
+
initializer
|
|
28
|
+
) as SdkSynchronizer
|
|
29
|
+
val repository = PagedTransactionRepository(initializer.context, 10, initializer.rustBackend, initializer.birthday, initializer.viewingKeys)
|
|
30
|
+
var isStarted = false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class RNZcashModule(private val reactContext: ReactApplicationContext) :
|
|
34
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Scope for anything that out-lives the synchronizer, meaning anything that can be used before
|
|
38
|
+
* the synchronizer starts or after it stops. Everything else falls within the scope of the
|
|
39
|
+
* synchronizer and should use `synchronizer.coroutineScope` whenever a scope is needed.
|
|
40
|
+
*
|
|
41
|
+
* In a real production app, we'd use the scope of the parent activity
|
|
42
|
+
*/
|
|
43
|
+
var moduleScope: CoroutineScope = CoroutineScope(EmptyCoroutineContext)
|
|
44
|
+
var synchronizerMap = mutableMapOf<String, WalletSynchronizer>()
|
|
45
|
+
|
|
46
|
+
val networks = mapOf("mainnet" to ZcashNetwork.Mainnet, "testnet" to ZcashNetwork.Testnet)
|
|
47
|
+
|
|
48
|
+
override fun getName() = "RNZcash"
|
|
49
|
+
|
|
50
|
+
@ReactMethod
|
|
51
|
+
fun initialize(extfvk: String, extpub: String, birthdayHeight: Int, alias: String, networkName: String = "mainnet", defaultHost: String = "mainnet.lightwalletd.com", defaultPort: Int = 9067, promise: Promise) =
|
|
52
|
+
promise.wrap {
|
|
53
|
+
Twig.plant(TroubleshootingTwig())
|
|
54
|
+
var vk = UnifiedViewingKey(extfvk, extpub)
|
|
55
|
+
if (synchronizerMap[alias] == null) {
|
|
56
|
+
val initializer = Initializer(reactApplicationContext) { config ->
|
|
57
|
+
config.importedWalletBirthday(birthdayHeight)
|
|
58
|
+
config.setViewingKeys(vk)
|
|
59
|
+
config.setNetwork(networks[networkName] ?: ZcashNetwork.Mainnet, defaultHost, defaultPort)
|
|
60
|
+
config.alias = alias
|
|
61
|
+
}
|
|
62
|
+
synchronizerMap[alias] = WalletSynchronizer(initializer)
|
|
63
|
+
val wallet = getWallet(alias)
|
|
64
|
+
}
|
|
65
|
+
val wallet = getWallet(alias)
|
|
66
|
+
wallet.synchronizer.hashCode().toString()
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@ReactMethod
|
|
71
|
+
fun start(alias: String, promise: Promise) = promise.wrap {
|
|
72
|
+
val wallet = getWallet(alias)
|
|
73
|
+
if (!wallet.isStarted) {
|
|
74
|
+
wallet.synchronizer.prepare()
|
|
75
|
+
wallet.synchronizer.start(moduleScope)
|
|
76
|
+
val scope = wallet.synchronizer.coroutineScope
|
|
77
|
+
wallet.synchronizer.processorInfo.collectWith(scope, { update ->
|
|
78
|
+
sendEvent("UpdateEvent") { args ->
|
|
79
|
+
args.putString("alias", alias)
|
|
80
|
+
args.putInt("lastDownloadedHeight", update.lastDownloadedHeight)
|
|
81
|
+
args.putInt("lastScannedHeight", update.lastScannedHeight)
|
|
82
|
+
args.putInt("scanProgress", update.scanProgress)
|
|
83
|
+
args.putInt("networkBlockHeight", update.networkBlockHeight)
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
wallet.synchronizer.status.collectWith(scope, { status ->
|
|
87
|
+
sendEvent("StatusEvent") { args ->
|
|
88
|
+
args.putString("alias", alias)
|
|
89
|
+
args.putString("name", status.toString())
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
wallet.synchronizer.saplingBalances.collectWith(scope, { walletBalance ->
|
|
93
|
+
sendEvent("BalanceEvent") { args ->
|
|
94
|
+
args.putString("alias", alias)
|
|
95
|
+
args.putString("availableZatoshi", walletBalance.availableZatoshi.toString())
|
|
96
|
+
args.putString("totalZatoshi", walletBalance.totalZatoshi.toString())
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
// add 'distinctUntilChanged' to filter by events that represent changes in txs, rather than each poll
|
|
100
|
+
wallet.synchronizer.clearedTransactions.distinctUntilChanged().collectWith(scope, { txList ->
|
|
101
|
+
sendEvent("TransactionEvent") { args ->
|
|
102
|
+
args.putString("alias", alias)
|
|
103
|
+
args.putBoolean("hasChanged", true)
|
|
104
|
+
args.putInt("transactionCount", txList.count())
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
wallet.repository.prepare()
|
|
108
|
+
wallet.isStarted = true
|
|
109
|
+
}
|
|
110
|
+
"success"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@ReactMethod
|
|
114
|
+
fun stop(alias: String, promise: Promise) = promise.wrap {
|
|
115
|
+
val wallet = getWallet(alias)
|
|
116
|
+
wallet.synchronizer.stop()
|
|
117
|
+
synchronizerMap.remove(alias)
|
|
118
|
+
"success"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@ReactMethod
|
|
122
|
+
fun getTransactions(alias: String, first: Int, last: Int, promise: Promise) {
|
|
123
|
+
val wallet = getWallet(alias)
|
|
124
|
+
moduleScope.launch {
|
|
125
|
+
promise.wrap {
|
|
126
|
+
val result = wallet.repository.findNewTransactions(first..last)
|
|
127
|
+
val nativeArray = Arguments.createArray()
|
|
128
|
+
|
|
129
|
+
for (i in 0..result.size - 1) {
|
|
130
|
+
val map = Arguments.createMap()
|
|
131
|
+
map.putString("value", result[i].value.toString())
|
|
132
|
+
map.putInt("minedHeight", result[i].minedHeight)
|
|
133
|
+
map.putInt("blockTimeInSeconds", result[i].blockTimeInSeconds.toInt())
|
|
134
|
+
map.putString("rawTransactionId", result[i].rawTransactionId.toHexReversed())
|
|
135
|
+
if (result[i].memo != null) map.putString("memo", result[i].memo?.decodeToString()?.trim('\u0000', '\uFFFD'))
|
|
136
|
+
if (result[i].toAddress != null) map.putString("toAddress", result[i].toAddress)
|
|
137
|
+
nativeArray.pushMap(map)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
nativeArray
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@ReactMethod
|
|
146
|
+
fun rescan(alias: String, height: Int, promise: Promise) {
|
|
147
|
+
val wallet = getWallet(alias)
|
|
148
|
+
moduleScope.launch {
|
|
149
|
+
wallet.synchronizer.rewindToNearestHeight(height)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@ReactMethod
|
|
154
|
+
fun deriveViewingKey(seedBytesHex: String, network: String = "mainnet", promise: Promise) {
|
|
155
|
+
var keys = DerivationTool.deriveUnifiedViewingKeys(seedBytesHex.fromHex(), networks.getOrDefault(network, ZcashNetwork.Mainnet))[0]
|
|
156
|
+
val map = Arguments.createMap()
|
|
157
|
+
map.putString("extfvk", keys.extfvk)
|
|
158
|
+
map.putString("extpub", keys.extpub)
|
|
159
|
+
promise.resolve(map)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@ReactMethod
|
|
163
|
+
fun deriveSpendingKey(seedBytesHex: String, network: String = "mainnet", promise: Promise) = promise.wrap {
|
|
164
|
+
DerivationTool.deriveSpendingKeys(seedBytesHex.fromHex(), networks.getOrDefault(network, ZcashNetwork.Mainnet))[0]
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//
|
|
168
|
+
// Properties
|
|
169
|
+
//
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@ReactMethod
|
|
173
|
+
fun getLatestNetworkHeight(alias: String, promise: Promise) = promise.wrap {
|
|
174
|
+
val wallet = getWallet(alias)
|
|
175
|
+
wallet.synchronizer.latestHeight
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@ReactMethod
|
|
179
|
+
fun getShieldedBalance(alias: String, promise: Promise) = promise.wrap {
|
|
180
|
+
val wallet = getWallet(alias)
|
|
181
|
+
val map = Arguments.createMap()
|
|
182
|
+
map.putString("totalZatoshi", wallet.synchronizer.saplingBalances.value.totalZatoshi.toString(10))
|
|
183
|
+
map.putString("availableZatoshi", wallet.synchronizer.saplingBalances.value.availableZatoshi.toString(10))
|
|
184
|
+
map
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@ReactMethod
|
|
188
|
+
fun spendToAddress(
|
|
189
|
+
alias: String,
|
|
190
|
+
zatoshi: String,
|
|
191
|
+
toAddress: String,
|
|
192
|
+
memo: String,
|
|
193
|
+
fromAccountIndex: Int,
|
|
194
|
+
spendingKey: String,
|
|
195
|
+
promise: Promise
|
|
196
|
+
) {
|
|
197
|
+
val wallet = getWallet(alias)
|
|
198
|
+
wallet.synchronizer.coroutineScope.launch {
|
|
199
|
+
try {
|
|
200
|
+
wallet.synchronizer.sendToAddress(
|
|
201
|
+
spendingKey,
|
|
202
|
+
zatoshi.toLong(),
|
|
203
|
+
toAddress,
|
|
204
|
+
memo,
|
|
205
|
+
fromAccountIndex
|
|
206
|
+
).collectWith(wallet.synchronizer.coroutineScope) {tx ->
|
|
207
|
+
// this block is called repeatedly for each update to the pending transaction, including all 10 confirmations
|
|
208
|
+
// the promise either shouldn't be used (and rely on events instead) or it can be resolved once the transaction is submitted to the network or mined
|
|
209
|
+
if (tx.isSubmitSuccess()) { // alternatively use it.isMined() but be careful about making a promise that never resolves!
|
|
210
|
+
val map = Arguments.createMap()
|
|
211
|
+
map.putString("txId", tx.rawTransactionId?.toHexReversed())
|
|
212
|
+
map.putString("raw", tx.raw?.toHexReversed())
|
|
213
|
+
promise.resolve(map)
|
|
214
|
+
} else if (tx.isFailure()) {
|
|
215
|
+
val map = Arguments.createMap()
|
|
216
|
+
map.putInt("expiryHeight", tx.expiryHeight)
|
|
217
|
+
map.putString("cancelled", tx.cancelled.toString())
|
|
218
|
+
map.putString("encodeAttempts", tx.encodeAttempts.toString())
|
|
219
|
+
map.putString("submitAttempts", tx.submitAttempts.toString())
|
|
220
|
+
if (tx.errorMessage != null) map.putString("errorMessage", tx.errorMessage)
|
|
221
|
+
if (tx.errorCode != null) map.putString("errorCode", tx.errorCode.toString())
|
|
222
|
+
promise.resolve(false)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} catch (t: Throwable) {
|
|
226
|
+
promise.reject("Err", t)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
//
|
|
233
|
+
// AddressTool
|
|
234
|
+
//
|
|
235
|
+
|
|
236
|
+
@ReactMethod
|
|
237
|
+
fun deriveShieldedAddress(viewingKey: String, network: String = "mainnet", promise: Promise) = promise.wrap {
|
|
238
|
+
DerivationTool.deriveShieldedAddress(viewingKey, networks.getOrDefault(network, ZcashNetwork.Mainnet))
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@ReactMethod
|
|
242
|
+
fun isValidShieldedAddress(address: String, network: String, promise: Promise) {
|
|
243
|
+
moduleScope.launch {
|
|
244
|
+
promise.wrap {
|
|
245
|
+
var isValid = false
|
|
246
|
+
val wallets = synchronizerMap.asIterable()
|
|
247
|
+
for (wallet in wallets) {
|
|
248
|
+
if (wallet.value.synchronizer.network.networkName == network) {
|
|
249
|
+
isValid = wallet.value.synchronizer.isValidShieldedAddr(address)
|
|
250
|
+
break
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
isValid
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@ReactMethod
|
|
259
|
+
fun isValidTransparentAddress(address: String, network: String, promise: Promise) {
|
|
260
|
+
moduleScope.launch {
|
|
261
|
+
promise.wrap {
|
|
262
|
+
var isValid = false
|
|
263
|
+
val wallets = synchronizerMap.asIterable()
|
|
264
|
+
for (wallet in wallets) {
|
|
265
|
+
if (wallet.value.synchronizer.network.networkName == network) {
|
|
266
|
+
isValid = wallet.value.synchronizer.isValidTransparentAddr(address)
|
|
267
|
+
break
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
isValid
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
//
|
|
276
|
+
// Utilities
|
|
277
|
+
//
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Retrieve wallet object from synchronizer map
|
|
281
|
+
*/
|
|
282
|
+
private fun getWallet(alias: String): WalletSynchronizer {
|
|
283
|
+
val wallet = synchronizerMap.get(alias)
|
|
284
|
+
if (wallet == null) throw Exception("Wallet not found")
|
|
285
|
+
return wallet
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Wrap the given block of logic in a promise, rejecting for any error.
|
|
291
|
+
*/
|
|
292
|
+
private inline fun <T> Promise.wrap(block: () -> T) {
|
|
293
|
+
try {
|
|
294
|
+
resolve(block())
|
|
295
|
+
} catch (t: Throwable) {
|
|
296
|
+
reject("Err", t)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private fun sendEvent(eventName: String, putArgs: (WritableMap) -> Unit) {
|
|
301
|
+
val args = Arguments.createMap()
|
|
302
|
+
putArgs(args)
|
|
303
|
+
reactApplicationContext
|
|
304
|
+
.getJSModule(RCTDeviceEventEmitter::class.java)
|
|
305
|
+
.emit(eventName, args)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// TODO: move this to the SDK
|
|
309
|
+
inline fun ByteArray?.toUtf8Memo(): String {
|
|
310
|
+
return if (this == null || this[0] >= 0xF5) "" else try {
|
|
311
|
+
// trim empty and "replacement characters" for codes that can't be represented in unicode
|
|
312
|
+
String(this, StandardCharsets.UTF_8).trim('\u0000', '\uFFFD')
|
|
313
|
+
} catch (t: Throwable) {
|
|
314
|
+
"Unable to parse memo."
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package app.edge.rnzcash;
|
|
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.Collections.emptyList
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RNZcashPackage : ReactPackage {
|
|
11
|
+
override fun createNativeModules(reactContext: ReactApplicationContext) =
|
|
12
|
+
listOf<NativeModule>(
|
|
13
|
+
RNZcashModule(reactContext)
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
|
|
17
|
+
emptyList()
|
|
18
|
+
}
|
package/ios/RNZcash.m
CHANGED
|
@@ -1,45 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
NSString *
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@interface RCT_EXTERN_MODULE(RNZcash, RCTEventEmitter<RCTBridgeModule>)
|
|
6
|
+
|
|
7
|
+
// Synchronizer
|
|
8
|
+
RCT_EXTERN_METHOD(initialize:(NSString *)extfvk
|
|
9
|
+
:(NSString *)extpub
|
|
10
|
+
:(NSInteger *)birthdayHeight
|
|
11
|
+
:(NSString *)alias
|
|
12
|
+
:(NSString *)networkName
|
|
13
|
+
:(NSString *)defaultHost
|
|
14
|
+
:(NSInteger *)defaultPort
|
|
15
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
16
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
RCT_EXTERN_METHOD(start:(NSString *)alias
|
|
20
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
21
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
RCT_EXTERN_METHOD(stop:(NSString *)alias
|
|
25
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
26
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
RCT_EXTERN_METHOD(spendToAddress:(NSString *)alias
|
|
30
|
+
:(NSString *)zatoshi
|
|
31
|
+
:(NSString *)toAddress
|
|
32
|
+
:(NSString *)memo
|
|
33
|
+
:(NSInteger *)fromAccountIndex
|
|
34
|
+
:(NSString *)spendingKey
|
|
35
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
36
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
RCT_EXTERN_METHOD(getTransactions:(NSString *)alias
|
|
40
|
+
:(NSInteger *)first
|
|
41
|
+
:(NSInteger *)last
|
|
42
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
43
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
RCT_EXTERN_METHOD(getShieldedBalance:(NSString *)alias
|
|
47
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
48
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
RCT_EXTERN_METHOD(rescan:(NSString *)alias
|
|
52
|
+
:(NSInteger *)height
|
|
53
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
54
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
// Derivation tool
|
|
58
|
+
RCT_EXTERN_METHOD(deriveViewingKey:(NSString *)seed
|
|
59
|
+
:(NSString *)network
|
|
60
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
61
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
RCT_EXTERN_METHOD(deriveSpendingKey:(NSString *)seed
|
|
65
|
+
:(NSString *)network
|
|
66
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
67
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
RCT_EXTERN_METHOD(deriveShieldedAddress:(NSString *)viewingKey
|
|
71
|
+
:(NSString *)network
|
|
72
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
73
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
RCT_EXTERN_METHOD(isValidTransparentAddress:(NSString *)address
|
|
77
|
+
:(NSString *)network
|
|
78
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
79
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
RCT_EXTERN_METHOD(isValidShieldedAddress:(NSString *)address
|
|
83
|
+
:(NSString *)network
|
|
84
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
85
|
+
rejecter:(RCTPromiseRejectBlock)reject
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
// Events
|
|
89
|
+
RCT_EXTERN_METHOD(supportedEvents)
|
|
44
90
|
|
|
45
91
|
@end
|