var globalVar = require("global").libcoinconst;
var Coin = require("./electrumCoin.js").ElectrumCoin;
const BitcoinAuth = require("./electrumCoin.js").BitcoinAuth;
const ElectrumCascade = require("./electrumCoin.js").ElectrumCascade;
const ElectrumCoin = require("./electrumCoin.js").ElectrumCoin;
var libraries = globalVar.libraries;
var Error = globalVar.Error;
var config = globalVar.config;
var slpclient;
/** @classdesc Initialize a new BCH coin with new xxx.BCH();
* @class
* @hideconstructor
* @extends Coin
* @extends ElectrumCoin
*/
globalVar.bch = {"decimals":8};
// Some variables, like blockHeight, estimatedFee, are tied to a global
class BCH extends ElectrumCoin {
constructor(config){
super("bch",config || {});
slpclient = libraries.slpclient;
console.warn("WARNING! Do not use BCH token with an address that may have an SLP token in it!");
}
_signTransaction(inputTx,unsigned,privateKey){
inputTx.signed = unsigned.sign(privateKey).serialize();
return inputTx;
}
async _buildTransaction(inputTx){
var balances = await this.slpHelper.slpBalances(address);
inputTx.amount = new libraries.bignumber(inputTx.amount);
inputTx.fee = this.fee || 0.0005;
console.log("here are unspent",unspent);
var transaction = new libraries.bch.Transaction()
.from(unspent) // Feed information about what unspent outputs one can use
.to(inputTx.toAddress, (inputTx.amount - inputTx.feePerInput.times(2))*100000000) // Add an output with the given amount of satoshis
.change(inputTx.changeAddress || inputTx.fromAddress); // set up a change address where unspent utxos will go
inputTx.unsigned = transaction;
return inputTx;
}
/**
Get all balances including SLP balances, sorted by token id
@param {string} Address A cryptocurrency address.
*/
async getAllBalances(address){
var balances = await this.slpHelper.slpBalances(address);
return balances;
}
}
class SLPAuth extends BitcoinAuth{
constructor(config){
super(config,"bch");
this.desc="SLPAddress";
}
_isCoinAddress(address){return libraries.slpsdk.Address.isCashAddress(address)}
_isTokenAddress(address){return libraries.slpsdk.Address.isSLPAddress(address)};
}
class SLPCascade extends ElectrumCascade{
constructor(parent,query,...args){
super(...args);
this.skip=true;
var _this=this;
this.Get = class SLPGet extends super.Get{
}
this.On = class SLPOn extends super.Get{
}
this.Off = class SLPOff extends super.Off{
}
this.Build = class SLPBuild extends super.Build{
}
this.Sign = class SLPSign extends super.Sign{
}
}
__on(...args){
}
__get(...args){
}
__off(...args){
}
}
/** @classdesc Initialize a new SLP token with <tt>await new xxx.SLP().token(tokenId)</tt> or <tt>await new xxx.SLP(yourprivatekey).token(tokenId)</tt>
* @class
* @hideconstructor
* @extends Coin
* @extends ElectrumCoin
* @extends BCH
*/
class SLP extends BCH{
constructor(config){
super(config);
this.isToken = true;
this.Live = SLPLive;
this.auth = new SLPAuth(config || {});
this.address=this.auth.address;
this.Live = SLPLive;
this.TxLive = SLPTxLive;
}
/*
* Assign your SLP instance to a particular token. Sync it to automatically get balances for this token at a given time
* @param {string} TokenID A Genesis TxID for a particular token
*/
async _token(tokenId){
var tokenInfo= libraries.getItem(tokenId);
tokenInfo = tokenInfo ? tokenInfo : await libraries.bitboxNetwork.getTokenInformation(tokenId);
libraries.setItem(tokenId,tokenInfo);
for(var key in tokenInfo){
if(key=="decimals")_this.tokenDecimals = tokenInfo[key];
else if(key=="genesisOrMintQuantity")_this.totalSupply = tokenInfo.genesisOrMintQuantity.toNumber();
else if(key=="documentUri")_this.url = tokenInfo.documentUri;
else if(["transactionType","batonVout","documentSha256","containsBaton"].indexOf(key)>-1)continue;
else if(key=="symbol")_this[key] = tokenInfo[key].toLowerCase()
else _this[key]=tokenInfo[key];
}
return this;
}
async _buildTransaction(inputTx){
var utxos = this.getUtxos(inputTx.fromAddress,this.tokenDecimals,this.tokenId);
}
async _getBalance(address){
var balances = await this.slpHelper.slpBalances(address);
this.balance = balances[this.tokenId].tokensAvailable.dividedBy(10**this.tokenDecimals).toNumber();
return this.balance;
}
/*
* Create a new token. See the source code for configuation details (very easy).
* @param {object} TokenConfig A JSON file to create a token
*/
async createToken(tokenConfig){
var address = tokenConfig.address || this.auth.address;
var createConfig = {
fundingAddress: config.fundingAddress || address,
fundingWif: config.fundingWif || this.auth.privateKey,
tokenReceiverAddress: config.tokenReceiverAddress || address,
batonReceiverAddress: config.batonReceiverAddress || null,
bchChangeReceiverAddress: config.bchChangeReceiverAddress || address,
decimals: config.decimals || 8,
name: config.name || "",
symbol: config.symbol || "",
documentUri: config.url || "",
documentHash: config.hash || null ,
initialTokenQty: config.amount || 13e6 // 13 million initial
}
return await libraries.slpsdk.TokenType1.create(createConfig);
}
async buildDexTransaction(makerOffer,takerOffer){
if(!this.isToken) throw 'You must build a DEX transaction with an instance of the token you are buying or selling, then can sign the transaction with the coin or token you are providing.';
makerOffer.makertaker="maker";
takerOffer.makertaker="taker";
p1 = DexOffer(makerOffer,this,this.feePerInput,libraries).then(function(mO){
makerOffer = mO;
});
p2 = DexOffer(takerOffer,this,this.feePerInput,libraries).then(function(tO){
takerOffer = tO;
});
await Promise.all([p1,p2]);
var coinProvider = makerOffer.provider == "coin" ? makerOffer : takerOffer;
var tokenProvider = coinProvider == makerOffer ? takerOffer : makerOffer;
// Set to addresses:
coinProvider.transaction.outputs.coin[0].to = tokenProvider.receiveAddress;
tokenProvider.transaction.outputs.token[0].to = coinProvider.receiveAddress;
var combinedTransaction = tokenProvider.transaction;
// for each coinProvider output, add the BCH amount to the tokenProvider output if it has the same address, otherwise append the output to the transaction
// 1. May send coinProvider's coins into tokenProviders change utxo
// 2. May send exchangeFees into single change utxo
// 3. May send tokenProvider's tokens into coinProvider's change utxo
coinProvider.transaction.outputs.forEach((e,i,a)=>{
var found = false;
tokenProvider.transaction.outputs.token.forEach((e2,i2,a2)=>{
if(e2.to == e.to && !found){found = true; combinedTransaction.outputs[i2].amount.plus(e.amount);}
})
if(!found)transaction.outputs.push(e);
});
var transaction = tokenProvider.transaction;
transaction.inputs.coin.concat(coinProvider.transaction.inputs.coin);
var transaction = BnTransaction(transaction,tokenInfo.decimals,this.decimals);
transaction.toFloats();
console.log(JSON.stringify(transaction,null,2));
}
}
function setbignum(value,decimals){
return bn.isBigNumber(value) ? value : (typeof value == "number" ? new bn.bignumber(value).times(10**decimals) : (typeof value =="object" ? (()=>{for(var key in value){value[key]=setbignum(value[key],decimals)};return value;})() : value))
}
function setfloat(value,decimals){
return bn.isBigNumber(value) ? value.dividedBy(10**decimals).toNumber() : (typeof value=="object" ? (()=>{for(var key in value){value[key]=setfloat(value[key],decimals)}return value;})() : value);
}
function AddBnConverters(object,coinDecimals,tokenDecimals){
for(var key in object)this[key]=object[key];
findAmounts = (obj,set)=>{
for(var key in obj){
obj[key] = typeof obj[key] =="object" ? findAmounts(obj,set) : (["amount","coinAvailable"].indexOf(key) > -1 ? set(obj[key],coinDecimals) : (["tokenAmount","tokensAvailable"].indexOf(key) > -1 ? set(obj[key],tokenDecimals) : obj[key]));
}
return obj;
}
this.toFloats = ()=>findAmounts(this,setfloat);
this.toBigNumbers = ()=>findAmounts(this,setbignum);
}
function validateTokenInputs(balances,offer){
var tokensAvailable = new bn(0);
var coinAvailable = new bn(0);
var tokenInputs = [];
balances[token.id].utxos.forEach((utxo,i,a)=>{
if(tokensAvailable.isGreaterThan(offer.amount))return;
coinAvailable = coinAvailable.plus(utxo.coinAmount);
utxo.slpTransactionDetails.sendOutputs.forEach((sendOutput,i2,a)=>{
console.warn("Does this actually work? Won't this show outputs going to places not owned by this key?");
tokensAvailable=tokensAvailable.plus(sendOutput.tokensAvailable)
});
utxo.label = "From the "+offer.provider+" provider.";
utxo.from = offer.fromAddress;
tokenInputs.push(utxo);
if(tokenInputs.length > maxTokenInputs){offer.networkFeeAmount.plus(token.coinFeePerInput * 10 **feeDecimals); offer.toBigNumbers();}
});
offer.tokenChange = tokensAvailable.isGreaterThan(offer.amount) ? tokensAvailable.minus(offer.amount) : (()=>{throw "Not enough tokens when validating UTxos"})();
return tokensAvailable, coinAvailable,tokenInputs;
}
function validateCoinInputs(balances,offer,coinAvailable){
if(balances[token.coin].coinAvailable.isLessThan(offer.coinNeeded)) throw new Error("Not enough coin balance for this offer");
var coinInputs = [];
coinAvailable = coinAvailable || new bn(0);
if(offer.coinNeeded.isGreaterThan(coinAvailable))balances[token.coin].utxos.forEach((utxo,i,a)=>{
if(coinAvailable.isGreaterThan(offer.coinNeeded))return;
coinAvailable = coinAvailable.plus(utxo.coinAmount);
utxo.label = "the "+offer.provider+" provider.";
utxo.from = offer.fromAddress;
coinInputs.push(utxo);
offer.networkFeeAmount = offer.networkFeeAmount.plus(token.coinFeePerInput * 10 **feeDecimals);
offer.toBigNumbers();
});
offer.coinChange = coinAvailable.isGreaterThan(offer.coinNeeded) ? coinAvailable.minus(offer.coinNeeded) : (()=>{throw "Please add: "+offer.networkFeeAmount.toNumber()+" "+token.coin+" to this address. You used "+tokenInputs.length+" when at most 3 are paid for by the coin provider."})();
return coinInputs;
}
async function DexOffer(offer,token,libraries){
// function(element, index, array)
var isUTXO = token.isUTXO || false;
["amount","price","fromAddress","buysell","makertaker","exchangeAddress"].forEach(e => !offer[e] ? (()=>{throw "Missing "+e+" for trade input"})() : null);
["exchangeFeeAmount","networkFeeAmount","coinNeeded","tokenChange","coinChange"].forEach(e => offer[e] ? (()=>{delete offer[e]})() : null);
var bn = libraries.bignumber;
var maxTokenInputs=3;
offer.receiveAddress = offer.receiveAddress || offer.fromAddress;
offer.changeAddress = offer.changeAddress || offer.fromAddress;
offer.provider = offer.buysell=="sell" ? offer.provider = "token" : offer.provider = "coin";
var feeDecimals = offer.provider=="token" ? token.tokenDecimals : token.coinDecimals;
var coinDecimals = token.coinDecimals;
var dustFee = token.coinDustFee ? setbignum(token.coinDustFee,token.coinDecimals) : new libraries.bignumber(0);
offer.toBigNumbers = function(){
offer.price = setbignum(offer.price,token.tokenDecimals - coinDecimals)
// group 1: units in TOKEN always
offer.amount = setbignum(offer.amount,token.tokenDecimals)
//offer.tradeAmount = offer.amount.minus(offer.exchangeFeeAmount);
offer.tokenChange = setbignum(offer.tokenChange || 0,token.tokenDecimals);
// group 2: in token or coin; always used by both
offer.exchangeFeeAmount = offer.exchangeFeeAmount ? setbignum(offer.exchangeFeeAmount,token.tokenDecimals) : (offer.makertaker=="taker" ? new bn(offer.takerFee || 0 ).times(offer.amount) : new bn(offer.makerFee || 0).times(offer.amount));
offer.exchangeFeeAmount = offer.provider == "coin" ? offer.exchangeFeeAmount.times(offer.price) : offer.exchangeFeeAmount;
// group 3: units in coin always, but may be used by token provider if excessively large # of inputs:
offer.networkFeeAmount = offer.networkFeeAmount ? setbignum(offer.networkFeeAmount,coinDecimals) : (offer.provider=="coin" ? new bn(maxTokenInputs * token.coinFeePerInput * 10 ** coinDecimals) : new bn(0));
offer.coinChange = offer.coinChange ? setbignum(offer.coinChange,8) : new bn(0);
// group 4: units in coin always, only used by coin provider:
offer.coinNeeded = offer.provider == "coin" ? offer.amount.times(offer.price).plus(offer.exchangeFeeAmount).plus(offer.networkFeeAmount) : offer.networkFeeAmount;
}
offer.toFloats = function(){
offer.price = setfloat(offer.price,coinDecimals-token.tokenDecimals);
["amount"].forEach((e,i,a)=>{
a[i] = setfloat(offer.amount,token.tokenDecimals);
});
offer.exchangeFeeAmount = offer.provider =="coin" ? setfloat(offer.exchangeFeeAmount,token.tokenDecimals) : setfloat(offer.exchangeFeeAmount,coinDecimals);
}
offer.toBigNumbers();
var balances = await libraries.slpHelper.slpBalances(offer.fromAddress);
if(offer.provider =="token"){
if (!token.auth.isTokenAddress(offer.fromAddress))throw new Error("Token fromAddress not in Token address format.");
if (!token.auth.isTokenAddress(offer.changeAddress))throw new Error("Token changeAddress not in Token address format.");
if (!token.auth.isTokenAddress(offer.receiveAddress) && !token.auth.isCoinAddress(offer.receiveAddress)) throw new Error("Address to receive coins from token is not cash or slp");
if(offer.amount.isGreaterThan(balances[token.id].tokensAvailable)) throw new Error("Not enough token balance for this offer");
if(!isUTXO){
offer.transaction = {"inputs":{"token":[{"from":offer.fromAddress,"label":"From the "+offer.provider+" provider","tokenAmount":offer.amount}]},"outputs":{"token":[{"to":"coin provider","tokenAmount":offer.amount.minus(offer.exchangeFeeAmount)},{"to":offer.exchangeAddress,"label":"Funds provided to exchange","tokenAmount":offer.exchangeFeeAmount}]}};
return offer;
}
var { tokensAvailable , coinAvailable, tokenInputs } = validateTokenInputs(balances,offer);
var coinInputs = validateCoinInputs(balances,offer,coinAvailable);
var tokenOutputs = [{"to":"coin provider","amount":dustFee,"tokenAmount":offer.amount.minus(offer.exchangeFeeAmount),"label":"To coin provider"}]
if(offer.tokenChange.isGreaterThan(0))tokenOutputs.push({"to":offer.changeAddress,"label":"Returning extra tokens to token provider from his/her very large input","amount":dustFee,"tokenAmount":offer.tokenChange});
if(offer.exchangeFeeAmount.isGreaterThan(0))tokenOutputs.push({"to":offer.exchangeAddress,"label":"Funds received by exchange from token provider","amount":dustFee,"tokenAmount":offer.exchangeFee});
// include OP return data and other stuff
var tokenAmounts = [];
tokenOutputs.forEach((e)=>{
tokenAmounts.push(e.tokenAmount.toNumber());
});
var op_return = libraries.rawslp.buildSendOpReturn({
tokenIdHex: token.id,
outputQtyArray: tokenAmounts,
});
this.preSendOpReturnCheck(slpBalances);
offer.transaction = {"inputs":{"token":tokenInputs,"coin":coinInputs},"outputs":{"token":tokenOutputs},"op_return":op_return};
resolve(offer);
}else if(offer.provider =="coin"){
if (!token.auth.isCoinAddress(offer.fromAddress) && !token.auth.isTokenAddress(offer.fromAddress)) throw "Address providing "+token.coin+" in token transfer is not valid coin or token address";
if (!token.auth.isCoinAddress(offer.changeAddress) && !token.auth.isTokenAddress(offer.changeAddress)) throw "Address to receive change "+token.coin+" is not valid coin or token address";
if (!token.auth.isTokenAddress(offer.receiveAddress)) throw "Token receive address is not valid";
if (offer.coinNeeded.isGreaterThan(balances[token.coin].coinAvailable)) throw 'Not enough coins for this trade';
if(!isUTXO){
offer.transaction = {"inputs":{"coin":[{"from":offer.fromAddress,"label":"From the "+offer.provider+" provider","amount":offer.coinNeeded}]},"outputs":{"coin":[{"to":"token provider","amount":offer.coinNeeded.minus(offer.exchangeFeeAmount)},{"to":offer.exchangeAddress,"label":"Funds provided to exchange","amount":offer.exchangeFeeAmount}]}};
return offer;
}
var coinInputs = validateCoinInputs(balances,offer);
var coinOutputs = [{"to":"token provider","amount":offer.amount.times(offer.price),"label":"To token provider"}];
if(offer.coinChange.isGreaterThan(0))coinOutputs.push({"to":offer.changeAddress,"amount":offer.coinChange,"label":"Returning extra coin to coin provider from his/her very large input."});
if(offer.exchangeFeeAmount.isGreaterThan(0))coinOutputs.push({"to":offer.exchangeAddress,"amount":offer.exchangeFeeAmount,"label":"Funds received by exchange from coin provider"});
offer.transaction = {"inputs":{"coin":coinInputs},"outputs":{"coin":coinOutputs}};
return offer;
}
}
function SlpValidator(libraries){
var utils = libraries.slp_libs.utils;
var index = libraries.slp_libs.index;
var bignumber_js_1 = libraries.bignumber;
var bchaddr = libraries.bchaddr;
var BITBOX = libraries.bitbox;
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
this.preSendSlpJudgementCheck = function (txo, tokenId) {
if (txo.slpUtxoJudgement === undefined || txo.slpUtxoJudgement === null || txo.slpUtxoJudgement === index_1.SlpUtxoJudgement.UNKNOWN)
throw Error("There at least one input UTXO that does not have a proper SLP judgement");
if (txo.slpUtxoJudgement === index_1.SlpUtxoJudgement.SLP_BATON)
throw Error("There is at least one input UTXO that is a baton. You can only spend batons in a MINT transaction.");
if (txo.slpTransactionDetails) {
if (txo.slpUtxoJudgement === index_1.SlpUtxoJudgement.SLP_TOKEN) {
if (!txo.slpUtxoJudgementAmount)
throw Error("There is at least one input token that does not have the 'slpUtxoJudgementAmount' property set.");
if (txo.slpTransactionDetails.tokenIdHex !== tokenId)
throw Error("There is at least one input UTXO that is a different SLP token than the one specified.");
return txo.slpTransactionDetails.tokenIdHex === tokenId;
}
}
return false;
};
}
function SlpHelper(libraries){
var _this = this;
var bitboxNetwork = libraries.bitboxNetwork;
function utxoStruct(config){
var _this=this;
this.coinAvailable = libraries.bignumber(0);
this.tokensAvailable = libraries.bignumber(0);
this.utxos = [];
for(var key in config)this[key]=config[key];
}
this.slpBalances = async function(address){
var balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(address);
var ret = {};
for(var _tokenId in balances.slpTokenUtxos){
ret[_tokenId] = new utxoStruct({
utxos:balances.slpTokenUtxos[_tokenId],
id:_tokenId
})
ret[_tokenId].utxos.forEach((utxo,i,a)=>{
utxo.coinAmount = utxo.satoshis;
ret[_tokenId].coinAvailable = ret[_tokenId].coinAvailable.plus(utxo.satoshis);
utxo.slpTransactionDetails.sendOutputs.forEach((sendOutput,i2,a)=>{
console.warn("Does this actually work? Won't this show outputs going to places not owned by this key?");
ret[_tokenId].tokensAvailable=ret[_tokenId].tokensAvailable.plus(sendOutput.tokensAvailable)
});
});
ret[_tokenId].utxos.filter(function (txo) {
return _this.validation.preSendSlpJudgementCheck(txo, _tokenId);
});
ret[_tokenId].utxos.sort((a,b)=>a.satoshis-b.satoshis);
}
ret.bch =new utxoStruct();
ret.bch.utxos = balances.nonSlpUtxos.length > 0 ? balances.nonSlpUtxos.sort((a,b) => a.satoshis - b.satoshis) : [];
for(var x=0; x < balances.nonSlpUtxos.length; x++){
balances.nonSlpUtxos[x].coinAmount = balances.nonSlpUtxos[x].satoshis;
ret.bch.coinAvailable = ret.bch.coinAvailable.plus(balances.nonSlpUtxos[x].satoshis);
}
return ret;
}
/*
this.checkTokenProviderBalance = async function(inputTx){
for(var x=0; x < _tokenutxos.length; x++){
bchAvailable=bchAvailable.plus(_tokenutxos[x].satoshis);
for(var y=0; y < _tokenutxos[x].slpTransactionDetails.sendOutputs.length; y++){
tokensAvailable=tokensAvailable.plus(_tokenutxos[x].slpTransactionDetails.sendOutputs[y].toNumber()); // toNumber??????????
}
sendUtxos.push(_tokenutxos[x]);
if(tokensAvailable.isGreaterThan(tradeAmount))break;
}
if(tokensAvailable.isLessThan(tradeAmount)) throw 'Not enough tokens are available for this trade amount -- the maker may have cancelled the order';
// token traders can include a maximum of 3 token inputs, covered by the bch trader, before requiring an additional bch miner fee from the token trader. token sender always receives any extra bch in their token inputs as change.
slpBalances.token.inputs=sendUtxos;
slpBalances.bch.inputs=[];
var changeBch;
if(sendUtxos.length > maxTokenInputs){
var b=0;
notEnoughBch=bchAvailable.isLessThan(dustFee.times(sendUtxos.length).plus(feePerInput.times(slpBalances.bch.inputs.length+sendUtxos.length-maxTokenInputs)));
while(b < _bchutxos.length && notEnoughBch){
bchAvailable=bchAvailable.plus(_bchutxos[b].satoshis);
utxos.bch.inputs.push(_bchutxos[b]);
notEnoughBch=bchAvailable.isLessThan(dustFee.times(sendUtxos.length).plus(feePerInput.times(utxos.token.bchinputs.length+sendUtxos.length-maxTokenInputs)));
}
if(notEnoughBch) throw 'Not enough bch available to cover that many token inputs. Send more BCH to your token address to cover your excessively large amount of inputs';
changeBch = bchAvailable.minus(feePerInput.times(utxos.bch.inputs.length+sendUtxos.length-maxTokenInputs));
}else changeBch = bchAvailable;
var tokenAmounts = [];
slpBalances.token.outputs=[
{"label":"to bch supplier","to":inputTx.otherToAddress || "not available yet","amount":dustFee.dividedBy(10**8).toNumber(),"tokenAmount":tradeAmount.dividedBy(10**slpBalances.token.decimals).toNumber()}
tokenAmounts.push(tradeAmount);
]
if(tokensAvailable.minus(exchangeFee).minus(tradeAmount).dividedBy(10**slpBalances.token.decimals).toNumber() > 0){
slpBalances.token.outputs.push({"label":"back to token supplier","to":changeAddress,"amount":dustFee.dividedBy(10**8).toNumber(),"tokenAmount":tokensAvailable.minus(exchangeFee).minus(tradeAmount).dividedBy(10**slpBalances.token.decimals).toNumber()});
tokenAmounts.push(tokensAvailable.minus(exchangeFee).minus(tradeAmount));
}
if(exchangeFee.isGreaterThan(0)){
slpBalances.token.outputs.push({"label":"exchange fee","to":inputTx.exchangeAddress,"amount":dustFee.dividedBy(10**8).toNumber(),"tokenAmount":exchangeFee.dividedBy(10**slpBalances.token.decimals).toNumber()});
tokenAmounts.push(exchangeFee);
}
slpBalances.op_return = libraries.rawslp.buildSendOpReturn({
tokenIdHex: slpBalances.token.id,
outputQtyArray: tokenAmounts,
});
this.preSendOpReturnCheck(slpBalances);
if(slpBalances.bch.inputs.length>0){
slpBalances.bch.outputs=[{"label":"back to token supplier","to":inputTx.changeAddress,"amount":changeBch.dividedBy(10**8).toNumber()}];
}
return slpBalances;
}
this.checkCoinProviderBalances =async function(inputTx,slpBalances,type){
if(type=="token"){
}else {
var _bchutxos = slpBalances.bch.utxos.sort((a,b) => a.satoshis - b.satoshis);
var utxoAmount = new libraries.bignumber(0);
amount = new libraries.bignumber(amount).times(10 ** 8);
exchangeFee = new libraries.bignumber(exchangeFee).times(amount);
var minerFee = new libraries.bignumber(0);
for(var x=0; x < _bchutxos.length; x++){
utxoAmount=utxoAmount.plus(_bchutxos[x].satoshis);
sendUtxos.push(_bchutxos[x]);
minerFee = feePerInput.times(maxTokenInputs+2+sendUtxos.length).plus(dustFee.times(maxTokenInputs));
if(utxoAmount.isGreaterThan(amount.plus(minerFee).plus(exchangeFee)))break
}
console.log("Utx amount,amount,minerFee,exchangeFee",utxoAmount.toNumber(),amount.toNumber(),minerFee.toNumber(),exchangeFee.toNumber());
if(utxoAmount.isLessThan(amount.plus(minerFee).plus(exchangeFee)))throw ' Not enough BCH for this transaction ';
slpBalances.bch.inputs=sendUtxos;
var tradeAmount=amount.minus(exchangeFee);
var changeAmount=utxoAmount.minus(tradeAmount).minus(exchangeFee).minus(minerFee);
// 'maxTokenInputs' is the maximum token inputs allowed by the token seller before he has to pay an extra fee
// '+2' is another token input for the exchange fee, and another for the token change tx.
slpBalances.bch.outputs=[
{"label":"to token supplier","to":inputTx.otherToAddress || "not available yet","amount":tradeAmount.dividedBy(10**8).toNumber()},
{"label":"to bch supplier","to":changeAddress,"amount":changeAmount.dividedBy(10**8).toNumber()}
]
if(exchangeFee.isGreaterThan(0))utxos.bch.outputs.push({"label":"exchange fee","to":inputTx.exchangeAddress,"amount":exchangeFee.dividedBy(10**8).toNumber()});
return slpBalances;
}
}
*/
this.info= async function(tokenId){
var tokenInfo = await bitboxNetwork.getTokenInformation(inputTx.tokenId||tokenId);
}
this.listAllTokens = async function(minBalance){
var tokens = await SLP.Utils.list();
for( var a=0; a < tokens.length; a++){
}
}
}
module.exports.BCH = BCH;
module.exports.SLP = SLP;