updated MyMoneroCoreCpp.js build; cryptonote_utils: extracted destination formatting and money amount formatting to sendingFunds_utils and money_format_utils respectively, and added IPCsafe (string instead of JSBigInt params) create_transaction variant to support call from electron renderer procs etc, and added more complete load readiness waiting interface, and added locateFile impl for passing as emscripten Module template to locate wasm file in various environments; monero_cryptonote_utils_instance: detecting electron renderer and exposing via electron.remote call (will this cause issues with anyone's build systems trying to include electron\?); commenting logs

pull/41/head
Paul Shapiro 6 years ago
parent ad4d8024f8
commit 902a35253c

File diff suppressed because one or more lines are too long

@ -33,30 +33,96 @@
// v--- These should maybe be injected into a context and supplied to currencyConfig for future platforms
const JSBigInt = require("./biginteger").BigInteger;
const cnBase58 = require("./cryptonote_base58").cnBase58;
var _CNCrypto = undefined; // undefined -> cause 'early' calls to CNCrypto to throw exception
require("./MyMoneroCoreCpp")().then(function(Module)
{
_CNCrypto = Module;
});
function loaded_CNCrypto()
{ // CAUTION: calling this method blocks until _CNCrypto is loaded
while (typeof _CNCrypto === 'undefined' || !_CNCrypto) {
}
return _CNCrypto;
}
const mnemonic = require("./mnemonic");
const nacl = require("./nacl-fast-cn");
const sha3 = require("./sha3");
const nettype_utils = require("./nettype");
var cnUtil = function(currencyConfig) {
var cnUtil = function(currencyConfig)
{
const currency_amount_format_utils = require("../cryptonote_utils/money_format_utils")(currencyConfig)
//
this._CNCrypto = undefined; // undefined -> cause 'early' calls to CNCrypto to throw exception
const ENVIRONMENT_IS_WEB = typeof window==="object";
const ENVIRONMENT_IS_WORKER = typeof importScripts==="function";
const ENVIRONMENT_IS_NODE = typeof process==="object" && process.browser !== true && typeof require==="function" && ENVIRONMENT_IS_WORKER == false; // we want this to be true for Electron but not for a WebView
const ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
var _CNCrypto_template =
{
locateFile: function(filename, scriptDirectory)
{
if (currencyConfig["locateFile"]) {
return currencyConfig["locateFile"](filename, scriptDirectory)
}
var this_scriptDirectory = scriptDirectory
const lastChar = this_scriptDirectory.charAt(this_scriptDirectory.length - 1)
if (lastChar == "/") {
this_scriptDirectory = this_scriptDirectory.substring(0, this_scriptDirectory.length - 1) // remove trailing "/"
}
const scriptDirectory_pathComponents = this_scriptDirectory.split("/")
const lastPathComponent = scriptDirectory_pathComponents[scriptDirectory_pathComponents.length - 1]
var pathTo_cryptonoteUtilsDir; // add trailing slash to this
if (lastPathComponent == "cryptonote_utils") { // typical node or electron-main process
pathTo_cryptonoteUtilsDir = scriptDirectory_pathComponents.join("/") + "/"
} else if (ENVIRONMENT_IS_WEB) { // this will still match on electron-renderer, so the path must be patched up…
if (typeof __dirname !== undefined && __dirname !== "/") { // looks like node running in browser.. assuming Electron-renderer
// have to check != "/" b/c webpack (I think) replaces __dirname
pathTo_cryptonoteUtilsDir = "file://" + __dirname + "/" // prepending "file://" because it's going to try to stream it
} else { // actual web browser
pathTo_cryptonoteUtilsDir = this_scriptDirectory + "/mymonero_core_js/cryptonote_utils/" // this works for the MyMonero browser build, and is quite general, at least
}
} else {
throw "Undefined pathTo_cryptonoteUtilsDir. Please pass locateFile() to cryptonote_utils init."
}
const fullPath = pathTo_cryptonoteUtilsDir + filename
//
return fullPath
}
}
// if (ENVIRONMENT_IS_WEB && ENVIRONMENT_IS_NODE) { // that means it's probably electron-renderer
// const fs = require("fs");
// const path = require("path");
// const filepath = path.normalize(path.join(__dirname, "MyMoneroCoreCpp.wasm"));
// const wasmBinary = fs.readFileSync(filepath)
// console.log("wasmBinary", wasmBinary)
// _CNCrypto_template["wasmBinary"] = wasmBinary
// }
this._CNCrypto = undefined;
var loaded_CNCrypto = this.loaded_CNCrypto = function()
{ // CAUTION: calling this method blocks until _CNCrypto is loaded
if (typeof this._CNCrypto === 'undefined' || !this._CNCrypto) {
throw "You must call OnceModuleReady to wait for _CNCrypto to be ready"
}
return this._CNCrypto;
}
this.moduleReadyFns = [] // initial (gets set to undefined once Module ready)
this.OnceModuleReady = function(fn)
{
if (this._CNCrypto == null) {
if (typeof this.moduleReadyFns == 'undefined' || !this.moduleReadyFns) {
throw "Expected moduleReadyFns"
}
this.moduleReadyFns.push(fn)
} else {
fn(Module)
}
}
require("./MyMoneroCoreCpp")(_CNCrypto_template).then(function(thisModule)
{
this._CNCrypto = thisModule
{
for (let fn of this.moduleReadyFns) {
fn(thisModule)
}
}
this.moduleReadyFns = [] // flash/free
});
//
var config = {}; // shallow copy of initConfig
for (var key in currencyConfig) {
config[key] = currencyConfig[key];
}
config.coinUnits = new JSBigInt(10).pow(config.coinUnitPlaces);
var HASH_STATE_BYTES = 200;
var HASH_SIZE = 32;
var ADDRESS_CHECKSUM_SIZE = 4;
@ -2613,7 +2679,7 @@ var cnUtil = function(currencyConfig) {
//run the for loop twice to sort ins by key image
//first generate key image and other construction data to sort it all in one go
for (i = 0; i < sources.length; i++) {
console.log(i + ": " + this.formatMoneyFull(sources[i].amount));
console.log(i + ": " + currency_amount_format_utils.formatMoneyFull(sources[i].amount));
if (sources[i].real_out >= sources[i].outputs.length) {
throw "real index >= outputs.length";
}
@ -2718,11 +2784,11 @@ var cnUtil = function(currencyConfig) {
if (outputs_money.add(fee_amount).compare(inputs_money) > 0) {
throw "outputs money (" +
this.formatMoneyFull(outputs_money) +
currency_amount_format_utils.formatMoneyFull(outputs_money) +
") + fee (" +
this.formatMoneyFull(fee_amount) +
currency_amount_format_utils.formatMoneyFull(fee_amount) +
") > inputs money (" +
this.formatMoneyFull(inputs_money) +
currency_amount_format_utils.formatMoneyFull(inputs_money) +
")";
}
if (!rct) {
@ -2790,6 +2856,43 @@ var cnUtil = function(currencyConfig) {
return tx;
};
this.create_transaction__IPCsafe = function(
pub_keys,
sec_keys,
serialized__dsts, // amounts are strings
outputs,
mix_outs,
fake_outputs_count,
serialized__fee_amount, // string amount
payment_id,
pid_encrypt,
realDestViewKey,
unlock_time,
rct,
nettype,
) {
const dsts = serialized__dsts.map(function(i) {
i.amount = new JSBigInt(i.amount)
return i
})
console.log("deserialized DSTS is... ", dsts)
return this.create_transaction(
pub_keys,
sec_keys,
dsts,
outputs,
mix_outs,
fake_outputs_count,
new JSBigInt(serialized__fee_amount),
payment_id,
pid_encrypt,
realDestViewKey,
unlock_time,
rct,
nettype,
);
}
this.create_transaction = function(
pub_keys,
sec_keys,
@ -2944,9 +3047,9 @@ var cnUtil = function(currencyConfig) {
}
} else if (cmp > 0) {
throw "Need more money than found! (have: " +
cnUtil.formatMoney(found_money) +
currency_amount_format_utils.formatMoney(found_money) +
" need: " +
cnUtil.formatMoney(needed_money) +
currency_amount_format_utils.formatMoney(needed_money) +
")";
}
return this.construct_tx(
@ -2996,156 +3099,6 @@ var cnUtil = function(currencyConfig) {
return size;
};
function trimRight(str, char) {
while (str[str.length - 1] == char) str = str.slice(0, -1);
return str;
}
function padLeft(str, len, char) {
while (str.length < len) {
str = char + str;
}
return str;
}
this.padLeft = padLeft;
this.printDsts = function(dsts) {
for (var i = 0; i < dsts.length; i++) {
console.log(
dsts[i].address + ": " + this.formatMoneyFull(dsts[i].amount),
);
}
};
this.formatMoneyFull = function(units) {
units = units.toString();
var symbol = units[0] === "-" ? "-" : "";
if (symbol === "-") {
units = units.slice(1);
}
var decimal;
if (units.length >= config.coinUnitPlaces) {
decimal = units.substr(
units.length - config.coinUnitPlaces,
config.coinUnitPlaces,
);
} else {
decimal = padLeft(units, config.coinUnitPlaces, "0");
}
return (
symbol +
(units.substr(0, units.length - config.coinUnitPlaces) || "0") +
"." +
decimal
);
};
this.formatMoneyFullSymbol = function(units) {
return this.formatMoneyFull(units) + " " + config.coinSymbol;
};
this.formatMoney = function(units) {
var f = trimRight(this.formatMoneyFull(units), "0");
if (f[f.length - 1] === ".") {
return f.slice(0, f.length - 1);
}
return f;
};
this.formatMoneySymbol = function(units) {
return this.formatMoney(units) + " " + config.coinSymbol;
};
this.parseMoney = function(str) {
if (!str) return JSBigInt.ZERO;
var negative = str[0] === "-";
if (negative) {
str = str.slice(1);
}
var decimalIndex = str.indexOf(".");
if (decimalIndex == -1) {
if (negative) {
return JSBigInt.multiply(str, config.coinUnits).negate();
}
return JSBigInt.multiply(str, config.coinUnits);
}
if (decimalIndex + config.coinUnitPlaces + 1 < str.length) {
str = str.substr(0, decimalIndex + config.coinUnitPlaces + 1);
}
if (negative) {
return new JSBigInt(str.substr(0, decimalIndex))
.exp10(config.coinUnitPlaces)
.add(
new JSBigInt(str.substr(decimalIndex + 1)).exp10(
decimalIndex + config.coinUnitPlaces - str.length + 1,
),
).negate;
}
return new JSBigInt(str.substr(0, decimalIndex))
.exp10(config.coinUnitPlaces)
.add(
new JSBigInt(str.substr(decimalIndex + 1)).exp10(
decimalIndex + config.coinUnitPlaces - str.length + 1,
),
);
};
this.decompose_amount_into_digits = function(amount) {
/*if (dust_threshold === undefined) {
dust_threshold = config.dustThreshold;
}*/
amount = amount.toString();
var ret = [];
while (amount.length > 0) {
//split all the way down since v2 fork
/*var remaining = new JSBigInt(amount);
if (remaining.compare(config.dustThreshold) <= 0) {
if (remaining.compare(0) > 0) {
ret.push(remaining);
}
break;
}*/
//check so we don't create 0s
if (amount[0] !== "0") {
var digit = amount[0];
while (digit.length < amount.length) {
digit += "0";
}
ret.push(new JSBigInt(digit));
}
amount = amount.slice(1);
}
return ret;
};
this.decompose_tx_destinations = function(dsts, rct) {
var out = [];
if (rct) {
for (var i = 0; i < dsts.length; i++) {
out.push({
address: dsts[i].address,
amount: dsts[i].amount,
});
}
} else {
for (var i = 0; i < dsts.length; i++) {
var digits = this.decompose_amount_into_digits(dsts[i].amount);
for (var j = 0; j < digits.length; j++) {
if (digits[j].compare(0) > 0) {
out.push({
address: dsts[i].address,
amount: digits[j],
});
}
}
}
}
return out.sort(function(a, b) {
return a["amount"] - b["amount"];
});
};
this.is_tx_unlocked = function(unlock_time, blockchain_height) {
if (!config.maxBlockNumber) {
throw "Max block number is not set in config!";

@ -0,0 +1,123 @@
// 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.
//
const JSBigInt = require("./biginteger").BigInteger;
//
module.exports = function(currencyConfig)
{
// `currencyConfig` needs coinUnitPlaces, and coinSymbol
var config = {}; // shallow copy of initConfig
{
for (var key in currencyConfig) {
config[key] = currencyConfig[key];
}
config.coinUnits = new JSBigInt(10).pow(config.coinUnitPlaces);
}
this.formatMoneyFull = function(units) {
units = units.toString();
var symbol = units[0] === "-" ? "-" : "";
if (symbol === "-") {
units = units.slice(1);
}
var decimal;
if (units.length >= config.coinUnitPlaces) {
decimal = units.substr(
units.length - config.coinUnitPlaces,
config.coinUnitPlaces
);
} else {
decimal = padLeft(units, config.coinUnitPlaces, "0");
}
return (
symbol +
(units.substr(0, units.length - config.coinUnitPlaces) || "0") +
"." +
decimal
);
};
this.formatMoneyFullSymbol = function(units) {
return this.formatMoneyFull(units) + " " + config.coinSymbol;
};
function padLeft(str, len, char) {
while (str.length < len) str = char + str;
return str;
}
function trimRight(str, char) {
while (str[str.length - 1] == char) str = str.slice(0, -1);
return str;
}
this.formatMoney = function(units) {
var f = trimRight(this.formatMoneyFull(units), "0");
if (f[f.length - 1] === ".") {
return f.slice(0, f.length - 1);
}
return f;
};
this.formatMoneySymbol = function(units) {
return this.formatMoney(units) + " " + config.coinSymbol;
};
this.parseMoney = function(str) {
if (!str) return JSBigInt.ZERO;
var negative = str[0] === "-";
if (negative) {
str = str.slice(1);
}
var decimalIndex = str.indexOf(".");
if (decimalIndex == -1) {
if (negative) {
return JSBigInt.multiply(str, config.coinUnits).negate();
}
return JSBigInt.multiply(str, config.coinUnits);
}
if (decimalIndex + config.coinUnitPlaces + 1 < str.length) {
str = str.substr(0, decimalIndex + config.coinUnitPlaces + 1);
}
if (negative) {
return new JSBigInt(str.substr(0, decimalIndex))
.exp10(config.coinUnitPlaces)
.add(
new JSBigInt(str.substr(decimalIndex + 1)).exp10(
decimalIndex + config.coinUnitPlaces - str.length + 1,
),
).negate;
}
return new JSBigInt(str.substr(0, decimalIndex))
.exp10(config.coinUnitPlaces)
.add(
new JSBigInt(str.substr(decimalIndex + 1)).exp10(
decimalIndex + config.coinUnitPlaces - str.length + 1,
),
);
};
return this;
};

@ -29,7 +29,7 @@
"use strict";
//
const JSBigInt = require("../cryptonote_utils/biginteger").BigInteger;
const monero_utils = require("../monero_utils/monero_cryptonote_utils_instance");
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(
@ -228,7 +228,7 @@ function Parsed_AddressTransactions__sync(
.subtract(transactions[i].total_sent || 0)
.toString();
transactions[i].approx_float_amount = parseFloat(
monero_utils.formatMoney(transactions[i].amount),
monero_amount_format_utils.formatMoney(transactions[i].amount),
);
transactions[i].timestamp = transactions[i].timestamp;
const record__payment_id = transactions[i].payment_id;
@ -370,9 +370,9 @@ function Parsed_UnspentOuts__sync(
!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
// 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 =
@ -402,7 +402,7 @@ function Parsed_UnspentOuts__sync(
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));
// console.log("💬 Output was spent; key image: " + key_image + " amount: " + monero_amount_format_utils.formatMoneyFull(finalized_unspentOutputs[i].amount));
// Remove output from list
finalized_unspentOutputs.splice(i, 1);
const finalized_unspentOutput_atI_afterSplice =
@ -414,17 +414,17 @@ function Parsed_UnspentOuts__sync(
}
i--;
} else {
console.log(
"💬 Output used as mixin (" +
key_image +
"/" +
finalized_unspentOutputs[i].spend_key_images[j] +
")",
);
// console.log(
// "💬 Output used as mixin (" +
// key_image +
// "/" +
// finalized_unspentOutputs[i].spend_key_images[j] +
// ")",
// );
}
}
}
console.log("Unspent outs: " + JSON.stringify(finalized_unspentOutputs));
// console.log("Unspent outs: " + JSON.stringify(finalized_unspentOutputs));
const unusedOuts = finalized_unspentOutputs.slice(0);
const returnValuesByKey = {
unspentOutputs: finalized_unspentOutputs,

@ -0,0 +1,35 @@
// 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 monero_config = require("./monero_config")
const money_format_utils = require("../cryptonote_utils/money_format_utils")
const instance = money_format_utils(monero_config)
//
module.exports = instance;

@ -28,8 +28,25 @@
//
"use strict";
//
const monero_config = require("./monero_config");
const cryptonote_utils = require("../cryptonote_utils/cryptonote_utils").cnUtil;
const monero_cryptonote_utils_instance = cryptonote_utils(monero_config);
//
module.exports = monero_cryptonote_utils_instance;
const ENVIRONMENT_IS_WEB = typeof window==="object";
const ENVIRONMENT_IS_WORKER = typeof importScripts==="function";
const ENVIRONMENT_IS_NODE = typeof process==="object" && process.browser !== true && typeof require==="function" && ENVIRONMENT_IS_WORKER == false; // we want this to be true for Electron but not for a WebView
var isElectronRenderer = (ENVIRONMENT_IS_NODE&&ENVIRONMENT_IS_WEB)/*this may become insufficient*/
|| (typeof window !== 'undefined' && window.IsElectronRendererProcess == true);
if (isElectronRenderer) {
// Require file again except on the main process ...
// this avoids a host of issues running wasm on the renderer side,
// for right now until we can load such files raw w/o unsafe-eval
// script-src CSP. makes calls synchronous. if that is a perf problem
// we can make API async.
//
// Resolves relative to the entrypoint of the main process.
const remotely_required = require('electron').remote.require("../mymonero_core_js/monero_utils/monero_cryptonote_utils_instance")
module.exports = remotely_required;
} else {
const monero_config = require("./monero_config");
const cryptonote_utils = require("../cryptonote_utils/cryptonote_utils").cnUtil;
const monero_cryptonote_utils_instance = cryptonote_utils(monero_config);
//
module.exports = monero_cryptonote_utils_instance;
}

@ -32,6 +32,7 @@ const async = require("async");
//
const monero_config = require("./monero_config");
const monero_utils = require("./monero_cryptonote_utils_instance");
const monero_amount_format_utils = require("./monero_amount_format_utils");
const monero_paymentID_utils = require("./monero_paymentID_utils");
const JSBigInt = require("../cryptonote_utils/biginteger").BigInteger;
//
@ -254,7 +255,7 @@ function SendFunds(
console.log(
"💬 Total to send, before fee: " + sweeping
? "all"
: monero_utils.formatMoney(totalAmountWithoutFee_JSBigInt),
: monero_amount_format_utils.formatMoney(totalAmountWithoutFee_JSBigInt),
);
if (!sweeping && totalAmountWithoutFee_JSBigInt.compare(0) <= 0) {
const errStr = "The amount you've entered is too low";
@ -338,7 +339,7 @@ function SendFunds(
}
console.log(
"Received dynamic per kb fee",
monero_utils.formatMoneySymbol(dynamic_feePerKB_JSBigInt),
monero_amount_format_utils.formatMoneySymbol(dynamic_feePerKB_JSBigInt),
);
_proceedTo_constructFundTransferListAndSendFundsByUsingUnusedUnspentOutsForMixin(
moneroReady_targetDescription_address,
@ -405,7 +406,7 @@ function SendFunds(
); /*.add(hostingService_chargeAmount) NOTE service fee removed for now */
console.log(
"Balance required: " +
monero_utils.formatMoneySymbol(totalAmountIncludingFees),
monero_amount_format_utils.formatMoneySymbol(totalAmountIncludingFees),
);
}
const usableOutputsAndAmounts = _outputsAndAmountToUseForMixin(
@ -440,11 +441,11 @@ function SendFunds(
newNeededFee,
);
if (totalAmountWithoutFee_JSBigInt.compare(0) < 1) {
const errStr = `Your spendable balance is too low. Have ${monero_utils.formatMoney(
const errStr = `Your spendable balance is too low. Have ${monero_amount_format_utils.formatMoney(
usingOutsAmount,
)} ${
monero_config.coinSymbol
} spendable, need ${monero_utils.formatMoney(
} spendable, need ${monero_amount_format_utils.formatMoney(
newNeededFee,
)} ${monero_config.coinSymbol}.`;
__trampolineFor_err_withStr(errStr);
@ -467,7 +468,7 @@ function SendFunds(
);
console.log(
"Using output: " +
monero_utils.formatMoney(out.amount) +
monero_amount_format_utils.formatMoney(out.amount) +
" - " +
JSON.stringify(out),
);
@ -488,7 +489,7 @@ function SendFunds(
}
console.log(
"New fee: " +
monero_utils.formatMoneySymbol(newNeededFee) +
monero_amount_format_utils.formatMoneySymbol(newNeededFee) +
" for " +
usingOuts.length +
" inputs",
@ -497,18 +498,18 @@ function SendFunds(
}
console.log(
"~ Balance required: " +
monero_utils.formatMoneySymbol(totalAmountIncludingFees),
monero_amount_format_utils.formatMoneySymbol(totalAmountIncludingFees),
);
// Now we can validate available balance with usingOutsAmount (TODO? maybe this check can be done before selecting outputs?)
const usingOutsAmount_comparedTo_totalAmount = usingOutsAmount.compare(
totalAmountIncludingFees,
);
if (usingOutsAmount_comparedTo_totalAmount < 0) {
const errStr = `Your spendable balance is too low. Have ${monero_utils.formatMoney(
const errStr = `Your spendable balance is too low. Have ${monero_amount_format_utils.formatMoney(
usingOutsAmount,
)} ${
monero_config.coinSymbol
} spendable, need ${monero_utils.formatMoney(
} spendable, need ${monero_amount_format_utils.formatMoney(
totalAmountIncludingFees,
)} ${monero_config.coinSymbol}.`;
__trampolineFor_err_withStr(errStr);
@ -540,7 +541,7 @@ function SendFunds(
// for RCT we don't presently care about dustiness so add entire change amount
console.log(
"Sending change of " +
monero_utils.formatMoneySymbol(changeAmount) +
monero_amount_format_utils.formatMoneySymbol(changeAmount) +
" to " +
wallet__public_address,
);
@ -559,7 +560,7 @@ function SendFunds(
// miners will add dusty change to fee
console.log(
"💬 Miners will add change of " +
monero_utils.formatMoneyFullSymbol(
monero_amount_format_utils.formatMoneyFullSymbol(
changeAmountDivRem[1],
) +
" to transaction fee (below dust threshold)",
@ -572,7 +573,7 @@ function SendFunds(
);
console.log(
"💬 Sending change of " +
monero_utils.formatMoneySymbol(usableChange) +
monero_amount_format_utils.formatMoneySymbol(usableChange) +
" to " +
wallet__public_address,
);
@ -632,10 +633,16 @@ function SendFunds(
preSuccess_nonTerminal_statusUpdate_fn(
SendFunds_ProcessStep_Code.constructingTransaction,
);
function printDsts(dsts)
{
for (var i = 0; i < dsts.length; i++) {
console.log(dsts[i].address + ": " + monero_amount_format_utils.formatMoneyFull(dsts[i].amount))
}
}
var signedTx;
try {
console.log("Destinations: ");
monero_utils.printDsts(fundTransferDescriptions);
printDsts(fundTransferDescriptions); // TODO: port this out
//
var realDestViewKey; // need to get viewkey for encrypting here, because of splitting and sorting
if (final__pid_encrypt) {
@ -645,21 +652,22 @@ function SendFunds(
).view;
console.log("got realDestViewKey", realDestViewKey);
}
var splitDestinations = monero_utils.decompose_tx_destinations(
console.log("fundTransferDescriptions", fundTransferDescriptions)
var IPCsafe_splitDestinations = decompose_tx_destinations( // TODO: port this out
fundTransferDescriptions,
isRingCT,
true // serialize (convert JSBigInts to strings for IPC)
);
console.log("Decomposed destinations:");
monero_utils.printDsts(splitDestinations);
printDsts(IPCsafe_splitDestinations);
//
signedTx = monero_utils.create_transaction(
signedTx = monero_utils.create_transaction__IPCsafe(
wallet__public_keys,
wallet__private_keys,
splitDestinations,
IPCsafe_splitDestinations,
usingOuts,
mix_outs,
mixin,
attemptAt_network_minimumFee,
attemptAt_network_minimumFee.toString(), // must serialize for IPC
final__payment_id,
final__pid_encrypt,
realDestViewKey,
@ -705,7 +713,7 @@ function SendFunds(
" bytes <= " +
numKB +
" KB (current fee: " +
monero_utils.formatMoneyFull(attemptAt_network_minimumFee) +
monero_amount_format_utils.formatMoneyFull(attemptAt_network_minimumFee) +
")",
);
const feeActuallyNeededByNetwork = calculate_fee__kb(
@ -721,11 +729,11 @@ function SendFunds(
) {
console.log(
"💬 Need to reconstruct the tx with enough of a network fee. Previous fee: " +
monero_utils.formatMoneyFull(
monero_amount_format_utils.formatMoneyFull(
attemptAt_network_minimumFee,
) +
" New fee: " +
monero_utils.formatMoneyFull(
monero_amount_format_utils.formatMoneyFull(
feeActuallyNeededByNetwork,
),
);
@ -747,7 +755,7 @@ function SendFunds(
const final_networkFee = attemptAt_network_minimumFee; // just to make things clear
console.log(
"💬 Successful tx generation, submitting tx. Going with final_networkFee of ",
monero_utils.formatMoney(final_networkFee),
monero_amount_format_utils.formatMoney(final_networkFee),
);
// status: submitting…
preSuccess_nonTerminal_statusUpdate_fn(
@ -770,7 +778,7 @@ function SendFunds(
moneroReady_targetDescription_address,
sweeping
? parseFloat(
monero_utils.formatMoneyFull(
monero_amount_format_utils.formatMoneyFull(
totalAmountWithoutFee_JSBigInt,
),
)
@ -831,7 +839,7 @@ function new_moneroReadyTargetDescriptions_fromTargetDescriptions(
// amount:
var moneroReady_amountToSend; // possibly need this ; here for the JS parser
try {
moneroReady_amountToSend = monero_utils.parseMoney(
moneroReady_amountToSend = monero_amount_format_utils.parseMoney(
targetDescription_amount,
);
} catch (e) {
@ -873,7 +881,7 @@ function _outputsAndAmountToUseForMixin(
) {
console.log(
"Selecting outputs to use. target: " +
monero_utils.formatMoney(target_amount),
monero_amount_format_utils.formatMoney(target_amount),
);
var toFinalize_usingOutsAmount = new JSBigInt(0);
const toFinalize_usingOuts = [];
@ -913,7 +921,7 @@ function _outputsAndAmountToUseForMixin(
);
console.log(
"Using output: " +
monero_utils.formatMoney(out_amount_JSBigInt) +
monero_amount_format_utils.formatMoney(out_amount_JSBigInt) +
" - " +
JSON.stringify(out),
);
@ -924,3 +932,59 @@ function _outputsAndAmountToUseForMixin(
remaining_unusedOuts: remaining_unusedOuts,
};
}
function decompose_amount_into_digits(amount)
{
/*if (dust_threshold === undefined) {
dust_threshold = config.dustThreshold;
}*/
amount = amount.toString();
var ret = [];
while (amount.length > 0) {
//split all the way down since v2 fork
/*var remaining = new JSBigInt(amount);
if (remaining.compare(config.dustThreshold) <= 0) {
if (remaining.compare(0) > 0) {
ret.push(remaining);
}
break;
}*/
//check so we don't create 0s
if (amount[0] !== "0") {
var digit = amount[0];
while (digit.length < amount.length) {
digit += "0";
}
ret.push(new JSBigInt(digit));
}
amount = amount.slice(1);
}
return ret;
}
function decompose_tx_destinations(dsts, rct, serializeForIPC)
{
var out = [];
if (rct) {
for (var i = 0; i < dsts.length; i++) {
out.push({
address: dsts[i].address,
amount: serializeForIPC ? dsts[i].amount.toString() : dsts[i].amount,
});
}
} else {
for (var i = 0; i < dsts.length; i++) {
var digits = decompose_amount_into_digits(dsts[i].amount);
for (var j = 0; j < digits.length; j++) {
if (digits[j].compare(0) > 0) {
out.push({
address: dsts[i].address,
amount: serializeForIPC ? digits[j].toString() : digits[j],
});
}
}
}
}
return out.sort(function(a, b) {
return a["amount"] - b["amount"];
});
};

@ -31,8 +31,6 @@
const dummy_test_utils = require("./dummy-test-utils.js");
const dummy_cnUtils_instance = require("./dummy-cnutils").cnUtil()
console.log("dummy_test_utils.Module", dummy_test_utils.Module)
dummy_test_utils.OnceModuleReady(
function(Module)
{

@ -0,0 +1,41 @@
// 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 monero_utils = require("../../monero_utils/monero_cryptonote_utils_instance");
try {
console.log("loaded_CNCrypto", monero_utils.loaded_CNCrypto())
} catch (e) {
console.log("Caught the expected exception while trying to call on CNCrypto while it's being loaded")
}
monero_utils.OnceModuleReady(function()
{
console.log("loaded_CNCrypto", monero_utils.loaded_CNCrypto())
})

@ -27,7 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"use strict";
const MyMoneroCoreCpp = require("../../cryptonote_utils/MyMoneroCoreCpp.js");
const MyMoneroCoreCpp_builder = require("../../cryptonote_utils/MyMoneroCoreCpp.js");
var public_key =
"904e49462268d771cc1649084c35aa1296bfb214880fe2e7f373620a3e2ba597";
@ -49,8 +49,10 @@ exports.OnceModuleReady = function(fn)
fn(Module)
}
}
MyMoneroCoreCpp().then(function(thisModule)
var Module_template =
{
}
MyMoneroCoreCpp_builder(Module_template).then(function(thisModule)
{
Module = thisModule
exports.Module = Module

Loading…
Cancel
Save