Skip to content

alexgo-io/bitcoin-oracle

Repository files navigation

Bitcoin Oracle

Introduction

This is a monorepo for Bitcoin Oracle project, which aims to provide a tamper-proof, censorship-resistant, on-chain oracle for meta-protocols on Bitcoin.

For the background on the project, you may want to read our efforts to build an "Indexer of Indexers" for BRC20, the leading meta-protocol on Bitcoin.

Structure

The repo contains following apps:

  • api-server
    • api-server is a nodejs server that provides REST API for the project. It uses NestJS framework.
  • bitcoin-sync
    • bitcoin-sync is a worker that syncs bitcoin header info for quick access for validators and relayers.
  • relayer
    • relayer is a used for submitting the proofs from validator to stacks-node.
  • validator
    • validator is a worker that validates meta-protocol events, bitcoin headers and submits the proofs to api-server.
  • indexer
    • indexer is a worker to process the n/m validation of the transactions.

Run Validator in Docker

  • [TODO: add instructions for running validator in docker]

Getting Started

Development Environment

direnv

This project uses direnv to manage environment variables. It also modified the PATH variable in project. Following description assuming that you have installed direnv and have it configured in your shell. Noting that ./node_modules/.bin is added into $PATH.

asdf

.tool-versions file contains list of tools and their versions used in project. Use asdf to install them with asdf install.

nx

This project uses Nx to manage monorepo. nx is installed as devDependency in project. With direnv, you can use nx command directly without npx nx.

/tools/bin directory

./tools/bin folder contains the custom development scripts, such as:

  • dev:
    • dev is a shortcut command to start up the dev environment with following command. They can be run separately.
    • dev-database:
      • starts local database
      • it will create the database and run the migrations
    • dev-vault:
      • start local vault service
      • it will set up proper rules for each componenet.
      • because the credential is loaded into environment variable by file reading in .envrc, please run direnv allow if this command is being run second time. (files changes does not trigger auto-reload for direnv)
    • dev-redis:
      • start redis
      • redis is used for caching.
  • dev-stacks:
    • starts local stacks-node and stacks-node-api
    • it will deploy the contracts and run setup transactions
    • dev-stacks is not part of dev command due to it requires more time to start.

Installation

direnv allow
pnpm install

Environment Variables

Create .envrc.override file in project root directory and add set necessary environment variables, such as:

export OK_ACCESS_KEY=""
export BIS_ACCESS_KEY=""
export UNISAT_API_KEY=""

Start Environment

dev

start in another shell:

dev-stacks

or run following:

dev-database
dev-stacks
dev-vault
dev-redis

Start Apps

nx serve api-server
nx serve bitcoin-sync
nx serve validator
nx serve relayer
nx serve indexer

Validator

Validator under packages/apps/validator folder is a worker that validates meta-protocol events, bitcoin headers and submits the proofs to api-server. It dynamically loads the module which implements the ValidatorProcessInterface interface.

Different type of validators is controlled by VALIDATOR_NAME environment variable when running nx serve validator. Set it differently in .envrc.override to use choice of yours.

Validator Process

An off-chain indexer who wants to participate as a validator must implement the follwing interface, which is then loaded by a validator worker.

export abstract class ValidatorProcessInterface {
  abstract processBlock$(block: number): Observable<unknown>;
}

Examples

Watcher API

Watcher API returns the debug information. The endpoint is ${HOST}/debug/query. The query parameter is defined in RequestQuery as follow:

  tx_id: Buffer;
  tx_hash: Buffer;
  output: bigint;
  satpoint: bigint;
  from_address: string;
  to_address: string;
  from: Buffer;
  to: Buffer;
  tick: string;
  amt: bigint;
  order_hash: Buffer;
  signature: Buffer;
  signer: string;
  height: bigint;
  stacks_tx_id: Buffer;
  block_hash: Buffer;
  block_header: Buffer;