Skip to content

Commit

Permalink
Feat: initial contracts folder setup, sbtc-registry structs (#127)
Browse files Browse the repository at this point in the history
* feat: initial contracts folder setup

* feat: initial registry contract and tests setup

* feat: update readme

* feat: add github action for contract tests

* feat: setup initial pnpm workspace

* feat: emit event when storing withdrawal request

* feat: add lint to contract tests CI
  • Loading branch information
hstove authored May 7, 2024
1 parent d15caf4 commit 55e897b
Show file tree
Hide file tree
Showing 24 changed files with 10,105 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/contract-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Contract tests
on: [push]

jobs:
contract_tests:
name: Contract tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- uses: pnpm/action-setup@v2
with:
version: 9.0.6
- name: Set Node Version
uses: actions/setup-node@v3
with:
node-version: 18.19.0
cache: "pnpm"
- name: Install dependencies
run: pnpm install
working-directory: ./contracts
- name: Type checks
run: pnpm typecheck
working-directory: ./contracts
- name: Tests
run: pnpm test
working-directory: ./contracts
- name: Lint
run: pnpm lint
working-directory: ./contracts
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,17 @@
**/.generated-sources
**.log
**/node_modules

## Contracts
contracts/settings/Mainnet.toml
contracts/settings/Testnet.toml
contracts/.cache/**
contracts/history.txt

contracts/logs
contracts/*.log
contracts/npm-debug.log*
contracts/coverage
contracts/*.info
contracts/costs-reports.json
contracts/node_modules
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ order to build and run the sources in this repository.

- **[Cargo](https://doc.rust-lang.org/cargo/)** - [Installation Guide](https://doc.rust-lang.org/cargo/getting-started/installation.html) - Builds rust packages.
- **[npm](https://www.npmjs.com/)** - [Installation Guide](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) - Manages node packages
- **[pnpm](https://pnpm.io)** - [Installation guide](https://pnpm.io/installation) - Manages node packages
- **[Smithy](https://smithy.io/2.0/index.html)** - [Installation Guide](https://smithy.io/2.0/guides/smithy-cli/cli_installation.html) - Generates OpenAPI templates
- **[OpenAPI Generator](https://openapi-generator.tech/)** - [Installation Guide](https://openapi-generator.tech/docs/installation/) - Generates API clients
- **[Java 21](https://www.oracle.com/java/)** - [Installation Guide](https://www.oracle.com/java/technologies/downloads/) - Required for OpenAPI Generator
Expand All @@ -52,7 +53,9 @@ echo "\n--- sBTC tool versions ---" \
&& echo "openapi-generator $(openapi-generator-cli version)" \
&& java --version
```

Below is the output on a machine that is able to build and run all the sources and tests.

```
--- sBTC tool versions ---
cargo 1.77.2 (e52e36006 2024-03-26)
Expand Down
4 changes: 4 additions & 0 deletions contracts/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

tests/** linguist-vendored
vitest.config.js linguist-vendored
* text=lf
26 changes: 26 additions & 0 deletions contracts/Clarigen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

# Set to your project's Clarinet config file
clarinet = "./Clarinet.toml"

# Set where you'd like TypeScript types output.
# Comment or remove section to skip TypeScript types
[types]
# `output` should be a path to a single file
output = "tests/clarigen-types.ts"

# You can also specify multiple output paths:
# outputs = [
# "src/clarigen-types.ts",
# "test/clarigen-types.ts"
# ]

after = "pnpm prettier --log-level error -w ./tests/clarigen-types.ts"

# Set where you'd like generated contract docs
# Generate docs by running `clarigen docs`
[docs]
# `output` should be a folder
output = "docs"

# `docs.after` - script to run after docs are generated.
after = "pnpm prettier --log-level error -w ./docs"
24 changes: 24 additions & 0 deletions contracts/Clarinet.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[project]
name = 'contracts'
description = ''
authors = []
telemetry = false
cache_dir = './.cache'
requirements = []
[contracts.sbtc-bootstrap-signers]
path = 'contracts/sbtc-bootstrap-signers.clar'
clarity_version = 2
epoch = 2.5

[contracts.sbtc-registry]
path = 'contracts/sbtc-registry.clar'
clarity_version = 2
epoch = 2.5
[repl.analysis]
passes = ['check_checker']

[repl.analysis.check_checker]
strict = false
trusted_sender = false
trusted_caller = true
callee_filter = true
53 changes: 53 additions & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# sBTC contracts

This folder contains the Clarity contracts and unit tests for
the sBTC protocol.

## Setup

Install dependencies:

```bash
pnpm install
```

## Running tests

```bash
pnpm test
```

To run tests in "watch" mode:

```bash
pnpm vitest
```

## Generating Clarigen types

This project uses Clarigen to automatically generate types
for contracts.

When contracts are updated, run:

```bash
pnpm clarigen
```

You can also run this in watch mode to automatically generate
types when contracts are updated:

```bash
pnpm clarigen --watch
```

## Contract documentation

Clarigen automatically creates Markdown docs for the contracts
in this folder. They're located in the [./docs](./docs) folder.

You can re-generate them with:

```bash
pnpm clarigen docs
```
30 changes: 30 additions & 0 deletions contracts/contracts/sbtc-bootstrap-signers.clar
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

;; title: sbtc-bootstrap-signers
;; version:
;; summary:
;; description:

;; traits
;;

;; token definitions
;;

;; constants
;;

;; data vars
;;

;; data maps
;;

;; public functions
;;

;; read only functions
;;

;; private functions
;;

119 changes: 119 additions & 0 deletions contracts/contracts/sbtc-registry.clar
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
;; sBTC Registry contract

;; Error codes

;; Contract caller is not authorized
(define-constant ERR_UNAUTHORIZED u400)

;; Invalid request ID
(define-constant ERR_INVALID_REQUEST_ID (err u401))

;; Internal data structure to store withdrawal
;; requests. Requests are associated with a unique
;; request ID.
(define-map withdrawal-requests uint {
;; Amount of sBTC being withdrawaled (in sats)
amount: uint,
max-fee: uint,
sender: principal,
;; BTC recipient address in the same format of
;; pox contracts
recipient: {
version: (buff 1),
hashbytes: (buff 32),
},
;; Burn block height where the withdrawal request was
;; created
block-height: uint,
})

(define-data-var last-withdrawal-request-id uint u0)

;; Data structure to map request-id to status
;; If status is `none`, the request is pending.
;; Otherwise, the boolean value indicates whether
;; the deposit was accepted.
(define-map withdrawal-status uint bool)

;; Public functions

;; Store a new withdrawal request.
;; Note that this function can only be called by other sBTC
;; contracts - it cannot be called by users directly.
;;
;; This function does not handle validation or moving the funds.
;; Instead, it is purely for the purpose of storing the request.
;;
;; The function will emit a print event with the topic "withdrawal-request"
;; and the data of the request.
(define-public (create-withdrawal-request
(amount uint)
(max-fee uint)
(sender principal)
(recipient { version: (buff 1), hashbytes: (buff 32) })
(height uint)
)
(let
(
(id (increment-last-withdrawal-request-id))
)
(try! (validate-caller))
;; #[allow(unchecked_data)]
(map-insert withdrawal-requests id {
amount: amount,
max-fee: max-fee,
sender: sender,
recipient: recipient,
block-height: height,
})
(print {
topic: "withdrawal-request",
amount: amount,
request-id: id,
sender: sender,
recipient: recipient,
block-height: height,
max-fee: max-fee,
})
(ok id)
)
)

;; Read-only functions

;; Get a withdrawal request by its ID.
;;
;; This function returns the fields of the withrawal
;; request, along with it's status.
(define-read-only (get-withdrawal-request (id uint))
(match (map-get? withdrawal-requests id)
request (some (merge request {
status: (map-get? withdrawal-status id)
}))
none
)
)

;; Private functions

;; Increment the last withdrawal request ID and
;; return the new value.
(define-private (increment-last-withdrawal-request-id)
(let
(
(next-value (+ u1 (var-get last-withdrawal-request-id)))
)
(var-set last-withdrawal-request-id next-value)
next-value
)
)

;; Validate the caller of the function.
;; TODO: Once other contracts are in place, update this
;; to use the sBTC controller.
(define-private (validate-caller)
;; To provide an explicit error type, add a branch that
;; wont be hit
;; (if (is-eq contract-caller .controller) (ok true) (err ERR_UNAUTHORIZED))
(if false (err ERR_UNAUTHORIZED) (ok true))
)
62 changes: 62 additions & 0 deletions contracts/deployments/default.simnet-plan.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
id: 0
name: "Simulated deployment, used as a default for `clarinet console`, `clarinet test` and `clarinet check`"
network: simnet
genesis:
wallets:
- name: deployer
address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
balance: "100000000000000"
- name: faucet
address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6
balance: "100000000000000"
- name: wallet_1
address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5
balance: "100000000000000"
- name: wallet_2
address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG
balance: "100000000000000"
- name: wallet_3
address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC
balance: "100000000000000"
- name: wallet_4
address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND
balance: "100000000000000"
- name: wallet_5
address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB
balance: "100000000000000"
- name: wallet_6
address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0
balance: "100000000000000"
- name: wallet_7
address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ
balance: "100000000000000"
- name: wallet_8
address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP
balance: "100000000000000"
contracts:
- costs
- pox
- pox-2
- pox-3
- pox-4
- lockup
- costs-2
- costs-3
- cost-voting
- bns
plan:
batches:
- id: 0
transactions:
- emulated-contract-publish:
contract-name: sbtc-bootstrap-signers
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/sbtc-bootstrap-signers.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: sbtc-registry
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/sbtc-registry.clar
clarity-version: 2
epoch: "2.5"
3 changes: 3 additions & 0 deletions contracts/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contracts

- [`sbtc-registry`](sbtc-registry.md)
Loading

0 comments on commit 55e897b

Please sign in to comment.