diff --git a/README.md b/README.md index 5e9c88c9..86679bf5 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,6 @@ const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX); let balances; (async function() { balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); console.log('BCH balance:', balances.satoshis_available_bch); })(); @@ -228,7 +227,6 @@ const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX); let balances; (async function() { balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); if(balances.slpBatonUtxos[tokenIdHexToMint]) console.log("You have the minting baton for this token"); else @@ -321,7 +319,6 @@ let tokenDecimals; let balances; (async function() { balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); console.log(balances); if(balances.slpTokenBalances[tokenId] === undefined) console.log("You need to fund the addresses provided in this example with tokens and BCH. Change the tokenId as required.") @@ -386,7 +383,6 @@ const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX); let balances; (async function() { balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set.", balances); if (balances.satoshis_available_bch < sendAmountsInSatoshi) { throw new Error("You need to fund the addresses provided in this example with BCH."); @@ -489,7 +485,6 @@ let tokenDecimals; let balances; (async function() { balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); console.log(balances); if(balances.slpTokenBalances[tokenId] === undefined) console.log("You need to fund the addresses provided in this example with tokens and BCH. Change the tokenId as required.") @@ -580,7 +575,6 @@ let fundingAddress = "simpleledger:pphnuh7dx24rcwjkj0sl6xqfyfzf23aj7udr0837gn"; let balances; (async function() { balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); console.log(balances); if(balances.slpTokenBalances[tokenId] === undefined) console.log("You need to fund the addresses provided in this example with tokens and BCH. Change the tokenId as required.") @@ -669,7 +663,6 @@ let tokenDecimals; let balances; (async function() { balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); console.log('Token balance:', balances.slpTokenBalances[tokenId].toFixed() / 10**tokenDecimals) })(); diff --git a/examples/1-get-token-balances-local.ts b/examples/1-get-token-balances-local.ts index c4ccf451..ea251dda 100644 --- a/examples/1-get-token-balances-local.ts +++ b/examples/1-get-token-balances-local.ts @@ -7,7 +7,7 @@ * using SLPDB. * * Instructions: - * (1) - Select Network and Address by commenting/uncommenting the desired + * (1) - Select Network and Address by commenting/un-commenting the desired * TESTNET or MAINNET section and providing valid BCH address. * (2) - Run `ts-node ` just before script execution, * or use vscode debugger w/ launch.json settings for "Current TS File" @@ -22,7 +22,7 @@ import { BchdNetwork } from "../lib/bchdnetwork"; import { GetRawTransactionsAsync } from "../lib/localvalidator"; // MAINNET NETWORK -const addr = "simpleledger:qp4a73gx6j5u3se0f7263us6rdxygh3rfvk0gu9mfa"; // "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu"; +const addr = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu"; const testnet = false; // TESTNET NETWORK diff --git a/examples/1-get-token-balances-trusted.ts b/examples/1-get-token-balances-trusted.ts index 1067084f..b8f44ec1 100644 --- a/examples/1-get-token-balances-trusted.ts +++ b/examples/1-get-token-balances-trusted.ts @@ -4,7 +4,7 @@ * using BCHD and SLPDB Trusted Validation * * Instructions: - * (1) - Select Network and Address by commenting/uncommenting the desired + * (1) - Select Network and Address by commenting/un-commenting the desired * TESTNET or MAINNET section and providing valid BCH address. * (2) - Run `ts-node ` just before script execution, * or use vscode debugger w/ launch.json settings for "Current TS File" @@ -16,7 +16,7 @@ const BITBOX = new BITBOXSDK.BITBOX(); import { GrpcClient } from "grpc-bchrpc-node"; import { BchdNetwork, BchdValidator, SlpBalancesResult } from "../index"; -const addr = "simpleledger:qpd2crqxr32tqmu72h6dkygryracrwtcwqy0enzf3z"; +const addr = "simpleledger:qpcgsyu3c4hd00luwhc5a9x5zcgnlw8kdqmdxyjsta"; const client = new GrpcClient({ url: "bchd.ny1.simpleledger.io" }); const validator = new BchdValidator(client); diff --git a/examples/10-burn-token.ts b/examples/10-burn-token.ts index 5ad7661d..0a7d95b3 100644 --- a/examples/10-burn-token.ts +++ b/examples/10-burn-token.ts @@ -19,22 +19,22 @@ * * ************************************************************************************/ -import * as BITBOXSDK from 'bitbox-sdk'; -import { BigNumber } from 'bignumber.js'; -import { BitboxNetwork, SlpBalancesResult, LocalValidator } from '../index'; +import { BigNumber } from "bignumber.js"; +import * as BITBOXSDK from "bitbox-sdk"; +import { BitboxNetwork, LocalValidator, SlpBalancesResult } from "../index"; + +(async () => { -(async function() { - // NETWORK: FOR MAINNET - const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' }); + const BITBOX = new BITBOXSDK.BITBOX({ restURL: "https://rest.bitcoin.com/v2/" }); const fundingAddress = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu"; // <-- must be simpleledger format const fundingWif = "L3gngkDg1HW5P9v5GdWWiCi3DWwvw5XnzjSPwNwVPN5DSck3AaiF"; // <-- compressed WIF format const bchChangeReceiverAddress = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu"; // <-- must be simpleledger format - let tokenId = "d32b4191d3f78909f43a3f5853ba59e9f2d137925f28e7780e717f4b4bfd4a3f"; - let burnAmount = 1; + const tokenId = "d32b4191d3f78909f43a3f5853ba59e9f2d137925f28e7780e717f4b4bfd4a3f"; + const burnAmount = 1; // VALIDATOR: Option 1: FOR REMOTE VALIDATION - //const bitboxNetwork = new BitboxNetwork(BITBOX); + // const bitboxNetwork = new BitboxNetwork(BITBOX); // VALIDATOR: Option 2: FOR LOCAL VALIDATOR / REMOTE JSON RPC // const getRawTransactions: GetRawTransactionsAsync = async function(txids: string[]) { @@ -46,27 +46,27 @@ import { BitboxNetwork, SlpBalancesResult, LocalValidator } from '../index'; // VALIDATOR: Option 3: LOCAL VALIDATOR / LOCAL FULL NODE JSON RPC const logger = console; - const RpcClient = require('bitcoin-rpc-promise'); - const connectionString = 'http://bitcoin:password@localhost:8332' + const RpcClient = require("bitcoin-rpc-promise"); + const connectionString = "http://bitcoin:password@localhost:8332" const rpc = new RpcClient(connectionString); const slpValidator = new LocalValidator(BITBOX, async (txids) => [ await rpc.getRawTransaction(txids[0]) ], logger) const bitboxNetwork = new BitboxNetwork(BITBOX, slpValidator); - + // 1) Fetch critical token information const tokenInfo = await bitboxNetwork.getTokenInformation(tokenId); - let tokenDecimals = tokenInfo.decimals; - console.log('Token precision:', tokenDecimals.toString()); + const tokenDecimals = tokenInfo.decimals; + console.log("Token precision:", tokenDecimals.toString()); // 2) Check that token balance is greater than our desired sendAmount - let balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); - if(balances.slpTokenBalances[tokenId]) - console.log('Token balance:', balances.slpTokenBalances[tokenId].toFixed() / 10**tokenDecimals) - else + const balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); + if (balances.slpTokenBalances[tokenId]) { + console.log("Token balance:", balances.slpTokenBalances[tokenId].toFixed() / 10**tokenDecimals) + } else { console.log("Funding addresss is not holding any tokens with id:", tokenId); + } // 3) Calculate send amount in "Token Satoshis". In this example we want to just send 1 token unit to someone... - let amount = (new BigNumber(burnAmount)).times(10**tokenDecimals); // Don't forget to account for token precision + const amount = (new BigNumber(burnAmount)).times(10**tokenDecimals); // Don't forget to account for token precision // 4) Get all of our token's UTXOs let inputUtxos = balances.slpTokenUtxos[tokenId]; @@ -75,14 +75,15 @@ import { BitboxNetwork, SlpBalancesResult, LocalValidator } from '../index'; inputUtxos = inputUtxos.concat(balances.nonSlpUtxos); // 6) Set the proper private key for each Utxo - inputUtxos.forEach(txo => txo.wif = fundingWif) + inputUtxos.forEach((txo) => txo.wif = fundingWif); // 7) Send token - let sendTxid = await bitboxNetwork.simpleTokenBurn( - tokenId, - amount, - inputUtxos, + const sendTxid = await bitboxNetwork.simpleTokenBurn( + tokenId, + amount, + inputUtxos, bchChangeReceiverAddress - ) - console.log("BURN txn complete:",sendTxid); + ); + + console.log("BURN txn complete:", sendTxid); })(); diff --git a/examples/2-get-txn-details-local.ts b/examples/2-get-txn-details-local.ts index 1b24dcc3..7e5f3f63 100644 --- a/examples/2-get-txn-details-local.ts +++ b/examples/2-get-txn-details-local.ts @@ -3,9 +3,9 @@ * Example 2: Fetch token details for given txid * * Instructions: - * (1) - Select Network and Address by commenting/uncommenting the desired + * (1) - Select Network and Address by commenting/un-commenting the desired * NETWORK section and providing valid BCH address. - * (2) - Select a Validation method by commenting/uncommenting the desired + * (2) - Select a Validation method by commenting/un-commenting the desired * VALIDATOR section. Chose from remote validator or local validator. * Both options rely on remote JSON RPC calls to rest.bitcoin.com. * (3) - Run `tsc && node ` just before script execution @@ -14,9 +14,9 @@ * ************************************************************************************/ import * as BITBOXSDK from "bitbox-sdk"; +import { GrpcClient } from "grpc-bchrpc-node"; import { BchdNetwork, LocalValidator } from "../index"; import { GetRawTransactionsAsync } from "../lib/localvalidator"; -import { GrpcClient } from "grpc-bchrpc-node"; const BITBOX = new BITBOXSDK.BITBOX(); const logger = console; diff --git a/examples/2-get-txn-details-trusted.ts b/examples/2-get-txn-details-trusted.ts index 6a478ae4..561a4d1e 100644 --- a/examples/2-get-txn-details-trusted.ts +++ b/examples/2-get-txn-details-trusted.ts @@ -3,9 +3,9 @@ * Example 2: Fetch token details for given txid * * Instructions: - * (1) - Select Network and Address by commenting/uncommenting the desired + * (1) - Select Network and Address by commenting/un-commenting the desired * NETWORK section and providing valid BCH address. - * (2) - Select a Validation method by commenting/uncommenting the desired + * (2) - Select a Validation method by commenting/un-commenting the desired * VALIDATOR section. Chose from remote validator or local validator. * Both options rely on remote JSON RPC calls to rest.bitcoin.com. * (3) - Run `tsc && node ` just before script execution @@ -14,16 +14,16 @@ * ************************************************************************************/ import * as BITBOXSDK from "bitbox-sdk"; +import { GrpcClient } from "grpc-bchrpc-node"; import { BchdNetwork } from "../index"; import { GetRawTransactionsAsync } from "../lib/localvalidator"; -import { GrpcClient } from "grpc-bchrpc-node"; import { TrustedValidator } from "../lib/trustedvalidator"; const BITBOX = new BITBOXSDK.BITBOX(); const logger = console; // NETWORK: FOR MAINNET COMMENT/UNCOMMENT -let txid = "c67c6423767a86e27c56ad9c04581f4500d88baff12b865611a39602f449b465"; +const txid = "c67c6423767a86e27c56ad9c04581f4500d88baff12b865611a39602f449b465"; const testnet = false; // VALIDATOR: FOR LOCAL VALIDATOR diff --git a/examples/3-genesis-token-type-1.ts b/examples/3-genesis-token-type-1.ts index da5836b5..bbdb3d0e 100644 --- a/examples/3-genesis-token-type-1.ts +++ b/examples/3-genesis-token-type-1.ts @@ -6,9 +6,9 @@ * (1) - Send some BCH to simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu * or tBCH to slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l * to fund the example. - * (2) - Select Network and Address by commenting/uncommenting the desired + * (2) - Select Network and Address by commenting/un-commenting the desired * NETWORK section and providing valid BCH address. - * (3) - Select a Validation method by commenting/uncommenting the desired + * (3) - Select a Validation method by commenting/un-commenting the desired * VALIDATOR section. Chose from remote validator or local validator. * Both options rely on remote JSON RPC calls to rest.bitcoin.com. * (4) - Run `tsc && node ` just before script execution @@ -51,14 +51,13 @@ const initialTokenQty = 1000000; // 1) Get all balances at the funding address. const balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress) as SlpBalancesResult; - console.log("'balances' variable is set."); console.log("BCH balance:", balances.satoshis_available_bch); // 2) Calculate the token quantity with decimal precision included const initialTokenQtyBN = (new BigNumber(initialTokenQty)).times(10 ** decimals); // 3) Set private keys - balances!.nonSlpUtxos.forEach(txo => txo.wif = fundingWif); + balances!.nonSlpUtxos.forEach((txo) => txo.wif = fundingWif); // 4) Use "simpleTokenGenesis()" helper method const genesisTxid = await bitboxNetwork.simpleTokenGenesis( diff --git a/examples/5-genesis-token-type-NFT1-child.ts b/examples/5-genesis-token-type-NFT1-child.ts index 4ee7512d..5f6ed173 100644 --- a/examples/5-genesis-token-type-NFT1-child.ts +++ b/examples/5-genesis-token-type-NFT1-child.ts @@ -39,7 +39,7 @@ const NFT1ParentGroupID = "240c44216936e86e624538866934c6f038a6cc4a5a83db232d735 const bchChangeReceiverAddress = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu"; // <-- cashAddr or slpAddr format // VALIDATOR SETUP: FOR REMOTE VALIDATION - const client = new GrpcClient(); + const client = new GrpcClient({ url: "bchd.greyh.at:8335" }); const getRawTransactions: GetRawTransactionsAsync = async (txids: string[]) => { const txid = txids[0]; const res = await client.getRawTransaction({ hash: txid, reversedHashOrder: true }); @@ -95,15 +95,15 @@ const NFT1ParentGroupID = "240c44216936e86e624538866934c6f038a6cc4a5a83db232d735 // 4) Use "simpleNFT1ChildGenesis()" helper method const genesisTxid = await bchdNetwork.simpleNFT1ChildGenesis( - NFT1ParentGroupID, - name, - ticker, - documentUri, - documentHash, - tokenReceiverAddress, - bchChangeReceiverAddress, - inputs, - ); + NFT1ParentGroupID, + name, + ticker, + documentUri, + documentHash, + tokenReceiverAddress, + bchChangeReceiverAddress, + inputs, + ); console.log("NFT1 Child GENESIS txn complete:", genesisTxid); })(); diff --git a/examples/6-mint-token.ts b/examples/6-mint-token.ts index d41289e6..82c30846 100644 --- a/examples/6-mint-token.ts +++ b/examples/6-mint-token.ts @@ -21,10 +21,10 @@ * * ************************************************************************************/ -import * as BITBOXSDK from "bitbox-sdk"; import { BigNumber } from "bignumber.js"; -import { BitboxNetwork, SlpBalancesResult, GetRawTransactionsAsync, LocalValidator } from "../index"; +import * as BITBOXSDK from "bitbox-sdk"; import { GetRawTransactionRequest, GrpcClient } from "grpc-bchrpc-node"; +import { BitboxNetwork, LocalValidator, SlpBalancesResult } from "../index"; (async () => { @@ -69,7 +69,6 @@ import { GetRawTransactionRequest, GrpcClient } from "grpc-bchrpc-node"; // 1) Get all balances at the funding address. const balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress) as SlpBalancesResult; - console.log("'balances' variable is set."); if (balances.slpBatonUtxos[tokenIdHexToMint]) { console.log("You have the minting baton for this token"); } else { @@ -78,7 +77,7 @@ import { GetRawTransactionRequest, GrpcClient } from "grpc-bchrpc-node"; // 2) Fetch critical token decimals information using bitdb const tokenInfo = await bitboxNetwork.getTokenInformation(tokenIdHexToMint); - const tokenDecimals = tokenInfo.decimals; + const tokenDecimals = tokenInfo.decimals; console.log("Token precision: " + tokenDecimals.toString()); // 3) Multiply the specified token quantity by 10^(token decimal precision) @@ -92,7 +91,7 @@ import { GetRawTransactionRequest, GrpcClient } from "grpc-bchrpc-node"; inputUtxos = inputUtxos.concat(balances.nonSlpUtxos); // 6) Set the proper private key for each Utxo - inputUtxos.forEach(txo => txo.wif = fundingWif); + inputUtxos.forEach((txo) => txo.wif = fundingWif); // 7) MINT token using simple function const mintTxid = await bitboxNetwork.simpleTokenMint( diff --git a/examples/7-send-token-p2pkh.ts b/examples/7-send-token-p2pkh.ts index 40ee1001..206fc732 100644 --- a/examples/7-send-token-p2pkh.ts +++ b/examples/7-send-token-p2pkh.ts @@ -69,7 +69,6 @@ import { BitboxNetwork, SlpBalancesResult, GetRawTransactionsAsync, LocalValidat // 2) Check that token balance is greater than our desired sendAmount const balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress) as SlpBalancesResult; - console.log("'balances' variable is set."); console.log(balances); if (balances.slpTokenBalances[tokenId] === undefined) { console.log("You need to fund the addresses provided in this example with tokens and BCH. Change the tokenId as required.") diff --git a/examples/8-send-token-p2sh-frozen.ts b/examples/8-send-token-p2sh-frozen.ts index e078ed75..7bc70abf 100644 --- a/examples/8-send-token-p2sh-frozen.ts +++ b/examples/8-send-token-p2sh-frozen.ts @@ -70,7 +70,6 @@ import { BitboxNetwork, SlpBalancesResult, Slp, TransactionHelpers, Utils } from // Check that token balance is greater than our desired sendAmount let balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); console.log(balances); if(balances.slpTokenBalances[tokenId] === undefined) console.log("You need to fund the addresses provided in this example with tokens and BCH. Change the tokenId as required.") diff --git a/examples/9-send-token-p2sh-multisig.ts b/examples/9-send-token-p2sh-multisig.ts index 1dc35950..076a1bfe 100644 --- a/examples/9-send-token-p2sh-multisig.ts +++ b/examples/9-send-token-p2sh-multisig.ts @@ -47,7 +47,6 @@ import { BitboxNetwork, SlpBalancesResult, Slp, TransactionHelpers } from '../in // 2) Check that token balance is greater than our desired sendAmount let fundingAddress = "simpleledger:pphnuh7dx24rcwjkj0sl6xqfyfzf23aj7udr0837gn"; let balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); - console.log("'balances' variable is set."); console.log(balances); if(balances.slpTokenBalances[tokenId] === undefined) console.log("You need to fund the addresses provided in this example with tokens and BCH. Change the tokenId as required.") diff --git a/examples/9-send-token-p2sh-p2pkh.ts b/examples/9-send-token-p2sh-p2pkh.ts new file mode 100644 index 00000000..076a1bfe --- /dev/null +++ b/examples/9-send-token-p2sh-p2pkh.ts @@ -0,0 +1,100 @@ +/*************************************************************************************** + * + * Example 9: Send any type of token using P2SH multisig + * + * Instructions: + * (1) - Select Network and Address by commenting/uncommenting the desired + * NETWORK section and providing valid BCH address. + * (2) - Select a Validation method by commenting/uncommenting the desired + * VALIDATOR section. Chose from remote validator or local validator. + * Both options rely on remote JSON RPC calls to rest.bitcoin.com. + * (3) - Run `tsc && node ` just before script execution + * (4) - Optional: Use vscode debugger w/ launch.json settings + * + * ************************************************************************************/ + +import * as BITBOXSDK from 'bitbox-sdk'; +import { BigNumber } from 'bignumber.js'; +import { BitboxNetwork, SlpBalancesResult, Slp, TransactionHelpers } from '../index'; + +(async function() { + + const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' }); + const slp = new Slp(BITBOX); + const helpers = new TransactionHelpers(slp); + + const pubkey_signer_1 = "02471e07bcf7d47afd40e0bf4f806347f9e8af4dfbbb3c45691bbaefd4ea926307"; // Signer #1 + const pubkey_signer_2 = "03472cfca5da3bf06a85c5fd860ffe911ef374cf2a9b754fd861d1ead668b15a32"; // Signer #2 + + // we have two signers for this 2-of-2 multisig address (so for the missing key we can just put "null") + const wifs = ["Ky6iiLSL2K9stMd4G5dLeXfpVKu5YRB6dhjCsHyof3eaB2cDngSr", "L2AdfmxwsYu3KnRASZ51C3UEnduUDy1b21sSF9JbLNVEPzsxEZib"] //[ "Ky6iiLSL2K9stMd4G5dLeXfpVKu5YRB6dhjCsHyof3eaB2cDngSr", null ]; + + // to keep this example alive we will just send everything to the same address + const tokenReceiverAddress = [ "simpleledger:pphnuh7dx24rcwjkj0sl6xqfyfzf23aj7udr0837gn" ]; // <-- must be simpleledger format + const bchChangeReceiverAddress = "simpleledger:pphnuh7dx24rcwjkj0sl6xqfyfzf23aj7udr0837gn"; // <-- must be simpleledger format + let tokenId = "497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"; + var sendAmounts: number[]|BigNumber[] = [ 1 ]; + + const bitboxNetwork = new BitboxNetwork(BITBOX); + + // 1) Fetch critical token information + const tokenInfo = await bitboxNetwork.getTokenInformation(tokenId); + let tokenDecimals = tokenInfo.decimals; + console.log("Token precision: " + tokenDecimals.toString()); + + // Wait for network responses... + + // 2) Check that token balance is greater than our desired sendAmount + let fundingAddress = "simpleledger:pphnuh7dx24rcwjkj0sl6xqfyfzf23aj7udr0837gn"; + let balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress); + console.log(balances); + if(balances.slpTokenBalances[tokenId] === undefined) + console.log("You need to fund the addresses provided in this example with tokens and BCH. Change the tokenId as required.") + console.log("Token balance:", balances.slpTokenBalances[tokenId].toFixed() / 10**tokenDecimals); + + // Wait for network responses... + + // 3) Calculate send amount in "Token Satoshis". In this example we want to just send 1 token unit to someone... + sendAmounts = sendAmounts.map(a => (new BigNumber(a)).times(10**tokenDecimals)); // Don't forget to account for token precision + + // 4) Get all of our token's UTXOs + let inputUtxos = balances.slpTokenUtxos[tokenId]; + + // 5) Simply sweep our BCH utxos to fuel the transaction + inputUtxos = inputUtxos.concat(balances.nonSlpUtxos); + + // 6) Estimate the additional fee for our larger p2sh scriptSigs + let extraFee = (2 * 33 + // two pub keys in each redeemScript + 2 * 72 + // two signatures in scriptSig + 10) * // for OP_CMS and various length bytes + inputUtxos.length // this many times since we swept inputs from p2sh address + + // 7) Build an unsigned transaction + let unsignedTxnHex = helpers.simpleTokenSend({ tokenId, sendAmounts, inputUtxos, tokenReceiverAddresses: tokenReceiverAddress, changeReceiverAddress: bchChangeReceiverAddress, extraFee }); + + // 8) Build scriptSigs for all intputs + let redeemData = helpers.build_P2SH_multisig_redeem_data(2, [pubkey_signer_1, pubkey_signer_2]); + let scriptSigs = inputUtxos.map((txo, i) => { + let sigData = redeemData.pubKeys.map((pk, j) => { + if(wifs[j]) { + return helpers.get_transaction_sig_p2sh(unsignedTxnHex, wifs[j]!, i, txo.satoshis, redeemData.lockingScript, redeemData.lockingScript) + } + else { + return helpers.get_transaction_sig_filler(i, pk) + } + }) + return helpers.build_P2SH_multisig_scriptSig(redeemData, i, sigData) + }) + + // 9) apply our scriptSigs to the unsigned transaction + let signedTxn = helpers.addScriptSigs(unsignedTxnHex, scriptSigs); + + // 10) OPTIONAL: Update transaction hex with input values to allow for our second signer who is using Electron Cash SLP edition (https://simpleledger.cash/project/electron-cash-slp-edition/) + //let input_values = inputUtxos.map(txo => txo.satoshis) + //signedTxn = helpers.insert_input_values_for_EC_signers(signedTxn, input_values) + + // 11) Send token + let sendTxid = await bitboxNetwork.sendTx(signedTxn) + console.log("SEND txn complete:", sendTxid); + +})();