Skip to content

Simple clients for interacting with different blockchains.

Notifications You must be signed in to change notification settings

catalogfi/blockchain

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

⛓️ blockchain

Tests Go Coverage

For any Catalog-related blockchain interactions, in Golang.

  • Bitcoin
  • Ethereum

Install

The blockchain package can be imported by running:

$ go get github.com/catalogfi/blockchain

Bitcoin

JSON-RPC

This client follows the standard bitcoind JSON-RPC interface.

Example:

    // Initialize the client.
    config := &rpcclient.ConnConfig{
        Params:       chaincfg.RegressionNetParams.Name,
        Host:         "0.0.0.0:18443",
        User:         user,
        Pass:         password,
        HTTPPostMode: true,
        DisableTLS:   true,
    }
    client := btc.NewClient(config)
    
    // Get the latest block.
    height, hash, err := client.LatestBlock()
    if err != nil {
    	panic(err)
    }

Indexer

The indexer client follows the electrs indexer API.

Example:

    // Initialize the client.
    logger, _ := zap.NewDevelopment()
    indexer := btc.NewElectrsIndexerClient(logger, host, btc.DefaultRetryInterval)
    
    addr := "xxxxxxx"
    utxos, err := indexer.GetUTXOs(context.Background(), addr)
    if err != nil {
        panic(err)
    }

Fee estimator

There are a few commonly used fee estimators to give you an estimate of the current network. Beware, these are mostly for mainnet, as min relay fees usually is enough for testnet and regnet.

The result is in sats/vB

Example:

    // Mempool uses the mempool's public fee estimation api (https://mempool.space/docs/api/rest#get-recommended-fees). 
    // It returns currently suggested fees for new transactions. It's safe for concurrent use and you can define a 
    // duration for how long you want to cache the result to avoid spamming the requests.
    estimator := btc.NewMempoolFeeEstimator(&chaincfg.MainNetParams, btc.MempoolFeeAPI, 15*time.Second)
    fees, err := estimator.FeeSuggestion()
    if err != nil {
        panic(err)
    }
    
    // Blockstream uses the blockstream api and returns a fee estimation basing on the past blocks. 
    estimator := btc.NewBlockstreamFeeEstimator(&chaincfg.MainNetParams, btc.BlockstreamAPI, 15*time.Second)
    fees, err := estimator.FeeSuggestion()
    if err != nil {
        panic(err)
    } 
    
    // If you know the exact fee rate you want, you can use the FixedFeeEstimator which will always return the provided 
    // fee rate. 
    estimator := btc.NewFixedFeeEstimator(10)
    fees, err := estimator.FeeSuggestion()
    if err != nil {
        panic(err)
    }

Build a bitcoin transaction

One important use case for this library is building a Bitcoin transaction. We typically use the BuildTransaction function for this purpose. Although this function has many parameters, they can be grouped into three categories:

  1. General
  • network: The network on which the transaction is built.
  • feeRate: The minimum fee rate for the transaction. The actual transaction fee might be slightly higher due to estimation using the upper bound.
  1. Inputs
  • inputs: The UTXOs (unspent transaction outputs) you want to spend in the transaction. These are guaranteed to be included. Provide the estimated size of these UTXOs. Use the default value NewRawInputs() if you don't have any specific UTXOs.
  • utxos: Available UTXOs that can be added to the inputs if their amount is insufficient to cover the output. The UTXOs are added in the order provided. Use nil if you don't have any.
  • sizeUpdater: Describes how much size each UTXO adds to the transaction. It assumes all UTXOs come from the same address. Predefined size updaters like P2pkhUpdater and P2wpkhUpdater are available. Use nil if utxos is empty.
  1. Outputs
  • recipients: Specifies who will receive the funds. All recipients are guaranteed to receive the specified amount.
  • changeAddr: The address where you want to send the change, typically the sender's address.

Examples:

  1. Transfer 0.1 btc to 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
    // Fetch available utxos of the address 
    utxos, err := indexer.GetUTXOs(ctx, sender)
	if err != nil {
	    panic(err)	
    }
    recipients := []btc.Recipient{
        {
            To:     "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
            Amount: 1e7,
        },
    }
	
    transaction, err := btc.BuildTransaction(&chaincfg.MainNetParams, 20, btc.NewRawInputs(), utxos, btc.P2pkhUpdater, recipients, sender)
    Expect(err).To(BeNil())
  1. Spend a UTXO and send all the money to 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
    rawInputs := btc.RawInputs{
        VIN:        utxos,
        BaseSize:   txsizes.RedeemP2PKHSigScriptSize * len(utxos),
        SegwitSize: 0,
    }
	sender := "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
	
    transaction, err := btc.BuildTransaction(&chaincfg.MainNetParams, 20, rawInputs, nil, nil, nil, sender)
    Expect(err).To(BeNil())
  1. Redeem an HTLC and send 0.1 btc to 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa and rest to sender
    htlcUtxos := []btc.UTXO{
        {
            TxID:   txid,
            Vout:   vout,
            Amount: amount,
        },
    }
    rawInputs := btc.RawInputs{
        VIN:        htlcUtxos,
        BaseSize:   0,
        SegwitSize: btc.RedeemHtlcRefundSigScriptSize,
    }
    recipients := []btc.Recipient{
        {
            To:     "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
            Amount: 1e7,
        },
    }
	
    transaction, err := btc.BuildTransaction(&chaincfg.MainNetParams, 20, rawInputs, nil, nil, recipients, sender)
    Expect(err).To(BeNil())

Bitcoin scripts

  • MultisigScript: Returns a 2-of-2 multisig script used by the Guardian component.
  • HtlcScript: Returns a HTLC script as described in BIP-199.