Skip to content

Commit 920684d

Browse files
committed
Move to monorepository structure
1 parent b9c1abd commit 920684d

File tree

73 files changed

+6458
-12733
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+6458
-12733
lines changed

.github/actions/setup/action.yml

Lines changed: 0 additions & 20 deletions
This file was deleted.

.github/workflows/checks.yml

Lines changed: 0 additions & 23 deletions
This file was deleted.

README.md

Lines changed: 3 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,5 @@
1-
# ERC-8002: SPV Gateway
1+
# ERC-8002: SPV Gateway
22

3-
Introduce a singleton contract for on-chain verification of transactions that happened on Bitcoin. The contract acts as a trustless Simplified Payment Verification (SPV) gateway where anyone can submit Bitcoin block headers. The gateway maintains the mainchain of blocks and allows the existence of Bitcoin transactions to be verified via Merkle proofs.
3+
This repository contains the smart contracts and services for the `SPV Gateway` — protocol that enables the trustless on-chain verification of transactions that happened on the Bitcoin network.
44

5-
Link to [ERC-8002](https://ethereum-magicians.org/t/erc-8002-simplified-payment-verification-gateway/25038).
6-
7-
> [!NOTE]
8-
> Since the ERC is currently a draft, there is no deployment on mainnet available. Please use [the contract on Sepolia](https://sepolia.etherscan.io/address/0xE8e6CA2113338c12eb397617371D92239f3E6A60) for testing purposes.
9-
10-
# How it Works
11-
12-
The gateway is a permissionless contract that operates by receiving raw Bitcoin block headers (anyone can submit them), which are then parsed and validated against Bitcoin's consensus rules:
13-
14-
1. Header Parsing: Raw 80-byte Bitcoin block headers are parsed into a structured *BlockHeader.HeaderData* format, handling Bitcoin's little-endian byte ordering.
15-
2. Double SHA256 Hashing: Each block header is double SHA256 hashed to derive its unique block hash, which is then saved in a big-endian format.
16-
3. Proof-of-Work Verification: The calculated block hash is checked against the current network difficulty target (derived from the *bits* field in the block header).
17-
4. Chain Extension & Reorganization: New blocks are added to a data structure that allows for tracking multiple chains. When a new block extends a chain with larger cumulative work, the *mainchainHead* is updated, reflecting potential chain reorganizations.
18-
5. Difficulty Adjustment: Every 2016 blocks, the contract calculates a new difficulty target based on the time taken to mine the preceding epoch. This ensures the 10-minute average block time is maintained.
19-
20-
Under the hood, the contract builds the mainchain but doesn't define its finality. The number of required block confirmations is up to the integration dApps to decide.
21-
22-
## Submitting Bitcoin Blocks
23-
24-
To submit a new Bitcoin block, call `addBlockHeader` function by passing a valid raw block header as a parameter. It is an open function that will revert in case Bitcoin PoW checks don't pass.
25-
26-
In case multiple blocks can be added, call `addBlockHeaderBatch` function to save ~15% on gas per block.
27-
28-
## Verifying Bitcoin Tx Inclusion
29-
30-
In order to verify the tx existence, the `checkTxInclusion` function needs to be called.
31-
32-
The list parameters to be passed:
33-
34-
1. `merkleProof` - Merkle path for a given transaction to be checked. The Merkle path can either be built locally or by calling `gettxoutproof` on a Bitcoin node.
35-
2. `blockHash` - Hash of the block to check the tx inclusion against. This block is required to exist in the SPV storage.
36-
3. `txId` - Tx hash (Merkle leaf) to be checked.
37-
4. `txIndex` - The Merkle "direction bits" to decide on left or right hashing order.
38-
5. `minConfirmationsCount` - Number of required mainchain confirmation for the block to have.
39-
40-
> [!TIP]
41-
> Please check out [this test case](./test/SPVGateway.test.ts#L223) for more integration information.
42-
43-
## Permissionlessness
44-
45-
In order for the gateway to be truly permissionless, the contract's initialization needs to be permissionless as well. Alongside the regular `SPVGateway`, the repository hosts a `HistoricalSPVGateway` contract, that uses a "proof-of-bitcoin" ZK proof for its initialization. This enables verification of historical Bitcoin blocks and transactions otherwise too expensive to include. Since syncing up the gateway from Bitcoin's genesis would cost ~100 ETH on the mainnet.
46-
47-
# HistoricalSPVGateway
48-
49-
`HistoricalSPVGateway` is an extension of the basic `SPVGateway` contract. It uses "proof-of-bitcoin" ZK proof that compresses the entire Bitcoin block history into a single Merkle root to be used during the contract's initialization. This root can then used to verify the "historical" existence of some blocks and transactions.
50-
51-
> [!IMPORTANT]
52-
> Currently, the "proof-of-bitcoin" ZK proof is generated to the first *912384* Bitcoin blocks. The circuits source code can be found [here](https://github.com/distributed-lab/bitcoin-prover).
53-
54-
## Building the History Merkle Tree
55-
56-
In order to prove the historical block existence, you need to pass the corresponding Merkle path to a smart contract. For that, the entire historical Merkle tree needs to be built:
57-
58-
1. Fetch all block hashes from the genesis block up to the height of `provedBlocksCount - 1`.
59-
2. Split these blocks into *1024-block* chunks.
60-
3. Create Level1 Merkle trees for each chunk.
61-
4. Create an array containing all the Level1 tree roots.
62-
5. Pad the array from the previous step with zeros for its length to reach the next power of 2.
63-
6. Create a Level2 Merkle tree, using the array from the previous step as the tree's values.
64-
65-
> [!NOTE]
66-
> For the Level1 Merkle tree use `SHA256("leaf1" | blockHash)` and `SHA256("node1" | left | right)` for hashing leaves and nodes. And for the Level2 Merkle tree, `SHA256("leaf2" | level1MerkleRoot)` and `SHA256("node2" | left | right)` respectively.
67-
68-
## Verifying History Bitcoin Blocks Inclusion
69-
70-
To verify the existence of a historical Bitcoin block, call the `checkHistoryBlockInclusion` function.
71-
72-
This function requires a `HistoryBlockInclusionProofData` struct as a parameter, which contains the following fields:
73-
74-
1. `level1MerkleProof` - Level1 Merkle path for the block hash being checked.
75-
2. `level2MerkleProof` - Level2 Merkle path for the Level1 Merkle root (which is calculated from the `level1MerkleProof`)
76-
3. `blockHash` - Block hash to be checked.
77-
4. `blockHeight` - Block height of the passed block hash.
78-
79-
> [!TIP]
80-
> Please check out [this test cases](./test/HistoricalSPVGateway.test.ts#L181) for more integration information.
81-
82-
## Verifying History Bitcoin Tx Inclusion
83-
84-
In order to verify the tx existence in the proven Bitcoin history, the `checkHistoryTxInclusion` function needs to be called.
85-
86-
The list of parameters to be passed:
87-
88-
1. `merkleProof` - Merkle path for a given transaction to be checked. The Merkle path can either be built locally or by calling `gettxoutproof` on a Bitcoin node.
89-
2. `blockHeaderRaw` - Raw block header of the block to check the transaction's inclusion against.
90-
3. `txId` - Tx hash (Merkle leaf) to be checked.
91-
4. `txIndex` - The Merkle "direction bits" to decide on left or right hashing order.
92-
5. `blockInclusionProofData` - The proof data for the historical block hash inclusion.
93-
94-
> [!TIP]
95-
> Please check out [this test case](./test/HistoricalSPVGateway.test.ts#L309) for more integration information.
96-
97-
# Disclaimer
98-
99-
Bitcoin + Ethereum = <3
5+
The protocol functions as a permissionless Simplified Payment Verification (SPV) gateway. Anyone can submit Bitcoin block headers to the gateway, which then validates them against Bitcoin's consensus rules. The gateway maintains the mainchain and allows dApps to verify a transaction's existence using Merkle proofs.

package.json

Lines changed: 9 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,14 @@
11
{
2-
"name": "@distributedlab/spv-gateway",
3-
"version": "0.1.0",
4-
"license": "MIT",
2+
"name": "root",
3+
"version": "0.0.0",
54
"author": "Distributed Lab",
6-
"description": "ERC-8002: SPV gateway reference implementation",
7-
"keywords": [
8-
"solidity",
9-
"smart-contracts",
10-
"bitcoin",
11-
"spv-gateway"
12-
],
13-
"files": [
14-
"**/*.sol",
15-
"!mock/**/*"
5+
"license": "SEE LICENSE IN EACH PACKAGE'S LICENSE FILE",
6+
"private": true,
7+
"workspaces":[
8+
"src/*"
169
],
1710
"scripts": {
18-
"prepare": "husky",
19-
"compile": "npx hardhat compile",
20-
"coverage": "npx hardhat coverage --solcoverjs ./.solcover.ts",
21-
"clean": "npx hardhat clean",
22-
"test": "npx hardhat test",
23-
"test-all": "npx hardhat migrate && npm run test",
24-
"private-network": "npx hardhat node",
25-
"private-network-fork": "npx hardhat node --fork https://mainnet.infura.io/v3/$(grep INFURA_KEY .env | cut -d '\"' -f2)",
26-
"deploy-localhost": "npx hardhat migrate --network localhost",
27-
"deploy-sepolia": "npx hardhat migrate --network sepolia --verify",
28-
"generate-types": "TYPECHAIN_FORCE=true npx hardhat typechain && npx hardhat gobind",
29-
"generate-docs": "npx hardhat markup",
30-
"solhint-check": "solhint --noPoster \"./contracts/**/*.sol\"",
31-
"lint-fix": "npm run lint-sol-fix && npm run lint-ts-fix && npm run lint-json-fix && npm run solhint-check",
32-
"lint-json-fix": "prettier --write \"./**/*.json\"",
33-
"lint-ts-fix": "prettier --write \"./**/*.ts\" --ignore-path .prettierignore",
34-
"lint-sol-fix": "prettier --write \"contracts/**/*.sol\"",
35-
"publish-to-npm": "npm run lint-fix && bash ./scripts/publish.sh --public"
36-
},
37-
"dependencies": {
38-
"@openzeppelin/contracts": "5.2.0",
39-
"@openzeppelin/contracts-upgradeable": "5.2.0",
40-
"@solarity/solidity-lib": "3.2.0",
41-
"solady": "0.1.23"
42-
},
43-
"devDependencies": {
44-
"@nomicfoundation/hardhat-chai-matchers": "^2.0.8",
45-
"@nomicfoundation/hardhat-ethers": "^3.0.8",
46-
"@nomicfoundation/hardhat-network-helpers": "^1.0.12",
47-
"@nomicfoundation/hardhat-verify": "^2.0.13",
48-
"@openzeppelin/merkle-tree": "^1.0.8",
49-
"@solarity/hardhat-gobind": "^1.2.2",
50-
"@solarity/hardhat-markup": "^1.0.10",
51-
"@solarity/hardhat-migrate": "^3.1.0",
52-
"@typechain/ethers-v6": "^0.5.1",
53-
"@typechain/hardhat": "^9.1.0",
54-
"@types/chai": "^4.3.20",
55-
"@types/fs-extra": "^11.0.4",
56-
"@types/mocha": "^10.0.10",
57-
"@types/node": "^22.13.2",
58-
"axios": "^1.9.0",
59-
"chai": "^4.5.0",
60-
"dotenv": "^16.4.7",
61-
"ethers": "^6.13.5",
62-
"fs-extra": "^11.3.0",
63-
"hardhat": "^2.22.18",
64-
"hardhat-contract-sizer": "^2.10.0",
65-
"hardhat-gas-reporter": "^2.2.2",
66-
"husky": "^9.1.7",
67-
"mocha": "^11.1.0",
68-
"prettier": "^3.5.0",
69-
"prettier-plugin-solidity": "^1.4.2",
70-
"solhint": "^6.0.0",
71-
"solhint-plugin-prettier": "^0.1.0",
72-
"solidity-coverage": "^0.8.14",
73-
"ts-node": "^10.9.2",
74-
"tsconfig-paths": "^4.2.0",
75-
"typechain": "^8.3.2",
76-
"typescript": "^5.7.3"
11+
"test": "npm run --if-present test --workspaces",
12+
"lint-fix": "npm run --if-present lint-fix --workspaces"
7713
}
78-
}
14+
}
File renamed without changes.

src/core-contracts/.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
node_modules
2+
.env
3+
.DS_Store
4+
5+
# Hardhat files
6+
cache
7+
artifacts
8+
coverage.json
9+
coverage
10+
abi
11+
12+
# Typechain generated files
13+
generated-types
14+
15+
# Hardhat migrate
16+
.storage.json

src/core-contracts/.prettierignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
node_modules
2+
.env
3+
.DS_Store
4+
package-lock.json
5+
6+
# Hardhat files
7+
cache
8+
artifacts
9+
coverage.json
10+
coverage
11+
12+
# Typechain generated files
13+
generated-types
14+
15+
# Hardhat migrate
16+
.storage.json
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)