This is a JavaScript Library for uploading and downloading files per the Bitcoin Files Protocol specification to the Bitcoin Cash blockchain. It's important to understand that files uploaded to any blockchain are permanent and cannot be deleted. All uploaded content is associated with the public key(s) you use to pay for uploading the content.
Other tools using the Bitcoin Files Protocol include:
npm install bitcoinfiles
<script src='https://unpkg.com/bitcoinfiles'></script>
constGrpc=require('grpc-bchrpc-node');// or window.bchrpcconstBfp=require('bitcoinfiles').Bfp;// or window.bitcoinfiles.Bfpconstgrpc=newGrpc.GrpcClient;constbfp=newBfp(grpc);// 1 - download file using URIletresult;(asyncfunction(){result=awaitbfp.downloadFile('bitcoinfile:7e4600323c934926369c136562f5483e3df79baf087c8dd2b0ed1aea69d5ee49');// Wait for download to complete -- Mario.png TAKES ABOUT 6 SEC TO DOWNLOAD!console.log("download complete.");// 2 - result includes a boolean check telling you if the file's sha256 matches the file's metadataif(result.passesHashCheck){console.log("Success: downloaded file sha256 matches file's metadata");}// 3 - do something with the file...letfileBuffer=result.fileBuf;})();Below is a simple example. For a more complete React.js file upload example visit SimpleToken.cash website
constGrpc=require('grpc-bchrpc-node');// or window's property equivalentsconstBfp=require('bitcoinfiles').Bfp;constUtils=require('bitcoinfiles').Utils;constgrpc=newGrpc.GrpcClient;constbfp=newBfp(grpc);// 1 - get a file and file metadata somehowconstsomeFileBuffer=Buffer.from('aabbccddeeff','hex');constfileName='a test file';constfileExt='txt';constfileSize=someFileBuffer.lengthconstfileSha256Hex=Utils.Sha256(someFileBuffer).toString('hex');// 2 - estimate upload cost for funding the transactionletuploadCost=Bfp.calculateFileUploadCost(fileSize);// Alternatively, use the new protocol intended for larger files:// let uploadCost = Bfp.calculateFileUploadCost(fileSize, null, 1, 2);console.log('upload cost: ',uploadCost);// 3 - create a funding transactionletfundingAddress='bitcoincash:qqgvrkm0xpmwqgyhfm65qxv70tjtwma6lgk07ffv9u'letfundingWif='KzcuA9xnDRrb9cPh29N7EQbBhQQLMWtcrDwKbEMoahmwBNACNRfa'// 4 - Make sure address above is funded with at least uploadCostletfundingUtxo={"txid": "85c1b22c116b44539ead07353c509502b46106344bb5b4bd46a880ba8a530c27","satoshis": 12000,"vout": 3};// wait for network to resolve...// 5 - upload the fileletfileId;(asyncfunction(){fileId=awaitbfp.uploadFile(fundingUtxo,fundingAddress,fundingWif,someFileBuffer,fileName,fileExt);console.log('fileId: ',fileId);})();// wait for upload to complete resolve... Done.asyncuploadFile(fundingUtxo: utxo,fundingAddress: string,fundingWif: string,fileDataArrayBuffer: Buffer,fileName?: string,fileExt?: string,prevFileSha256Hex?: string,fileExternalUri?: string,fileReceiverAddress?: string,signProgressCallback?: Function,signFinishedCallback?: Function,uploadProgressCallback?: Function,uploadFinishedCallback?: Function,delay_ms=500,uploadMethod=1): Promise<string>;uploadFile is the method used to a upload file
Mandatory parameters:
fundingUtxois the utxo to fund the uploading transaction(s). It must have a value no less than calculated bycalculateFileUploadCostfundingAddressis the address to which belongs the utxofundingWifis the private key which unlocks the funding address in Wallet Import FormatfileDataArrayBufferis the data to be uploaded, which may be a NodeJSBufferor a browserArrayBuffer; see bottom for notes aboutArrayBufferusage
Optional parameters:
fileNameis the file namefileExtis the file extensionprevFileSha256Hexis a reference to the previous filefileExternalUriis a URI for the filefileReceiverAddressis a recipient address for the last uploading transaction, to be used instead of fundingAddresssignProgressCallback,signFinishedCallback,uploadProgressCallback,uploadFinishedCallbackare callback functions for upload progress updatesdelay_msis the delay between uploading consecutive transactionsuploadMethodrefers to the upload protocol:1for small data pushes and backwards compatibility,2for 0.6.0+ compatible more efficient data pushes intended for larger files
Returns the fileId, which contains a prefix (bitcoinfile:) and the TXID
asyncdownloadFile(bfpUri: string,progressCallback?: Function): Promise<{passesHashCheck: boolean;fileBuf: Buffer;}>;downloadFile is the method used to download a file
bfpUrimay be the TXID of the metadata-containing transaction, or the TXID prepended withbitcoinfile:orbitcoinfiles:progressCallbackis an optional download progress callback function
Returns an object with passesHashCheck which determines if downloading was sucessful and fileBuf which has the file contents; see bottom for notes about ArrayBuffer usage
staticcalculateFileUploadCost(fileSizeBytes: number,configMetadataOpReturn?: FileMetadata,fee_rate?: number,uploadMethod?: number): number;Mandatory parameter:
fileSizeBytes is the length of file contents in terms of octets
Optional parameters:
configMetadataOpReturn is the metadata that would be uploaded with the file, passing this instead of null may yield a better estimate with a lower calculated cost
fee_rate is the fee rate in satoshis per byte
uploadMethod is the upload protocol; see uploadFile documentation for details
export interface FileMetadata {
msgType: number;
chunkCount: number;
fileName?: string;
fileExt?: string;
fileSize: number;
fileSha256Hex?: string;
prevFileSha256Hex?: string;
fileUri?: string;
chunkData?: Buffer;
}
msgTypeis a synonym ofuploadMethod, which is described inuploadFiledocumentationchunkCountis a placeholder that can be set as1chunkDatais a placeholder that can be set asnull
The other values can be set as described earlier
export interface utxo {
txid: string;
vout: number;
satoshis: number;
}
The fields that should be set are shown above for an unspent output
Buffer: This may be a NodeJS buffer or an ArrayBuffer. For use in a browser,
it is suggested that an ArrayBuffer of Uint8Array should be used.
For a variable fileContents of type Uint8Array, the ArrayBuffer can be accessed
as fileContents.buffer. However, this might not always work, for example if .subarray(...)
was applied to fileContents before .buffer. In this case, the approach here can be taken.
