All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.coinspark.samples.CoinSparkSamples Maven / Gradle / Ivy

Go to download

CoinSpark is a lightweight scalable solution for colored coins. The CoinSpark libraries help you integrate support for the CoinSpark protocol into your wallet, or any other tool or service.

The newest version!
/*
 * CoinSpark 2.1 - Java sample code
 *
 * Copyright (c) Coin Sciences Ltd
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */



package org.coinspark.samples;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.coinspark.protocol.CoinSparkAddress;
import org.coinspark.protocol.CoinSparkAssetRef;
import org.coinspark.protocol.CoinSparkBase;
import org.coinspark.protocol.CoinSparkGenesis;
import org.coinspark.protocol.CoinSparkIORange;
import org.coinspark.protocol.CoinSparkMessage;
import org.coinspark.protocol.CoinSparkMessagePart;
import org.coinspark.protocol.CoinSparkPaymentRef;
import org.coinspark.protocol.CoinSparkTransfer;
import org.coinspark.protocol.CoinSparkTransferList;

/**
 *
 * @author mike
 */
public class CoinSparkSamples {
    
    public static void CreateCoinSparkAddress()
    {        
        System.out.println("\nCreating a CoinSpark address...\n");

        CoinSparkAddress address=new CoinSparkAddress();

        address.setBitcoinAddress("149wHUMa41Xm2jnZtqgRx94uGbZD9kPXnS");
        address.setAddressFlags(CoinSparkAddress.COINSPARK_ADDRESS_FLAG_ASSETS | CoinSparkAddress.COINSPARK_ADDRESS_FLAG_PAYMENT_REFS);
        address.setPaymentRef(new CoinSparkPaymentRef(0)); // or any unsigned 52-bit integer up to CoinSparkPaymentRef.COINSPARK_PAYMENT_REF_MAX

        String addressString=address.encode();

        if (addressString!=null)
            System.out.println("CoinSpark address: "+addressString);
        else
            System.out.println("CoinSpark address encode failed!");
    }
    
    public static void DecodeCoinSparkAddress()
    {
        System.out.println("\nDecoding a CoinSpark address...\n");

        CoinSparkAddress address=new CoinSparkAddress();

        if (address.decode("s6GUHy69HWkwFqzFhJCY49seL8EFv")) {
            System.out.println("Bitcoin address: "+address.getBitcoinAddress());
            System.out.println("Address flags: "+address.getAddressFlags());
            System.out.println("Payment reference: "+address.getPaymentRef().getRef());

            System.out.print(address.toString());

        } else
            System.out.println("CoinSpark address decode failed!");
    }
    
    public static void ProcessTransaction(byte[][] scriptPubKeys, int countInputs)
    {
        System.out.println("\nExtracting CoinSpark metadata from a transaction...\n");

        // scriptPubKeys is an array containing each output script of a transaction as raw binary data.       
        // The transaction has scriptPubKeys.length outputs and countInputs inputs.

        byte[] metadata=CoinSparkBase.scriptsToMetadata(scriptPubKeys);

        if (metadata!=null) {
            CoinSparkGenesis genesis=new CoinSparkGenesis();                                
            if (genesis.decode(metadata))
                System.out.print(genesis.toString());
                    
            CoinSparkTransferList transferList=new CoinSparkTransferList();
            if (transferList.decode(metadata, countInputs, scriptPubKeys.length))
                System.out.print(transferList.toString());                    
    
            CoinSparkPaymentRef paymentRef=new CoinSparkPaymentRef();
            if (paymentRef.decode(metadata))
                System.out.print(paymentRef.toString());
        }
    }
    
    public static void ProcessTransaction(String[] scriptPubKeys, int countInputs)
    {
        System.out.println("\nExtracting CoinSpark metadata from a transaction...\n");

        // scriptPubKeys is an array containing each output script of a transaction as a hex string
        // or raw binary (commented above). The transaction has scriptPubKeys.length outputs and
        // countInputs inputs.

        byte[] metadata=CoinSparkBase.scriptsToMetadata(scriptPubKeys);

        if (metadata!=null) {
            CoinSparkGenesis genesis=new CoinSparkGenesis();                                
            if (genesis.decode(metadata))
                System.out.print(genesis.toString());
                    
            CoinSparkTransferList transferList=new CoinSparkTransferList();
            if (transferList.decode(metadata, countInputs, scriptPubKeys.length))
                System.out.print(transferList.toString());                    
    
            CoinSparkPaymentRef paymentRef=new CoinSparkPaymentRef();
            if (paymentRef.decode(metadata))
                System.out.print(paymentRef.toString());

            CoinSparkMessage message=new CoinSparkMessage();
            if (message.decode(metadata,scriptPubKeys.length))
                System.out.print(message.toString());
        }
    }
    
    public static byte[] EncodeMetaData(byte[] metadata)
    {
        System.out.println("\nEncoding CoinSpark metadata in a script...\n");

        // first get metadata from the encode() method of a CoinSparkGenesis, CoinSparkTransferList
        // or CoinSparkPaymentRef object, or the CoinSparkBase.metadataAppend() method.

        byte[] scriptPubKey=null;
        
        if (metadata!=null) {
            scriptPubKey=CoinSparkBase.metadataToScript(metadata);

            if (scriptPubKey!=null)
                ; // now embed the raw bytes in $scriptPubKey directly in a transaction output
            else
                ; // handle the error
    
        } else
            ; // handle the error

        return scriptPubKey;
    }
    
    public static String EncodeMetaDataToHex(byte [] metadata)
    {
        System.out.println("\nEncoding CoinSpark metadata in a script...\n");

        // first get metadata from the encode() method of a CoinSparkGenesis, CoinSparkTransferList
        // or CoinSparkPaymentRef object, or the CoinSparkBase.metadataAppend() method.

        String scriptPubKey=null;
        
        if (metadata!=null) {
            scriptPubKey=CoinSparkBase.metadataToScriptHex(metadata);

            if (scriptPubKey!=null)
                System.out.println("Script: "+scriptPubKey);
            else
                System.out.println("Metadata encode failed!");

        } else
            ; // handle the error

        return scriptPubKey;
    }
    
    public static byte[] CoinSparkPaymentRefTransfersEncode(CoinSparkPaymentRef paymentRef,
        CoinSparkTransferList transferList, int countInputs, int countOutputs, int metadataMaxLen)
    {
        byte[] metadata=paymentRef.encode(metadataMaxLen);
        if (metadata==null)
            return null;

        int appendMetadataMaxLen=CoinSparkBase.metadataMaxAppendLen(metadata, metadataMaxLen);
            // this is not simply metadataMaxLen-metadata.length since combining saves space

        byte[] appendMetaData=transferList.encode(countInputs, countOutputs, appendMetadataMaxLen);
        if (appendMetaData==null)
            return null;
   
        return CoinSparkBase.metadataAppend(metadata, metadataMaxLen, appendMetaData);
    }
    
    public static CoinSparkGenesis CreateGenesis()
    {
        System.out.println("\nCreating and encoding genesis metadata...\n");

        CoinSparkGenesis genesis=new CoinSparkGenesis();

        genesis.setQty(1234567, 1); // 1234567 units rounded up     
        long actualQty=genesis.getQty(); // can check final quantity assigned

        genesis.setChargeFlat(4321, 0); // 4321 units rounded to nearest
        long actualChargeFlat=genesis.getChargeFlat(); // can check final flat charge assigned

        genesis.setChargeBasisPoints((short)10); // additional 0.1% per payment

        genesis.setUseHttps(false);
        genesis.setDomainName("www.example.com");
        genesis.setUsePrefix(true);
        genesis.setPagePath("usd-1");

        int assetHashLen=genesis.calcHashLen(40); // 40 byte limit for OP_RETURN
        genesis.setAssetHashLen(assetHashLen);
        byte[] assetHash = new byte [assetHashLen];        
        Random rnd=new Random();        
        rnd.nextBytes(assetHash); // random hash in example    
        genesis.setAssetHash(assetHash);

        byte[] metadata=genesis.encode(40); // 40 byte limit for OP_RETURNs

        if (metadata!=null)
            ; // use CoinSparkBase.metadataToScript() to embed metadata in an output script
        else
            ; // handle error

        return genesis;
    }

    public static CoinSparkMessage CreateMessage()
    {
        System.out.println("\nCreating and encoding message metadata...\n");

        CoinSparkMessage message=new CoinSparkMessage();
 
        message.setUseHttps(true);
        message.setServerHost("123.45.67.89");
        message.setUsePrefix(false);
        message.setServerPath("msg");
        message.setIsPublic(false);
        message.addOutputs(new CoinSparkIORange(0, 2)); // message is for outputs 0 and 1
 
        int countOutputs=3; // 3 outputs for this transaction
        int hashLen=message.calcHashLen(countOutputs, 40); // 40 byte limit for OP_RETURN
        message.setHashLen(hashLen);
        byte[] hash = new byte [hashLen];       
        Random rnd=new Random();       
        rnd.nextBytes(hash); // random hash in example   
        message.setHash(hash);

        byte[] metadata=message.encode(countOutputs, 40); // 40 byte limit for OP_RETURNs

        if (metadata!=null)
            ; // use CoinSparkBase.metadataToScript() to embed metadata in an output script
        else
            ; // handle error
        
        return message;
    }
    
    public static CoinSparkTransferList CreateTransferList()
    {
        System.out.println("\nCreating and encoding transfer metadata...\n");

        int countInputs=3;
        int countOutputs=5;
        CoinSparkTransferList transferList=new CoinSparkTransferList();

        CoinSparkTransfer transfer=new CoinSparkTransfer();
        CoinSparkAssetRef assetRef=new CoinSparkAssetRef();
        assetRef.decode("456789-65432-23456");
        transfer.setAssetRef(assetRef);
        transfer.setInputs(new CoinSparkIORange(0, 2)); // transfer from inputs 0 and 1
        transfer.setOutputs(new CoinSparkIORange(0, 1)); // transfer to outputs 0 only
        transfer.setQtyPerOutput(123);
        transferList.setTransfer(0, transfer);

        transfer=new CoinSparkTransfer();
        transfer.setAssetRef(transferList.getTransfer(0).getAssetRef()); // second transfer is for same asset type
        transfer.setInputs(new CoinSparkIORange(2, 1)); // transfer from input 2 only
        transfer.setOutputs(new CoinSparkIORange(1, 3)); // transfer to outputs 1, 2 and 3
        transfer.setQtyPerOutput(456);    
        transferList.setTransfer(1, transfer);

        byte[] metadata=transferList.encode(countInputs, countOutputs, 40); // 40 byte limit for OP_RETURNs

        if (metadata!=null)
            ; // use CoinSparkBase.metadataToScript() to embed metadata in an output script
        else
            ; // handle error

        return transferList;
    }
    
    public static long[] CalcTransactionOutputBalances(
        CoinSparkAssetRef assetRef, CoinSparkGenesis genesis, 
        CoinSparkTransferList transferList,
        long minFeeSatoshis, long feeSatoshis, 
        long[] inputBalances, boolean[] outputsRegular)
    {
        // assetRef is a CoinSparkAssetRef object describing the CoinSpark asset type of interest.
        // genesis is a CoinSparkGenesis object describing the same asset type.
        // transferList is a CoinSparkTransferList object from the decoded transfer metadata -
        // If there is no transfer metadata, you can pass in a new CoinSparkTransferList().
        // minFeeSatoshis is the minimum transaction fee required to make those transfers valid.
        // feeSatoshis is the quantity of bitcoin satoshis in this transaction's fee.
        // inputBalances is an array of the asset's balances in the transaction's inputs.
        // outputsRegular is an array indicating which outputs are regular, via CoinSparkBase.scriptIsRegular().
   
        // Returns the balances of that asset in each output

        long[] outputBalances;

        if (feeSatoshis>=minFeeSatoshis)
            outputBalances=transferList.apply(assetRef, genesis, inputBalances, outputsRegular);
        else
            outputBalances=transferList.applyNone(assetRef, genesis, inputBalances, outputsRegular);

        return outputBalances;
    }
    
    public static CoinSparkAssetRef CreateAssetRef()
    {
        System.out.println("\nFormatting an asset reference for users...\n");

        CoinSparkAssetRef assetRef=new CoinSparkAssetRef();

        assetRef.setBlockNum(456789);
        assetRef.setTxOffset(65432);
        assetRef.setTxIDPrefix(new byte[] {(byte)0xa0, (byte)0x5b});

        System.out.println("Asset reference: "+assetRef.encode());

        return assetRef;
    }
    
    public static CoinSparkAssetRef readAssetRef()
    {
        System.out.println("\nReading a user-provided asset reference...\n");

        CoinSparkAssetRef assetRef=new CoinSparkAssetRef();

        if (assetRef.decode("456789-65432-23456")) {
            System.out.println("Block number: "+assetRef.getBlockNum());
            System.out.println("Byte offset: "+assetRef.getTxOffset());
            System.out.println("TxID prefix: "+String.format("%02X%02X", assetRef.getTxIDPrefix()[0], assetRef.getTxIDPrefix()[1]));
    
            System.out.print(assetRef.toString());            

        } else
            System.out.println("Asset reference could not be read!");                        

        return assetRef;
    }

    private static String file_get_contents (String Address)
    {    
        URL url;
        try {
            url = new URL(Address);
        } catch (MalformedURLException ex) {
            Logger.getLogger(CoinSparkSamples.class.getName()).log(Level.SEVERE, null, ex);
            return "";
        }
        
        URLConnection connection;
        try {        
            connection = url.openConnection();
        } catch (IOException ex) {
            Logger.getLogger(CoinSparkSamples.class.getName()).log(Level.SEVERE, null, ex);
            return "";
        }
        
        InputStream input;
        try {
            input = connection.getInputStream();
        } catch (IOException ex) {
            Logger.getLogger(CoinSparkSamples.class.getName()).log(Level.SEVERE, null, ex);
            return "";
        }
        byte[] buffer = new byte[4096];
        int n = - 1;

        StringBuilder sb = new StringBuilder();        
        try {
            while ( (n = input.read(buffer)) != -1)
            {
                if (n > 0)
                {
                    sb.append(new String(buffer, 0, n, "UTF-8"));
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(CoinSparkSamples.class.getName()).log(Level.SEVERE, null, ex);
            return "";
        }
        
        return sb.toString();
    }
    
    public static byte[] CalculateMessageHash() throws UnsupportedEncodingException
    {
        byte[] salt = new byte [32];        
        Random rnd=new Random();        
        rnd.nextBytes(salt); 
     
        CoinSparkMessagePart [] contentParts=new CoinSparkMessagePart[2];            
            
        contentParts[0]=new CoinSparkMessagePart();
        contentParts[0].mimeType="text/plain";   // implies UTF-8 encoding
        contentParts[0].fileName=null;
        contentParts[0].content="Payment for the attached invoice - Bob".getBytes("UTF-8");
        
        contentParts[1]=new CoinSparkMessagePart();
        contentParts[1].mimeType="application/pdf";
        contentParts[1].fileName="Invoice AB123.pdf";
        contentParts[1].content=file_get_contents("files/Invoice AB123.pdf").getBytes("UTF-8");
        // assume we have some function like this that we can use
        
        byte[] messageHash=CoinSparkMessage.calcMessageHash(salt, contentParts);
        // The messageHash variable now contains the CoinSpark message hash
        
        return messageHash;                
    }
     
    public static byte[] CalculateAssetHash()
    {
        String name="Credit at John Doe's";
        String issuer="John Doe's Restaurant Chain";
        String description="Can be used for any purchase at John Doe's, excluding breakfasts.";
        String units="1 US Dollar";
        String issueDate="2014-03-01";
        String expiryDate="2024-02-29";
        double interestRate=0.0;
        double multiple=0.01;
        String contractURL="http://www.john-doe-dining.com/bitcoin-credits-contract.pdf";

        byte[] contractContent;
        String contractContentString=file_get_contents(contractURL);
        if(contractContentString != null)
        {
            contractContent=contractContentString.getBytes();
        }
        else
        {
            ; // handle error
            return null;
        }
            // assume we have some function like this that we can use

        byte[] assetHash=null;

        if (contractContent!=null)
            assetHash=CoinSparkGenesis.calcAssetHash(name, issuer, description, units, issueDate,
                expiryDate, interestRate, multiple, contractContent);
        else
            ; // handle error

        return assetHash;        
    }
    
    public static CoinSparkPaymentRef CreatePaymentRef()
    {
        System.out.println("\nCreating and encoding payment reference metadata...\n");

        CoinSparkPaymentRef paymentRef=new CoinSparkPaymentRef();
        paymentRef.randomize(); // randomizes the payment reference
        byte[] metadata = paymentRef.encode(40); // assume 40 byte limit for OP_RETURNs

        if (metadata!=null)
            ; // use CoinSparkBase.metadataToScript() to embed metadata in an output script
        else
            ; // handle error

        return paymentRef;
    }

    // public static boolean CheckGenesisFee(CoinSparkGenesis genesis, long feeSatoshis,
    //     long[] outputsSatoshis, byte[][] scriptPubKeys)

    public static boolean CheckGenesisFee(CoinSparkGenesis genesis, long feeSatoshis,
        long[] outputsSatoshis, String[] scriptPubKeys)
    {
        // genesis is a CoinSparkGenesis object, already extracted from the transaction.
        // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
        // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
        // scriptPubKeys is an array containing each output script of a transaction as a hex string
        // or raw binary (commented above), so that the transaction has scriptPubKeys.length outputs.

        int countOutputs=scriptPubKeys.length;
        boolean[] outputsRegular=new boolean[countOutputs];

        for (int output=0; output=genesis.calcMinFee(outputsSatoshis, outputsRegular);
    }

    // public static boolean CheckTransfersFee(CoinSparkTransferList transferList, long feeSatoshis,
    //     long[] outputsSatoshis, byte[][] scriptPubKeys, int countInputs)

    public static boolean CheckTransfersFee(CoinSparkTransferList transferList, long feeSatoshis,
        long[] outputsSatoshis, String[] scriptPubKeys, int countInputs)
    {
        // transferList is a CoinSparkTransferList object, already extracted from the transaction.
        // feeSatoshis is the quantity of bitcoin satoshis in the transaction fee.
        // outputsSatoshis is an array of bitcoin satoshi quantities in each output of the transaction.
        // scriptPubKeys is an array containing each output script of a transaction as a hex string
        // or raw binary (commented above), so that the transaction has scriptPubKeys.length outputs
        // and countInputs inputs.

        int countOutputs=scriptPubKeys.length;
        boolean[] outputsRegular=new boolean[countOutputs];

        for (int output=0; output=transferList.calcMinFee(countInputs, outputsSatoshis, outputsRegular);
    }
    
    public static void main(String [] args)
    {
        CreateCoinSparkAddress();

        DecodeCoinSparkAddress();

        ProcessTransaction(new String [] {"6A2853504B6750A4AE00F454956DF4C7D6DE7BF8192486006A4ADF65B048BF847FE26D70588E9FA828D5"},15856);

        ProcessTransaction(new String [] {"abc","6A2053504B743F282321E438188C4B381807227C10812B47920642B32E12417D8279","def"},59364);
        
        ProcessTransaction(new String [] {"6A2553504B0872876AAE4C1CC00A747A3E6F1BC14CD7752DA0D507BD05ED903A1C8407CCE38087"},1925);

        byte [] metadataTransfers = CoinSparkBase.scriptToMetadata("6A2053504B743F282321E438188C4B381807227C10812B47920642B32E12417D8279");
        EncodeMetaDataToHex(metadataTransfers);

        CoinSparkGenesis genesis=CreateGenesis();

        CoinSparkMessage message=CreateMessage();
        
        CoinSparkTransferList transferList=CreateTransferList();

        CoinSparkPaymentRef paymentRef=CreatePaymentRef();

        byte [] metadata = CoinSparkPaymentRefTransfersEncode(paymentRef,transferList,3, 5, 40);
        
        ProcessTransaction(new byte[][] {EncodeMetaData(metadata),new byte[0],new byte[0],new byte[0],new byte[0]},3);

        CoinSparkAssetRef assetRef=CreateAssetRef();

        readAssetRef();

        CalculateAssetHash();
        
        try {
            CalculateMessageHash();
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(CoinSparkSamples.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy