Skip to content

Commit 3a73c41

Browse files
Initial CBTC BTC Implementation (#4443)
* Initial CBTC BTC Implementation * Implement CBTC BTC Attester and Canton Digital Assets Proof of Reserves Adapters - Added @chainlink/dlc-cbtc-btc-attester-por-adapter for querying Bitcoin reserves. - Introduced @chainlink/dlc-cbtc-canton-digital-assets-por-adapter for retrieving total CBTC supply from the Digital Asset API. - Updated .pnp.cjs and .yarnrc.yml to reflect new package references and enabled ESM loader. - Created necessary configuration, endpoints, and transport layers for both adapters. - Included comprehensive tests for both adapters to ensure functionality and accuracy. * Added DA/Attester POR endpoints * tidyup * Enhance BTC Proof of Reserves Adapter - Added dependencies for Bitcoin address calculation: bip32, bitcoinjs-lib, and tiny-secp256k1. - Introduced CHANGELOG.md for the @chainlink/dlc-cbtc-btc-por-adapter, documenting the initial release and key features. - Updated README.md to reflect changes in configuration and functionality. - Implemented address calculation logic in address.ts, ensuring trustless verification against the Attester API. - Enhanced reserves calculation logic in por.ts, including confirmation counting and pending spend handling. - Added comprehensive unit and integration tests to validate the adapter's functionality. * Fixes + cleanup * Fixed structuring issues * Fixed issues raised in PR * Fixed additional issues raised in PR * Refactor BTC PoR Adapter Configuration and Response Handling - Updated configuration to replace `BITCOIN_NETWORK` with `CHAIN_NAME`, supporting `canton-mainnet` and `canton-testnet`. - Modified response types to return reserves as strings for consistency. - Adjusted integration tests and fixtures to reflect the new configuration and response format. - Enhanced background processing logic to improve clarity and maintainability. * Additional fixes and cleanup * Update default endpoint * Add CBTC Proof of Reserves Rollout Document and Update Configurations - Introduced a new ROLLOUT.md document detailing the deployment and configuration of the CBTC Proof of Reserves system. - Updated adapter configuration descriptions for clarity. - Corrected terminology from 'attestor' to 'attester' in relevant files for consistency. - Adjusted integration tests to reflect changes in endpoint naming conventions. * Fix package name * Fix GH actions * update gitignore * Refactor BTC PoR Adapter to Support Multiple Attester API URLs - Updated configuration to use `ATTESTER_API_URLS` as a comma-separated list of URLs. - Introduced utility functions `parseUrls` and `medianBigInt` for handling URL parsing and median calculation. - Modified transport logic to query multiple attesters and calculate reserves independently. - Adjusted integration and unit tests to accommodate changes in configuration and functionality. * Enhance CBTC PoR Adapter with Multi-URL Support and Utility Functions - Updated configuration to utilize `ATTESTER_API_URLS` for multiple attester endpoints. - Added utility functions `buildUrl`, `parseUrls`, and `medianBigInt` for improved URL handling and median calculations. - Modified transport logic to fetch data from multiple attesters in parallel and compute the median supply. - Adjusted integration and unit tests to reflect the new configuration and functionality. * Implement DLC CBTC Proof of Reserves Adapter - Introduced the new adapter for CBTC Proof of Reserves, supporting multiple endpoints: `attesterSupply`, `daSupply`, and `reserves`. - Added configuration options for API URLs and execution intervals. - Developed utility functions for URL handling and median calculations. - Created integration and unit tests to validate the adapter's functionality and ensure accurate responses. - Removed the deprecated BTC PoR adapter and its associated files to streamline the codebase. * Small fixes * mm/dlc cbtc por (#4508) * update changeset, remove unused test-payload file * removing customInputValidation on required config * Small comment * fix pipeline * update tsconfigs to standard * Fixed typing issue for GH action failure * Regenerate snapshot file * Tidyup * Fixed snapshot build issue --------- Co-authored-by: mmcallister-cll <139181225+mmcallister-cll@users.noreply.github.com> Co-authored-by: Matthew McAllister <matthew.mcallister@smartcontract.com>
1 parent f0a5124 commit 3a73c41

37 files changed

+2216
-2
lines changed

.changeset/new-drinks-suffer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@chainlink/dlc-cbtc-por-adapter': major
3+
---
4+
5+
dlc-cbtc-por initial release

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ packages/k6/src/config/http.json
2929
# IDE metadata
3030
.vscode
3131
.idea
32+
.editorconfig
33+
.gitattributes
3234

3335
# Secrets
3436
.envrc
3537
.env
38+

.pnp.cjs

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
1.13 MB
Binary file not shown.
6.06 KB
Binary file not shown.
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# DLC CBTC Proof of Reserves Adapter
2+
3+
This adapter provides multiple endpoints for CBTC proof of reserves:
4+
5+
- **`attesterSupply`** (default): CBTC supply from DLC.Link Attester APIs
6+
- **`daSupply`**: CBTC supply from Digital Asset's API
7+
- **`reserves`**: Bitcoin reserves calculated from on-chain UTXOs
8+
9+
## Configuration
10+
11+
| Variable | Required | Default | Description |
12+
| ----------------------- | -------- | ---------------- | ------------------------------------------------------------------------------------ |
13+
| `ATTESTER_API_URLS` | Yes | - | Comma-separated list of DLC.Link Attester API base URLs |
14+
| `BITCOIN_RPC_ENDPOINT` | Yes | - | Electrs-compatible Bitcoin blockchain API endpoint |
15+
| `CANTON_API_URL` | No | - | Digital Asset API endpoint URL for token metadata |
16+
| `CHAIN_NAME` | No | `canton-mainnet` | Chain name to filter addresses (`canton-mainnet`, `canton-testnet`, `canton-devnet`) |
17+
| `BACKGROUND_EXECUTE_MS` | No | `10000` | Interval in milliseconds between background executions |
18+
19+
## Endpoints
20+
21+
### `attesterSupply` (default)
22+
23+
Returns the total CBTC supply from DLC.Link Attester APIs as an integer string (scaled by 10^10).
24+
25+
Queries multiple attesters in parallel and returns the **median** of successful responses. Requires at least 1 successful response.
26+
27+
#### Example Request
28+
29+
```json
30+
{
31+
"data": {}
32+
}
33+
```
34+
35+
#### Example Response
36+
37+
```json
38+
{
39+
"result": "143127387999",
40+
"data": {
41+
"result": "143127387999"
42+
},
43+
"statusCode": 200
44+
}
45+
```
46+
47+
### `daSupply`
48+
49+
Returns the total CBTC supply from the Digital Asset API as an integer string (scaled by 10^decimals).
50+
51+
Requires `CANTON_API_URL` to be set.
52+
53+
#### Example Request
54+
55+
```json
56+
{
57+
"data": {
58+
"endpoint": "daSupply"
59+
}
60+
}
61+
```
62+
63+
#### Example Response
64+
65+
```json
66+
{
67+
"result": "143127388000",
68+
"data": {
69+
"result": "143127388000"
70+
},
71+
"statusCode": 200
72+
}
73+
```
74+
75+
### `reserves`
76+
77+
Returns the total Bitcoin reserves (in satoshis) across all vault addresses.
78+
79+
The endpoint:
80+
81+
1. Fetches vault address data from attesters
82+
2. Independently calculates Bitcoin addresses from the threshold public key
83+
3. Verifies calculated addresses match attester-provided addresses
84+
4. Queries the Bitcoin blockchain for UTXOs with at least 1 confirmation
85+
5. Returns the **median** reserves across all attesters
86+
87+
#### Example Request
88+
89+
```json
90+
{
91+
"data": {
92+
"endpoint": "reserves"
93+
}
94+
}
95+
```
96+
97+
#### Example Response
98+
99+
```json
100+
{
101+
"result": "789982326000",
102+
"data": {
103+
"result": "789982326000"
104+
},
105+
"statusCode": 200
106+
}
107+
```
108+
109+
## Precision Handling
110+
111+
The `result` is a **string** to preserve precision for values exceeding `Number.MAX_SAFE_INTEGER` (9×10^15).
112+
113+
CBTC uses 10 decimals, so the maximum supply (21M BTC) would be 2.1×10^17 in base units, exceeding JavaScript's safe integer limit.
114+
115+
## Error Handling
116+
117+
The adapter returns a 502 error when:
118+
119+
**attesterSupply:**
120+
121+
- No successful attester responses
122+
- Attester status is not `"ready"`
123+
- `total_supply_cbtc` is missing, empty, or whitespace-only
124+
125+
**daSupply:**
126+
127+
- No instruments found in API response
128+
- CBTC instrument not found
129+
- `totalSupply` is missing, empty, or whitespace-only
130+
- `decimals` is missing or negative
131+
132+
**reserves:**
133+
134+
- No successful attester responses
135+
- Address verification fails (calculated address doesn't match attester)
136+
- No vault addresses found for the configured chain
137+
138+
The adapter **never** returns a default value like `0` on error - it either succeeds with valid data or fails explicitly.
139+
140+
## Running Locally
141+
142+
```bash
143+
# Build
144+
yarn build
145+
146+
# Set environment variables
147+
export ATTESTER_API_URLS="https://attester1.example.com,https://attester2.example.com"
148+
export BITCOIN_RPC_ENDPOINT="https://your-electrs-endpoint.com"
149+
export CANTON_API_URL="https://your-canton-api-endpoint.com/instruments"
150+
151+
# Start
152+
yarn start
153+
154+
# Query attesterSupply (default)
155+
curl -X POST http://localhost:8080 -H "Content-Type: application/json" -d '{"data": {}}'
156+
157+
# Query daSupply
158+
curl -X POST http://localhost:8080 -H "Content-Type: application/json" -d '{"data": {"endpoint": "daSupply"}}'
159+
160+
# Query reserves
161+
curl -X POST http://localhost:8080 -H "Content-Type: application/json" -d '{"data": {"endpoint": "reserves"}}'
162+
```
163+
164+
## Running Tests
165+
166+
```bash
167+
# From repo root - run all tests
168+
yarn jest packages/sources/dlc-cbtc-por/test/ --no-coverage
169+
170+
# Run unit tests only
171+
yarn jest packages/sources/dlc-cbtc-por/test/unit/ --no-coverage
172+
173+
# Run integration tests only
174+
yarn jest packages/sources/dlc-cbtc-por/test/integration/ --no-coverage
175+
```
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"name": "@chainlink/dlc-cbtc-por-adapter",
3+
"version": "0.0.0",
4+
"description": "Chainlink DLC CBTC Proof of Reserves adapter. Queries Attester APIs, Digital Asset API, and Bitcoin blockchain for CBTC reserves.",
5+
"keywords": [
6+
"Chainlink",
7+
"LINK",
8+
"CBTC",
9+
"Canton",
10+
"BTC",
11+
"Bitcoin",
12+
"Digital Assets",
13+
"blockchain",
14+
"oracle",
15+
"Proof of Reserves"
16+
],
17+
"main": "dist/index.js",
18+
"types": "dist/index.d.ts",
19+
"files": [
20+
"dist"
21+
],
22+
"repository": {
23+
"url": "https://github.com/smartcontractkit/external-adapters-js",
24+
"type": "git"
25+
},
26+
"license": "MIT",
27+
"scripts": {
28+
"clean": "rm -rf dist && rm -f tsconfig.tsbuildinfo",
29+
"prepack": "yarn build",
30+
"build": "tsc -b",
31+
"server": "node -e 'require(\"./index.js\").server()'",
32+
"server:dist": "node -e 'require(\"./dist/index.js\").server()'",
33+
"start": "yarn server:dist"
34+
},
35+
"dependencies": {
36+
"@chainlink/external-adapter-framework": "2.11.4",
37+
"bip32": "^4.0.0",
38+
"bitcoinjs-lib": "^6.1.7",
39+
"tiny-secp256k1": "^2.2.4",
40+
"tslib": "^2.3.1"
41+
},
42+
"devDependencies": {
43+
"@types/jest": "^29.5.14",
44+
"@types/node": "22.14.1",
45+
"nock": "13.5.6",
46+
"typescript": "5.8.3"
47+
}
48+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { AdapterConfig } from '@chainlink/external-adapter-framework/config'
2+
3+
export const config = new AdapterConfig(
4+
{
5+
// Shared config
6+
ATTESTER_API_URLS: {
7+
description: 'Comma-separated list of DLC.Link Attester API URLs',
8+
type: 'string',
9+
required: true,
10+
},
11+
// Canton/DA Supply config
12+
CANTON_API_URL: {
13+
description: 'Digital Asset API endpoint URL for CBTC token metadata',
14+
type: 'string',
15+
},
16+
// BTC Reserves config
17+
CHAIN_NAME: {
18+
description: 'Chain name to filter addresses from Attester API',
19+
type: 'enum',
20+
options: ['canton-mainnet', 'canton-testnet', 'canton-devnet'],
21+
default: 'canton-mainnet',
22+
},
23+
BITCOIN_RPC_ENDPOINT: {
24+
description: 'Electrs-compatible Bitcoin blockchain API endpoint for UTXO queries',
25+
type: 'string',
26+
required: true,
27+
},
28+
// General config
29+
BACKGROUND_EXECUTE_MS: {
30+
description: 'Interval in milliseconds between background executions',
31+
type: 'number',
32+
default: 10_000,
33+
},
34+
},
35+
{
36+
envDefaultOverrides: {
37+
CACHE_MAX_AGE: 10_000,
38+
},
39+
},
40+
)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { AdapterEndpoint } from '@chainlink/external-adapter-framework/adapter'
2+
import { EmptyInputParameters } from '@chainlink/external-adapter-framework/validation/input-params'
3+
import { config } from '../config'
4+
import { transport } from '../transport/attester-supply'
5+
import { StringResultResponse } from '../types'
6+
7+
export type BaseEndpointTypes = {
8+
Parameters: EmptyInputParameters
9+
Response: StringResultResponse
10+
Settings: typeof config.settings
11+
}
12+
13+
export const attesterSupply = new AdapterEndpoint({
14+
name: 'attesterSupply',
15+
transport,
16+
})

0 commit comments

Comments
 (0)