Git Product home page Git Product logo

slpjs's Introduction

SLPJS

SLPJS is a JavaScript Library for validating and building Simple Ledger Protocol (SLP) token transactions. GENESIS, MINT, and SEND token functions are supported. See change log for updates.

NPM

Table of Contents

Installation

NOTE: Using SLPJS has peer dependencies bitbox-sdk and bitcore-lib-cash, so these also need to be installed.

For node.js

npm install slpjs bitbox-sdk bitcore-lib-cash

For browser

<script src='https://unpkg.com/slpjs'></script>

NOTE: The latest version of slpjs package will be refactored to fix this problem.

Transaction Examples

The following code snippet examples can be copy/pasted directly into the node.js CLI. See the examples directory for example files written in TypeScript than can be run using tsc & node <filename>.

Wallets utilizing this library will want to write their own methods in place of the methods found in TransactionHelpers and BitboxNetwork classes.

NOTES:

  • The BigNumber.js library is used to avoid precision issues with numbers having more than 15 significant digits.
  • For the fastest validation performance all of the following transaction examples show how to use SLPJS using default SLP validation via rest.bitcoin.com. See the Local Validation section for instructions on how to validate SLP locally with your own full node.
  • All SLPJS methods require token quantities to be expressed in the smallest possible unit of account for the token (i.e., token satoshis). This requires the token's precision to be used to calculate the quantity. For example, token having a decimal precision of 9 sending an amount of 1.01 tokens would need to first calculate the sending amount using 1.01 x 10^9 => 1010000000.

Get Balances

Get all balances for a given example. See also the TypeScript example.

// Install BITBOX-SDK v8.1+ for blockchain access
// For more information visit: https://www.npmjs.com/package/bitbox-sdk
const BITBOXSDK = require('bitbox-sdk')
const slpjs = require('slpjs');

// FOR MAINNET UNCOMMENT
let addr = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";
const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' });

// FOR TESTNET UNCOMMENT
// let addr = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://trest.bitcoin.com/v2/' });

const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);

let balances;
(async function() {
  balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(addr);
  console.log("balances: ", balances);
})();

// RETURNS ALL BALANCES & UTXOs: 

// { satoshis_available_bch: 190889,
//   satoshis_locked_in_slp_baton: 546,
//   satoshis_locked_in_slp_token: 1092,
//   satoshis_in_invalid_token_dag: 0,
//   satoshis_in_invalid_baton_dag: 0,
//   slpTokenBalances: {
//      '1cda254d0a995c713b7955298ed246822bee487458cd9747a91d9e81d9d28125': BigNumber { s: 1, e: 3, c: [ 1000 ] },
//      '047918c612e94cce03876f1ad2bd6c9da43b586026811d9b0d02c3c3e910f972': BigNumber { s: 1, e: 2, c: [ 100 ] } 
//   },
//   nftParentChildBalances: {
//      'parentId1': {
//            'childId1': BigNumber
//            'childId2': BigNumber
//      }
//      'parentId2': {
//            'childId1': BigNumber
//            'childId2': BigNumber
//      }
//   }
//   slpTokenUtxos: [ ... ],
//   slpBatonUtxos: [ ... ],
//   invalidTokenUtxos: [ ... ],
//   invalidBatonUtxos: [ ... ],
//   nonSlpUtxos: [ ... ]
//   unknownTokenTypeUtxos: [ ... ]
// }

GENESIS - Create a new token

GENESIS is the most simple type of SLP transaction since no special inputs are required. The following example shows how to create a fungible token. Also see the TypeScript examples for:

// Install BITBOX-SDK v8.1+ for blockchain access
// For more information visit: https://www.npmjs.com/package/bitbox-sdk
const BITBOXSDK = require('bitbox-sdk')
const BigNumber = require('bignumber.js');
const slpjs = require('slpjs');

// FOR MAINNET UNCOMMENT
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 tokenReceiverAddress     = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";  // <-- must be simpleledger format
const bchChangeReceiverAddress = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";  // <-- cashAddr or slpAddr format
// For unlimited issuance provide a "batonReceiverAddress"
const batonReceiverAddress     = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";

// FOR TESTNET UNCOMMENT
// const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://trest.bitcoin.com/v2/' });
// const fundingAddress           = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// const fundingWif               = "cVjzvdHGfQDtBEq7oddDRcpzpYuvNtPbWdi8tKQLcZae65G4zGgy";
// const tokenReceiverAddress     = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// const bchChangeReceiverAddress = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// // For unlimited issuance provide a "batonReceiverAddress"
// const batonReceiverAddress     = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";

const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);

// 1) Get all balances at the funding address.
let balances; 
(async function() {
  balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress);
  console.log('BCH balance:', balances.satoshis_available_bch);
})();

// WAIT FOR NETWORK RESPONSE...

// 2) Select decimal precision for this new token
let decimals = 2;
let name = "Awesome SLPJS README Token";
let ticker = "SLPJS";
let documentUri = "[email protected]";
let documentHash = null
let initialTokenQty = 1000000

// 3) Calculate the token quantity with decimal precision included
initialTokenQty = (new BigNumber(initialTokenQty)).times(10**decimals);

// 4) Set private keys
balances.nonSlpUtxos.forEach(txo => txo.wif = fundingWif)

// 5) Use "simpleTokenGenesis()" helper method
let genesisTxid;
(async function(){
    genesisTxid = await bitboxNetwork.simpleTokenGenesis(
        name, 
        ticker, 
        initialTokenQty,
        documentUri,
        documentHash,
        decimals,
        tokenReceiverAddress,
        batonReceiverAddress,
        bchChangeReceiverAddress,
        balances.nonSlpUtxos
        )
    console.log("GENESIS txn complete:",genesisTxid)
})();

MINT - Create additional tokens

Adding additional tokens for a token that already exists is possible if you are in control of the minting "baton". This minting baton is a special UTXO that gives authority to add to the token's circulating supply. Also see the TypeScript example.

// Install BITBOX-SDK v8.1+ for blockchain access
// For more information visit: https://www.npmjs.com/package/bitbox-sdk
const BITBOXSDK = require('bitbox-sdk')
const BigNumber = require('bignumber.js');
const slpjs = require('slpjs');

// FOR MAINNET UNCOMMENT
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 tokenReceiverAddress     = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";  // <-- must be simpleledger format
const batonReceiverAddress     = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";
const bchChangeReceiverAddress = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";  // <-- cashAddr or slpAddr format
const tokenIdHexToMint = "adcf120f51d45056bc79353a2831ecd1843922b3d9fac5f109160bd2d49d3f4c";
let additionalTokenQty = 1000

// FOR TESTNET UNCOMMENT
// const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://trest.bitcoin.com/v2/' });
// const fundingAddress           = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// const fundingWif               = "cVjzvdHGfQDtBEq7oddDRcpzpYuvNtPbWdi8tKQLcZae65G4zGgy";
// const tokenReceiverAddress     = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// const batonReceiverAddress     = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// const bchChangeReceiverAddress = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";
// const tokenIdHexToMint = "a67e2abb2fcfaa605c6a3b0dfb642cc830b63138d85b5e95eee523fdbded4d74";
// let additionalTokenQty = 1000

const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);

// 1) Get all balances at the funding address.
let balances; 
(async function() {
  balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress);
  if(balances.slpBatonUtxos[tokenIdHexToMint])
    console.log("You have the minting baton for this token");
  else
    throw Error("You don't have the minting baton for this token");
})();

// 2) Fetch critical token decimals information using bitdb
let tokenDecimals;
(async function() {
    const tokenInfo = await bitboxNetwork.getTokenInformation(tokenIdHexToMint);
    tokenDecimals = tokenInfo.decimals; 
    console.log("Token precision: " + tokenDecimals.toString());
})();

// WAIT FOR ASYNC METHOD TO COMPLETE

// 3) Multiply the specified token quantity by 10^(token decimal precision)
let mintQty = (new BigNumber(additionalTokenQty)).times(10**tokenDecimals)

// 4) Filter the list to choose ONLY the baton of interest 
// NOTE: (spending other batons for other tokens will result in losing ability to mint those tokens)
let inputUtxos = balances.slpBatonUtxos[tokenIdHexToMint]

// 5) Simply sweep our BCH (non-SLP) utxos to fuel the transaction
inputUtxos = inputUtxos.concat(balances.nonSlpUtxos);

// 6) Set the proper private key for each Utxo
inputUtxos.forEach(txo => txo.wif = fundingWif)

// 7) MINT token using simple function
let mintTxid;
(async function() {
    mintTxid = await bitboxNetwork.simpleTokenMint(
        tokenIdHexToMint, 
        mintQty, 
        inputUtxos, 
        tokenReceiverAddress, 
        batonReceiverAddress, 
        bchChangeReceiverAddress
        )
    console.log("MINT txn complete:",mintTxid);
})();

SEND - Send tokens

This example shows the general workflow for sending an existing token. Also see the TypeScript example.

// Install BITBOX-SDK v8.1+ for blockchain access
// For more information visit: https://www.npmjs.com/package/bitbox-sdk
const BITBOXSDK = require('bitbox-sdk');
const BigNumber = require('bignumber.js');
const slpjs = require('slpjs');

// FOR MAINNET UNCOMMENT
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 tokenReceiverAddress     = [ "simpleledger:qplrqmjgpug2qrfx4epuknvwaf7vxpnuevyswakrq9" ]; // <-- must be simpleledger format
const bchChangeReceiverAddress = "simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu";     // <-- must be simpleledger format
let tokenId = "d32b4191d3f78909f43a3f5853ba59e9f2d137925f28e7780e717f4b4bfd4a3f";
let sendAmounts = [ 1 ];

// FOR TESTNET UNCOMMENT
// const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://trest.bitcoin.com/v2/' });
// const fundingAddress           = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";   // <-- must be simpleledger format
// const fundingWif               = "cVjzvdHGfQDtBEq7oddDRcpzpYuvNtPbWdi8tKQLcZae65G4zGgy"; // <-- compressed WIF format
// const tokenReceiverAddress     = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";   // <-- must be simpleledger format
// const bchChangeReceiverAddress = "slptest:qpwyc9jnwckntlpuslg7ncmhe2n423304ueqcyw80l";   // <-- must be simpleledger format
// let tokenId = "78d57a82a0dd9930cc17843d9d06677f267777dd6b25055bad0ae43f1b884091";
// let sendAmounts = [ 10 ];

const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);

// 1) Fetch critical token information
let tokenDecimals;
(async function() {
    const tokenInfo = await bitboxNetwork.getTokenInformation(tokenId);
    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 balances; 
(async function() {
  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) Set the proper private key for each Utxo
inputUtxos.forEach(txo => txo.wif = fundingWif);

// 7) Send token
let sendTxid;
(async function(){
    sendTxid = await bitboxNetwork.simpleTokenSend(
        tokenId, 
        sendAmounts, 
        inputUtxos, 
        tokenReceiverAddress, 
        bchChangeReceiverAddress
        )
    console.log("SEND txn complete:", sendTxid);
})();

SEND - Send BCH

This example demonstrates how to send BCH from a SLP enabled wallet. This API ensures the BCH transaction does not use SLP UTXOs which can cause token loss for the wallet.

// Install BITBOX-SDK v8.1+ for blockchain access
// For more information visit: https://www.npmjs.com/package/bitbox-sdk
const BITBOXSDK = require('bitbox-sdk');
const BigNumber = require('bignumber.js');
const slpjs = require('slpjs');

// FOR MAINNET
const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' });
const fundingAddress           = "bitcoincash:qzq6g2dzadew2ctt6cfhthwcc2q9m60mj56ld2hj5l";     // <-- must be CashAddr format

// can use BITBOX.HDNode.toWIF() to generate this
const fundingWif               = "KzzMBS6twjSLAjH3a1wkd7rWs3PpiHq4eQzqSEfHuxbXfxYFUBiL";        // <-- compressed WIF format
const bchReceiverAddress       = [ "bitcoincash:qz42xz5y2hfltsa94mwm36pnl3ew8u72cc9l038x8m" ]; // <-- must be CashAddr format
const bchChangeReceiverAddress = "bitcoincash:qzd5hqnlu2gprdxphqt6jvft33s3m2hegcqtu6mktg";     // <-- must be CashAddr format

let sendAmountsInSatoshi       = 1000;


const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);


// 1) Check that token balance is greater than our desired sendAmount
let balances; 
(async function() {
  balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress);
  
  if (balances.satoshis_available_bch < sendAmountsInSatoshi) {
    throw new Error("You need to fund the addresses provided in this example with BCH.");
  }
  console.log("BCH balance in sats:", balances.satoshis_available_bch);
})();

// Wait for network responses...

// 2) construct sendAmounts as an array of BigInt
let sendAmounts = [ new BigInt(sendAmountsInSatoshi) ];

// 3) Get all of non-SLP UTXOs
let inputUtxos = balances.nonSlpUtxos;

// 4) Set the proper private key for each Utxo
inputUtxos = inputUtxos.map(utxo => ({ ...utxo, wif: fundingWif }));

// 5) Send token
let sendTxId;
(async () => {
  sendTxId = await bitboxNetwork.simpleBchSend(
    sendAmounts, 
    inputUtxos, 
    bchReceiverAddress, 
    bchChangeReceiverAddress
  );
  console.log("SEND txn complete:", sendTxId);
})();

SEND - Send tokens from a frozen address

This example shows how to freeze funds until a future time using OP_CLTV. Also see the TypeScript example. First, the address is calculated based on a user-defined public key and locktime. After the locktime has elapsed the user can proceed to spend those funds as demonstrated in this example:

redeemScript (locking script) = <locktime> OP_CHECKLOCKTIMEVERIFY OP_DROP <pubkey> OP_CHECKSIG

unlocking script = <signature>

const BITBOXSDK = require('bitbox-sdk');
const BigNumber = require('bignumber.js');
const slpjs = require('slpjs');
const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://trest.bitcoin.com/v2/' });
const slp = new slpjs.Slp(BITBOX);
const helpers = new slpjs.TransactionHelpers(slp);
const opcodes = BITBOX.Script.opcodes;

const pubkey = "0286d74c6fb92cb7b70b817094f48bf8fd398e64663bc3ddd7acc0a709212b9f69";
const wif = "cPamRLmPyuuwgRAbB6JHhXvrGwvHtmw9LpVi8QnUZYBubCeyjgs1";
const tokenReceiverAddress     = [ "slptest:prk685k6r508xkj7u9g8v9p3f97hrmgr2qp7r4safs" ]; // <-- must be simpleledger format
const bchChangeReceiverAddress = "slptest:prk685k6r508xkj7u9g8v9p3f97hrmgr2qp7r4safs";     // <-- must be simpleledger format
let tokenId = "f0c7a8a7addc29edbc193212057d91c3eb004678e15e4662773146bdd51f8d7a";
let sendAmounts = [ 1 ];

// Set our BIP-113 time lock (subtract an hour to acount for MTP-11)
const time_delay_seconds = 0;  // let's just set it to 0 so we can redeem it immediately.
let locktime, locktimeBip62;
(async function(){
  locktime = (await BITBOX.Blockchain.getBlockchainInfo()).mediantime + time_delay_seconds - 3600;

  // NOTE: the following locktime is hard-coded so that we can reuse the same P2SH address.
  locktimeBip62 = 'c808f05c' //slpjs.Utils.get_BIP62_locktime_hex(locktime);  
})();

// Wait for network response...

let redeemScript = BITBOX.Script.encode([
  Buffer.from(locktimeBip62, 'hex'),
  opcodes.OP_CHECKLOCKTIMEVERIFY,
  opcodes.OP_DROP,
  Buffer.from(pubkey, 'hex'),
  opcodes.OP_CHECKSIG
])

// Calculate the address for this script contract 
// We need to send some token and BCH to it before we can spend it!
let fundingAddress = slpjs.Utils.slpAddressFromHash160(
                              BITBOX.Crypto.hash160(redeemScript), 
                              'testnet', 
                              'p2sh'
                            );

// gives us: slptest:prk685k6r508xkj7u9g8v9p3f97hrmgr2qp7r4safs

const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);

// Fetch critical token information
let tokenDecimals;
(async function() {
    const tokenInfo = await bitboxNetwork.getTokenInformation(tokenId);
    tokenDecimals = tokenInfo.decimals; 
    console.log("Token precision: " + tokenDecimals.toString());
})();

// Wait for network response...

// Check that token balance is greater than our desired sendAmount
let balances; 
(async function() {
  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 response...

// 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

// Get all of our token's UTXOs
let inputUtxos = balances.slpTokenUtxos[tokenId];

// Simply sweep our BCH utxos to fuel the transaction
inputUtxos = inputUtxos.concat(balances.nonSlpUtxos);

// Estimate the additional fee for our larger p2sh scriptSigs
let extraFee = (8) *  // for OP_CTLV and timelock data push
                inputUtxos.length  // this many times since we swept inputs from p2sh address

// Build an unsigned transaction
let unsignedTxnHex = helpers.simpleTokenSend(tokenId, sendAmounts, inputUtxos, tokenReceiverAddress, bchChangeReceiverAddress, [], extraFee);
unsignedTxnHex = helpers.enableInputsCLTV(unsignedTxnHex);
unsignedTxnHex = helpers.setTxnLocktime(unsignedTxnHex, locktime);

// Build scriptSigs 
let scriptSigs = inputUtxos.map((txo, i) => {
    let sigObj = helpers.get_transaction_sig_p2sh(unsignedTxnHex, wif, i, txo.satoshis, redeemScript)
    return {
      index: i,
      lockingScriptBuf: redeemScript,
      unlockingScriptBufArray: [ sigObj.signatureBuf ]
  } 
})

let signedTxn = helpers.addScriptSigs(unsignedTxnHex, scriptSigs);

// 11) Send token
let sendTxid;
(async function(){
    sendTxid = await bitboxNetwork.sendTx(signedTxn)
    console.log("SEND txn complete:", sendTxid);
})();

SEND - Send tokens from 2-of-2 multisig (P2SH)

This example shows the general workflow for sending tokens from a P2SH multisig address. Also see the TypeScript example. Electron Cash SLP edition 3.4.13 is compatible with signing the partially signed transactions generated from this example by using the insert_input_values_for_EC_signers helper method.

// Install BITBOX-SDK v8.1+ for blockchain access
// For more information visit: https://www.npmjs.com/package/bitbox-sdk
const BITBOXSDK = require('bitbox-sdk');
const BigNumber = require('bignumber.js');
const slpjs = require('slpjs');
const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' });
const slp = new slpjs.Slp(BITBOX);
const helpers = new slpjs.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 just put "null")
const wifs = [ null, "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";
let sendAmounts = [ 1 ];

const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);

// 1) Fetch critical token information
let tokenDecimals;
(async function() {
    const tokenInfo = await bitboxNetwork.getTokenInformation(tokenId);
    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; 
(async function() {
  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, tokenReceiverAddress, 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)
      }
      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) 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;
(async function(){
    sendTxid = await bitboxNetwork.sendTx(signedTxn)
    console.log("SEND txn complete:", sendTxid);
})();

BURN - Destroy tokens for a certain Token Id

This example shows the general workflow for sending an existing token. Also see the TypeScript example.

// Install BITBOX-SDK v8.1+ for blockchain access
// For more information visit: https://www.npmjs.com/package/bitbox-sdk
const BITBOXSDK = require('bitbox-sdk')
const BigNumber = require('bignumber.js');
const slpjs = require('slpjs');

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 = "495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a";
let burnAmount = 102;

const bitboxNetwork = new slpjs.BitboxNetwork(BITBOX);

// 1) Fetch critical token information
let tokenDecimals;
(async function() {
    const tokenInfo = await bitboxNetwork.getTokenInformation(tokenId);
    tokenDecimals = tokenInfo.decimals; 
    console.log('Token precision:', tokenDecimals.toString());
})();

// 2) Check that token balance is greater than our desired sendAmount
let balances; 
(async function() {
  balances = await bitboxNetwork.getAllSlpBalancesAndUtxos(fundingAddress);
  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...
let 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];

// 5) Simply sweep our BCH utxos to fuel the transaction
inputUtxos = inputUtxos.concat(balances.nonSlpUtxos);

// 6) Set the proper private key for each Utxo
inputUtxos.forEach(txo => txo.wif = fundingWif)

// 7) Send token
let sendTxid;
(async function(){
    sendTxid = await bitboxNetwork.simpleTokenBurn(
        tokenId, 
        amount, 
        inputUtxos, 
        bchChangeReceiverAddress
        )
    console.log("BURN txn complete:",sendTxid);
})();

Address Conversion

let Utils = require('slpjs').Utils;

let slpAddr = Utils.toSlpAddress("bitcoincash:qzat5lfxt86mtph2fdmp96stxdmmw8hchyxrcmuhqf");
console.log(slpAddr);
// simpleledger:qzat5lfxt86mtph2fdmp96stxdmmw8hchy2cnqfh7h

let cashAddr = Utils.toCashAddress(slpAddr);
console.log(cashAddr);
// bitcoincash:qzat5lfxt86mtph2fdmp96stxdmmw8hchyxrcmuhqf

Validation Examples

The following examples show three different ways how you can use this library to validate SLP transactions. The validation techniques include:

  • Local Validator with a JSON RPC full node connection
  • Local Validation with a remote full node (using rest.bitcoin.com)
  • Remote Validation (using rest.bitcoin.com)

Local Validator with a JSON RPC full node connection

Validate SLP transaction locally with a local full node.

const BITBOXSDK = require('bitbox-sdk')
const BITBOX = new BITBOXSDK.BITBOX();
const slpjs = require('slpjs');
const logger = console;
const RpcClient = require('bitcoin-rpc-promise');
const connectionString = 'http://bitcoin:password@localhost:8332'
const rpc = new RpcClient(connectionString);
const slpValidator = new slpjs.LocalValidator(BITBOX, async (txids) => [ await rpc.getRawTransaction(txids[0]) ], logger)

// Result = false
//let txid = "903432f451049357d51c19eb529478621272e7572b05179f89bcb7be31e55aa7";

// Result = true
let txid = "4a3829d6da924a16bbc0cc43d5d62b40996648a0c8f74725c15ec56ee930d0fa";

let isValid;
(async function() {
  console.log("Validating:", txid);
  console.log("This may take a several seconds...");
  isValid = await slpValidator.isValidSlpTxid(txid);
  console.log("Final Result:", isValid);
})();

Local Validation with a remote full node (using rest.bitcoin.com)

Validate SLP transaction locally with a remote full node (i.e., rest.bitcoin.com).

const BITBOXSDK = require('bitbox-sdk')
const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' });
const slpjs = require('slpjs');
const logger = console;

const getRawTransactions = async function(txids) { return await BITBOX.RawTransactions.getRawTransaction(txids) }
const slpValidator = new slpjs.LocalValidator(BITBOX, getRawTransactions, logger);

// Result = false
//let txid = "903432f451049357d51c19eb529478621272e7572b05179f89bcb7be31e55aa7";

// Result = true
let txid = "4a3829d6da924a16bbc0cc43d5d62b40996648a0c8f74725c15ec56ee930d0fa";

let isValid;
(async function() {
  console.log("Validating:", txid);
  console.log("This may take a several seconds...");
  isValid = await slpValidator.isValidSlpTxid(txid);
  console.log("Final Result:", isValid);
})();

Remote Validation (using rest.bitcoin.com)

Validate SLP transaction using rest.bitcoin.com.

const BITBOXSDK = require('bitbox-sdk')
const BITBOX = new BITBOXSDK.BITBOX({ restURL: 'https://rest.bitcoin.com/v2/' });
const slpjs = require('slpjs');
const logger = console;

const slpValidator = new slpjs.BitboxNetwork(BITBOX, undefined, logger);

// Result = false
//let txid = "903432f451049357d51c19eb529478621272e7572b05179f89bcb7be31e55aa7";

// Result = true
let txid = "ab1550876e217d68bfac55e50b4a82535bb20842f976bdfbc07cca19e8028f13";

let isValid;
(async function() {
  console.log("Validating:", txid);
  console.log("This may take a several seconds...");
  isValid = await slpValidator.isValidSlpTxid(txid);
  console.log("Final Result:", isValid);
})();

Building & Testing

Building this project creates lib/*.js files and then creates browserified versions in the dist folder.

Requirements

Running the unit tests require node.js v8.15+.

Build

npm run build

Test

npm run test

Change Log

0.27.9

  • Updates for creating and sending NFT1 group and children token types

0.27.8

  • Simplify BchdValidator behavior and API

0.27.7

  • Add BchdValidator class for leveraging BCHD SLP indexer

0.27.6

  • Update BchdNetwork to use an interface for gRPC client
  • Note: 0.27.5 was skipped due to an error during publishing

0.27.4

  • Fixed false positive edge case for NFT child GENESIS validation using new SLP unit test vectors

0.27.3

  • Update packages
  • Minor updates to token send example
  • Remove extraneous regex checks
  • Add flag to disable validator transaction cache in LocalValidator

0.27.2

  • Fixed false positive case for MINT validation

0.27.1

  • Updated for trusted validator
  • Specify

0.27.0

  • Update slp.ts internals to accept validator instead of network
  • Add TrustedValidator class and example

0.26.0

  • Utilizing simpleledger/slp-mdm package, update associated unit tests
  • Update BigNumber library

0.25.6

  • Update unit tests and examples for bchd based network
  • Patch missing tokenIdHex in getTokenInformation after recent refactoring

0.25.4/5

  • Typings fixes

0.25.3

  • Typings update for bitcore-cash-lib
  • Update mocha version and settings

0.25.2

  • Update typings for bitcore-cash-lib

0.25.1

  • Update typings for BchdNetwork

0.25.0

  • Make bitcore-lib-cash a peer dependency to prevent conflicting version issues
  • Breaking change: processUtxosForSlpAbstract now has getRawTransaction method parameter
  • Add TrustedValidator class for remote validation
  • Add BchdNetwork class, as an alternative to BitboxNetwork class

0.24.3

  • Include extra baton/receiver sats in mint/genesis change calculation

0.24.0

  • breaking change: use destructured parameters in txn helpers
  • Truncate all decimals in satoshis value

0.23.1

  • Update retrieveRawTransaction method in slp validator

0.23.0

  • (breaking change) Enable "esModuleInterop" in tsconfig.json to align with default tsc --init settings
  • Update bitbox-sdk to 8.11.1

0.22.3

  • Upgrade TransactionHelpers.simpleTokenMint and Slp.buildRawMintTx for p2sh compatibility

0.22.2

  • Publish *.d.ts files instead of *.ts files
  • Update types for bitbox-sdk

0.22.1

  • Update bitbox-sdk to latest version
  • Add toRegtestAddress method in Utils
  • Added bitbox-sdk to peerDependency list in package.json
  • Added missing typings modules to vendors.d.ts (for bitbox)

0.22.0

  • Update bchaddr-slp package (adds "regtest:" compatibility)
  • Add TransactionOutput interface to primatives.ts
  • Updated unit tests with "allow_inconclusive" on missing tranasaction
  • More linting
  • (breaking change) Update applyInitialSlpJudgement (to be able to work with non-BITBOX sources of utxo data)

0.21.4

  • Fixed a critical security vulnerability in the validation message parser
  • Add ts linting / allow json comments

0.21.3

  • Judge NFT1 child created directly from valid NFT1 Parent Genesis as valid
  • Removed map files from npm package module

0.21.2

  • Export bitcore

0.21.1

  • Fix local validator cache for SLPDB (bug should have only impacted SLPDB application performance)
  • Updated examples with more validation options

0.21.0

  • Added new code examples for NFT1 Genesis Parent and Child (see examples directory)
  • Updated Genesis/Mint/Send methods for handling new token types appropriately
  • Breaking: Removed old NFT1 methods from v0.15.12, these were likely never used by anyone but bumping the version just in case.

0.20.5

  • Fix accounting for unknown token type UTXOs in SlpBalancesResult by adding satoshis_in_unknown_token_type and unknownTokenTypeUtxos objects.

0.20.4

  • Now NFT Parents/Children are readily visible when using getAllSlpBalancesAndUtxos(<address>)
    • Add nftParentChildBalances dict/map to SlpBalancesResult.
    • Add nftParentId property to each SLP UTXO object (in type SlpAddressUtxoResult).
  • Created an examples directory, starting to mirror/migrate README examples to this folder. This will allow easier execution of the examples when they are in TypeScript

0.20.3

  • Bump version for npm issue with previous version

0.20.2

  • Export Primatives namespace
  • Add 'Primatives.parseFromBuffer()' method
  • Remove unused typing from vendors.d.ts
  • Update dependency versions to address security flags

0.20.1

  • Minor typings update

0.20.0

  • Added full NFT1 validation support with updates to both the validator and parser.
  • Critical Issue Fixed: This version fixed a critical bug associated with unsupported token types. All previous versions will allow unsupported token types to be burned because they are treated as if they are non-SLP UTXOs. This version includes a new type of UTXO judgement for unsupported token types (UNSUPPORTED_TYPE), and they any UTXO receiving this judgement is prevented from being spent in the built-in transaction methods.
  • Added more descriptive code commenting to localvalidator.ts.

0.19.0

  • Breaking Change: Added initial NFT1 validation support (not yet activated in parser). Change is breaking due to new tokenTypeFilter parameter in method isValidSlpTxid()

0.18.4

  • Tweaked type for ScriptSigP2SH.unlockingScriptBufArray

0.18.3

  • Added simpleTokenGenesis to bitbox network class

0.18.2

  • Added example for freezing tokens
  • Added Locktime and CLTV helper methods to TransactionHelpers
  • Added get_BIP62_locktime_hex method to Utils
  • Breaking Change: Updated Slp.buildSendOpReturn, Slp.buildMintOpReturn, and Slp.buildGenesisOpReturn methods to static

0.18.1

  • Added generic support for P2SH
  • Added specific helper methods for multisig compatible with Electron Cash signing
  • Added README example for multisig w/ Electron Cash SLP co-signer

0.18.0

  • Added simpleledger: URI scheme parser & builder to Utils class per spec
  • Removed unused remote proxy validator code
  • Bumped Bitbox dep to v8.1 with TypeScript updates

0.17.0

  • Breaking changes:
    • Dev dependency BITBOX updated to latestest version 8.0.1 from 3.0.11
    • Throws on network error instead of returning null/false
  • Non-breaking changes:
    • Added tests for BitboxNetwork class
    • added "decimalConversion" parameter to getTransactionDetails() and getTokenInformation() methods in BitboxNetwork, default is false

0.16.3

  • Added slp address to getTransactionDetails() response

0.16.2

  • Added optional logger to LocalValidator & BitboxNetwork classes
  • Fixed bug in default remote validation for BitboxNetwork.isValidSlpTxid()
  • Added comments warning users about two rate limited methods

0.16.1

  • Improved error messages for insufficient inputs and fee too low

0.16.0

  • Breaking changes:
    • For all types of SEND transactions the change address must be provided, and the change address must be in simpleledger address format since it may contain token change.
  • Non-breaking changes:
    • Added new vout property to validation parents in LocalValidator class
    • Added change log to readme.md
    • Refactored transaction builder methods into a new class called TransactionHelpers

0.15.13

  • Fixed issue in isSlpAddress where it would throw instead of return false on some inputs.
  • Added isLegacyAddress, toLegacy, and slpAddressFromHash160 methods to Utils class.

0.15.12

  • Add transaction helper methods for NFT1

0.15.11

  • validate chunks of 20 with bitcoin.com validator endpoint

0.15.10

  • handle array object type response from sendRawTransaction method in BitboxNetwork class

0,15.9

  • Add default remote validation for BitboxNetwork
  • Simplified all README examples to use default validator
  • Add description for how to override the default validator

slpjs's People

Contributors

blockparty-sh avatar dependabot[bot] avatar gubatron avatar jcramer avatar maikelmclauflin avatar p0o avatar paool avatar rawb0t avatar spendbch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slpjs's Issues

Throwing error while using simpleTokenSend function

I'm using a transaction very similar to the example on the Readme to send a SLP token (or NFT). The same transaction works pretty well on v0.24.0 but it will burn the NFT because there is no support for it in that version. So I upgraded to v.27.11 which by semver versioning shouldn't have any backward incompatibility but same transaction doesn't work anymore and throw this error:

Uncaught (in promise) TypeError: "list" argument must be an Array of Buffers
    concat index.js:399
    pushdata util.js:8
    createOpReturnSend util.js:152
    send tokentype1.js:7
    buildSendOpReturn slptokentype1.js:50
    buildSendOpReturn slp.js:128
    simpleTokenSend transactionhelpers.js:90
    simpleTokenSend bitboxnetwork.js:260
    step bitboxnetwork.js:52
    verb bitboxnetwork.js:33
    __awaiter bitboxnetwork.js:27
    __awaiter bitboxnetwork.js:23
    simpleTokenSend bitboxnetwork.js:255
    _callee2$ transactions.js:101
    Babel 14
    sendSlpTx transactions.js:57

Apparently the problem is with slp_mdm_1.TokenType1.send(tokenIdHex, outputQtyArray); and new slp-mdm library because on versions before addition of this, same tx is working fine. Any ideas?

npm install slpjs facing errors

I have node version running 12.8.2
During installation of slpjs and all other related packages facing the following error

image

Help required..

Post Office-like state

Is it possible to get a transaction into a state similar to what Vin Armani proposes with a Post Office, i.e. to get inputs and outputs of SLP signed, then serialize the transaction to hex and unserialize it server-side, add BCH inputs to pay for the fee.

I looked at buildRawSendTx, it's nearly possible to build a tx with signed SLP inputs/outputs only, as I see it, but it seems that it'll throw Error("Transaction input BCH amount is too low. Add more BCH inputs to fund this transaction.");, but even if that's avoidable by creating a copy of buildRawSendTx - let's say I serialize the TX to hex, is there a way to unserialize it from hex back to TransactionBuilder at the server-side (let's assume node.js + slp) to add the BCH inputs?

Also are there plans to support Post Offices officially in slpjs?

Any guidance would be greatly appreciated! Thank you!

SLPJS fails to get token UTXOs

I'm still investigating this issue. This GitHub Issue will be used to track the data as I uncover the root-cause. I've followed the trail to slpjs and suspect the issue I'm seeing is caused by the switch to SLPDB v1.

Overview

The slp-sdk e2e test recently started failing, with the error Could not find any SLP token UTXOs. The error is originating from this line in the slp-sdk send() method of the TokenType1.ts library.

That bitboxNetwork.getTokenInformation(tokenId) call is returning a query from SLPDB with the slpTokenUtxos property as an empty object for an address that does have a token UTXO. This is ultimately what is causing the error.

I'm not familiar with the slpjs code base. It appears to be calling Bitcore? Then makes a query SLPDB. I can't seem to follow the code at this point.

I suspect that the root cause of this issue is one of two possible sources:

  • Changes we've recently made to rest.bitcoin.com to switch the SLP endpoints to use SLPDB v1.
  • Changes in SLPDB v1 that no longer support whatever query is being made.

I've updated slp-sdk to use the latest version slpjs (v0.24.3) with no change.

Unit Tests call Network

One of the things I'm a stickler on is that unit tests not make network calls. The primary differences between unit and integration tests, is that unit tests do not call external services. External services need to be mocked for unit tests, and live for integration tests.

If unit tests make external calls, then any CI system relying on unit tests will fail when those services fail, and then bad things happen. The reliability of the CI system is thrown into question and the ability to push a fix fails if the CI can't pass tests and validate the PR.

I ran all tests on slpjs and they passed. But then I turned off my wifi and ran the tests again. The following tests failed:

165 passing (113ms)
  12 failing

  1) BitdbNetwork
       getTokenInformation()
         returns token information for a given valid tokenId:
     Error: getaddrinfo ENOTFOUND bitdb.bch.sx bitdb.bch.sx:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  2) BitdbNetwork
       getTokenInformation()
         throws when tokeId is not found:

      AssertionError [ERR_ASSERTION]: 'getaddrinfo ENOTFOUND bitdb.bch.sx bitdb.bch.sx:443' == 'Token not found'
      + expected - actual

      -getaddrinfo ENOTFOUND bitdb.bch.sx bitdb.bch.sx:443
      +Token not found
      
      at Context.it (test/bitdbnetwork.js:36:24)
      at process._tickCallback (internal/process/next_tick.js:68:7)

  3) JsonRpcProxyValidator
       mainnet isValidSlpTxid()
         returns true for a valid SEND token transaction:
     Error: getaddrinfo ENOTFOUND validate.simpleledger.info validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  4) JsonRpcProxyValidator
       mainnet isValidSlpTxid()
         returns false for an unknown txid:
     Error: getaddrinfo ENOTFOUND validate.simpleledger.info validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  5) JsonRpcProxyValidator
       mainnet isValidSlpTxid()
         returns true for MINT transaction:
     Error: getaddrinfo ENOTFOUND validate.simpleledger.info validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  6) JsonRpcProxyValidator
       mainnet validateSlpTransactions()
         works for valid SEND token transactions:
     Error: getaddrinfo ENOTFOUND validate.simpleledger.info validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  7) JsonRpcProxyValidator
       mainnet validateSlpTransactions()
         works for invalid SEND token transactions:
     Error: getaddrinfo ENOTFOUND validate.simpleledger.info validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  8) JsonRpcProxyValidator
       testnet isValidSlpTxid()
         returns true for a valid SEND token transaction:
     Error: getaddrinfo ENOTFOUND testnet-validate.simpleledger.info testnet-validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  9) JsonRpcProxyValidator
       testnet isValidSlpTxid()
         returns false for an unknown txid:
     Error: getaddrinfo ENOTFOUND testnet-validate.simpleledger.info testnet-validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  10) JsonRpcProxyValidator
       testnet isValidSlpTxid()
         returns true for MINT transaction:
     Error: getaddrinfo ENOTFOUND testnet-validate.simpleledger.info testnet-validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  11) JsonRpcProxyValidator
       testnet validateSlpTransactions()
         works for valid SEND token transactions:
     Error: getaddrinfo ENOTFOUND testnet-validate.simpleledger.info testnet-validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)

  12) JsonRpcProxyValidator
       testnet validateSlpTransactions()
         works for invalid SEND token transactions:
     Error: getaddrinfo ENOTFOUND testnet-validate.simpleledger.info testnet-validate.simpleledger.info:443
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)



npm ERR! Test failed.  See above for more details.

Question about prospect of this project

Hi @jcramer
I'm planning to create a pull request for this project.
Since this project relies on bitbox.js which is unmaintained/deprecate.
So I was wondering if there a plan to continue to maintain this project going forward?
Thank

Token change issue

static async sendToken(tokenId, sendAmount, fundingAddress, fundingWif, tokenReceiverAddress, bchChangeReceiverAddress){

There are two issues with the bitboxnetwork.sendToken() method.

  1. When token change is 0 there is a dust output still created to receive 0 tokens.
  2. Address for receiving the token change should be the same as the bchChangeAddress parameter
  3. Rename the bchChangeAddress parameter so that it is clear that both token change and bch change are going back to this address.

Also, if this isn't provided where does the change go? The funding address?

test failed

It looks like an error that fails to handle bignumber.js, but I don't know how to deal with it.

I didn't understand the relationship between slpjs and spl-mdm, so I posted it here.


git clone https://github.com/simpleledger/slpjs.git
yarn install
yarn test

that log >>

lib/slptokentype1.ts:36:41 - error TS2345: Argument of type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default' is not assignable to parameter of type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default'.
Types have separate declarations of a private property '_isBigNumber'.

36 initialQuantity
~~~~~~~~~~~~~~~

lib/slptokentype1.ts:57:41 - error TS2345: Argument of type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default' is not assignable to parameter of type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default'.

57 initialQuantity
~~~~~~~~~~~~~~~

lib/slptokentype1.ts:72:52 - error TS2345: Argument of type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default[]' is not assignable to parameter of type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default[]'.
Type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default' is not assignable to type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default'.

72 return TokenType1.send(tokenIdHex, outputQtyArray);
~~~~~~~~~~~~~~

lib/slptokentype1.ts:80:52 - error TS2345: Argument of type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default[]' is not assignable to parameter of type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default[]'.

80 return NFT1.Child.send(tokenIdHex, outputQtyArray);
~~~~~~~~~~~~~~

lib/slptokentype1.ts:82:52 - error TS2345: Argument of type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default[]' is not assignable to parameter of type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default[]'.

82 return NFT1.Group.send(tokenIdHex, outputQtyArray);
~~~~~~~~~~~~~~

lib/slptokentype1.ts:91:63 - error TS2345: Argument of type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default' is not assignable to parameter of type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default'.

91 return TokenType1.mint(tokenIdHex, batonVout, mintQuantity);
~~~~~~~~~~~~

lib/slptokentype1.ts:95:63 - error TS2345: Argument of type 'import("/Users/jasagiri/src/slpjs/node_modules/bignumber.js/bignumber").default' is not assignable to parameter of type 'import("/Users/jasagiri/src/slpjs/node_modules/slp-mdm/node_modules/bignumber.js/bignumber").default'.

95 return NFT1.Group.mint(tokenIdHex, batonVout, mintQuantity);
~~~~~~~~~~~~

Found 7 errors.

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Is simpleBchSend reliable to be used?

is simpleBchSend function reliable to be used? I noticed it's not documented so wanted to ask if there is a reason?

I guess as far as I could understand it does not filter the utxos and should be supplied with the array item of nonSlpUtxos from getAllSlpBalancesAndUtxos(). Am I correct?

Can I decouple this from bitbox network?

Is it possible to use the util functions in this library to judge the UTXOs that I receive from other nodes? For example from BCHD or insomnia which gives you indexed UTXOs.

Websockets

I'd like to listen for token transactions using the API at slpdb. Is this the library that would enable that? I cannot find documentation for this

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.