UNPKG

haven-core-js

Version:

The JS library containing the Haven crypto plus lightweight wallet functions

397 lines (375 loc) 12.3 kB
// Copyright (c) 2014-2019, 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_amount_format_utils = require("../monero_utils/monero_amount_format_utils"); 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, coreBridge_instance, ) { // -> returnValuesByKey let total_received = {}; data.total_received && Object.keys(data.total_received). forEach( key => total_received[key] = new JSBigInt(data.total_received[key])) let total_received_unlocked = {}; data.total_received_unlocked && Object.keys(data.total_received_unlocked). forEach( key => total_received_unlocked[key] = new JSBigInt(data.total_received_unlocked[key])) const locked_balance = new JSBigInt(data.locked_funds || 0); let total_sent = {} data.total_sent && Object.keys(data.total_sent). forEach( key => total_sent[key] = new JSBigInt(data.total_sent[key])) // 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 || []; // /* * loop through all possible spent outputs to calc the right total sent amount */ 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, coreBridge_instance, ); /* * if its nout our output just subtract from total sent calced by backend ( which doesn't hold the private key ) */ if (spent_output.key_image !== key_image) { // console.log('💬 Output used as mixin (' + spent_output.key_image + '/' + key_image + ')') total_sent[spent_output.asset_type] = new JSBigInt(total_sent[spent_output.asset_type]).subtract(spent_output.amount); } } // const ratesBySymbol = data.rates || {}; // jic it's not there // // serialize JSBigInt let total_received_String = {}; Object.keys(total_received).forEach(assetType => { total_received_String[assetType] = total_received[assetType].toString(); }) // serialize JSBigInt let total_received_unlocked_String = {}; Object.keys(total_received_unlocked).forEach(assetType => { total_received_unlocked_String[assetType] = total_received_unlocked[assetType].toString(); }) // serialize JSBigInt let total_sent_String = {}; Object.keys(total_sent).forEach(assetType => { total_sent_String[assetType] = total_sent[assetType].toString(); }) const returnValuesByKey = { total_received_String, total_received_unlocked_String, total_sent_String, 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, coreBridge_instance, ) { // -> 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, coreBridge_instance, ); } function Parsed_AddressInfo( keyImage_cache, data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, fn, // (err?, returnValuesByKey) -> Void ) { const returnValuesByKey = Parsed_AddressInfo__sync( keyImage_cache, data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, ); fn(null, returnValuesByKey); } function Parsed_AddressInfo__keyImageManaged( data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, fn, ) { // -> returnValuesByKey Parsed_AddressInfo( monero_keyImage_cache_utils.Lazy_KeyImageCacheForWalletWith(address), data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, 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, coreBridge_instance, fn, // (err?, returnValuesByKey) -> Void ) { const returnValuesByKey = Parsed_AddressTransactions__sync( keyImage_cache, data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, ); fn(null, returnValuesByKey); } function Parsed_AddressTransactions__sync( keyImage_cache, data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, ) { 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) { const transaction = transactions[i]; const fromAsset = transaction.from_asset_type; const toAsset = transaction.to_asset_type; if ((transaction.spent_outputs || []).length > 0) { for (var j = 0; j < transaction.spent_outputs.length; ++j) { var key_image = monero_keyImage_cache_utils.Lazy_KeyImage( keyImage_cache, transaction.spent_outputs[j].tx_pub_key, transaction.spent_outputs[j].out_index, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, ); if (transaction.spent_outputs[j].key_image !== key_image) { /* * output was only used as mixin */ // console.log('Output used as mixin, ignoring (' + transactions[i].spent_outputs[j].key_image + '/' + key_image + ')') transaction.total_sent[fromAsset] = new JSBigInt( transaction.total_sent[fromAsset], ) .subtract(transaction.spent_outputs[j].amount) .toString(); transaction.spent_outputs.splice(j, 1); j--; } } } /* * if we didn't transfer any at all, delete tx and continue with next tx * ( do it only for regular txs and not for exchange txs ) */ if(fromAsset === toAsset) { if ( new JSBigInt(transaction.total_received[toAsset] || 0) .add(transaction.total_sent[fromAsset] || 0) .compare(0) <= 0 ) { transactions.splice(i, 1); i--; continue; } } /** * regardless whetver its a normal tx or not we set a fromAmount and toAmount */ transaction.fromAmount = new JSBigInt( transaction.total_received[fromAsset] || 0, ) .subtract(transaction.total_sent[fromAsset] || 0) .toString(); transaction.toAmount = new JSBigInt( transaction.total_received[toAsset] || 0, ) .subtract(transaction.total_sent[toAsset] || 0) .toString(); transaction.approx_float_amount = parseFloat( monero_amount_format_utils.formatMoney(transaction.fromAmount), ); transaction.timestamp = transaction.timestamp; const record__payment_id = transaction.payment_id; if (typeof record__payment_id !== "undefined" && record__payment_id) { if (record__payment_id.length == 16) { // short (encrypted) pid if (transaction.approx_float_amount < 0) { // outgoing delete transaction["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.fromAmount = transaction.fromAmount.toString(); // JSBigInt -> String transaction.toAmount = transaction.toAmount.toString(); // JSBigInt -> String Object.keys(transaction.total_sent).forEach(assetType => { transaction.total_sent[assetType] = transaction.total_sent[assetType].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, coreBridge_instance, ) { 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, coreBridge_instance, ); } function Parsed_AddressTransactions__keyImageManaged( data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, fn, ) { Parsed_AddressTransactions( monero_keyImage_cache_utils.Lazy_KeyImageCacheForWalletWith(address), data, address, view_key__private, spend_key__public, spend_key__private, coreBridge_instance, 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;