UNPKG

syscointx-js

Version:

A transaction creation library interfacing with coin selection for Syscoin.

170 lines (159 loc) 5.02 kB
const BN = require('bn.js') const ext = require('./bn-extensions') const bitcoin = require('bitcoinjs-lib') const { ECPairFactory } = require('ecpair') const ecc = require('@bitcoinerlab/secp256k1') // Initialize ECPair with ecc const ECPair = ECPairFactory(ecc) // Initialize bitcoinjs-lib with ecc if (typeof bitcoin.initEccLib === 'function') { bitcoin.initEccLib(ecc) } const MAX_BIP125_RBF_SEQUENCE = 0xfffffffd const SYSCOIN_TX_VERSION_NEVM_DATA = 137 const SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN = 138 const SYSCOIN_TX_VERSION_SYSCOIN_BURN_TO_ALLOCATION = 139 const SYSCOIN_TX_VERSION_ALLOCATION_MINT = 140 const SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM = 141 const SYSCOIN_TX_VERSION_ALLOCATION_SEND = 142 const COIN = 100000000 const CENT = 1000000 const bitcoinNetworks = { mainnet: bitcoin.networks.bitcoin, testnet: bitcoin.networks.testnet } const syscoinNetworks = { mainnet: { messagePrefix: '\x18Syscoin Signed Message:\n', bech32: 'sys', bip32: { public: 0x0488b21e, private: 0x0488ade4 }, pubKeyHash: 0x3f, scriptHash: 0x05, wif: 0x80 }, testnet: { messagePrefix: '\x18Syscoin Signed Message:\n', bech32: 'tsys', bip32: { public: 0x043587cf, private: 0x04358394 }, pubKeyHash: 0x41, scriptHash: 0xc4, wif: 0xef } } function isNonAssetFunded (txVersion) { return txVersion === SYSCOIN_TX_VERSION_SYSCOIN_BURN_TO_ALLOCATION || txVersion === SYSCOIN_TX_VERSION_ALLOCATION_MINT } function isAllocationBurn (txVersion) { return txVersion === SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN || txVersion === SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM } function isAssetAllocationTx (txVersion) { return txVersion === SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM || txVersion === SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN || txVersion === SYSCOIN_TX_VERSION_SYSCOIN_BURN_TO_ALLOCATION || txVersion === SYSCOIN_TX_VERSION_ALLOCATION_SEND } function isSyscoinTx (txVersion) { return isAssetAllocationTx(txVersion) } function isPoDATx (txVersion) { return txVersion === SYSCOIN_TX_VERSION_NEVM_DATA } function USHRT_MAX () { return 65535 } // Amount compression: // * If the amount is 0, output 0 // * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) // * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) // * call the result n // * output 1 + 10*(9*n + d - 1) + e // * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 // (this is decodable, as d is in [1-9] and e is in [0-9]) function compressAmount (n) { if (n.isZero()) { return n } let e = 0 const tenBN = new BN(10) const nineBN = new BN(9) while ((ext.eq(ext.mod(n, tenBN), ext.BN_ZERO)) && e < 9) { n = ext.div(n, tenBN) e++ } if (e < 9) { const d = ext.mod(n, tenBN).toNumber() n = ext.div(n, tenBN) let retVal = ext.mul(n, nineBN) retVal = ext.add(retVal, new BN(d)) retVal = ext.sub(retVal, ext.BN_ONE) retVal = ext.mul(retVal, tenBN) retVal = ext.add(retVal, ext.BN_ONE) retVal = ext.add(retVal, new BN(e)) return retVal } else { let retVal = ext.sub(n, ext.BN_ONE) retVal = ext.mul(retVal, tenBN) retVal = ext.add(retVal, ext.BN_ONE) retVal = ext.add(retVal, nineBN) return retVal } } function decompressAmount (x) { // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 if (x.isZero()) { return x } const tenBN = new BN(10) const nineBN = new BN(9) x = ext.sub(x, ext.BN_ONE) // x = 10*(9*n + d - 1) + e let e = ext.mod(x, tenBN).toNumber() x = ext.div(x, tenBN) let n = ext.BN_ZERO if (e < 9) { // x = 9*n + d - 1 const d = ext.add(ext.mod(x, nineBN), ext.BN_ONE) x = ext.div(x, nineBN) // x = n n = ext.add(ext.mul(x, tenBN), d) } else { n = ext.add(x, ext.BN_ONE) } while (e > 0) { n = ext.mul(n, tenBN) e-- } return n } function signHash (WIF, hash, network) { const keyPair = ECPair.fromWIF(WIF, network) // signRecoverable returns { signature: Buffer, recoveryId: number } const sigObj = ecc.signRecoverable(hash, keyPair.privateKey) const recId = 27 + sigObj.recoveryId + (keyPair.compressed ? 4 : 0) const recIdBuffer = Buffer.allocUnsafe(1) recIdBuffer.writeInt8(recId) const rawSignature = Buffer.concat([recIdBuffer, sigObj.signature]) return rawSignature } module.exports = { compressAmount, decompressAmount, USHRT_MAX, COIN, CENT, SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN, SYSCOIN_TX_VERSION_SYSCOIN_BURN_TO_ALLOCATION, SYSCOIN_TX_VERSION_ALLOCATION_MINT, SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM, SYSCOIN_TX_VERSION_ALLOCATION_SEND, SYSCOIN_TX_VERSION_NEVM_DATA, isNonAssetFunded, isAllocationBurn, isAssetAllocationTx, isSyscoinTx, isPoDATx, signHash, MAX_BIP125_RBF_SEQUENCE, syscoinNetworks, bitcoinNetworks }