swap-bch-js
Version:
Signal, Watch and Pay (SWaP) Protocol on the Bitcoin Cash blockchain
1 lines • 1.25 MB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.swapBchJs=f()}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){let bfp=require("./lib/bfp");let swp=require("./lib/swp");let utils=require("./lib/utils");let network=require("./lib/network");module.exports={bfp:bfp,swp:swp,utils:utils,network:network}},{"./lib/bfp":2,"./lib/network":5,"./lib/swp":6,"./lib/utils":7}],2:[function(require,module,exports){(function(Buffer){let utils=require("./utils");let Network=require("./network");let Bitdb=require("./bitdb");let bchrpc=require("grpc-bchrpc-node");const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));class Bfp{constructor(BITBOX,network="mainnet",grpcUrl=null){this.BITBOX=BITBOX;this.networkstring=network;this.network=new Network(this.BITBOX,grpcUrl);this.bitdb=new Bitdb(network);if(grpcUrl)this.client=new bchrpc.GrpcClient(grpcUrl);else this.client=new bchrpc.GrpcClient}static get lokadIdHex(){return"42465000"}async uploadHashOnlyObject(type,fundingUtxo,fundingAddress,fundingWif,objectDataArrayBuffer,objectName=null,objectExt=null,prevObjectSha256Hex=null,objectExternalUri=null,objectReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null){console.log("objectDataArrayBuffer",objectDataArrayBuffer);let fileSize=objectDataArrayBuffer.byteLength;let hash=this.BITBOX.Crypto.sha256(new Buffer(objectDataArrayBuffer)).toString("hex");let chunkCount=0;let configEmptyMetaOpReturn={msgType:type,chunkCount:chunkCount,fileName:objectName,fileExt:objectExt,fileSize:fileSize,fileSha256Hex:hash,prevFileSha256Hex:prevObjectSha256Hex,fileUri:objectExternalUri,chunkData:null};let transactions=[];let txid=fundingUtxo.txid;let satoshis=fundingUtxo.satoshis;let vout=fundingUtxo.vout;let metaOpReturn=Bfp.buildMetadataOpReturn(configEmptyMetaOpReturn);let configMetaTx={bfpMetadataOpReturn:metaOpReturn,input_utxo:{txid:txid,vout:vout,satoshis:satoshis,wif:fundingWif},fileReceiverAddress:objectReceiverAddress!=null?objectReceiverAddress:fundingAddress};let metaTx=this.buildMetadataTx(configMetaTx);transactions.push(metaTx);if(signProgressCallback!=null){signProgressCallback(100)}if(signFinishedCallback!=null){signFinishedCallback()}if(uploadProgressCallback!=null){uploadProgressCallback(0)}console.log("transaction: ",transactions[0].toHex());var bfTxId=await this.network.sendTxWithRetry(transactions[0].toHex());if(uploadProgressCallback!=null){uploadProgressCallback(100)}bfTxId="bitcoinfile:"+bfTxId;if(uploadFinishedCallback!=null){uploadFinishedCallback(bfTxId)}return bfTxId}async uploadFolderHashOnly(fundingUtxo,fundingAddress,fundingWif,folderDataArrayBuffer,folderName=null,folderExt=null,prevFolderSha256Hex=null,folderExternalUri=null,folderReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null){return await this.uploadHashOnlyObject(3,fundingUtxo,fundingAddress,fundingWif,folderDataArrayBuffer,folderName,folderExt,prevFolderSha256Hex,folderExternalUri,folderReceiverAddress,signProgressCallback,signFinishedCallback,uploadProgressCallback,uploadFinishedCallback)}async uploadFileHashOnly(fundingUtxo,fundingAddress,fundingWif,fileDataArrayBuffer,fileName=null,fileExt=null,prevFileSha256Hex=null,fileExternalUri=null,fileReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null){return await this.uploadHashOnlyObject(1,fundingUtxo,fundingAddress,fundingWif,fileDataArrayBuffer,fileName,fileExt,prevFileSha256Hex,fileExternalUri,fileReceiverAddress,signProgressCallback,signFinishedCallback,uploadProgressCallback,uploadFinishedCallback)}async uploadFile(fundingUtxo,fundingAddress,fundingWif,fileDataArrayBuffer,fileName=null,fileExt=null,prevFileSha256Hex=null,fileExternalUri=null,fileReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null,delay_ms=500){let fileSize=fileDataArrayBuffer.byteLength;let hash=this.BITBOX.Crypto.sha256(new Buffer(fileDataArrayBuffer)).toString("hex");let chunks=[];let chunkCount=Math.floor(fileSize/220);for(let nId=0;nId<chunkCount;nId++){chunks.push(fileDataArrayBuffer.slice(nId*220,(nId+1)*220))}if(fileSize%220){chunks[chunkCount]=fileDataArrayBuffer.slice(chunkCount*220,fileSize);chunkCount++}let configEmptyMetaOpReturn={msgType:1,chunkCount:chunkCount,fileName:fileName,fileExt:fileExt,fileSize:fileSize,fileSha256Hex:hash,prevFileSha256Hex:prevFileSha256Hex,fileUri:fileExternalUri,chunkData:null};let transactions=[];let nDiff=100/chunkCount;let nCurPos=0;for(let nId=0;nId<chunkCount;nId++){let chunkOpReturn=Bfp.buildDataChunkOpReturn(chunks[nId]);let txid="";let satoshis=0;let vout=1;if(nId===0){txid=fundingUtxo.txid;satoshis=fundingUtxo.satoshis;vout=fundingUtxo.vout}else{txid=transactions[nId-1].getId();satoshis=transactions[nId-1].outs[1].value}let configChunkTx={bfpChunkOpReturn:chunkOpReturn,input_utxo:{address:fundingAddress,txid:txid,vout:vout,satoshis:satoshis,wif:fundingWif}};let chunksTx=this.buildChunkTx(configChunkTx);if(nId===chunkCount-1){let emptyOpReturn=Bfp.buildMetadataOpReturn(configEmptyMetaOpReturn);let capacity=223-emptyOpReturn.length;if(capacity>=chunks[nId].byteLength){let configMetaOpReturn={msgType:1,chunkCount:chunkCount,fileName:fileName,fileExt:fileExt,fileSize:fileSize,fileSha256Hex:hash,prevFileSha256Hex:prevFileSha256Hex,fileUri:fileExternalUri,chunkData:chunks[nId]};let metaOpReturn=Bfp.buildMetadataOpReturn(configMetaOpReturn);let configMetaTx={bfpMetadataOpReturn:metaOpReturn,input_utxo:{txid:txid,vout:vout,satoshis:satoshis,wif:fundingWif},fileReceiverAddress:fileReceiverAddress!=null?fileReceiverAddress:fundingAddress};let metaTx=this.buildMetadataTx(configMetaTx);transactions.push(metaTx)}else{transactions.push(chunksTx);let metaOpReturn=Bfp.buildMetadataOpReturn(configEmptyMetaOpReturn);let configMetaTx={bfpMetadataOpReturn:metaOpReturn,input_utxo:{txid:chunksTx.getId(),vout:vout,satoshis:chunksTx.outs[1].value,wif:fundingWif},fileReceiverAddress:fileReceiverAddress!=null?fileReceiverAddress:fundingAddress};let metaTx=this.buildMetadataTx(configMetaTx);transactions.push(metaTx)}}else{transactions.push(chunksTx)}if(signProgressCallback!=null){signProgressCallback(nCurPos)}nCurPos+=nDiff}if(signFinishedCallback!=null){signFinishedCallback()}nDiff=100/transactions.length;nCurPos=0;if(uploadProgressCallback!=null){uploadProgressCallback(0)}for(let nId=0;nId<transactions.length;nId++){console.log("transaction: ",transactions[nId].toHex());var bfTxId=await this.network.sendTxWithRetry(transactions[nId].toHex());if(uploadProgressCallback!=null){uploadProgressCallback(nCurPos)}nCurPos+=nDiff;await sleep(delay_ms)}bfTxId="bitcoinfile:"+bfTxId;if(uploadFinishedCallback!=null){uploadFinishedCallback(bfTxId)}return bfTxId}async downloadFile(bfpUri,progressCallback=null){let chunks=[];let size=0;let txid=bfpUri.replace("bitcoinfile:","");txid=txid.replace("bitcoinfiles:","");let tx=await this.client.getTransaction({hash:txid,reversedHashOrder:true});let prevHash=Buffer.from(tx.getTransaction().getInputsList()[0].getOutpoint().getHash_asU8()).toString("hex");let metadata_opreturn_hex=Buffer.from(tx.getTransaction().getOutputsList()[0].getPubkeyScript_asU8()).toString("hex");let bfpMsg=this.parsebfpDataOpReturn(metadata_opreturn_hex);let downloadCount=bfpMsg.chunk_count;if(bfpMsg.chunk_count>0&&bfpMsg.chunk!=null){downloadCount=bfpMsg.chunk_count-1;chunks.push(bfpMsg.chunk);size+=bfpMsg.chunk.length}for(let index=0;index<downloadCount;index++){let tx=await this.client.getTransaction({hash:prevHash});prevHash=Buffer.from(tx.getTransaction().getInputsList()[0].getOutpoint().getHash_asU8()).toString("hex");let op_return_hex=Buffer.from(tx.getTransaction().getOutputsList()[0].getPubkeyScript_asU8()).toString("hex");let bfpMsg=this.parsebfpDataOpReturn(op_return_hex);chunks.push(bfpMsg.chunk);size+=bfpMsg.chunk.length;if(progressCallback!=null){progressCallback(index/(downloadCount-1))}}chunks=chunks.reverse();let fileBuf=new Buffer.alloc(size);let index=0;chunks.forEach(chunk=>{chunk.copy(fileBuf,index);index+=chunk.length});let passesHashCheck=false;if(bfpMsg.sha256!=null){let fileSha256=this.BITBOX.Crypto.sha256(fileBuf);let res=Buffer.compare(fileSha256,bfpMsg.sha256);if(res===0){passesHashCheck=true}}return{passesHashCheck:passesHashCheck,fileBuf:fileBuf}}static buildMetadataOpReturn(config){let script=[];script.push(106);let lokadId=Buffer.from(Bfp.lokadIdHex,"hex");script.push(utils.getPushDataOpcode(lokadId));lokadId.forEach(item=>script.push(item));script.push(utils.getPushDataOpcode([config.msgType]));script.push(config.msgType);let chunkCount=utils.int2FixedBuffer(config.chunkCount,1);script.push(utils.getPushDataOpcode(chunkCount));chunkCount.forEach(item=>script.push(item));if(config.fileName==null||config.fileName.length===0||config.fileName==""){[76,0].forEach(item=>script.push(item))}else{let fileName=Buffer.from(config.fileName,"utf8");script.push(utils.getPushDataOpcode(fileName));fileName.forEach(item=>script.push(item))}if(config.fileExt==null||config.fileExt.length===0||config.fileExt==""){[76,0].forEach(item=>script.push(item))}else{let fileExt=Buffer.from(config.fileExt,"utf8");script.push(utils.getPushDataOpcode(fileExt));fileExt.forEach(item=>script.push(item))}let fileSize=utils.int2FixedBuffer(config.fileSize,2);script.push(utils.getPushDataOpcode(fileSize));fileSize.forEach(item=>script.push(item));var re=/^[0-9a-fA-F]+$/;if(config.fileSha256Hex==null||config.fileSha256Hex.length===0||config.fileSha256Hex==""){[76,0].forEach(item=>script.push(item))}else if(config.fileSha256Hex.length===64&&re.test(config.fileSha256Hex)){let fileSha256Buf=Buffer.from(config.fileSha256Hex,"hex");script.push(utils.getPushDataOpcode(fileSha256Buf));fileSha256Buf.forEach(item=>script.push(item))}else{throw Error("File hash must be provided as a 64 character hex string")}if(config.prevFileSha256Hex==null||config.prevFileSha256Hex.length===0||config.prevFileSha256Hex==""){[76,0].forEach(item=>script.push(item))}else if(config.prevFileSha256Hex.length===64&&re.test(config.prevFileSha256Hex)){let prevFileSha256Buf=Buffer.from(config.prevFileSha256Hex,"hex");script.push(utils.getPushDataOpcode(prevFileSha256Buf));prevFileSha256Buf.forEach(item=>script.push(item))}else{throw Error("Previous File hash must be provided as a 64 character hex string")}if(config.fileUri==null||config.fileUri.length===0||config.fileUri==""){[76,0].forEach(item=>script.push(item))}else{let fileUri=Buffer.from(config.fileUri,"utf8");script.push(utils.getPushDataOpcode(fileUri));fileUri.forEach(item=>script.push(item))}if(config.chunkData==null||config.chunkData.length===0){[76,0].forEach(item=>script.push(item))}else{let chunkData=Buffer.from(config.chunkData);script.push(utils.getPushDataOpcode(chunkData));chunkData.forEach(item=>script.push(item))}let encodedScript=utils.encodeScript(script);if(encodedScript.length>223){throw Error("Script too long, must be less than 223 bytes.")}return encodedScript}static buildDataChunkOpReturn(chunkData){let script=[];script.push(106);if(chunkData===undefined||chunkData===null||chunkData.length===0){[76,0].forEach(item=>script.push(item))}else{let chunkDataBuf=Buffer.from(chunkData);script.push(utils.getPushDataOpcode(chunkDataBuf));chunkDataBuf.forEach(item=>script.push(item))}let encodedScript=utils.encodeScript(script);if(encodedScript.length>223){throw Error("Script too long, must be less than 223 bytes.")}return encodedScript}buildFundingTx(config){let transactionBuilder;if(this.networkstring==="mainnet")transactionBuilder=new this.BITBOX.TransactionBuilder("bitcoincash");else transactionBuilder=new this.BITBOX.TransactionBuilder("bchtest");let satoshis=0;config.input_utxos.forEach(token_utxo=>{transactionBuilder.addInput(token_utxo.txid,token_utxo.vout);satoshis+=token_utxo.satoshis});let fundingMinerFee=this.BITBOX.BitcoinCash.getByteCount({P2PKH:config.input_utxos.length},{P2PKH:1});let outputAmount=satoshis-fundingMinerFee;transactionBuilder.addOutput(config.outputAddress,outputAmount);let i=0;for(const txo of config.input_utxos){let paymentKeyPair=this.BITBOX.ECPair.fromWIF(txo.wif);transactionBuilder.sign(i,paymentKeyPair,null,transactionBuilder.hashTypes.SIGHASH_ALL,txo.satoshis);i++}return transactionBuilder.build()}buildChunkTx(config){let transactionBuilder;if(this.networkstring==="mainnet")transactionBuilder=new this.BITBOX.TransactionBuilder("bitcoincash");else transactionBuilder=new this.BITBOX.TransactionBuilder("bchtest");transactionBuilder.addInput(config.input_utxo.txid,config.input_utxo.vout);let chunkTxFee=this.calculateDataChunkMinerFee(config.bfpChunkOpReturn.length);let outputAmount=config.input_utxo.satoshis-chunkTxFee;transactionBuilder.addOutput(config.bfpChunkOpReturn,0);transactionBuilder.addOutput(config.input_utxo.address,outputAmount);let paymentKeyPair=this.BITBOX.ECPair.fromWIF(config.input_utxo.wif);transactionBuilder.sign(0,paymentKeyPair,null,transactionBuilder.hashTypes.SIGHASH_ALL,config.input_utxo.satoshis);return transactionBuilder.build()}buildMetadataTx(config){let transactionBuilder;if(this.networkstring==="mainnet")transactionBuilder=new this.BITBOX.TransactionBuilder("bitcoincash");else transactionBuilder=new this.BITBOX.TransactionBuilder("bchtest");let inputSatoshis=0;transactionBuilder.addInput(config.input_utxo.txid,config.input_utxo.vout);inputSatoshis+=config.input_utxo.satoshis;let metadataFee=this.calculateMetadataMinerFee(config.bfpMetadataOpReturn.length);let output=inputSatoshis-metadataFee;transactionBuilder.addOutput(config.bfpMetadataOpReturn,0);let outputAddress=this.BITBOX.Address.toCashAddress(config.fileReceiverAddress);transactionBuilder.addOutput(outputAddress,output);let paymentKeyPair=this.BITBOX.ECPair.fromWIF(config.input_utxo.wif);transactionBuilder.sign(0,paymentKeyPair,null,transactionBuilder.hashTypes.SIGHASH_ALL,config.input_utxo.satoshis);return transactionBuilder.build()}calculateMetadataMinerFee(genesisOpReturnLength,feeRate=1){let fee=this.BITBOX.BitcoinCash.getByteCount({P2PKH:1},{P2PKH:1});fee+=genesisOpReturnLength;fee+=10;fee*=feeRate;return fee}calculateDataChunkMinerFee(sendOpReturnLength,feeRate=1){let fee=this.BITBOX.BitcoinCash.getByteCount({P2PKH:1},{P2PKH:1});fee+=sendOpReturnLength;fee+=10;fee*=feeRate;return fee}static calculateFileUploadCost(fileSizeBytes,configMetadataOpReturn,fee_rate=1){let byte_count=fileSizeBytes;let whole_chunks_count=Math.floor(fileSizeBytes/220);let last_chunk_size=fileSizeBytes%220;let final_op_return_no_chunk=Bfp.buildMetadataOpReturn(configMetadataOpReturn);byte_count+=final_op_return_no_chunk.length;byte_count+=35;byte_count+=148+1;byte_count+=(whole_chunks_count+1)*3;if(!Bfp.chunk_can_fit_in_final_opreturn(final_op_return_no_chunk.length,last_chunk_size)){byte_count+=149+35;byte_count+=16}byte_count+=35*whole_chunks_count;byte_count+=(148+1)*whole_chunks_count;byte_count+=22*(whole_chunks_count+1);let dust_amount=546;return byte_count*fee_rate+dust_amount}static chunk_can_fit_in_final_opreturn(script_length,chunk_data_length){if(chunk_data_length===0){return true}let op_return_capacity=223-script_length;if(op_return_capacity>=chunk_data_length){return true}return false}parsebfpDataOpReturn(hex){const script=this.BITBOX.Script.toASM(Buffer.from(hex,"hex")).split(" ");let bfpData={};bfpData.type="metadata";if(script.length==2){bfpData.type="chunk";try{bfpData.chunk=Buffer.from(script[1],"hex")}catch(e){bfpData.chunk=null}return bfpData}if(script[0]!="OP_RETURN"){throw new Error("Not an OP_RETURN")}if(script[1]!==Bfp.lokadIdHex){throw new Error("Not a BFP OP_RETURN")}if(script[2]!="OP_1"){throw new Error("Not a BFP file (type 0x01)")}bfpData.chunk_count=parseInt(script[3],16);if(script[3].includes("OP_")){let val=script[3].replace("OP_","");bfpData.chunk_count=parseInt(val)}if(script[4]=="OP_0"){bfpData.filename=null}else{bfpData.filename=Buffer.from(script[4],"hex").toString("utf8")}if(script[5]=="OP_0"){bfpData.fileext=null}else{bfpData.fileext=Buffer.from(script[5],"hex").toString("utf8")}if(script[6]=="OP_0"){bfpData.filesize=null}else{bfpData.filesize=parseInt(script[6],16)}if(script[7]=="OP_0"){bfpData.sha256=null}else{bfpData.sha256=Buffer.from(script[7],"hex")}if(script[8]=="OP_0"){bfpData.prevsha256=null}else{bfpData.prevsha256=Buffer.from(script[8],"hex")}if(script[9]=="OP_0"){bfpData.uri=null}else{bfpData.uri=Buffer.from(script[9],"hex").toString("utf8")}if(script[10]=="OP_0"){bfpData.chunk=null}else{try{bfpData.chunk=Buffer.from(script[10],"hex")}catch(e){bfpData.chunk=null}}return bfpData}}module.exports=Bfp}).call(this,require("buffer").Buffer)},{"./bitdb":3,"./network":5,"./utils":7,buffer:38,"grpc-bchrpc-node":43}],3:[function(require,module,exports){(function(Buffer){const axios=require("axios");module.exports=class BfpBitdb{constructor(network){this.bitDbUrl=network==="mainnet"?"https://bitdb.bitcoin.com/q/":"https://tbitdb.bitcoin.com/q/"}async getFileMetadata(txid,apiKey=null){txid=txid.replace("bitcoinfile:","");txid=txid.replace("bitcoinfiles:","");let query={v:3,q:{find:{"tx.h":txid,"out.h1":"42465000","out.h2":"01"}},r:{f:'[ .[] | { timestamp: (if .blk? then (.blk.t | strftime("%Y-%m-%d %H:%M")) else null end), chunks: .out[0].h3, filename: .out[0].s4, fileext: .out[0].s5, size: .out[0].h6, sha256: .out[0].h7, prev_sha256: .out[0].h8, ext_uri: .out[0].s9, URI: "bitcoinfile:\\(.tx.h)" } ]'}};const json_str=JSON.stringify(query);const data=Buffer.from(json_str).toString("base64");const response=(await axios({method:"GET",url:this.bitDbUrl+data,headers:null,json:true})).data;if(response.status==="error"){throw new Error(response.message||"API error message missing")}const list=[];if(response.c){list.push(...response.c)}if(response.u){list.push(...response.u)}if(list.length===0){throw new Error("File not found")}console.log("bitdb response: ",list[0]);return list[0]}}}).call(this,require("buffer").Buffer)},{axios:10,buffer:38}],4:[function(require,module,exports){(function(Buffer){const axios=require("axios");const utils=require("./utils");module.exports=class BfpBitdb{constructor(network){this.bitDbUrl=network==="mainnet"?"https://bitdb.bitcoin.com/q/":"https://tbitdb.bitcoin.com/q/";this.jqQueries={signal:[{f:'[ .[] | { timestamp: (if .blk? then (.blk.t | strftime("%Y-%m-%d %H:%M")) else null end), tokenId: .out[0].h4, buyOrSell: .out[0].s5, rate: .out[0].h6, reserves: .out[0].h7, exactUtxos: .out[0].h8, minSatsToExchange: .out[0].h9, URI: "swap:\\(.tx.h)" } ]'},{f:'[ .[] | { timestamp: (if .blk? then (.blk.t | strftime("%Y-%m-%d %H:%M")) else null end), oracleBfp: "bitcoinfiles:\\(.out[0].h4)", contractTermsIndex: .out[0].h5, contractPartyIndex: .out[0].h6, compilerId: .out[0].s7, CompilerVersion: .out[0].s8, pubKey: .out[0].h9, appendedScriptPubKey: .out[0].h10, appendedSats: .out[0].h11, URI: "swap:\\(.tx.h)" } ]'}]};this.qQuery={find:{"out.h1":"53575000"}}}async getSignalMetadata(msgType,txid=null,tokenOrOracleId=null,apiKey=null){let jqQuery=this.jqQueries.signal[msgType-1];let qQuery=JSON.parse(JSON.stringify(this.qQuery));qQuery.find["out.h2"]="01";qQuery.find["out.h3"]=utils.int2FixedBuffer(msgType,1).toString("hex");if(txid)qQuery.find["tx.h"]=txid.replace("swap:","");else if(!txid&&tokenOrOracleId){qQuery.find["out.h4"]=tokenOrOracleId}let metadata=await this.getFileMetadata(qQuery,jqQuery,apiKey);for(let i=0;i<metadata.length;i++){if(msgType==1){metadata[i].rate=parseInt(metadata[i].rate,16);metadata[i].reserves=metadata[i].reserves=="01"?true:false;metadata[i].exactUtxos=metadata[i].exactUtxos=="01"?true:false;metadata[i].minSatsToExchange=parseInt(metadata[i].minSatsToExchange,16)}else if(msgType==2){metadata[i].contractTermsIndex=parseInt(metadata[i].contractTermsIndex,16),metadata[i].contractPartyIndex=parseInt(metadata[i].contractPartyIndex,16);metadata[i].appendedSats=parseInt(metadata[i].appendedSats,16)}}if(qQuery.find["tx.h"])return metadata[0];return metadata}async getFileMetadata(qQuery,jqQuery=null,apiKey=null){if(!jqQuery)jqQuery={f:'[ .[] | { timestamp: (if .blk? then (.blk.t | strftime("%Y-%m-%d %H:%M")) else null end), offer_txid: .out[0].h4, URI: "swap:\\(.tx.h)" } ]'};let query={v:3,q:qQuery,r:jqQuery};const json_str=JSON.stringify(query);const data=Buffer.from(json_str).toString("base64");const response=(await axios({method:"GET",url:this.bitDbUrl+data,headers:null,json:true})).data;if(response.status==="error"){throw new Error(response.message||"API error message missing")}const list=[];if(response.c){list.push(...response.c)}if(response.u){list.push(...response.u)}if(list.length===0){throw new Error("File not found")}return list}}}).call(this,require("buffer").Buffer)},{"./utils":7,axios:10,buffer:38}],5:[function(require,module,exports){let bchrpc=require("grpc-bchrpc-web");const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));class BfpNetwork{constructor(BITBOX,grpcUrl="https://bchd.greyh.at:8335"){this.BITBOX=BITBOX;this.stopPayMonitor=false;this.isMonitoringPayment=false;if(grpcUrl)this.client=new bchrpc.Client(grpcUrl);else this.client=new bchrpc.Client}async getLastUtxoWithRetry(address,retries=40){let result;let count=0;while(result==undefined){result=await this.getLastUtxo(address);console.log(result);count++;if(count>retries)throw new Error("BITBOX.Address.utxo endpoint experienced a problem");await sleep(250)}return result}async getTransactionDetailsWithRetry(txid,retries=40){let result;let count=0;while(result==undefined){result=await this.BITBOX.Transaction.details(txid);count++;if(count>retries)throw new Error("BITBOX.Address.details endpoint experienced a problem");await sleep(250)}return result}async getLastUtxo(address){if(!this.BITBOX.Address.isCashAddress(address)&&!this.BITBOX.Address.isLegacyAddress(address))throw new Error("Not an a valid address format, must be cashAddr or Legacy address format.");let res=(await this.BITBOX.Address.utxo([address]))[0];if(res&&res.utxos&&res.utxos.length>0)return res.utxos[0];return res}async sendTx(hex,log=true){let res=await this.BITBOX.RawTransactions.sendRawTransaction(hex);if(res&&res.error)return undefined;if(res==="64: too-long-mempool-chain")throw new Error("Mempool chain too long");if(log)console.log("sendTx() res: ",res);return res}async sendTxWithRetry(hex,retries=40){let res;let count=0;while(res===undefined||res.length!=64){res=await this.sendTx(hex);count++;if(count>retries)break;await sleep(250)}if(res.length!=64)throw new Error("BITBOX network error");return res}async monitorForPayment(paymentAddress,fee,onPaymentCB){if(this.isMonitoringPayment||this.stopPayMonitor)return;this.isMonitoringPayment=true;if(!this.BITBOX.Address.isCashAddress(paymentAddress)&&!this.BITBOX.Address.isLegacyAddress(paymentAddress))throw new Error("Not an a valid address format, must be cashAddr or Legacy address format.");while(true){try{var utxo=await this.getLastUtxo(paymentAddress);if(utxo&&utxo&&utxo.satoshis>=fee&&utxo.confirmations===0){break}}catch(ex){console.log("monitorForPayment() error: ",ex)}if(this.stopPayMonitor){this.isMonitoringPayment=false;return}await sleep(2e3)}this.isMonitoringPayment=false;onPaymentCB(utxo)}}module.exports=BfpNetwork},{"grpc-bchrpc-web":47}],6:[function(require,module,exports){(function(Buffer){let utils=require("./utils");let Network=require("./network");let Bitdb=require("./bitdbSwp");let bchrpc=require("grpc-bchrpc-node");const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));class Swp{constructor(BITBOX,network="mainnet",grpcUrl=null){this.BITBOX=BITBOX;this.networkstring=network;this.network=new Network(this.BITBOX,grpcUrl);this.bitdb=new Bitdb(network);if(grpcUrl)this.client=new bchrpc.GrpcClient(grpcUrl);else this.client=new bchrpc.GrpcClient}static get lokadIdHex(){return"53575000"}async uploadSignal(msgType,fundingUtxo,fundingAddress,fundingWif,dataObj,objectReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null){let msgClass=1;let configEmptyMetaOpReturn={msgClass:1,msgType:msgType};if(msgType==1){configEmptyMetaOpReturn.buyOrSell=dataObj.buyOrSell;configEmptyMetaOpReturn.tokenId=dataObj.tokenId;configEmptyMetaOpReturn.rate=dataObj.rate;configEmptyMetaOpReturn.reserve=dataObj.reserve?1:0;configEmptyMetaOpReturn.exactUtxos=dataObj.exactUtxos?1:0;configEmptyMetaOpReturn.minSatsToExchange=dataObj.minSatsToExchange?dataObj.minSatsToExchange:0}else if(msgType==2){configEmptyMetaOpReturn.oracleBfp=dataObj.oracleBfp;configEmptyMetaOpReturn.contractTermsIndex=dataObj.contractTermsIndex;configEmptyMetaOpReturn.contractPartyIndex=dataObj.contractPartyIndex;configEmptyMetaOpReturn.compilerId=dataObj.compilerId;configEmptyMetaOpReturn.compilerVersion=dataObj.compilerVersion;configEmptyMetaOpReturn.pubKey=dataObj.pubKey;configEmptyMetaOpReturn.appendedScriptPubKey=dataObj.appendedScriptPubKey?dataObj.appendedScriptPubKey:null;configEmptyMetaOpReturn.appendedSats=dataObj.appendedSats?dataObj.appendedSats:0}let transactions=[];let txid=fundingUtxo.txid;let satoshis=fundingUtxo.satoshis;let vout=fundingUtxo.vout;let metaOpReturn=Swp.buildMetadataOpReturn(configEmptyMetaOpReturn);let configMetaTx={bfpMetadataOpReturn:metaOpReturn,input_utxo:{txid:txid,vout:vout,satoshis:satoshis,wif:fundingWif},fileReceiverAddress:objectReceiverAddress!=null?objectReceiverAddress:fundingAddress};let metaTx=this.buildMetadataTx(configMetaTx);transactions.push(metaTx);if(signProgressCallback!=null){signProgressCallback(100)}if(signFinishedCallback!=null){signFinishedCallback()}if(uploadProgressCallback!=null){uploadProgressCallback(0)}console.log("transaction: ",transactions[0].toHex());var bfTxId=await this.network.sendTxWithRetry(transactions[0].toHex());if(uploadProgressCallback!=null){uploadProgressCallback(100)}bfTxId="swap:"+bfTxId;if(uploadFinishedCallback!=null){uploadFinishedCallback(bfTxId)}return bfTxId}async uploadFolderHashOnly(fundingUtxo,fundingAddress,fundingWif,folderDataArrayBuffer,folderName=null,folderExt=null,prevFolderSha256Hex=null,folderExternalUri=null,folderReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null){return await this.uploadHashOnlyObject(3,fundingUtxo,fundingAddress,fundingWif,folderDataArrayBuffer,folderName,folderExt,prevFolderSha256Hex,folderExternalUri,folderReceiverAddress,signProgressCallback,signFinishedCallback,uploadProgressCallback,uploadFinishedCallback)}async uploadFileHashOnly(fundingUtxo,fundingAddress,fundingWif,fileDataArrayBuffer,fileName=null,fileExt=null,prevFileSha256Hex=null,fileExternalUri=null,fileReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null){return await this.uploadHashOnlyObject(1,fundingUtxo,fundingAddress,fundingWif,fileDataArrayBuffer,fileName,fileExt,prevFileSha256Hex,fileExternalUri,fileReceiverAddress,signProgressCallback,signFinishedCallback,uploadProgressCallback,uploadFinishedCallback)}async uploadPayment(fundingUtxo,fundingAddress,fundingWif,fileDataArrayBuffer,fileSha256Hex=null,fileReceiverAddress=null,signProgressCallback=null,signFinishedCallback=null,uploadProgressCallback=null,uploadFinishedCallback=null,delay_ms=500){let fileSize=fileDataArrayBuffer.byteLength;let chunks=[];let chunkCount=Math.floor(fileSize/220);for(let nId=0;nId<chunkCount;nId++){chunks.push(fileDataArrayBuffer.slice(nId*220,(nId+1)*220))}if(fileSize%220){chunks[chunkCount]=fileDataArrayBuffer.slice(chunkCount*220,fileSize);chunkCount++}let configEmptyMetaOpReturn={msgClass:1,msgType:1,fileSize:fileSize,chunkCount:chunkCount,fileSha256Hex:fileSha256Hex,chunkData:null};let transactions=[];let nDiff=100/chunkCount;let nCurPos=0;for(let nId=0;nId<chunkCount;nId++){let chunkOpReturn=Swp.buildDataChunkOpReturn(chunks[nId]);let txid="";let satoshis=0;let vout=1;if(nId===0){txid=fundingUtxo.txid;satoshis=fundingUtxo.satoshis;vout=fundingUtxo.vout}else{txid=transactions[nId-1].getId();satoshis=transactions[nId-1].outs[1].value}let configChunkTx={bfpChunkOpReturn:chunkOpReturn,input_utxo:{address:fundingAddress,txid:txid,vout:vout,satoshis:satoshis,wif:fundingWif}};let chunksTx=this.buildChunkTx(configChunkTx);if(nId===chunkCount-1){let emptyOpReturn=Swp.buildMetadataOpReturn(configEmptyMetaOpReturn);let capacity=223-emptyOpReturn.length;if(capacity>=chunks[nId].byteLength){let configMetaOpReturn={msgType:1,fileSize:fileSize,chunkCount:chunkCount,fileSha256Hex:fileSha256Hex,chunkData:chunks[nId]};let metaOpReturn=Swp.buildMetadataOpReturn(configMetaOpReturn);let configMetaTx={bfpMetadataOpReturn:metaOpReturn,input_utxo:{txid:txid,vout:vout,satoshis:satoshis,wif:fundingWif},fileReceiverAddress:fileReceiverAddress!=null?fileReceiverAddress:fundingAddress};let metaTx=this.buildMetadataTx(configMetaTx);transactions.push(metaTx)}else{transactions.push(chunksTx);let metaOpReturn=Swp.buildMetadataOpReturn(configEmptyMetaOpReturn);let configMetaTx={bfpMetadataOpReturn:metaOpReturn,input_utxo:{txid:chunksTx.getId(),vout:vout,satoshis:chunksTx.outs[1].value,wif:fundingWif},fileReceiverAddress:fileReceiverAddress!=null?fileReceiverAddress:fundingAddress};let metaTx=this.buildMetadataTx(configMetaTx);transactions.push(metaTx)}}else{transactions.push(chunksTx)}if(signProgressCallback!=null){signProgressCallback(nCurPos)}nCurPos+=nDiff}if(signFinishedCallback!=null){signFinishedCallback()}nDiff=100/transactions.length;nCurPos=0;if(uploadProgressCallback!=null){uploadProgressCallback(0)}for(let nId=0;nId<transactions.length;nId++){console.log("transaction: ",transactions[nId].toHex());var bfTxId=await this.network.sendTxWithRetry(transactions[nId].toHex());if(uploadProgressCallback!=null){uploadProgressCallback(nCurPos)}nCurPos+=nDiff;await sleep(delay_ms)}bfTxId="swap:"+bfTxId;if(uploadFinishedCallback!=null){uploadFinishedCallback(bfTxId)}return bfTxId}async downloadFile(bfpUri,progressCallback=null){let chunks=[];let size=0;let txid=bfpUri.replace("bitcoinswap:","");let tx=await this.client.getTransaction({hash:txid,reversedHashOrder:true});let prevHash=Buffer.from(tx.getTransaction().getInputsList()[0].getOutpoint().getHash_asU8()).toString("hex");let metadata_opreturn_hex=Buffer.from(tx.getTransaction().getOutputsList()[0].getPubkeyScript_asU8()).toString("hex");let bfpMsg=this.parsebfpDataOpReturn(metadata_opreturn_hex);let downloadCount=bfpMsg.chunk_count;if(bfpMsg.chunk_count>0&&bfpMsg.chunk!=null){downloadCount=bfpMsg.chunk_count-1;chunks.push(bfpMsg.chunk);size+=bfpMsg.chunk.length}for(let index=0;index<downloadCount;index++){let tx=await this.client.getTransaction({hash:prevHash});prevHash=Buffer.from(tx.getTransaction().getInputsList()[0].getOutpoint().getHash_asU8()).toString("hex");let op_return_hex=Buffer.from(tx.getTransaction().getOutputsList()[0].getPubkeyScript_asU8()).toString("hex");let bfpMsg=this.parsebfpDataOpReturn(op_return_hex);chunks.push(bfpMsg.chunk);size+=bfpMsg.chunk.length;if(progressCallback!=null){progressCallback(index/(downloadCount-1))}}chunks=chunks.reverse();let fileBuf=new Buffer.alloc(size);let index=0;chunks.forEach(chunk=>{chunk.copy(fileBuf,index);index+=chunk.length});let passesHashCheck=true;return{passesHashCheck:passesHashCheck,fileBuf:fileBuf}}static buildMetadataOpReturn(config){let script=[];let re=/^[0-9a-fA-F]+$/;script.push(106);let lokadId=Buffer.from(Swp.lokadIdHex,"hex");script.push(utils.getPushDataOpcode(lokadId));lokadId.forEach(item=>script.push(item));script.push(utils.getPushDataOpcode([config.msgClass]));script.push(config.msgClass);script.push(utils.getPushDataOpcode([config.msgType]));script.push(config.msgType);if(config.msgClass==1){if(config.msgType==1){if(config.tokenId==null||config.tokenId.length===0||config.tokenId==""){[76,0].forEach(item=>script.push(item))}else if(config.tokenId.length===64&&re.test(config.tokenId)){let tokenIdBuf=Buffer.from(config.tokenId,"hex");script.push(utils.getPushDataOpcode(tokenIdBuf));tokenIdBuf.forEach(item=>script.push(item))}else{throw Error("Token Id must be provided as a 64 character hex string")}let validActions=["BUY","SELL"];let action=config.buyOrSell.toUpperCase();if(validActions.includes(action)){let buyOrSell=Buffer.from(action,"utf8");script.push(utils.getPushDataOpcode(buyOrSell));buyOrSell.forEach(item=>script.push(item))}else{throw Error("Action must be either BUY or SELL")}let rate=utils.int2FixedBuffer(config.rate,1);script.push(utils.getPushDataOpcode(rate));rate.forEach(item=>script.push(item));let reserves=utils.int2FixedBuffer(config.reserve,1);script.push(utils.getPushDataOpcode(reserves));reserves.forEach(item=>script.push(item));let exactUtxos=utils.int2FixedBuffer(config.exactUtxos,1);script.push(utils.getPushDataOpcode(exactUtxos));exactUtxos.forEach(item=>script.push(item));let minExchange=utils.int2FixedBuffer(config.minSatsToExchange,1);script.push(utils.getPushDataOpcode(minExchange));minExchange.forEach(item=>script.push(item))}else if(config.msgType==2){if(config.oracleBfp.length===64&&re.test(config.oracleBfp)){let oracleBfpBuf=Buffer.from(config.oracleBfp,"hex");script.push(utils.getPushDataOpcode(oracleBfpBuf));oracleBfpBuf.forEach(item=>script.push(item))}else{throw Error("Oracle BFP hash must be provided as a 64 character hex string")}let terms=utils.int2FixedBuffer(config.contractTermsIndex,1);script.push(utils.getPushDataOpcode(terms));terms.forEach(item=>script.push(item));let party=utils.int2FixedBuffer(config.contractPartyIndex,1);script.push(utils.getPushDataOpcode(party));party.forEach(item=>script.push(item));let compiler=Buffer.from(config.compilerId,"utf8");script.push(utils.getPushDataOpcode(compiler));compiler.forEach(item=>script.push(item));let compilerContract=Buffer.from(config.compilerVersion,"utf8");script.push(utils.getPushDataOpcode(compilerContract));compilerContract.forEach(item=>script.push(item));if(re.test(config.pubKey)){let oraclePubKey=Buffer.from(config.pubKey,"hex");script.push(utils.getPushDataOpcode(oraclePubKey));oraclePubKey.forEach(item=>script.push(item))}else{throw Error("Oracle public key must be a hex string")}if(config.appendedScriptPubKey==null||config.appendedScriptPubKey.length===0||config.appendedScriptPubKey==""){[76,0].forEach(item=>script.push(item))}else if(re.test(config.appendedScriptPubKey)){let appendedScriptPubKey=Buffer.from(config.appendedScriptPubKey,"hex");script.push(utils.getPushDataOpcode(appendedScriptPubKey));appendedScriptPubKey.forEach(item=>script.push(item))}else{throw Error("scriptPubKey must be a hex string")}let appendedSats=utils.int2FixedBuffer(config.appendedSats,1);script.push(utils.getPushDataOpcode(appendedSats));appendedSats.forEach(item=>script.push(item))}}if(config.msgClass==2){let chunkCount=utils.int2FixedBuffer(config.chunkCount,1);script.push(utils.getPushDataOpcode(chunkCount));chunkCount.forEach(item=>script.push(item));if(config.oracleBfp==null||config.oracleBfp.length===0||config.oracleBfp==""){[76,0].forEach(item=>script.push(item))}else if(config.fileSha256Hex.length===64&&re.test(config.fileSha256Hex)){let fileSha256Buf=Buffer.from(config.fileSha256Hex,"hex");script.push(utils.getPushDataOpcode(fileSha256Buf));fileSha256Buf.forEach(item=>script.push(item))}else{throw Error("Offer tx hash must be provided as a 64 character hex string")}if(config.msgType==2){let subscriptEnc=Buffer.from(config.subscriptEnc,"utf8");script.push(utils.getPushDataOpcode(subScriptEnc));subscriptEnc.forEach(item=>script.push(item))}if(config.chunkData==null||config.chunkData.length===0){[76,0].forEach(item=>script.push(item))}else{let chunkData=Buffer.from(config.chunkData);script.push(utils.getPushDataOpcode(chunkData));chunkData.forEach(item=>script.push(item))}}let encodedScript=utils.encodeScript(script);if(encodedScript.length>223){throw Error("Script too long, must be less than 223 bytes.")}return encodedScript}static buildDataChunkOpReturn(chunkData){let script=[];script.push(106);if(chunkData===undefined||chunkData===null||chunkData.length===0){[76,0].forEach(item=>script.push(item))}else{let chunkDataBuf=Buffer.from(chunkData);script.push(utils.getPushDataOpcode(chunkDataBuf));chunkDataBuf.forEach(item=>script.push(item))}let encodedScript=utils.encodeScript(script);if(encodedScript.length>223){throw Error("Script too long, must be less than 223 bytes.")}return encodedScript}buildFundingTx(config){let transactionBuilder;if(this.networkstring==="mainnet")transactionBuilder=new this.BITBOX.TransactionBuilder("bitcoincash");else transactionBuilder=new this.BITBOX.TransactionBuilder("bchtest");let satoshis=0;config.input_utxos.forEach(token_utxo=>{transactionBuilder.addInput(token_utxo.txid,token_utxo.vout);satoshis+=token_utxo.satoshis});let fundingMinerFee=this.BITBOX.BitcoinCash.getByteCount({P2PKH:config.input_utxos.length},{P2PKH:1});let outputAmount=satoshis-fundingMinerFee;transactionBuilder.addOutput(config.outputAddress,outputAmount);let i=0;for(const txo of config.input_utxos){let paymentKeyPair=this.BITBOX.ECPair.fromWIF(txo.wif);transactionBuilder.sign(i,paymentKeyPair,null,transactionBuilder.hashTypes.SIGHASH_ALL,txo.satoshis);i++}return transactionBuilder.build()}buildChunkTx(config){let transactionBuilder;if(this.networkstring==="mainnet")transactionBuilder=new this.BITBOX.TransactionBuilder("bitcoincash");else transactionBuilder=new this.BITBOX.TransactionBuilder("bchtest");transactionBuilder.addInput(config.input_utxo.txid,config.input_utxo.vout);let chunkTxFee=this.calculateDataChunkMinerFee(config.bfpChunkOpReturn.length);let outputAmount=config.input_utxo.satoshis-chunkTxFee;transactionBuilder.addOutput(config.bfpChunkOpReturn,0);transactionBuilder.addOutput(config.input_utxo.address,outputAmount);let paymentKeyPair=this.BITBOX.ECPair.fromWIF(config.input_utxo.wif);transactionBuilder.sign(0,paymentKeyPair,null,transactionBuilder.hashTypes.SIGHASH_ALL,config.input_utxo.satoshis);return transactionBuilder.build()}buildMetadataTx(config){let transactionBuilder;if(this.networkstring==="mainnet")transactionBuilder=new this.BITBOX.TransactionBuilder("bitcoincash");else transactionBuilder=new this.BITBOX.TransactionBuilder("bchtest");let inputSatoshis=0;transactionBuilder.addInput(config.input_utxo.txid,config.input_utxo.vout);inputSatoshis+=config.input_utxo.satoshis;let metadataFee=this.calculateMetadataMinerFee(config.bfpMetadataOpReturn.length);let output=inputSatoshis-metadataFee;transactionBuilder.addOutput(config.bfpMetadataOpReturn,0);let outputAddress=this.BITBOX.Address.toCashAddress(config.fileReceiverAddress);transactionBuilder.addOutput(outputAddress,output);let paymentKeyPair=this.BITBOX.ECPair.fromWIF(config.input_utxo.wif);transactionBuilder.sign(0,paymentKeyPair,null,transactionBuilder.hashTypes.SIGHASH_ALL,config.input_utxo.satoshis);return transactionBuilder.build()}calculateMetadataMinerFee(genesisOpReturnLength,feeRate=1){let fee=this.BITBOX.BitcoinCash.getByteCount({P2PKH:1},{P2PKH:1});fee+=genesisOpReturnLength;fee+=10;fee*=feeRate;return fee}calculateDataChunkMinerFee(sendOpReturnLength,feeRate=1){let fee=this.BITBOX.BitcoinCash.getByteCount({P2PKH:1},{P2PKH:1});fee+=sendOpReturnLength;fee+=10;fee*=feeRate;return fee}static calculateFileUploadCost(fileSizeBytes,configMetadataOpReturn,fee_rate=1){let byte_count=fileSizeBytes;let whole_chunks_count=Math.floor(fileSizeBytes/220);let last_chunk_size=fileSizeBytes%220;configMetadataOpReturn.chunkCount=last_chunk_size>0?whole_chunks_count+1:whole_chunks_count;let final_op_return_no_chunk=Swp.buildMetadataOpReturn(configMetadataOpReturn);byte_count+=final_op_return_no_chunk.length;byte_count+=35;byte_count+=148+1;byte_count+=(whole_chunks_count+1)*3;if(!Swp.chunk_can_fit_in_final_opreturn(final_op_return_no_chunk.length,last_chunk_size)){byte_count+=149+35;byte_count+=16}byte_count+=35*whole_chunks_count;byte_count+=(148+1)*whole_chunks_count;byte_count+=22*(whole_chunks_count+1);let dust_amount=546;return byte_count*fee_rate+dust_amount}static chunk_can_fit_in_final_opreturn(script_length,chunk_data_length){if(chunk_data_length===0){return true}let op_return_capacity=223-script_length;if(op_return_capacity>=chunk_data_length){return true}return false}parsebfpDataOpReturn(hex){const script=this.BITBOX.Script.toASM(Buffer.from(hex,"hex")).split(" ");let bfpData={};bfpData.type="metadata";if(script.length==2){bfpData.type="chunk";try{bfpData.chunk=Buffer.from(script[1],"hex")}catch(e){bfpData.chunk=null}return bfpData}if(script[0]!="OP_RETURN"){throw new Error("Not an OP_RETURN")}if(script[1]!==Swp.lokadIdHex){throw new Error("Not a BFP OP_RETURN")}if(script[2]!="OP_1"){throw new Error("Not a BFP file (type 0x01)")}bfpData.chunk_count=parseInt(script[3],16);if(script[3].includes("OP_")){let val=script[3].replace("OP_","");bfpData.chunk_count=parseInt(val)}if(script[4]=="OP_0"){bfpData.sha256=null}else{bfpData.sha256=Buffer.from(script[4],"hex")}if(script[5]=="OP_0"){bfpData.chunk=null}else{try{bfpData.chunk=Buffer.from(script[5],"hex")}catch(e){bfpData.chunk=null}}return bfpData}}module.exports=Swp}).call(this,require("buffer").Buffer)},{"./bitdbSwp":4,"./network":5,"./utils":7,buffer:38,"grpc-bchrpc-node":43}],7:[function(require,module,exports){(function(Buffer){class BfpUtils{static getPushDataOpcode(data){let length=data.length;if(length===0)return[76,0];else if(length<76)return length;else if(length<256)return[76,length];else throw Error("Pushdata too large")}static int2FixedBuffer(amount,size){let hex=amount.toString(16);hex=hex.padStart(size*2,"0");if(hex.length%2)hex="0"+hex;return Buffer.from(hex,"hex")}static encodeScript(script){const bufferSize=script.reduce((acc,cur)=>{if(Array.isArray(cur))return acc+cur.length;else return acc+1},0);const buffer=Buffer.allocUnsafe(bufferSize);let offset=0;script.forEach(scriptItem=>{if(Array.isArray(scriptItem)){scriptItem.forEach(item=>{buffer.writeUInt8(item,offset);offset+=1})}else{buffer.writeUInt8(scriptItem,offset);offset+=1}});return buffer}}module.exports=BfpUtils}).call(this,require("buffer").Buffer)},{buffer:38}],8:[function(require,module,exports){!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var n=t();for(var r in n)("object"==typeof exports?exports:e)[r]=n[r]}}(this,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=11)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(4);t.Metadata=r.BrowserHeaders},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.debug=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];console.debug?console.debug.apply(null,e):console.log.apply(null,e)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=null;t.default=function(e){null===r?(r=[e],setTimeout(function(){!function e(){if(r){var t=r;r=null;for(var n=0;n<t.length;n++)try{t[n]()}catch(s){null===r&&(r=[],setTimeout(function(){e()},0));for(var o=t.length-1;o>n;o--)r.unshift(t[o]);throw s}}}()},0)):r.push(e)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(0),o=n(9),s=n(10),i=n(1),a=n(2),u=n(5),d=n(15);t.client=function(e,t){return new c(e,t)};var c=function(){function e(e,t){this.started=!1,this.sentFirstMessage=!1,this.completed=!1,this.closed=!1,this.finishedSending=!1,this.onHeadersCallbacks=[],this.onMessageCallbacks=[],this.onEndCallbacks=[],this.parser=new o.ChunkParser,this.methodDefinition=e,this.props=t,this.createTransport()}return e.prototype.createTransport=function(){var e=this.props.host+"/"+this.methodDefinition.service.serviceName+"/"+this.methodDefinition.methodName,t={methodDefinition:this.methodDefinition,debug:this.props.debug||!1,url:e,onHeaders:this.onTransportHeaders.bind(this),onChunk:this.onTransportChunk.bind(this),onEnd:this.onTransportEnd.bind(this)};this.props.transport?this.transport=this.props.transport(t):this.transport=u.makeDefaultTransport(t)},e.prototype.onTransportHeaders=function(e,t){if(this.props.debug&&i.debug("onHeaders",e,t),this.closed)this.props.debug&&i.debug("grpc.onHeaders received after request was closed - ignoring");else if(0===t);else{this.responseHeaders=e,this.props.debug&&i.debug("onHeaders.responseHeaders",JSON.stringify(this.responseHeaders,null,2));var n=p(e);this.props.debug&&i.debug("onHeaders.gRPCStatus",n);var r=n&&n>=0?n:s.httpStatusToCode(t);this.props.debug&&i.debug("onHeaders.code",r);var o=e.get("grpc-message")||[];if(this.props.debug&&i.debug("onHeaders.gRPCMessage",o),this.rawOnHeaders(e),r!==s.Code.OK){var a=this.decodeGRPCStatus(o[0]);this.rawOnError(r,a,e)}}},e.prototype.onTransportChunk=function(e){var t=this;if(this.closed)this.props.debug&&i.debug("grpc.onChunk received after request was closed - ignoring");else{var n=[];try{n=this.parser.parse(e)}catch(e){return this.props.debug&&i.debug("onChunk.parsing error",e,e.message),void this.rawOnError(s.Code.Internal,"parsing error: "+e.message)}n.forEach(function(e){if(e.chunkType===o.ChunkType.MESSAGE){var n=t.methodDefinition.responseType.deserializeBinary(e.data);t.rawOnMessage(n)}else e.chunkType===o.ChunkType.TRAILERS&&(t.responseHeaders?(t.responseTrailers=new r.Metadata(e.trailers),t.props.debug&&i.debug("onChunk.trailers",t.responseTrailers)):(t.responseHeaders=new r.Metadata(e.trailers),t.rawOnHeaders(t.responseHeaders)))})}},e.prototype.onTransportEnd=function(){if(this.props.debug&&i.debug("grpc.onEnd"),this.closed)this.props.debug&&i.debug("grpc.onEnd received after request was closed - ignoring");else if(void 0!==this.responseTrailers){var e=p(this.responseTrailers);if(null!==e){var t=this.responseTrailers.get("grpc-message"),n=this.decodeGRPCStatus(t[0]);this.rawOnEnd(e,n,this.responseTrailers)}else this.rawOnError(s.Code.Internal,"Response closed without grpc-status (Trailers provided)")}else{if(void 0===this.responseHeaders)return void this.rawOnError(s.Code.Unknown,"Response closed without headers");var r=p(this.responseHeaders),o=this.responseHeaders.get("grpc-message");if(this.props.debug&&i.debug("grpc.headers only response ",r,o),null===r)return void this.rawOnEnd(s.Code.Unknown,"Response closed without grpc-status (Headers only)",this.responseHeaders);var a=this.decodeGRPCStatus(o[0]);this.rawOnEnd(r,a,this.responseHeaders)}},e.prototype.decodeGRPCStatus=function(e){if(!e)return"";try{return decodeURIComponent(e)}catch(t){return e}},e.prototype.rawOnEnd=function(e,t,n){var r=this;this.props.debug&&i.debug("rawOnEnd",e,t,n),this.completed||(this.completed=!0,this.onEndCallbacks.forEach(function(o){a.default(function(){r.closed||o(e,t,n)})}))},e.prototype.rawOnHeaders=function(e){this.props.debug&&i.debug("rawOnHeaders",e),this.completed||this.onHeadersCallbacks.forEach(function(t){a.default(function(){t(e)})})},e.prototype.rawOnError=function(e,t,n){var o=this;void 0===n&&(n=new r.Metadata),this.props.debug&&i.debug("rawOnError",e,t),this.completed||(this.completed=!0,this.onEndCallbacks.forEach(function(r){a.default(function(){o.closed||r(e,t,n)})}))},e.prototype.rawOnMessage=function(e){var t=this;this.props.debug&&i.debug("rawOnMessage",e.toObject()),this.completed||this.closed||this.onMessageCallbacks.forEach(function(n){a.default(function(){t.closed||n(e)})})},e.prototype.onHeaders=function(e){this.onHeadersCallbacks.push(e)},e.prototype.onMessage=function(e){this.onMessageCallbacks.push(e)},e.prototype.onEnd=function(e){this.onEndCallbacks.push(e)},e.prototype.start=function(e){if(this.started)throw new Error("Client already started - cannot .start()");this.started=!0;var t=new r.Metadata(e||{});t.set("content-type","application/grpc-web+proto"),t.set("x-grpc-web","1"),this.transport.start(t)},e.prototype.send=function(e){if(!this.started)throw new Error("Client not started - .start() must be called before .send()");if(this.closed)throw new Error("Client already closed - cannot .send()");if(this.finishedSending)throw new Error("Client already finished sending - cannot .send()");if(!this.methodDefinition.requestStream&&this.sentFirstMessage)throw new Error("Message already sent for non-client-streaming method - cannot .send()");this.sentFirstMessage=!0;var t=d.frameRequest(e);this.transport.sendMessage(t)},e.prototype.finishSend=function(){if(!this.started)throw new Error("Cli