// Copyright (c) 2014-2018, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
"use strict" ;
//
const JSBigInt = require ( "../cryptonote_utils/biginteger" ) . BigInteger ;
const monero _utils = require ( "../monero_utils/monero_cryptonote_utils_instance" ) ;
const monero _keyImage _cache _utils = require ( "../monero_utils/monero_keyImage_cache_utils" ) ;
//
function Parsed _AddressInfo _ _sync (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) {
// -> returnValuesByKey
const total _received = new JSBigInt ( data . total _received || 0 ) ;
const locked _balance = new JSBigInt ( data . locked _funds || 0 ) ;
var total _sent = new JSBigInt ( data . total _sent || 0 ) ; // will be modified in place
//
const account _scanned _tx _height = data . scanned _height || 0 ;
const account _scanned _block _height = data . scanned _block _height || 0 ;
const account _scan _start _height = data . start _height || 0 ;
const transaction _height = data . transaction _height || 0 ;
const blockchain _height = data . blockchain _height || 0 ;
const spent _outputs = data . spent _outputs || [ ] ;
//
for ( let spent _output of spent _outputs ) {
var key _image = monero _keyImage _cache _utils . Lazy _KeyImage (
keyImage _cache ,
spent _output . tx _pub _key ,
spent _output . out _index ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
if ( spent _output . key _image !== key _image ) {
// console.log('💬 Output used as mixin (' + spent_output.key_image + '/' + key_image + ')')
total _sent = new JSBigInt ( total _sent ) . subtract ( spent _output . amount ) ;
}
}
//
const ratesBySymbol = data . rates || { } ; // jic it's not there
//
const returnValuesByKey = {
total _received _String : total _received
? total _received . toString ( )
: null ,
locked _balance _String : locked _balance
? locked _balance . toString ( )
: null ,
total _sent _String : total _sent ? total _sent . toString ( ) : null ,
// ^serialized JSBigInt
spent _outputs : spent _outputs ,
account _scanned _tx _height : account _scanned _tx _height ,
account _scanned _block _height : account _scanned _block _height ,
account _scan _start _height : account _scan _start _height ,
transaction _height : transaction _height ,
blockchain _height : blockchain _height ,
//
ratesBySymbol : ratesBySymbol ,
} ;
return returnValuesByKey ;
}
function Parsed _AddressInfo _ _sync _ _keyImageManaged (
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) {
// -> returnValuesByKey
const keyImageCache = monero _keyImage _cache _utils . Lazy _KeyImageCacheForWalletWith (
address ,
) ;
return Parsed _AddressInfo _ _sync (
keyImageCache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
}
function Parsed _AddressInfo (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn , // (err?, returnValuesByKey) -> Void
) {
const returnValuesByKey = Parsed _AddressInfo _ _sync (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
fn ( null , returnValuesByKey ) ;
}
function Parsed _AddressInfo _ _keyImageManaged (
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn ,
) {
// -> returnValuesByKey
Parsed _AddressInfo (
monero _keyImage _cache _utils . Lazy _KeyImageCacheForWalletWith ( address ) ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn ,
) ;
}
exports . Parsed _AddressInfo = Parsed _AddressInfo ;
exports . Parsed _AddressInfo _ _keyImageManaged = Parsed _AddressInfo _ _keyImageManaged ; // in case you can't send a mutable key image cache dictionary
exports . Parsed _AddressInfo _ _sync _ _keyImageManaged = Parsed _AddressInfo _ _sync _ _keyImageManaged ; // in case you can't send a mutable key image cache dictionary
exports . Parsed _AddressInfo _ _sync = Parsed _AddressInfo _ _sync ;
//
function Parsed _AddressTransactions (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn , // (err?, returnValuesByKey) -> Void
) {
const returnValuesByKey = Parsed _AddressTransactions _ _sync (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
fn ( null , returnValuesByKey ) ;
}
function Parsed _AddressTransactions _ _sync (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) {
const account _scanned _height = data . scanned _height || 0 ;
const account _scanned _block _height = data . scanned _block _height || 0 ;
const account _scan _start _height = data . start _height || 0 ;
const transaction _height = data . transaction _height || 0 ;
const blockchain _height = data . blockchain _height || 0 ;
//
const transactions = data . transactions || [ ] ;
//
// TODO: rewrite this with more clarity if possible
for ( let i = 0 ; i < transactions . length ; ++ i ) {
if ( ( transactions [ i ] . spent _outputs || [ ] ) . length > 0 ) {
for ( var j = 0 ; j < transactions [ i ] . spent _outputs . length ; ++ j ) {
var key _image = monero _keyImage _cache _utils . Lazy _KeyImage (
keyImage _cache ,
transactions [ i ] . spent _outputs [ j ] . tx _pub _key ,
transactions [ i ] . spent _outputs [ j ] . out _index ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
if ( transactions [ i ] . spent _outputs [ j ] . key _image !== key _image ) {
// console.log('Output used as mixin, ignoring (' + transactions[i].spent_outputs[j].key_image + '/' + key_image + ')')
transactions [ i ] . total _sent = new JSBigInt (
transactions [ i ] . total _sent ,
)
. subtract ( transactions [ i ] . spent _outputs [ j ] . amount )
. toString ( ) ;
transactions [ i ] . spent _outputs . splice ( j , 1 ) ;
j -- ;
}
}
}
if (
new JSBigInt ( transactions [ i ] . total _received || 0 )
. add ( transactions [ i ] . total _sent || 0 )
. compare ( 0 ) <= 0
) {
transactions . splice ( i , 1 ) ;
i -- ;
continue ;
}
transactions [ i ] . amount = new JSBigInt (
transactions [ i ] . total _received || 0 ,
)
. subtract ( transactions [ i ] . total _sent || 0 )
. toString ( ) ;
transactions [ i ] . approx _float _amount = parseFloat (
monero _utils . formatMoney ( transactions [ i ] . amount ) ,
) ;
transactions [ i ] . timestamp = transactions [ i ] . timestamp ;
const record _ _payment _id = transactions [ i ] . payment _id ;
if ( typeof record _ _payment _id !== "undefined" && record _ _payment _id ) {
if ( record _ _payment _id . length == 16 ) {
// short (encrypted) pid
if ( transactions [ i ] . approx _float _amount < 0 ) {
// outgoing
delete transactions [ i ] [ "payment_id" ] ; // need to filter these out .. because the server can't filter out short (encrypted) pids on outgoing txs
}
}
}
}
transactions . sort ( function ( a , b ) {
if ( a . mempool == true ) {
if ( b . mempool != true ) {
return - 1 ; // a first
}
// both mempool - fall back to .id compare
} else if ( b . mempool == true ) {
return 1 ; // b first
}
return b . id - a . id ;
} ) ;
// prepare transactions to be serialized
for ( let transaction of transactions ) {
transaction . amount = transaction . amount . toString ( ) ; // JSBigInt -> String
if (
typeof transaction . total _sent !== "undefined" &&
transaction . total _sent !== null
) {
transaction . total _sent = transaction . total _sent . toString ( ) ;
}
}
// on the other side, we convert transactions timestamp to Date obj
const returnValuesByKey = {
account _scanned _height : account _scanned _height ,
account _scanned _block _height : account _scanned _block _height ,
account _scan _start _height : account _scan _start _height ,
transaction _height : transaction _height ,
blockchain _height : blockchain _height ,
serialized _transactions : transactions ,
} ;
return returnValuesByKey ;
}
function Parsed _AddressTransactions _ _sync _ _keyImageManaged (
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) {
const keyImageCache = monero _keyImage _cache _utils . Lazy _KeyImageCacheForWalletWith (
address ,
) ;
return Parsed _AddressTransactions _ _sync (
keyImageCache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
}
function Parsed _AddressTransactions _ _keyImageManaged (
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn ,
) {
Parsed _AddressTransactions (
monero _keyImage _cache _utils . Lazy _KeyImageCacheForWalletWith ( address ) ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn ,
) ;
}
exports . Parsed _AddressTransactions = Parsed _AddressTransactions ;
exports . Parsed _AddressTransactions _ _keyImageManaged = Parsed _AddressTransactions _ _keyImageManaged ;
exports . Parsed _AddressTransactions _ _sync = Parsed _AddressTransactions _ _sync ;
exports . Parsed _AddressTransactions _ _sync _ _keyImageManaged = Parsed _AddressTransactions _ _sync _ _keyImageManaged ;
//
function Parsed _UnspentOuts (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn , // (err?, returnValuesByKey)
) {
const returnValuesByKey = Parsed _UnspentOuts _ _sync (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
fn ( null , returnValuesByKey ) ;
}
function Parsed _UnspentOuts _ _sync (
keyImage _cache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) {
const data _outputs = data . outputs ;
const finalized _unspentOutputs = data . outputs || [ ] ; // to finalize:
for ( var i = 0 ; i < finalized _unspentOutputs . length ; i ++ ) {
const unspent _output = finalized _unspentOutputs [ i ] ;
if (
unspent _output === null ||
typeof unspent _output === "undefined" ||
! unspent _output // just preserving what was in the original code
) {
throw "unspent_output at index " + i + " was null" ;
}
const spend _key _images = unspent _output . spend _key _images ;
if (
spend _key _images === null ||
typeof spend _key _images === "undefined"
) {
throw "spend_key_images of unspent_output at index " +
i +
" was null" ;
}
for ( var j = 0 ; j < spend _key _images . length ; j ++ ) {
const finalized _unspentOutput _atI _beforeSplice =
finalized _unspentOutputs [ i ] ;
if (
! finalized _unspentOutput _atI _beforeSplice ||
typeof finalized _unspentOutput _atI _beforeSplice === "undefined"
) {
console . warn (
` This unspent output at i ${ i } was literally undefined! Skipping. ` ,
) ; // NOTE: Looks like the i-- code below should exit earlier if this is necessary
continue ;
}
const beforeSplice _ _tx _pub _key =
finalized _unspentOutput _atI _beforeSplice . tx _pub _key ;
const beforeSplice _ _index =
finalized _unspentOutput _atI _beforeSplice . index ;
if (
typeof beforeSplice _ _tx _pub _key === "undefined" ||
! beforeSplice _ _tx _pub _key
) {
console . warn (
"This unspent out was missing a tx_pub_key! Skipping." ,
finalized _unspentOutput _atI _beforeSplice ,
) ;
continue ;
}
var key _image = monero _keyImage _cache _utils . Lazy _KeyImage (
keyImage _cache ,
beforeSplice _ _tx _pub _key ,
beforeSplice _ _index ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
if (
key _image ===
finalized _unspentOutput _atI _beforeSplice . spend _key _images [ j ]
) {
// console.log("💬 Output was spent; key image: " + key_image + " amount: " + monero_utils.formatMoneyFull(finalized_unspentOutputs[i].amount));
// Remove output from list
finalized _unspentOutputs . splice ( i , 1 ) ;
const finalized _unspentOutput _atI _afterSplice =
finalized _unspentOutputs [ i ] ;
if ( finalized _unspentOutput _atI _afterSplice ) {
j =
finalized _unspentOutput _atI _afterSplice . spend _key _images
. length ;
}
i -- ;
} else {
console . log (
"💬 Output used as mixin (" +
key _image +
"/" +
finalized _unspentOutputs [ i ] . spend _key _images [ j ] +
")" ,
) ;
}
}
}
console . log ( "Unspent outs: " + JSON . stringify ( finalized _unspentOutputs ) ) ;
const unusedOuts = finalized _unspentOutputs . slice ( 0 ) ;
const returnValuesByKey = {
unspentOutputs : finalized _unspentOutputs ,
unusedOuts : unusedOuts ,
per _kb _fee : data . per _kb _fee , // String
} ;
return returnValuesByKey ;
}
function Parsed _UnspentOuts _ _sync _ _keyImageManaged (
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) {
const keyImageCache = monero _keyImage _cache _utils . Lazy _KeyImageCacheForWalletWith (
address ,
) ;
return Parsed _UnspentOuts _ _sync (
keyImageCache ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
) ;
}
function Parsed _UnspentOuts _ _keyImageManaged (
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn ,
) {
Parsed _UnspentOuts (
monero _keyImage _cache _utils . Lazy _KeyImageCacheForWalletWith ( address ) ,
data ,
address ,
view _key _ _private ,
spend _key _ _public ,
spend _key _ _private ,
fn ,
) ;
}
exports . Parsed _UnspentOuts = Parsed _UnspentOuts ;
exports . Parsed _UnspentOuts _ _keyImageManaged = Parsed _UnspentOuts _ _keyImageManaged ;
exports . Parsed _UnspentOuts _ _sync = Parsed _UnspentOuts _ _sync ;
exports . Parsed _UnspentOuts _ _sync _ _keyImageManaged = Parsed _UnspentOuts _ _sync _ _keyImageManaged ;