@@ -11,16 +11,12 @@ import {
1111 InsufficientFundsError ,
1212 NoAmountSpecifiedError
1313} from 'edge-core-js/types'
14- import type {
15- ConfirmedTransaction ,
16- SpendInfo ,
17- StatusEvent
18- } from 'react-native-piratechain'
14+ import type { PirateTransaction } from 'react-native-pirate-wallet'
1915import { base16 , base64 } from 'rfc4648'
2016
2117import { CurrencyEngine } from '../common/CurrencyEngine'
2218import { PluginEnvironment } from '../common/innerPlugin'
23- import { cleanTxLogs } from '../common/utils'
19+ import { cleanTxLogs , safeParseInt } from '../common/utils'
2420import type { PiratechainIo , PiratechainSynchronizer } from './piratechainIo'
2521import {
2622 makePiratechainSyncTracker ,
@@ -44,9 +40,8 @@ export class PiratechainEngine extends CurrencyEngine<
4440 pluginId : string
4541 networkInfo : PiratechainNetworkInfo
4642 otherData ! : PiratechainWalletOtherData
47- synchronizerStatus ! : StatusEvent [ 'name' ]
43+ synchronizerStatus ! : 'STOPPED' | 'SYNCING' | 'SYNCED'
4844 availableZatoshi ! : string
49- initialNumBlocksToDownload ! : number
5045 birthdayHeight : number
5146 queryMutex : boolean
5247 makeSynchronizer : PiratechainIo [ 'makeSynchronizer' ]
@@ -57,7 +52,6 @@ export class PiratechainEngine extends CurrencyEngine<
5752 synchronizer ?: PiratechainSynchronizer
5853 synchronizerPromise : Promise < PiratechainSynchronizer >
5954 synchronizerResolver ! : ( synchronizer : PiratechainSynchronizer ) => void
60- lastUpdateFromSynchronizer ?: number
6155
6256 constructor (
6357 env : PluginEnvironment < PiratechainNetworkInfo > ,
@@ -85,17 +79,8 @@ export class PiratechainEngine extends CurrencyEngine<
8579 }
8680
8781 initData ( ) : void {
88- // walletLocalData
89- if ( this . otherData . blockRange . first === 0 ) {
90- this . otherData . blockRange = {
91- first : this . birthdayHeight ,
92- last : this . birthdayHeight
93- }
94- }
95-
9682 // Engine variables
97- this . initialNumBlocksToDownload = - 1
98- this . synchronizerStatus = 'DISCONNECTED'
83+ this . synchronizerStatus = 'STOPPED'
9984 this . availableZatoshi = '0'
10085 }
10186
@@ -115,18 +100,13 @@ export class PiratechainEngine extends CurrencyEngine<
115100 this . synchronizerStatus = payload . name
116101 await this . queryAll ( )
117102 } )
118- this . synchronizer . on ( 'error' , async payload => {
103+ this . synchronizer . on ( 'error' , payload => {
104+ // The polling synchronizer retries transient errors on its own:
119105 this . log . warn ( `Synchronizer error: ${ payload . message } ` )
120- if ( payload . level === 'critical' ) {
121- await this . killEngine ( )
122- this . lastUpdateFromSynchronizer = undefined
123- await this . startEngine ( )
124- }
125106 } )
126107 }
127108
128109 async queryAll ( ) : Promise < void > {
129- this . lastUpdateFromSynchronizer = Date . now ( )
130110 if ( this . queryMutex ) return
131111 this . queryMutex = true
132112 try {
@@ -150,10 +130,10 @@ export class PiratechainEngine extends CurrencyEngine<
150130 async queryBalance ( ) : Promise < void > {
151131 if ( ! this . isSynced ( ) || this . synchronizer == null ) return
152132 try {
153- const balances = await this . synchronizer . getBalance ( )
154- if ( balances . totalZatoshi === '-1' ) return
155- this . availableZatoshi = balances . availableZatoshi
156- this . updateBalance ( null , balances . totalZatoshi )
133+ const balance = await this . synchronizer . getBalance ( )
134+ // `total` includes pending; `spendable` is the confirmed balance:
135+ this . availableZatoshi = String ( balance . spendable )
136+ this . updateBalance ( null , String ( balance . total ) )
157137 this . syncTracker . updateBalanceRatio ( 1 )
158138 } catch ( e : any ) {
159139 this . warn ( 'Failed to update balances' , e )
@@ -164,42 +144,10 @@ export class PiratechainEngine extends CurrencyEngine<
164144 async queryTransactions ( ) : Promise < void > {
165145 if ( this . synchronizer == null ) return
166146 try {
167- let first = this . otherData . blockRange . first
168- let last = this . otherData . blockRange . last
169- const blocksToHeight =
170- this . walletLocalData . blockHeight - this . birthdayHeight
171- while ( this . isSynced ( ) && last <= this . walletLocalData . blockHeight ) {
172- const transactions = await this . synchronizer . getTransactions ( {
173- first,
174- last
175- } )
176-
177- for ( const tx of transactions ) this . processTransaction ( tx )
178-
179- if ( last === this . walletLocalData . blockHeight ) {
180- first = this . walletLocalData . blockHeight
181- this . walletLocalDataDirty = true
182- this . syncTracker . updateTransactionRatio ( 1 )
183- break
184- }
185-
186- first = last + 1
187- last =
188- last + this . networkInfo . transactionQueryLimit <
189- this . walletLocalData . blockHeight
190- ? last + this . networkInfo . transactionQueryLimit
191- : this . walletLocalData . blockHeight
192-
193- this . otherData . blockRange = {
194- first,
195- last
196- }
197- this . walletLocalDataDirty = true
198-
199- if ( blocksToHeight > 0 ) {
200- const historyRatio = ( last - this . birthdayHeight ) / blocksToHeight
201- this . syncTracker . updateTransactionRatio ( historyRatio )
202- }
147+ const transactions = await this . synchronizer . getTransactions ( )
148+ for ( const tx of transactions ) this . processTransaction ( tx )
149+ if ( this . isSynced ( ) ) {
150+ this . syncTracker . updateTransactionRatio ( 1 )
203151 }
204152 } catch ( e : any ) {
205153 this . error (
@@ -209,41 +157,39 @@ export class PiratechainEngine extends CurrencyEngine<
209157 }
210158 }
211159
212- processTransaction ( tx : ConfirmedTransaction ) : void {
213- let netNativeAmount = tx . value
160+ processTransaction ( tx : PirateTransaction ) : void {
161+ // A negative amount is a send and already includes the network fee:
162+ const netNativeAmount = String ( tx . amount )
214163 const ourReceiveAddresses = [ ]
215- if ( tx . toAddress != null ) {
216- // check if tx is a spend
217- netNativeAmount = `-${ add (
218- netNativeAmount ,
219- this . networkInfo . defaultNetworkFee
220- ) } `
221- } else {
164+ if ( tx . amount >= 0 ) {
222165 ourReceiveAddresses . push ( this . walletInfo . keys . publicKey )
223166 }
224167
225- const edgeMemos : EdgeMemo [ ] = tx . memos
226- . filter ( text => text !== '' )
227- . map ( text => ( {
228- memoName : 'memo' ,
229- type : 'text' ,
230- value : text
231- } ) )
168+ const edgeMemos : EdgeMemo [ ] =
169+ tx . memo != null && tx . memo !== ''
170+ ? [
171+ {
172+ memoName : 'memo' ,
173+ type : 'text' ,
174+ value : tx . memo
175+ }
176+ ]
177+ : [ ]
232178
233179 const edgeTransaction : EdgeTransaction = {
234- blockHeight : tx . minedHeight ,
180+ blockHeight : tx . height ?? 0 ,
235181 currencyCode : this . currencyInfo . currencyCode ,
236- date : tx . blockTimeInSeconds ,
182+ date : tx . timestamp ,
237183 isSend : netNativeAmount . startsWith ( '-' ) ,
238184 memos : edgeMemos ,
239185 nativeAmount : netNativeAmount ,
240- networkFee : this . networkInfo . defaultNetworkFee ,
186+ networkFee : String ( tx . fee ) ,
241187 networkFees : [ ] ,
242188 otherParams : { } ,
243189 ourReceiveAddresses, // blank if you sent money otherwise array of addresses that are yours in this transaction
244190 signedTx : '' ,
245191 tokenId : null ,
246- txid : tx . rawTransactionId ,
192+ txid : tx . txId ,
247193 walletId : this . walletId
248194 }
249195 this . addTransaction ( null , edgeTransaction )
@@ -256,26 +202,21 @@ export class PiratechainEngine extends CurrencyEngine<
256202 this . currencyInfo . pluginId
257203 ) ( opts ?. privateKeys )
258204
259- const { rpcNode } = this . networkInfo
260205 this . birthdayHeight = piratechainPrivateKeys . birthdayHeight
261206
262207 try {
263208 // Replace this.synchronizerPromise with a fresh promise. The old promise might have already been resolved
264209 this . synchronizerPromise = this . makeSynchronizer ( {
265- mnemonicSeed : piratechainPrivateKeys . mnemonic ,
266- birthdayHeight : piratechainPrivateKeys . birthdayHeight ,
267- alias : base16 . stringify ( base64 . parse ( this . walletId ) ) ,
268- ...rpcNode
210+ name : base16 . stringify ( base64 . parse ( this . walletId ) ) ,
211+ mnemonic : piratechainPrivateKeys . mnemonic ,
212+ birthdayHeight : piratechainPrivateKeys . birthdayHeight
269213 } )
270214 this . synchronizer = await this . synchronizerPromise
271215 // People might be waiting on the old promise, so resolve that
272216 this . synchronizerResolver ( this . synchronizer )
273217 } catch ( e ) {
274- // The synchronizer cannot start if it isn't present.
275- if (
276- String ( e ) ===
277- 'Invariant Violation: `new NativeEventEmitter()` requires a non-null argument.'
278- ) {
218+ // The synchronizer cannot start if the native module isn't present:
219+ if ( String ( e ) . includes ( 'native module is not linked' ) ) {
279220 this . log . warn ( 'SDK not present' )
280221 } else throw e
281222 }
@@ -309,8 +250,10 @@ export class PiratechainEngine extends CurrencyEngine<
309250 await super . killEngine ( )
310251 await this . clearBlockchainCache ( )
311252 await this . startEngine ( )
312- this . synchronizer
313- ?. rescan ( )
253+ this . synchronizerPromise
254+ . then ( async synchronizer => {
255+ await synchronizer . rescan ( this . birthdayHeight )
256+ } )
314257 . catch ( ( e : any ) => this . warn ( 'resyncBlockchain failed: ' , e ) )
315258 this . initData ( )
316259 this . syncTracker . resetSync ( )
@@ -381,42 +324,42 @@ export class PiratechainEngine extends CurrencyEngine<
381324 }
382325
383326 async broadcastTx (
384- edgeTransaction : EdgeTransaction ,
385- opts ?: EdgeEnginePrivateKeyOptions
327+ edgeTransaction : EdgeTransaction
386328 ) : Promise < EdgeTransaction > {
387329 const { memos } = edgeTransaction
388- const piratechainPrivateKeys = asPiratechainPrivateKeys ( this . pluginId ) (
389- opts ?. privateKeys
390- )
391330 if (
392331 edgeTransaction . spendTargets == null ||
393332 edgeTransaction . spendTargets . length !== 1
394333 )
395334 throw new Error ( 'Invalid spend targets' )
396335
397- const memo = memos [ 0 ] ?. type === 'text' ? memos [ 0 ] . value : ''
398336 const spendTarget = edgeTransaction . spendTargets [ 0 ]
399- const txParams : SpendInfo = {
400- zatoshi : sub (
401- abs ( edgeTransaction . nativeAmount ) ,
402- edgeTransaction . networkFee
403- ) ,
404- toAddress : spendTarget . publicAddress ,
405- memo,
406- mnemonicSeed : piratechainPrivateKeys . mnemonic
407- }
337+ if ( spendTarget . publicAddress == null )
338+ throw new Error ( 'Missing publicAddress' )
339+
340+ // The registry wallet holds the spending keys, so the send call
341+ // only needs the outputs. Edge's nativeAmount includes the fee:
342+ const memo = memos [ 0 ] ?. type === 'text' ? memos [ 0 ] . value : undefined
343+ const spendAmount = sub (
344+ abs ( edgeTransaction . nativeAmount ) ,
345+ edgeTransaction . networkFee
346+ )
408347
409348 try {
410349 const synchronizer = await this . synchronizerPromise
411- const signedTx = await synchronizer . sendToAddress ( txParams )
412- if ( 'txId' in signedTx ) {
413- edgeTransaction . txid = signedTx . txId
414- edgeTransaction . signedTx = signedTx . raw
415- edgeTransaction . date = Date . now ( ) / 1000
416- this . warn ( `SUCCESS broadcastTx\n${ cleanTxLogs ( edgeTransaction ) } ` )
417- } else {
418- throw new Error ( signedTx . errorMessage )
419- }
350+ const txid = await synchronizer . send (
351+ [
352+ {
353+ addr : spendTarget . publicAddress ,
354+ amount : safeParseInt ( spendAmount ) ,
355+ memo
356+ }
357+ ] ,
358+ safeParseInt ( edgeTransaction . networkFee )
359+ )
360+ edgeTransaction . txid = txid
361+ edgeTransaction . date = Date . now ( ) / 1000
362+ this . warn ( `SUCCESS broadcastTx\n${ cleanTxLogs ( edgeTransaction ) } ` )
420363 } catch ( e : any ) {
421364 this . warn ( 'FAILURE broadcastTx failed: ' , e )
422365 throw e
@@ -427,11 +370,11 @@ export class PiratechainEngine extends CurrencyEngine<
427370 async getFreshAddress ( ) : Promise < EdgeFreshAddress > {
428371 const getSynchronizerAddresses = async ( ) : Promise < EdgeFreshAddress > => {
429372 const synchronizer = await this . synchronizerPromise
430- const { saplingAddress } = await synchronizer . deriveUnifiedAddress ( )
431- this . otherData . cachedAddress = saplingAddress
373+ const publicAddress = await synchronizer . getCurrentAddress ( )
374+ this . otherData . cachedAddress = publicAddress
432375 this . walletLocalDataDirty = true
433376 return {
434- publicAddress : saplingAddress
377+ publicAddress
435378 }
436379 }
437380
0 commit comments