Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Bug Report
description: File a bug report
labels: ['bug']
body:
- type: markdown
attributes:
value: Thanks for taking the time to fill out this bug report!
- type: input
id: version
attributes:
label: "Project version"
placeholder: "1.2.3"
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A brief description of what happened and what you expected to happen
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: "Minimal reproduction steps"
description: "The minimal steps needed to reproduce the bug"
validations:
required: true
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/feature-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: Feature request
description: Suggest a new feature
labels: ['feature']
body:
- type: textarea
id: feature-description
attributes:
label: "Describe the feature"
description: "A description of what you would like to see in the project"
validations:
required: true
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/other-issue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
name: Other issue
about: Other kind of issue
---
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Linting Checks and Tests

on:
push:
branches:
- main
- dev
pull_request:

permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint-and-test:
name: Lint and Test (Ubuntu)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy, rustfmt

- name: Cache cargo registry, git and target
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Run Rust fmt
run: cargo fmt --all --check

- name: Run clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings

- name: Run tests
run: cargo test --workspace --all-features --locked --no-fail-fast
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# Ignoring .js files, as typescript firstly compiles into it
/tests/*.js

# Disable logs that have obtained during run
/logs
*.log
.env

# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
.vscode/

# frontend code
node_modules/
dist/

# Mac OSX temporary files
.DS_Store
**/.DS_Store

# Logs
logs/*
1 change: 1 addition & 0 deletions .simplicity-dex.example/keypair.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<your_private_key>
1 change: 1 addition & 0 deletions .simplicity-dex.example/relays.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<your_preferred_relays>
31 changes: 31 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[workspace]
resolver = "3"
members = [
"crates/*"
]

[workspace.package]
version = "0.1.0"
edition = "2024"
rust-version = "1.91.0"
authors = ["Blockstream"]
readme = "README.md"


[workspace.dependencies]
anyhow = { version = "1.0.100" }
clap = { version = "4.5.49", features = ["derive"] }
dirs = {version = "6.0.0"}
futures-util = { version = "0.3.31" }
global-utils = { path = "crates/global-utils" }
nostr = { version = "0.43.1", features = ["std"] }
nostr-sdk = { version = "0.43.0" }
dex-nostr-relay = { path = "./crates/dex-nostr-relay"}
serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.145" }
thiserror = { version = "2.0.17" }
tokio = { version = "1.48.0", features = ["macros", "test-util", "rt", "rt-multi-thread"] }
tracing = { version = "0.1.41" }
tracing-appender = { version = "0.2.3" }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
url = { version = "2.5.7" }
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## This help screen
help:
@printf "Available targets:\n\n"
@awk '/^[a-zA-Z\-\_0-9%:\\]+/ { \
helpMessage = match(lastLine, /^## (.*)/); \
if (helpMessage) { \
helpCommand = $$1; \
helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
gsub("\\\\", "", helpCommand); \
gsub(":+$$", "", helpCommand); \
printf " \x1b[32;01m%-35s\x1b[0m %s\n", helpCommand, helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST) | sort -u
@printf "\n"

## Format code
fmt:
cargo +nightly fmt --all

## Show lints
clippy:
cargo clippy -- -Dclippy::pedantic

## Show lints for all features
clippy_all_features:
cargo clippy --workspace --all-targets --all-features -- -D warnings
125 changes: 125 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Simplicity DEX

A distributed exchange built on the NOSTR protocol, leveraging Simplicity smart contracts and the PACT (PACT for
Auditable Contract Transactions) messaging protocol.

## Overview

Simplicity DEX is a decentralized exchange that combines the power of Simplicity smart contracts with the distributed
messaging capabilities of NOSTR. By utilizing the PACT protocol, we enable secure, auditable, and transparent trading of
digital assets without relying on centralized intermediaries.

## Key Features

- **Decentralized Architecture**: Built on NOSTR for censorship-resistant, distributed messaging
- **Simplicity Smart Contracts**: Leveraging Bitcoin's Simplicity language for provably secure contract execution
- **PACT Protocol**: Standardized format for auditable contract transactions
- **Open Ecosystem**: Compatible with any NOSTR client for maximum interoperability
- **Maker Identity Registry**: On-chain reputation system for market makers

## DEX Messaging Protocol

The core of our DEX is the **PACT (PACT for Auditable Contract Transactions)** protocol, which defines the format of
trading offers. This protocol is fully adapted to be compatible with the NOSTR event structure.

### Offer Structure

A PACT offer is implemented as a standard NOSTR event with kind `30078` (non-standard, ephemeral event kind for DEX
offers). The event structure maps to PACT requirements as follows:

| NOSTR Field | PACT Field | Data Type | Required | Description |
|---------------|---------------|-----------------------|----------|-------------------------------------------------------------------------------------------------------------------|
| `id` | Event ID | string (64-char hex) | Yes | SHA-256 hash of canonical serialized event data (excluding `sig`). Serves as unique, content-addressed identifier |
| `pubkey` | Maker Key | string (64-char hex) | Yes | 32-byte x-only Schnorr public key of market maker. Must be registered in on-chain Maker Identity Registry |
| `created_at` | Timestamp | integer | Yes | Unix timestamp (seconds) when offer was created |
| `description` | Description | string | No | Human-readable description of instrument and complex terms |
| `kind` | Event Type | integer | Yes | Event type identifier. Value `1` reserved for standard offers. Enables future protocol extensions |
| `tags` | Metadata | array of arrays | Yes | Structured machine-readable metadata for filtering and discovery |
| `content` | Contract Code | string | Yes | Stringified JSON containing full Simplicity contract code |
| `sig` | Signature | string (128-char hex) | Yes | 64-byte Schnorr signature proving authenticity and integrity |

### Tag Examples

The `tags` field contains structured metadata as key-value pairs:

```json
[
[
"asset_to_sell",
"<liquid_asset_id>"
],
[
"asset_to_buy",
"<liquid_asset_id>"
],
[
"price",
"1000000",
"sats_per_contract"
],
[
"expiry",
"1735689600"
],
[
"compiler",
"simplicity-v1.2.3",
"deterministic_build_hash"
]
]
```

### Protocol Benefits

- **Interoperability**: Any NOSTR-compatible client can parse and validate offers
- **Transparency**: All offers are publicly auditable
- **Censorship Resistance**: Distributed messaging prevents single points of failure
- **Standardization**: Consistent format enables ecosystem growth
- **Extensibility**: Protocol designed for future enhancements

## Getting Started

### Basic Usage

1. **Create an Offer**: Generate a PACT-compliant NOSTR event with your trading parameters
2. **Broadcast**: Publish the offer to NOSTR relays
3. **Discovery**: Takers can filter and discover offers using tag-based queries
4. **Execution**: Complete trades through Simplicity contract execution

## Architecture

```text
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Maker Client │ │ NOSTR Relays │ │ Taker Client │
│ │<───>| │<───>│ │
│ - Create Offers │ │ - Store Events │ │ - Discover │
│ - Sign Contracts│ │ - Relay Messages │ │ - Execute Trades│
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
│ ┌──────────────────┐ │
└─────────────>│ Liquid Network │<────────────┘
│ │
│ - Asset Registry │
│ - Contract Exec │
│ - Settlement │
└──────────────────┘
```

## Contributing

We welcome contributions to the Simplicity DEX project.

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Links

- [Simplicity Language](https://github.com/ElementsProject/simplicity)
- [NOSTR Protocol](https://github.com/nostr-protocol/nostr)
- [Liquid Network](https://liquid.net/)

## Disclaimer

This software is experimental and should be used with caution. Always verify contract code and understand the risks
before trading.
18 changes: 18 additions & 0 deletions crates/dex-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "simplicity-dex"
version = "0.1.0"
edition = "2024"

[dependencies]
anyhow = { workspace = true }
nostr = { workspace = true }
global-utils = { workspace = true }
futures-util = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
clap = { workspace = true }
dirs = { workspace = true }
tracing = { workspace = true }
thiserror = { workspace = true }
dex-nostr-relay = { workspace = true }

Loading