react-native-zcash 0.6.0 → 0.6.2

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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # React Native Zcash
2
2
 
3
+ ## 0.6.2 (2023-10-16)
4
+
5
+ - changed: Upgrade ZcashLightClientKit to v2.0.2
6
+ - changed: Make `rescan` async
7
+ - changed: Throttle sync status to only report changes (iOS)
8
+
9
+ ## 0.6.1 (2023-10-11)
10
+
11
+ - added: Add `shieldFunds` support
12
+ - changed: Package now exports types
13
+ - deprecated: Balance event fields `availableZatoshi` and `totalZatoshi`
14
+
15
+ Android
16
+
17
+ - changed: Various syntax cleanups
18
+ - fixed: Transactions event now returns confirmed and pending (<10 confirmations) transactions
19
+
3
20
  ## 0.6.0 (2023-10-10)
4
21
 
5
22
  - added: Balances and transactions are no longer queryable and are now emitted as updates are found
package/README.md CHANGED
@@ -42,11 +42,12 @@ buildscript {
42
42
  - `rescan`
43
43
  - `getLatestNetworkHeight`
44
44
  - `sendToAddress`
45
+ - `shieldFunds`
45
46
  - `deriveUnifiedAddress`
46
47
 
47
48
  `Tools` contains methods that don't require a running synchronizer (with one exception, `isValidAddress` on Android which does requires any synchronizer connected to the requested network). In addition to the methods above, the following events can be subscribed to:
48
49
 
49
- - `BalanceEvent`- aggregate total and available balances
50
+ - `BalanceEvent`- available and total transparent and shielded balances
50
51
  - `StatusEvent` - current synchronizer activity (`STOPPED`, `DISCONNECTED`, `SYNCING`, and `SYNCED`)
51
52
  - `TransactionEvent`- confirmed transactions
52
53
  - `UpdateEvent` - syncing progress and network height
@@ -0,0 +1,8 @@
1
+ {
2
+ "network": "main",
3
+ "height": "2260000",
4
+ "hash": "00000000014b3b907e559bd87daba56c85c16446aef59e9ce9dba37ad2691b86",
5
+ "time": 1697204301,
6
+ "saplingTree": "01ccd67f580cc75af1faf952deaa774c5008496e49f2b8c3f4de936ee0c268846b001a00000001db3f7578a2f0e1d7ce61030a4192f0500c655626c81edd69be7e2bb012cb5b3b0001299a4e80c4c7c13553248aae4f35f03318cc04713927b8aa9abf086df2d8375d0000015811cf08cc569867834281fd88ea6bc930529573fa2cbbff8fd0f64963cee702000169d3b6e6999f905b302b4f1d2f84acf1b84e04d1fe8a1d107efd1971faa0bd0e0001e192d9d422a7fdd876027946e61dc5034f54ae4df2834eda15800658196e731f000001ffdd1a0628296bf274daa5ea13fb57818d678957d49f91ccd69efae0bac249340182ac7ebe2f7e9d8084a38aa8be56b1bd86292babf05f98882a6959cf9d318c110001d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
7
+ "orchardTree": "01bf80f9a026cba7ffd8e4eb99895eefc6e7e7b1f3f451cd0272f8c8ee09b81e0601c94fc93463e006682dc287e10035a898a577becb7af338c7aad32b6aeeb592111f000151634a9677c3589d76542b11db3c79efccc8fbbe3cb521b9adf599ad3895dc020163ee08cae7b538138c74534a346d723e37beb3a886d9fc7e1b69e938a48c6d220188d5ac292703a08902cc79a54a801b13b41360e03cfb130e3b7ca9e76bd8961401b1021539f9d34c2df786324de29594dfd12f260ec6f893e37490a9c4cf7f7f380000014c3bc5b55f752c69ac57e14b8cb7c2bc00a1c7c21231dc4b1c9124fe434ea13900000000012ffae608e1b4d4de4f5ac38068b613d9761ba34d95430e5ec8d058848cc9c0250001dd3e61f3e1d497d923486bd000737ea0ffac885fa481316727d0d8f7fc2138100001cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
8
+ }
@@ -15,16 +15,14 @@ import co.electriccoin.lightwallet.client.model.Response
15
15
  import co.electriccoin.lightwallet.client.new
16
16
  import com.facebook.react.bridge.*
17
17
  import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
18
- import kotlinx.coroutines.async
19
18
  import kotlinx.coroutines.CoroutineScope
20
19
  import kotlinx.coroutines.Dispatchers
21
- import kotlinx.coroutines.ExperimentalCoroutinesApi
20
+ import kotlinx.coroutines.async
22
21
  import kotlinx.coroutines.flow.*
23
22
  import kotlinx.coroutines.launch
24
23
 
25
24
  class RNZcashModule(private val reactContext: ReactApplicationContext) :
26
25
  ReactContextBaseJavaModule(reactContext) {
27
-
28
26
  /**
29
27
  * Scope for anything that out-lives the synchronizer, meaning anything that can be used before
30
28
  * the synchronizer starts or after it stops. Everything else falls within the scope of the
@@ -38,144 +36,176 @@ class RNZcashModule(private val reactContext: ReactApplicationContext) :
38
36
  override fun getName() = "RNZcash"
39
37
 
40
38
  @ReactMethod
41
- fun initialize(seed: String, birthdayHeight: Int, alias: String, networkName: String = "mainnet", defaultHost: String = "mainnet.lightwalletd.com", defaultPort: Int = 9067, newWallet: Boolean, promise: Promise) =
42
- moduleScope.launch {
43
- promise.wrap {
44
- val network = networks.getOrDefault(networkName, ZcashNetwork.Mainnet)
45
- val endpoint = LightWalletEndpoint(defaultHost, defaultPort, true)
46
- val seedPhrase = SeedPhrase.new(seed)
47
- val initMode = if (newWallet) WalletInitMode.NewWallet else WalletInitMode.ExistingWallet
48
- if (!synchronizerMap.containsKey(alias)) {
49
- synchronizerMap[alias] = Synchronizer.new(reactApplicationContext, network, alias, endpoint, seedPhrase.toByteArray(), BlockHeight.new(network, birthdayHeight.toLong()), initMode) as SdkSynchronizer
50
- }
51
- val wallet = getWallet(alias)
52
- val scope = wallet.coroutineScope
53
- combine(wallet.progress, wallet.networkHeight) { progress, networkHeight ->
54
- return@combine mapOf("progress" to progress, "networkHeight" to networkHeight)
55
- }.collectWith(scope) { map ->
56
- val progress = map["progress"] as PercentDecimal
57
- var networkBlockHeight = map["networkHeight"] as BlockHeight?
58
- if (networkBlockHeight == null) networkBlockHeight = BlockHeight.new(wallet.network, birthdayHeight.toLong())
39
+ fun initialize(
40
+ seed: String,
41
+ birthdayHeight: Int,
42
+ alias: String,
43
+ networkName: String = "mainnet",
44
+ defaultHost: String = "mainnet.lightwalletd.com",
45
+ defaultPort: Int = 9067,
46
+ newWallet: Boolean,
47
+ promise: Promise,
48
+ ) = moduleScope.launch {
49
+ promise.wrap {
50
+ val network = networks.getOrDefault(networkName, ZcashNetwork.Mainnet)
51
+ val endpoint = LightWalletEndpoint(defaultHost, defaultPort, true)
52
+ val seedPhrase = SeedPhrase.new(seed)
53
+ val initMode = if (newWallet) WalletInitMode.NewWallet else WalletInitMode.ExistingWallet
54
+ if (!synchronizerMap.containsKey(alias)) {
55
+ synchronizerMap[alias] =
56
+ Synchronizer.new(
57
+ reactApplicationContext, network, alias, endpoint, seedPhrase.toByteArray(),
58
+ BlockHeight.new(network, birthdayHeight.toLong()), initMode,
59
+ ) as SdkSynchronizer
60
+ }
61
+ val wallet = getWallet(alias)
62
+ val scope = wallet.coroutineScope
63
+ combine(wallet.progress, wallet.networkHeight) { progress, networkHeight ->
64
+ return@combine mapOf("progress" to progress, "networkHeight" to networkHeight)
65
+ }.collectWith(scope) { map ->
66
+ val progress = map["progress"] as PercentDecimal
67
+ var networkBlockHeight = map["networkHeight"] as BlockHeight?
68
+ if (networkBlockHeight == null) networkBlockHeight = BlockHeight.new(wallet.network, birthdayHeight.toLong())
59
69
 
60
- sendEvent("UpdateEvent") { args ->
61
- args.putString("alias", alias)
62
- args.putInt(
63
- "scanProgress",
64
- progress.toPercentage()
65
- )
66
- args.putInt("networkBlockHeight", networkBlockHeight.value.toInt())
67
- }
70
+ sendEvent("UpdateEvent") { args ->
71
+ args.putString("alias", alias)
72
+ args.putInt(
73
+ "scanProgress",
74
+ progress.toPercentage(),
75
+ )
76
+ args.putInt("networkBlockHeight", networkBlockHeight.value.toInt())
68
77
  }
69
- wallet.status.collectWith(scope) { status ->
70
- sendEvent("StatusEvent") { args ->
71
- args.putString("alias", alias)
72
- args.putString("name", status.toString())
73
- }
78
+ }
79
+ wallet.status.collectWith(scope) { status ->
80
+ sendEvent("StatusEvent") { args ->
81
+ args.putString("alias", alias)
82
+ args.putString("name", status.toString())
74
83
  }
75
- wallet.transactions.collectWith(scope) { txList ->
76
- scope.launch {
77
- val nativeArray = Arguments.createArray()
78
- txList.filter { tx -> tx.transactionState == TransactionState.Confirmed }.map { tx -> launch {
84
+ }
85
+ wallet.transactions.collectWith(scope) { txList ->
86
+ scope.launch {
87
+ val nativeArray = Arguments.createArray()
88
+ txList.filter { tx -> tx.transactionState != TransactionState.Expired }.map { tx ->
89
+ launch {
79
90
  val parsedTx = parseTx(wallet, tx)
80
91
  nativeArray.pushMap(parsedTx)
81
- } }.forEach { it.join() }
82
-
83
- sendEvent("TransactionEvent") { args ->
84
- args.putString("alias", alias)
85
- args.putArray(
86
- "transactions",
87
- nativeArray
88
- )
89
92
  }
93
+ }.forEach { it.join() }
94
+
95
+ sendEvent("TransactionEvent") { args ->
96
+ args.putString("alias", alias)
97
+ args.putArray(
98
+ "transactions",
99
+ nativeArray,
100
+ )
90
101
  }
91
102
  }
92
- combine(wallet.transparentBalances, wallet.saplingBalances, wallet.orchardBalances) { transparentBalances, saplingBalances, orchardBalances ->
93
- return@combine mapOf("transparentBalances" to transparentBalances, "saplingBalances" to saplingBalances, "orchardBalances" to orchardBalances)
94
- }.collectWith(scope) { map ->
95
- val transparentBalances = map["transparentBalances"]
96
- val saplingBalances = map["saplingBalances"]
97
- val orchardBalances = map["orchardBalances"]
98
-
99
- var availableZatoshi = Zatoshi(0L)
100
- var totalZatoshi = Zatoshi(0L)
101
-
102
- availableZatoshi = availableZatoshi.plus(transparentBalances?.available ?: Zatoshi(0L))
103
- totalZatoshi = totalZatoshi.plus(transparentBalances?.total ?: Zatoshi(0L))
103
+ }
104
+ combine(
105
+ wallet.transparentBalances,
106
+ wallet.saplingBalances,
107
+ ) { transparentBalances, saplingBalances ->
108
+ return@combine mapOf(
109
+ "transparentBalances" to transparentBalances,
110
+ "saplingBalances" to saplingBalances,
111
+ )
112
+ }.collectWith(scope) { map ->
113
+ val transparentBalances = map["transparentBalances"]
114
+ val saplingBalances = map["saplingBalances"]
104
115
 
105
- availableZatoshi = availableZatoshi.plus(saplingBalances?.available ?: Zatoshi(0L))
106
- totalZatoshi = totalZatoshi.plus(saplingBalances?.total ?: Zatoshi(0L))
116
+ val transparentAvailableZatoshi = transparentBalances?.available ?: Zatoshi(0L)
117
+ val transparentTotalZatoshi = transparentBalances?.total ?: Zatoshi(0L)
107
118
 
108
- availableZatoshi = availableZatoshi.plus(orchardBalances?.available ?: Zatoshi(0L))
109
- totalZatoshi = totalZatoshi.plus(orchardBalances?.total ?: Zatoshi(0L))
119
+ val saplingAvailableZatoshi = saplingBalances?.available ?: Zatoshi(0L)
120
+ val saplingTotalZatoshi = saplingBalances?.total ?: Zatoshi(0L)
110
121
 
111
- sendEvent("BalanceEvent") { args ->
112
- args.putString("alias", alias)
113
- args.putString(
114
- "totalZatoshi",
115
- totalZatoshi.value.toString()
116
- )
117
- args.putString(
118
- "availableZatoshi",
119
- availableZatoshi.value.toString()
120
- )
121
- }
122
+ sendEvent("BalanceEvent") { args ->
123
+ args.putString("alias", alias)
124
+ args.putString("transparentAvailableZatoshi", transparentAvailableZatoshi.value.toString())
125
+ args.putString("transparentTotalZatoshi", transparentTotalZatoshi.value.toString())
126
+ args.putString("saplingAvailableZatoshi", saplingAvailableZatoshi.value.toString())
127
+ args.putString("saplingTotalZatoshi", saplingTotalZatoshi.value.toString())
122
128
  }
123
- return@wrap null
124
129
  }
130
+ return@wrap null
125
131
  }
132
+ }
126
133
 
127
134
  @ReactMethod
128
- fun stop(alias: String, promise: Promise) {
135
+ fun stop(
136
+ alias: String,
137
+ promise: Promise,
138
+ ) {
129
139
  val wallet = getWallet(alias)
130
140
  wallet.close()
131
141
  synchronizerMap.remove(alias)
132
142
  promise.resolve(null)
133
143
  }
134
144
 
135
- private suspend fun parseTx(wallet: SdkSynchronizer, tx: TransactionOverview): WritableMap {
145
+ private suspend fun parseTx(
146
+ wallet: SdkSynchronizer,
147
+ tx: TransactionOverview,
148
+ ): WritableMap {
136
149
  val map = Arguments.createMap()
137
- val job = wallet.coroutineScope.launch {
138
- map.putString("value", tx.netValue.value.toString())
139
- if (tx.feePaid != null) {
140
- map.putString("fee", tx.feePaid!!.value.toString())
141
- }
142
- map.putInt("minedHeight", tx.minedHeight!!.value.toInt())
143
- map.putInt("blockTimeInSeconds", tx.blockTimeEpochSeconds!!.toInt())
144
- map.putString("rawTransactionId", tx.rawId.byteArray.toHexReversed())
145
- if (tx.raw != null) {
146
- map.putString("raw", tx.raw!!.byteArray.toHex())
147
- }
148
- if (tx.isSentTransaction) {
149
- val recipient = wallet.getRecipients(tx).first()
150
- if (recipient is TransactionRecipient.Address) {
151
- map.putString("toAddress", recipient.addressValue)
150
+ val job =
151
+ wallet.coroutineScope.launch {
152
+ map.putString("value", tx.netValue.value.toString())
153
+ if (tx.feePaid != null) {
154
+ map.putString("fee", tx.feePaid!!.value.toString())
155
+ }
156
+ map.putInt("minedHeight", tx.minedHeight?.value?.toInt() ?: 0)
157
+ map.putInt("blockTimeInSeconds", tx.blockTimeEpochSeconds?.toInt() ?: 0)
158
+ map.putString("rawTransactionId", tx.rawId.byteArray.toHexReversed())
159
+ if (tx.raw != null) {
160
+ map.putString("raw", tx.raw!!.byteArray.toHex())
161
+ }
162
+ if (tx.isSentTransaction) {
163
+ try {
164
+ val recipient = wallet.getRecipients(tx).first()
165
+ if (recipient is TransactionRecipient.Address) {
166
+ map.putString("toAddress", recipient.addressValue)
167
+ }
168
+ } catch (t: Throwable) {
169
+ // Error is OK. SDK limitation means we cannot find recipient for shielding transactions
170
+ }
171
+ }
172
+ if (tx.memoCount > 0) {
173
+ val memos = wallet.getMemos(tx).take(tx.memoCount).toList()
174
+ map.putArray("memos", Arguments.fromList(memos))
175
+ } else {
176
+ map.putArray("memos", Arguments.createArray())
152
177
  }
153
178
  }
154
- if (tx.memoCount > 0) {
155
- val memos = wallet.getMemos(tx).take(tx.memoCount).toList()
156
- map.putArray("memos", Arguments.fromList(memos))
157
- } else {
158
- map.putArray("memos", Arguments.createArray())
159
- }
160
- }
161
179
  job.join()
162
180
  return map
163
181
  }
164
182
 
165
183
  @ReactMethod
166
- fun rescan(alias: String, promise: Promise) {
184
+ fun rescan(
185
+ alias: String,
186
+ promise: Promise,
187
+ ) {
167
188
  val wallet = getWallet(alias)
168
189
  wallet.coroutineScope.launch {
169
- wallet.coroutineScope.async { wallet.rewindToNearestHeight(wallet.latestBirthdayHeight) }.await()
190
+ wallet.rewindToNearestHeight(wallet.latestBirthdayHeight)
170
191
  promise.resolve(null)
171
192
  }
172
193
  }
173
194
 
174
195
  @ReactMethod
175
- fun deriveViewingKey(seed: String, network: String = "mainnet", promise: Promise) {
196
+ fun deriveViewingKey(
197
+ seed: String,
198
+ network: String = "mainnet",
199
+ promise: Promise,
200
+ ) {
176
201
  val seedPhrase = SeedPhrase.new(seed)
177
202
  moduleScope.launch {
178
- val keys = moduleScope.async { DerivationTool.getInstance().deriveUnifiedFullViewingKeys(seedPhrase.toByteArray(), networks.getOrDefault(network, ZcashNetwork.Mainnet), DerivationTool.DEFAULT_NUMBER_OF_ACCOUNTS)[0] }.await()
203
+ val keys =
204
+ DerivationTool.getInstance().deriveUnifiedFullViewingKeys(
205
+ seedPhrase.toByteArray(),
206
+ networks.getOrDefault(network, ZcashNetwork.Mainnet),
207
+ DerivationTool.DEFAULT_NUMBER_OF_ACCOUNTS,
208
+ )[0]
179
209
  promise.resolve(keys.encoding)
180
210
  }
181
211
  }
@@ -185,13 +215,20 @@ class RNZcashModule(private val reactContext: ReactApplicationContext) :
185
215
  //
186
216
 
187
217
  @ReactMethod
188
- fun getLatestNetworkHeight(alias: String, promise: Promise) = promise.wrap {
218
+ fun getLatestNetworkHeight(
219
+ alias: String,
220
+ promise: Promise,
221
+ ) = promise.wrap {
189
222
  val wallet = getWallet(alias)
190
223
  return@wrap wallet.latestHeight
191
224
  }
192
225
 
193
226
  @ReactMethod
194
- fun getBirthdayHeight(host: String, port: Int, promise: Promise) {
227
+ fun getBirthdayHeight(
228
+ host: String,
229
+ port: Int,
230
+ promise: Promise,
231
+ ) {
195
232
  moduleScope.launch {
196
233
  promise.wrap {
197
234
  val endpoint = LightWalletEndpoint(host, port, true)
@@ -213,7 +250,6 @@ class RNZcashModule(private val reactContext: ReactApplicationContext) :
213
250
  }
214
251
  }
215
252
 
216
- @OptIn(ExperimentalCoroutinesApi::class)
217
253
  @ReactMethod
218
254
  fun sendToAddress(
219
255
  alias: String,
@@ -226,14 +262,15 @@ class RNZcashModule(private val reactContext: ReactApplicationContext) :
226
262
  val wallet = getWallet(alias)
227
263
  wallet.coroutineScope.launch {
228
264
  val seedPhrase = SeedPhrase.new(seed)
229
- val usk = wallet.coroutineScope.async { DerivationTool.getInstance().deriveUnifiedSpendingKey(seedPhrase.toByteArray(), wallet.network, Account.DEFAULT) }.await()
265
+ val usk = DerivationTool.getInstance().deriveUnifiedSpendingKey(seedPhrase.toByteArray(), wallet.network, Account.DEFAULT)
230
266
  try {
231
- val internalId = wallet.sendToAddress(
232
- usk,
233
- Zatoshi(zatoshi.toLong()),
234
- toAddress,
235
- memo,
236
- )
267
+ val internalId =
268
+ wallet.sendToAddress(
269
+ usk,
270
+ Zatoshi(zatoshi.toLong()),
271
+ toAddress,
272
+ memo,
273
+ )
237
274
  val tx = wallet.coroutineScope.async { wallet.transactions.first().first() }.await()
238
275
  val map = Arguments.createMap()
239
276
  map.putString("txId", tx.rawId.byteArray.toHexReversed())
@@ -245,28 +282,67 @@ class RNZcashModule(private val reactContext: ReactApplicationContext) :
245
282
  }
246
283
  }
247
284
 
285
+ @ReactMethod
286
+ fun shieldFunds(
287
+ alias: String,
288
+ seed: String,
289
+ memo: String,
290
+ threshold: String,
291
+ promise: Promise,
292
+ ) {
293
+ val wallet = getWallet(alias)
294
+ wallet.coroutineScope.launch {
295
+ val seedPhrase = SeedPhrase.new(seed)
296
+ val usk = DerivationTool.getInstance().deriveUnifiedSpendingKey(seedPhrase.toByteArray(), wallet.network, Account.DEFAULT)
297
+ try {
298
+ val internalId =
299
+ wallet.shieldFunds(
300
+ usk,
301
+ memo,
302
+ )
303
+ val tx = wallet.coroutineScope.async { wallet.transactions.first().first() }.await()
304
+ val parsedTx = parseTx(wallet, tx)
305
+
306
+ // Hack: Memos aren't ready to be queried right after broadcast
307
+ val memos = Arguments.createArray()
308
+ memos.pushString(memo)
309
+ parsedTx.putArray("memos", memos)
310
+ promise.resolve(parsedTx)
311
+ } catch (t: Throwable) {
312
+ promise.reject("Err", t)
313
+ }
314
+ }
315
+ }
316
+
248
317
  //
249
318
  // AddressTool
250
319
  //
251
320
 
252
321
  @ReactMethod
253
- fun deriveUnifiedAddress(alias: String, promise: Promise) {
322
+ fun deriveUnifiedAddress(
323
+ alias: String,
324
+ promise: Promise,
325
+ ) {
254
326
  val wallet = getWallet(alias)
255
327
  wallet.coroutineScope.launch {
256
- val unifiedAddress = wallet.coroutineScope.async { wallet.getUnifiedAddress(Account(0)) }.await()
257
- val saplingAddress = wallet.coroutineScope.async { wallet.getSaplingAddress(Account(0)) }.await()
258
- val transparentAddress = wallet.coroutineScope.async { wallet.getTransparentAddress(Account(0)) }.await()
328
+ val unifiedAddress = wallet.getUnifiedAddress(Account(0))
329
+ val saplingAddress = wallet.getSaplingAddress(Account(0))
330
+ val transparentAddress = wallet.getTransparentAddress(Account(0))
259
331
 
260
- val map = Arguments.createMap()
261
- map.putString("unifiedAddress", unifiedAddress)
262
- map.putString("saplingAddress", saplingAddress)
263
- map.putString("transparentAddress", transparentAddress)
264
- promise.resolve(map)
332
+ val map = Arguments.createMap()
333
+ map.putString("unifiedAddress", unifiedAddress)
334
+ map.putString("saplingAddress", saplingAddress)
335
+ map.putString("transparentAddress", transparentAddress)
336
+ promise.resolve(map)
265
337
  }
266
338
  }
267
339
 
268
340
  @ReactMethod
269
- fun isValidAddress(address: String, network: String, promise: Promise) {
341
+ fun isValidAddress(
342
+ address: String,
343
+ network: String,
344
+ promise: Promise,
345
+ ) {
270
346
  moduleScope.launch {
271
347
  promise.wrap {
272
348
  var isValid = false
@@ -304,7 +380,10 @@ class RNZcashModule(private val reactContext: ReactApplicationContext) :
304
380
  }
305
381
  }
306
382
 
307
- private fun sendEvent(eventName: String, putArgs: (WritableMap) -> Unit) {
383
+ private fun sendEvent(
384
+ eventName: String,
385
+ putArgs: (WritableMap) -> Unit,
386
+ ) {
308
387
  val args = Arguments.createMap()
309
388
  putArgs(args)
310
389
  reactApplicationContext
@@ -12,6 +12,5 @@ class RNZcashPackage : ReactPackage {
12
12
  RNZcashModule(reactContext),
13
13
  )
14
14
 
15
- override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
16
- emptyList()
15
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> = emptyList()
17
16
  }
package/ios/RNZcash.m CHANGED
@@ -45,6 +45,14 @@ resolver:(RCTPromiseResolveBlock)resolve
45
45
  rejecter:(RCTPromiseRejectBlock)reject
46
46
  )
47
47
 
48
+ RCT_EXTERN_METHOD(shieldFunds:(NSString *)alias
49
+ :(NSString *)seed
50
+ :(NSString *)memo
51
+ :(NSString *)threshold
52
+ resolver:(RCTPromiseResolveBlock)resolve
53
+ rejecter:(RCTPromiseRejectBlock)reject
54
+ )
55
+
48
56
  RCT_EXTERN_METHOD(rescan:(NSString *)alias
49
57
  resolver:(RCTPromiseResolveBlock)resolve
50
58
  rejecter:(RCTPromiseRejectBlock)reject
package/ios/RNZcash.swift CHANGED
@@ -13,7 +13,7 @@ struct ConfirmedTx {
13
13
  var blockTimeInSeconds: Int
14
14
  var value: String
15
15
  var fee: String?
16
- var memos: Array<String>?
16
+ var memos: [String]?
17
17
  var dictionary: [String: Any?] {
18
18
  return [
19
19
  "minedHeight": minedHeight,
@@ -32,12 +32,16 @@ struct ConfirmedTx {
32
32
  }
33
33
 
34
34
  struct TotalBalances {
35
- var availableZatoshi: String
36
- var totalZatoshi: String
35
+ var transparentAvailableZatoshi: Zatoshi
36
+ var transparentTotalZatoshi: Zatoshi
37
+ var saplingAvailableZatoshi: Zatoshi
38
+ var saplingTotalZatoshi: Zatoshi
37
39
  var dictionary: [String: Any] {
38
40
  return [
39
- "availableZatoshi": availableZatoshi,
40
- "totalZatoshi": totalZatoshi,
41
+ "transparentAvailableZatoshi": String(transparentAvailableZatoshi.amount),
42
+ "transparentTotalZatoshi": String(transparentTotalZatoshi.amount),
43
+ "saplingAvailableZatoshi": String(saplingAvailableZatoshi.amount),
44
+ "saplingTotalZatoshi": String(saplingTotalZatoshi.amount),
41
45
  ]
42
46
  }
43
47
  var nsDictionary: NSDictionary {
@@ -81,7 +85,8 @@ class RNZcash: RCTEventEmitter {
81
85
  // Synchronizer
82
86
  @objc func initialize(
83
87
  _ seed: String, _ birthdayHeight: Int, _ alias: String, _ networkName: String,
84
- _ defaultHost: String, _ defaultPort: Int, _ newWallet: Bool, resolver resolve: @escaping RCTPromiseResolveBlock,
88
+ _ defaultHost: String, _ defaultPort: Int, _ newWallet: Bool,
89
+ resolver resolve: @escaping RCTPromiseResolveBlock,
85
90
  rejecter reject: @escaping RCTPromiseRejectBlock
86
91
  ) {
87
92
  Task {
@@ -234,6 +239,43 @@ class RNZcash: RCTEventEmitter {
234
239
  }
235
240
  }
236
241
 
242
+ @objc func shieldFunds(
243
+ _ alias: String, _ seed: String, _ memo: String, _ threshold: String,
244
+ resolver resolve: @escaping RCTPromiseResolveBlock,
245
+ rejecter reject: @escaping RCTPromiseRejectBlock
246
+ ) {
247
+ Task {
248
+ if let wallet = SynchronizerMap[alias] {
249
+ if !wallet.fullySynced {
250
+ reject("shieldFunds", "Wallet is not synced", genericError)
251
+ return
252
+ }
253
+
254
+ do {
255
+ let spendingKey = try deriveUnifiedSpendingKey(seed, wallet.synchronizer.network)
256
+ let sdkMemo = try Memo(string: memo)
257
+ let shieldingThreshold = Int64(threshold) ?? 10000
258
+
259
+ let tx = try await wallet.synchronizer.shieldFunds(
260
+ spendingKey: spendingKey,
261
+ memo: sdkMemo,
262
+ shieldingThreshold: Zatoshi(shieldingThreshold)
263
+ )
264
+
265
+ var confTx = await wallet.parseTx(tx: tx)
266
+
267
+ // Hack: Memos aren't ready to be queried right after broadcast
268
+ confTx.memos = [memo]
269
+ resolve(confTx.nsDictionary)
270
+ } catch {
271
+ reject("shieldFunds", "Failed to shield funds", genericError)
272
+ }
273
+ } else {
274
+ reject("shieldFunds", "Wallet does not exist", genericError)
275
+ }
276
+ }
277
+ }
278
+
237
279
  @objc func rescan(
238
280
  _ alias: String, resolver resolve: @escaping RCTPromiseResolveBlock,
239
281
  rejecter reject: @escaping RCTPromiseRejectBlock
@@ -250,8 +292,8 @@ class RNZcash: RCTEventEmitter {
250
292
  wallet.restart = true
251
293
  wallet.initializeProcessorState()
252
294
  wallet.cancellables.forEach { $0.cancel() }
253
- wallet.subscribe()
254
295
  try await wallet.synchronizer.start()
296
+ wallet.subscribe()
255
297
  resolve(nil)
256
298
  case .failure:
257
299
  reject("RescanError", "Failed to rescan wallet", genericError)
@@ -315,11 +357,12 @@ class RNZcash: RCTEventEmitter {
315
357
  do {
316
358
  let unifiedAddress = try await wallet.synchronizer.getUnifiedAddress(accountIndex: 0)
317
359
  let saplingAddress = try await wallet.synchronizer.getSaplingAddress(accountIndex: 0)
318
- let transparentAddress = try await wallet.synchronizer.getTransparentAddress(accountIndex: 0)
360
+ let transparentAddress = try await wallet.synchronizer.getTransparentAddress(
361
+ accountIndex: 0)
319
362
  let addresses: NSDictionary = [
320
363
  "unifiedAddress": unifiedAddress.stringEncoded,
321
364
  "saplingAddress": saplingAddress.stringEncoded,
322
- "transparentAddress": transparentAddress.stringEncoded
365
+ "transparentAddress": transparentAddress.stringEncoded,
323
366
  ]
324
367
  resolve(addresses)
325
368
  return
@@ -379,12 +422,15 @@ class WalletSynchronizer: NSObject {
379
422
  scanProgress: 0,
380
423
  networkBlockHeight: 0
381
424
  )
382
- self.balances = TotalBalances(availableZatoshi: "0", totalZatoshi: "0")
425
+ self.balances = TotalBalances(
426
+ transparentAvailableZatoshi: Zatoshi(0),
427
+ transparentTotalZatoshi: Zatoshi(0),
428
+ saplingAvailableZatoshi: Zatoshi(0),
429
+ saplingTotalZatoshi: Zatoshi(0))
383
430
  }
384
431
 
385
432
  public func subscribe() {
386
433
  self.synchronizer.stateStream
387
- .throttle(for: .seconds(0.3), scheduler: DispatchQueue.main, latest: true)
388
434
  .sink(receiveValue: { [weak self] state in self?.updateSyncStatus(event: state) })
389
435
  .store(in: &cancellables)
390
436
  self.synchronizer.stateStream
@@ -393,35 +439,38 @@ class WalletSynchronizer: NSObject {
393
439
  self.synchronizer.eventStream
394
440
  .sink { SynchronizerEvent in
395
441
  switch SynchronizerEvent {
396
- case .minedTransaction(let transaction):
397
- self.emitTxs(transactions: [transaction])
398
- case .foundTransactions(let transactions, _):
399
- self.emitTxs(transactions: transactions)
400
- default:
401
- return
402
- }
442
+ case .minedTransaction(let transaction):
443
+ self.emitTxs(transactions: [transaction])
444
+ case .foundTransactions(let transactions, _):
445
+ self.emitTxs(transactions: transactions)
446
+ default:
447
+ return
448
+ }
403
449
  }
404
450
  .store(in: &cancellables)
405
451
  }
406
452
 
407
453
  func updateSyncStatus(event: SynchronizerState) {
408
-
454
+ var status = self.status
455
+
409
456
  if !self.fullySynced {
410
457
  switch event.internalSyncStatus {
411
458
  case .syncing:
412
- self.status = "SYNCING"
459
+ status = "SYNCING"
413
460
  self.restart = false
414
461
  case .synced:
415
462
  if self.restart {
416
463
  // The synchronizer emits "synced" status after starting a rescan. We need to ignore these.
417
464
  return
418
465
  }
419
- self.status = "SYNCED"
466
+ status = "SYNCED"
420
467
  self.fullySynced = true
421
468
  default:
422
469
  break
423
470
  }
424
471
 
472
+ if status == self.status { return }
473
+ self.status = status
425
474
  let data: NSDictionary = ["alias": self.alias, "name": self.status]
426
475
  emit("StatusEvent", data)
427
476
  }
@@ -441,10 +490,18 @@ class WalletSynchronizer: NSObject {
441
490
  return
442
491
  }
443
492
 
444
- if (scanProgress == self.processorState.scanProgress && event.latestBlockHeight == self.processorState.networkBlockHeight) { return }
493
+ if scanProgress == self.processorState.scanProgress
494
+ && event.latestBlockHeight == self.processorState.networkBlockHeight
495
+ {
496
+ return
497
+ }
445
498
 
446
- self.processorState = ProcessorState(scanProgress: scanProgress, networkBlockHeight: event.latestBlockHeight)
447
- let data: NSDictionary = ["alias": self.alias, "scanProgress": self.processorState.scanProgress, "networkBlockHeight": self.processorState.networkBlockHeight]
499
+ self.processorState = ProcessorState(
500
+ scanProgress: scanProgress, networkBlockHeight: event.latestBlockHeight)
501
+ let data: NSDictionary = [
502
+ "alias": self.alias, "scanProgress": self.processorState.scanProgress,
503
+ "networkBlockHeight": self.processorState.networkBlockHeight,
504
+ ]
448
505
  emit("UpdateEvent", data)
449
506
  updateBalanceState(event: event)
450
507
  }
@@ -454,68 +511,86 @@ class WalletSynchronizer: NSObject {
454
511
  scanProgress: 0,
455
512
  networkBlockHeight: 0
456
513
  )
457
- self.balances = TotalBalances(availableZatoshi: "0", totalZatoshi: "0")
514
+ self.balances = TotalBalances(
515
+ transparentAvailableZatoshi: Zatoshi(0),
516
+ transparentTotalZatoshi: Zatoshi(0),
517
+ saplingAvailableZatoshi: Zatoshi(0),
518
+ saplingTotalZatoshi: Zatoshi(0))
458
519
  }
459
520
 
460
521
  func updateBalanceState(event: SynchronizerState) {
461
522
  let transparentBalance = event.transparentBalance
462
523
  let shieldedBalance = event.shieldedBalance
463
524
 
464
- let availableTransparentBalance = transparentBalance.verified
465
- let totalTransparentBalance = transparentBalance.total
525
+ let transparentAvailableZatoshi = transparentBalance.verified
526
+ let transparentTotalZatoshi = transparentBalance.total
466
527
 
467
- let availableShieldedBalance = shieldedBalance.verified
468
- let totalShieldedBalance = shieldedBalance.total
528
+ let saplingAvailableZatoshi = shieldedBalance.verified
529
+ let saplingTotalZatoshi = shieldedBalance.total
469
530
 
470
- let availableZatoshi = String((availableShieldedBalance + availableTransparentBalance).amount)
471
- let totalZatoshi = String((totalShieldedBalance + totalTransparentBalance).amount)
472
-
473
- if (availableZatoshi == self.balances.availableZatoshi && totalZatoshi == self.balances.totalZatoshi) { return }
531
+ if transparentAvailableZatoshi == self.balances.transparentAvailableZatoshi
532
+ && transparentTotalZatoshi == self.balances.transparentTotalZatoshi
533
+ && saplingAvailableZatoshi == self.balances.saplingAvailableZatoshi
534
+ && saplingTotalZatoshi == self.balances.saplingTotalZatoshi
535
+ {
536
+ return
537
+ }
474
538
 
475
- self.balances = TotalBalances(availableZatoshi: availableZatoshi, totalZatoshi: totalZatoshi)
476
- let data: NSDictionary = ["alias": self.alias, "availableZatoshi": self.balances.availableZatoshi, "totalZatoshi": self.balances.totalZatoshi]
539
+ self.balances = TotalBalances(
540
+ transparentAvailableZatoshi: transparentAvailableZatoshi,
541
+ transparentTotalZatoshi: transparentTotalZatoshi,
542
+ saplingAvailableZatoshi: saplingAvailableZatoshi,
543
+ saplingTotalZatoshi: saplingTotalZatoshi
544
+ )
545
+ let data = NSMutableDictionary(dictionary: self.balances.nsDictionary)
546
+ data["alias"] = self.alias
477
547
  emit("BalanceEvent", data)
478
548
  }
479
549
 
550
+ func parseTx(tx: ZcashTransaction.Overview) async -> ConfirmedTx {
551
+ var confTx = ConfirmedTx(
552
+ minedHeight: tx.minedHeight ?? 0,
553
+ rawTransactionId: (tx.rawID.toHexStringTxId()),
554
+ blockTimeInSeconds: Int(tx.blockTime ?? 0),
555
+ value: String(describing: abs(tx.value.amount))
556
+ )
557
+ if tx.raw != nil {
558
+ confTx.raw = tx.raw!.hexEncodedString()
559
+ }
560
+ if tx.fee != nil {
561
+ confTx.fee = String(describing: abs(tx.value.amount))
562
+ }
563
+ if tx.isSentTransaction {
564
+ let recipients = await self.synchronizer.getRecipients(for: tx)
565
+ if recipients.count > 0 {
566
+ let addresses = recipients.compactMap {
567
+ if case let .address(address) = $0 {
568
+ return address
569
+ } else {
570
+ return nil
571
+ }
572
+ }
573
+ if addresses.count > 0 {
574
+ confTx.toAddress = addresses.first!.stringEncoded
575
+ }
576
+ }
577
+ }
578
+ if tx.memoCount > 0 {
579
+ let memos = (try? await self.synchronizer.getMemos(for: tx)) ?? []
580
+ let textMemos = memos.compactMap {
581
+ return $0.toString()
582
+ }
583
+ confTx.memos = textMemos
584
+ }
585
+ return confTx
586
+ }
587
+
480
588
  func emitTxs(transactions: [ZcashTransaction.Overview]) {
481
589
  Task {
482
590
  var out: [NSDictionary] = []
483
591
  for tx in transactions {
484
- if (tx.isExpiredUmined ?? false) { continue }
485
- var confTx = ConfirmedTx(
486
- minedHeight: tx.minedHeight!,
487
- rawTransactionId: (tx.rawID.toHexStringTxId()),
488
- blockTimeInSeconds: Int(tx.blockTime!),
489
- value: String(describing: abs(tx.value.amount))
490
- )
491
- if tx.raw != nil {
492
- confTx.raw = tx.raw!.hexEncodedString()
493
- }
494
- if tx.fee != nil {
495
- confTx.fee = String(describing: abs(tx.value.amount))
496
- }
497
- if tx.isSentTransaction {
498
- let recipients = await self.synchronizer.getRecipients(for: tx)
499
- if recipients.count > 0 {
500
- let addresses = recipients.compactMap {
501
- if case let .address(address) = $0 {
502
- return address
503
- } else {
504
- return nil
505
- }
506
- }
507
- if addresses.count > 0 {
508
- confTx.toAddress = addresses.first!.stringEncoded
509
- }
510
- }
511
- }
512
- if tx.memoCount > 0 {
513
- let memos = (try? await self.synchronizer.getMemos(for: tx)) ?? []
514
- let textMemos = memos.compactMap {
515
- return $0.toString()
516
- }
517
- confTx.memos = textMemos
518
- }
592
+ if tx.isExpiredUmined ?? false { continue }
593
+ let confTx = await parseTx(tx: tx)
519
594
  out.append(confTx.nsDictionary)
520
595
  }
521
596
 
@@ -22,7 +22,7 @@ actor CompactBlockProcessor {
22
22
  private var syncTask: Task<Void, Error>?
23
23
 
24
24
  private let actions: [CBPState: Action]
25
- private var context: ActionContext
25
+ var context: ActionContext
26
26
 
27
27
  private(set) var config: Configuration
28
28
  private let configProvider: ConfigProvider
@@ -346,6 +346,8 @@ extension CompactBlockProcessor {
346
346
  } catch {
347
347
  return await context.completion(.failure(error))
348
348
  }
349
+
350
+ await resetContext(restoreLastEnhancedHeight: false)
349
351
 
350
352
  await context.completion(.success(rewindBlockHeight))
351
353
  }
@@ -615,10 +617,12 @@ extension CompactBlockProcessor {
615
617
  }
616
618
  }
617
619
 
618
- private func resetContext() async {
619
- let lastEnhancedheight = await context.lastEnhancedHeight
620
+ func resetContext(restoreLastEnhancedHeight: Bool = true) async {
621
+ let lastEnhancedHeight = await context.lastEnhancedHeight
620
622
  context = ActionContextImpl(state: .idle)
621
- await context.update(lastEnhancedHeight: lastEnhancedheight)
623
+ if restoreLastEnhancedHeight {
624
+ await context.update(lastEnhancedHeight: lastEnhancedHeight)
625
+ }
622
626
  }
623
627
 
624
628
  private func syncStarted() async {
@@ -98,7 +98,12 @@ public enum ZcashSDK {
98
98
  public static let defaultPollInterval: TimeInterval = 20
99
99
 
100
100
  /// Default attempts at retrying.
101
- public static let defaultRetries: Int = 5
101
+ // This has been tweaked in https://github.com/zcash/ZcashLightClientKit/issues/1303
102
+ // There are many places that rely on hasRetryAttempt() that reads and compares this value.
103
+ // Better solution is to think about retry logic and potentially either remove completely
104
+ // or implement more sophisticated solutuion. Until that time, Int.max solves our UX issues
105
+ // TODO: [#1304] smart retry logic, https://github.com/zcash/ZcashLightClientKit/issues/1304
106
+ public static let defaultRetries = Int.max
102
107
 
103
108
  /// The default maximum amount of time to wait during retry backoff intervals. Failed loops will never wait longer than
104
109
  /// this before retrying.
@@ -0,0 +1,8 @@
1
+ {
2
+ "network": "main",
3
+ "height": "2260000",
4
+ "hash": "00000000014b3b907e559bd87daba56c85c16446aef59e9ce9dba37ad2691b86",
5
+ "time": 1697204301,
6
+ "saplingTree": "01ccd67f580cc75af1faf952deaa774c5008496e49f2b8c3f4de936ee0c268846b001a00000001db3f7578a2f0e1d7ce61030a4192f0500c655626c81edd69be7e2bb012cb5b3b0001299a4e80c4c7c13553248aae4f35f03318cc04713927b8aa9abf086df2d8375d0000015811cf08cc569867834281fd88ea6bc930529573fa2cbbff8fd0f64963cee702000169d3b6e6999f905b302b4f1d2f84acf1b84e04d1fe8a1d107efd1971faa0bd0e0001e192d9d422a7fdd876027946e61dc5034f54ae4df2834eda15800658196e731f000001ffdd1a0628296bf274daa5ea13fb57818d678957d49f91ccd69efae0bac249340182ac7ebe2f7e9d8084a38aa8be56b1bd86292babf05f98882a6959cf9d318c110001d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
7
+ "orchardTree": "01bf80f9a026cba7ffd8e4eb99895eefc6e7e7b1f3f451cd0272f8c8ee09b81e0601c94fc93463e006682dc287e10035a898a577becb7af338c7aad32b6aeeb592111f000151634a9677c3589d76542b11db3c79efccc8fbbe3cb521b9adf599ad3895dc020163ee08cae7b538138c74534a346d723e37beb3a886d9fc7e1b69e938a48c6d220188d5ac292703a08902cc79a54a801b13b41360e03cfb130e3b7ca9e76bd8961401b1021539f9d34c2df786324de29594dfd12f260ec6f893e37490a9c4cf7f7f380000014c3bc5b55f752c69ac57e14b8cb7c2bc00a1c7c21231dc4b1c9124fe434ea13900000000012ffae608e1b4d4de4f5ac38068b613d9761ba34d95430e5ec8d058848cc9c0250001dd3e61f3e1d497d923486bd000737ea0ffac885fa481316727d0d8f7fc2138100001cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
8
+ }
@@ -8,32 +8,32 @@
8
8
  <key>BinaryPath</key>
9
9
  <string>libzcashlc.a</string>
10
10
  <key>LibraryIdentifier</key>
11
- <string>ios-arm64</string>
11
+ <string>ios-arm64_x86_64-simulator</string>
12
12
  <key>LibraryPath</key>
13
13
  <string>libzcashlc.a</string>
14
14
  <key>SupportedArchitectures</key>
15
15
  <array>
16
16
  <string>arm64</string>
17
+ <string>x86_64</string>
17
18
  </array>
18
19
  <key>SupportedPlatform</key>
19
20
  <string>ios</string>
21
+ <key>SupportedPlatformVariant</key>
22
+ <string>simulator</string>
20
23
  </dict>
21
24
  <dict>
22
25
  <key>BinaryPath</key>
23
26
  <string>libzcashlc.a</string>
24
27
  <key>LibraryIdentifier</key>
25
- <string>ios-arm64_x86_64-simulator</string>
28
+ <string>ios-arm64</string>
26
29
  <key>LibraryPath</key>
27
30
  <string>libzcashlc.a</string>
28
31
  <key>SupportedArchitectures</key>
29
32
  <array>
30
33
  <string>arm64</string>
31
- <string>x86_64</string>
32
34
  </array>
33
35
  <key>SupportedPlatform</key>
34
36
  <string>ios</string>
35
- <key>SupportedPlatformVariant</key>
36
- <string>simulator</string>
37
37
  </dict>
38
38
  </array>
39
39
  <key>CFBundlePackageType</key>
package/lib/rnzcash.rn.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var biggystring = require('biggystring');
5
6
  var reactNative = require('react-native');
6
7
 
7
8
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
@@ -145,9 +146,17 @@ var Synchronizer = /*#__PURE__*/function () {
145
146
  return getLatestNetworkHeight;
146
147
  }();
147
148
 
148
- _proto.rescan = function rescan() {
149
- RNZcash.rescan(this.alias);
150
- };
149
+ _proto.rescan = /*#__PURE__*/function () {
150
+ var _rescan = _asyncToGenerator(function* () {
151
+ yield RNZcash.rescan(this.alias);
152
+ });
153
+
154
+ function rescan() {
155
+ return _rescan.apply(this, arguments);
156
+ }
157
+
158
+ return rescan;
159
+ }();
151
160
 
152
161
  _proto.sendToAddress = /*#__PURE__*/function () {
153
162
  var _sendToAddress = _asyncToGenerator(function* (spendInfo) {
@@ -160,6 +169,19 @@ var Synchronizer = /*#__PURE__*/function () {
160
169
  }
161
170
 
162
171
  return sendToAddress;
172
+ }();
173
+
174
+ _proto.shieldFunds = /*#__PURE__*/function () {
175
+ var _shieldFunds = _asyncToGenerator(function* (shieldFundsInfo) {
176
+ var result = yield RNZcash.shieldFunds(this.alias, shieldFundsInfo.seed, shieldFundsInfo.memo, shieldFundsInfo.threshold);
177
+ return result;
178
+ });
179
+
180
+ function shieldFunds(_x10) {
181
+ return _shieldFunds.apply(this, arguments);
182
+ }
183
+
184
+ return shieldFunds;
163
185
  }() // Events
164
186
  ;
165
187
 
@@ -168,7 +190,15 @@ var Synchronizer = /*#__PURE__*/function () {
168
190
  onStatusChanged = _ref.onStatusChanged,
169
191
  onTransactionsChanged = _ref.onTransactionsChanged,
170
192
  onUpdate = _ref.onUpdate;
171
- this.setListener('BalanceEvent', onBalanceChanged);
193
+ this.setListener('BalanceEvent', function (event) {
194
+ var transparentAvailableZatoshi = event.transparentAvailableZatoshi,
195
+ transparentTotalZatoshi = event.transparentTotalZatoshi,
196
+ saplingAvailableZatoshi = event.saplingAvailableZatoshi,
197
+ saplingTotalZatoshi = event.saplingTotalZatoshi;
198
+ event.availableZatoshi = biggystring.add(transparentAvailableZatoshi, saplingAvailableZatoshi);
199
+ event.totalZatoshi = biggystring.add(transparentTotalZatoshi, saplingTotalZatoshi);
200
+ onBalanceChanged(event);
201
+ });
172
202
  this.setListener('StatusEvent', onStatusChanged);
173
203
  this.setListener('TransactionEvent', onTransactionsChanged);
174
204
  this.setListener('UpdateEvent', onUpdate);
@@ -203,7 +233,7 @@ var makeSynchronizer = /*#__PURE__*/function () {
203
233
  return synchronizer;
204
234
  });
205
235
 
206
- return function makeSynchronizer(_x10) {
236
+ return function makeSynchronizer(_x11) {
207
237
  return _ref2.apply(this, arguments);
208
238
  };
209
239
  }();
@@ -1 +1 @@
1
- {"version":3,"file":"rnzcash.rn.js","sources":["../src/react-native.ts"],"sourcesContent":["import {\n EventSubscription,\n NativeEventEmitter,\n NativeModules\n} from 'react-native'\n\nimport {\n Addresses,\n InitializerConfig,\n Network,\n SpendFailure,\n SpendInfo,\n SpendSuccess,\n SynchronizerCallbacks,\n UnifiedViewingKey\n} from './types'\n\nconst { RNZcash } = NativeModules\n\ntype Callback = (...args: any[]) => any\n\nexport const Tools = {\n deriveViewingKey: async (\n seedBytesHex: string,\n network: Network\n ): Promise<UnifiedViewingKey> => {\n const result = await RNZcash.deriveViewingKey(seedBytesHex, network)\n return result\n },\n getBirthdayHeight: async (host: string, port: number): Promise<number> => {\n const result = await RNZcash.getBirthdayHeight(host, port)\n return result\n },\n isValidAddress: async (\n address: string,\n network: Network = 'mainnet'\n ): Promise<boolean> => {\n const result = await RNZcash.isValidAddress(address, network)\n return result\n }\n}\n\nexport class Synchronizer {\n eventEmitter: NativeEventEmitter\n subscriptions: EventSubscription[]\n alias: string\n network: Network\n\n constructor(alias: string, network: Network) {\n this.eventEmitter = new NativeEventEmitter(RNZcash)\n this.subscriptions = []\n this.alias = alias\n this.network = network\n }\n\n async stop(): Promise<String> {\n this.unsubscribe()\n const result = await RNZcash.stop(this.alias)\n return result\n }\n\n async initialize(initializerConfig: InitializerConfig): Promise<void> {\n await RNZcash.initialize(\n initializerConfig.mnemonicSeed,\n initializerConfig.birthdayHeight,\n initializerConfig.alias,\n initializerConfig.networkName,\n initializerConfig.defaultHost,\n initializerConfig.defaultPort,\n initializerConfig.newWallet\n )\n }\n\n async deriveUnifiedAddress(): Promise<Addresses> {\n const result = await RNZcash.deriveUnifiedAddress(this.alias)\n return result\n }\n\n async getLatestNetworkHeight(alias: string): Promise<number> {\n const result = await RNZcash.getLatestNetworkHeight(alias)\n return result\n }\n\n rescan(): void {\n RNZcash.rescan(this.alias)\n }\n\n async sendToAddress(\n spendInfo: SpendInfo\n ): Promise<SpendSuccess | SpendFailure> {\n const result = await RNZcash.sendToAddress(\n this.alias,\n spendInfo.zatoshi,\n spendInfo.toAddress,\n spendInfo.memo,\n spendInfo.mnemonicSeed\n )\n return result\n }\n\n // Events\n\n subscribe({\n onBalanceChanged,\n onStatusChanged,\n onTransactionsChanged,\n onUpdate\n }: SynchronizerCallbacks): void {\n this.setListener('BalanceEvent', onBalanceChanged)\n this.setListener('StatusEvent', onStatusChanged)\n this.setListener('TransactionEvent', onTransactionsChanged)\n this.setListener('UpdateEvent', onUpdate)\n }\n\n private setListener<T>(\n eventName: string,\n callback: Callback = (t: any) => null\n ): void {\n this.subscriptions.push(\n this.eventEmitter.addListener(eventName, arg =>\n arg.alias === this.alias ? callback(arg) : null\n )\n )\n }\n\n unsubscribe(): void {\n this.subscriptions.forEach(subscription => {\n subscription.remove()\n })\n }\n}\n\nexport const makeSynchronizer = async (\n initializerConfig: InitializerConfig\n): Promise<Synchronizer> => {\n const synchronizer = new Synchronizer(\n initializerConfig.alias,\n initializerConfig.networkName\n )\n await synchronizer.initialize(initializerConfig)\n return synchronizer\n}\n"],"names":["RNZcash","NativeModules","Tools","deriveViewingKey","seedBytesHex","network","result","getBirthdayHeight","host","port","isValidAddress","address","Synchronizer","alias","eventEmitter","NativeEventEmitter","subscriptions","stop","unsubscribe","initialize","initializerConfig","mnemonicSeed","birthdayHeight","networkName","defaultHost","defaultPort","newWallet","deriveUnifiedAddress","getLatestNetworkHeight","rescan","sendToAddress","spendInfo","zatoshi","toAddress","memo","subscribe","onBalanceChanged","onStatusChanged","onTransactionsChanged","onUpdate","setListener","eventName","callback","t","push","addListener","arg","forEach","subscription","remove","makeSynchronizer","synchronizer"],"mappings":"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"}
1
+ {"version":3,"file":"rnzcash.rn.js","sources":["../src/react-native.ts"],"sourcesContent":["import { add } from 'biggystring'\nimport {\n EventSubscription,\n NativeEventEmitter,\n NativeModules\n} from 'react-native'\n\nimport {\n Addresses,\n InitializerConfig,\n Network,\n ShieldFundsInfo,\n SpendFailure,\n SpendInfo,\n SpendSuccess,\n SynchronizerCallbacks,\n Transaction,\n UnifiedViewingKey\n} from './types'\nexport * from './types'\n\nconst { RNZcash } = NativeModules\n\ntype Callback = (...args: any[]) => any\n\nexport const Tools = {\n deriveViewingKey: async (\n seedBytesHex: string,\n network: Network\n ): Promise<UnifiedViewingKey> => {\n const result = await RNZcash.deriveViewingKey(seedBytesHex, network)\n return result\n },\n getBirthdayHeight: async (host: string, port: number): Promise<number> => {\n const result = await RNZcash.getBirthdayHeight(host, port)\n return result\n },\n isValidAddress: async (\n address: string,\n network: Network = 'mainnet'\n ): Promise<boolean> => {\n const result = await RNZcash.isValidAddress(address, network)\n return result\n }\n}\n\nexport class Synchronizer {\n eventEmitter: NativeEventEmitter\n subscriptions: EventSubscription[]\n alias: string\n network: Network\n\n constructor(alias: string, network: Network) {\n this.eventEmitter = new NativeEventEmitter(RNZcash)\n this.subscriptions = []\n this.alias = alias\n this.network = network\n }\n\n async stop(): Promise<string> {\n this.unsubscribe()\n const result = await RNZcash.stop(this.alias)\n return result\n }\n\n async initialize(initializerConfig: InitializerConfig): Promise<void> {\n await RNZcash.initialize(\n initializerConfig.mnemonicSeed,\n initializerConfig.birthdayHeight,\n initializerConfig.alias,\n initializerConfig.networkName,\n initializerConfig.defaultHost,\n initializerConfig.defaultPort,\n initializerConfig.newWallet\n )\n }\n\n async deriveUnifiedAddress(): Promise<Addresses> {\n const result = await RNZcash.deriveUnifiedAddress(this.alias)\n return result\n }\n\n async getLatestNetworkHeight(alias: string): Promise<number> {\n const result = await RNZcash.getLatestNetworkHeight(alias)\n return result\n }\n\n async rescan(): Promise<void> {\n await RNZcash.rescan(this.alias)\n }\n\n async sendToAddress(\n spendInfo: SpendInfo\n ): Promise<SpendSuccess | SpendFailure> {\n const result = await RNZcash.sendToAddress(\n this.alias,\n spendInfo.zatoshi,\n spendInfo.toAddress,\n spendInfo.memo,\n spendInfo.mnemonicSeed\n )\n return result\n }\n\n async shieldFunds(shieldFundsInfo: ShieldFundsInfo): Promise<Transaction> {\n const result = await RNZcash.shieldFunds(\n this.alias,\n shieldFundsInfo.seed,\n shieldFundsInfo.memo,\n shieldFundsInfo.threshold\n )\n return result\n }\n\n // Events\n\n subscribe({\n onBalanceChanged,\n onStatusChanged,\n onTransactionsChanged,\n onUpdate\n }: SynchronizerCallbacks): void {\n this.setListener('BalanceEvent', event => {\n const {\n transparentAvailableZatoshi,\n transparentTotalZatoshi,\n saplingAvailableZatoshi,\n saplingTotalZatoshi\n } = event\n\n event.availableZatoshi = add(\n transparentAvailableZatoshi,\n saplingAvailableZatoshi\n )\n event.totalZatoshi = add(transparentTotalZatoshi, saplingTotalZatoshi)\n onBalanceChanged(event)\n })\n this.setListener('StatusEvent', onStatusChanged)\n this.setListener('TransactionEvent', onTransactionsChanged)\n this.setListener('UpdateEvent', onUpdate)\n }\n\n private setListener<T>(\n eventName: string,\n callback: Callback = (t: any) => null\n ): void {\n this.subscriptions.push(\n this.eventEmitter.addListener(eventName, arg =>\n arg.alias === this.alias ? callback(arg) : null\n )\n )\n }\n\n unsubscribe(): void {\n this.subscriptions.forEach(subscription => {\n subscription.remove()\n })\n }\n}\n\nexport const makeSynchronizer = async (\n initializerConfig: InitializerConfig\n): Promise<Synchronizer> => {\n const synchronizer = new Synchronizer(\n initializerConfig.alias,\n initializerConfig.networkName\n )\n await synchronizer.initialize(initializerConfig)\n return synchronizer\n}\n"],"names":["RNZcash","NativeModules","Tools","deriveViewingKey","seedBytesHex","network","result","getBirthdayHeight","host","port","isValidAddress","address","Synchronizer","alias","eventEmitter","NativeEventEmitter","subscriptions","stop","unsubscribe","initialize","initializerConfig","mnemonicSeed","birthdayHeight","networkName","defaultHost","defaultPort","newWallet","deriveUnifiedAddress","getLatestNetworkHeight","rescan","sendToAddress","spendInfo","zatoshi","toAddress","memo","shieldFunds","shieldFundsInfo","seed","threshold","subscribe","onBalanceChanged","onStatusChanged","onTransactionsChanged","onUpdate","setListener","event","transparentAvailableZatoshi","transparentTotalZatoshi","saplingAvailableZatoshi","saplingTotalZatoshi","availableZatoshi","add","totalZatoshi","eventName","callback","t","push","addListener","arg","forEach","subscription","remove","makeSynchronizer","synchronizer"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { EventSubscription, NativeEventEmitter } from 'react-native';
2
- import { Addresses, InitializerConfig, Network, SpendFailure, SpendInfo, SpendSuccess, SynchronizerCallbacks, UnifiedViewingKey } from './types';
2
+ import { Addresses, InitializerConfig, Network, ShieldFundsInfo, SpendFailure, SpendInfo, SpendSuccess, SynchronizerCallbacks, Transaction, UnifiedViewingKey } from './types';
3
+ export * from './types';
3
4
  export declare const Tools: {
4
5
  deriveViewingKey: (seedBytesHex: string, network: Network) => Promise<UnifiedViewingKey>;
5
6
  getBirthdayHeight: (host: string, port: number) => Promise<number>;
@@ -11,12 +12,13 @@ export declare class Synchronizer {
11
12
  alias: string;
12
13
  network: Network;
13
14
  constructor(alias: string, network: Network);
14
- stop(): Promise<String>;
15
+ stop(): Promise<string>;
15
16
  initialize(initializerConfig: InitializerConfig): Promise<void>;
16
17
  deriveUnifiedAddress(): Promise<Addresses>;
17
18
  getLatestNetworkHeight(alias: string): Promise<number>;
18
- rescan(): void;
19
+ rescan(): Promise<void>;
19
20
  sendToAddress(spendInfo: SpendInfo): Promise<SpendSuccess | SpendFailure>;
21
+ shieldFunds(shieldFundsInfo: ShieldFundsInfo): Promise<Transaction>;
20
22
  subscribe({ onBalanceChanged, onStatusChanged, onTransactionsChanged, onUpdate }: SynchronizerCallbacks): void;
21
23
  private setListener;
22
24
  unsubscribe(): void;
@@ -14,6 +14,11 @@ export interface SpendInfo {
14
14
  memo?: string;
15
15
  mnemonicSeed: string;
16
16
  }
17
+ export interface ShieldFundsInfo {
18
+ seed: string;
19
+ memo: string;
20
+ threshold: string;
21
+ }
17
22
  export interface SpendSuccess {
18
23
  txId: string;
19
24
  raw: string;
@@ -27,6 +32,11 @@ export interface UnifiedViewingKey {
27
32
  extpub: string;
28
33
  }
29
34
  export interface BalanceEvent {
35
+ transparentAvailableZatoshi: string;
36
+ transparentTotalZatoshi: string;
37
+ saplingAvailableZatoshi: string;
38
+ saplingTotalZatoshi: string;
39
+ /** @deprecated */
30
40
  availableZatoshi: string;
31
41
  totalZatoshi: string;
32
42
  }
@@ -35,7 +45,7 @@ export interface StatusEvent {
35
45
  name: 'STOPPED' /** Indicates that [stop] has been called on this Synchronizer and it will no longer be used. */ | 'DISCONNECTED' /** Indicates that this Synchronizer is disconnected from its lightwalletd server. When set, a UI element may want to turn red. */ | 'SYNCING' /** Indicates that this Synchronizer is actively downloading and scanning new blocks */ | 'SYNCED'; /** Indicates that this Synchronizer is fully up to date and ready for all wallet functions. When set, a UI element may want to turn green. In this state, the balance can be trusted. */
36
46
  }
37
47
  export interface TransactionEvent {
38
- transactions: ConfirmedTransaction[];
48
+ transactions: Transaction[];
39
49
  }
40
50
  export interface UpdateEvent {
41
51
  alias: string;
@@ -52,7 +62,7 @@ export interface BlockRange {
52
62
  first: number;
53
63
  last: number;
54
64
  }
55
- export interface ConfirmedTransaction {
65
+ export interface Transaction {
56
66
  rawTransactionId: string;
57
67
  raw?: string;
58
68
  blockTimeInSeconds: number;
@@ -62,6 +72,8 @@ export interface ConfirmedTransaction {
62
72
  toAddress?: string;
63
73
  memos: string[];
64
74
  }
75
+ /** @deprecated Renamed `Transaction` because the package can now return unconfirmed shielding transactions */
76
+ export declare type ConfirmedTransaction = Transaction;
65
77
  export interface Addresses {
66
78
  unifiedAddress: string;
67
79
  saplingAddress: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-zcash",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Zcash library for React Native",
5
5
  "homepage": "https://github.com/EdgeApp/react-native-zcash",
6
6
  "repository": {
@@ -45,6 +45,7 @@
45
45
  "*.{js,ts}": "eslint"
46
46
  },
47
47
  "dependencies": {
48
+ "biggystring": "^4.1.3",
48
49
  "rfc4648": "^1.3.0"
49
50
  },
50
51
  "devDependencies": {
@@ -1,3 +1,4 @@
1
+ import { add } from 'biggystring'
1
2
  import {
2
3
  EventSubscription,
3
4
  NativeEventEmitter,
@@ -8,12 +9,15 @@ import {
8
9
  Addresses,
9
10
  InitializerConfig,
10
11
  Network,
12
+ ShieldFundsInfo,
11
13
  SpendFailure,
12
14
  SpendInfo,
13
15
  SpendSuccess,
14
16
  SynchronizerCallbacks,
17
+ Transaction,
15
18
  UnifiedViewingKey
16
19
  } from './types'
20
+ export * from './types'
17
21
 
18
22
  const { RNZcash } = NativeModules
19
23
 
@@ -53,7 +57,7 @@ export class Synchronizer {
53
57
  this.network = network
54
58
  }
55
59
 
56
- async stop(): Promise<String> {
60
+ async stop(): Promise<string> {
57
61
  this.unsubscribe()
58
62
  const result = await RNZcash.stop(this.alias)
59
63
  return result
@@ -81,8 +85,8 @@ export class Synchronizer {
81
85
  return result
82
86
  }
83
87
 
84
- rescan(): void {
85
- RNZcash.rescan(this.alias)
88
+ async rescan(): Promise<void> {
89
+ await RNZcash.rescan(this.alias)
86
90
  }
87
91
 
88
92
  async sendToAddress(
@@ -98,6 +102,16 @@ export class Synchronizer {
98
102
  return result
99
103
  }
100
104
 
105
+ async shieldFunds(shieldFundsInfo: ShieldFundsInfo): Promise<Transaction> {
106
+ const result = await RNZcash.shieldFunds(
107
+ this.alias,
108
+ shieldFundsInfo.seed,
109
+ shieldFundsInfo.memo,
110
+ shieldFundsInfo.threshold
111
+ )
112
+ return result
113
+ }
114
+
101
115
  // Events
102
116
 
103
117
  subscribe({
@@ -106,7 +120,21 @@ export class Synchronizer {
106
120
  onTransactionsChanged,
107
121
  onUpdate
108
122
  }: SynchronizerCallbacks): void {
109
- this.setListener('BalanceEvent', onBalanceChanged)
123
+ this.setListener('BalanceEvent', event => {
124
+ const {
125
+ transparentAvailableZatoshi,
126
+ transparentTotalZatoshi,
127
+ saplingAvailableZatoshi,
128
+ saplingTotalZatoshi
129
+ } = event
130
+
131
+ event.availableZatoshi = add(
132
+ transparentAvailableZatoshi,
133
+ saplingAvailableZatoshi
134
+ )
135
+ event.totalZatoshi = add(transparentTotalZatoshi, saplingTotalZatoshi)
136
+ onBalanceChanged(event)
137
+ })
110
138
  this.setListener('StatusEvent', onStatusChanged)
111
139
  this.setListener('TransactionEvent', onTransactionsChanged)
112
140
  this.setListener('UpdateEvent', onUpdate)
package/src/types.ts CHANGED
@@ -17,6 +17,12 @@ export interface SpendInfo {
17
17
  mnemonicSeed: string
18
18
  }
19
19
 
20
+ export interface ShieldFundsInfo {
21
+ seed: string
22
+ memo: string
23
+ threshold: string
24
+ }
25
+
20
26
  export interface SpendSuccess {
21
27
  txId: string
22
28
  raw: string
@@ -33,6 +39,12 @@ export interface UnifiedViewingKey {
33
39
  }
34
40
 
35
41
  export interface BalanceEvent {
42
+ transparentAvailableZatoshi: string
43
+ transparentTotalZatoshi: string
44
+ saplingAvailableZatoshi: string
45
+ saplingTotalZatoshi: string
46
+
47
+ /** @deprecated */
36
48
  availableZatoshi: string
37
49
  totalZatoshi: string
38
50
  }
@@ -47,7 +59,7 @@ export interface StatusEvent {
47
59
  }
48
60
 
49
61
  export interface TransactionEvent {
50
- transactions: ConfirmedTransaction[]
62
+ transactions: Transaction[]
51
63
  }
52
64
 
53
65
  export interface UpdateEvent {
@@ -68,7 +80,7 @@ export interface BlockRange {
68
80
  last: number
69
81
  }
70
82
 
71
- export interface ConfirmedTransaction {
83
+ export interface Transaction {
72
84
  rawTransactionId: string
73
85
  raw?: string
74
86
  blockTimeInSeconds: number
@@ -79,6 +91,9 @@ export interface ConfirmedTransaction {
79
91
  memos: string[]
80
92
  }
81
93
 
94
+ /** @deprecated Renamed `Transaction` because the package can now return unconfirmed shielding transactions */
95
+ export type ConfirmedTransaction = Transaction
96
+
82
97
  export interface Addresses {
83
98
  unifiedAddress: string
84
99
  saplingAddress: string