Skip to content
Draft
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
19 changes: 12 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# The network: devnet, testnet or mainnet. Every per-network value follows it.
ENVIRONMENT=devnet

# The asset the Token Standard examples work on: cbtc or beth.
# The asset the Token Standard examples work on: cbtc, beth or chype.
# The bridge examples under examples/<asset>/ ignore it.
ASSET=cbtc

Expand All @@ -28,16 +28,21 @@ KEYCLOAK_PASSWORD=your-password
# The bridge examples under examples/<asset>/ ignore these overrides.

# Mint and redeem. WITHDRAW_AMOUNT is in the asset's unit: BTC for the cbtc
# examples, ETH for the beth examples. The value below suits cbtc; set it to
# a BETH amount, for example 0.01, before you run beth_redeem_flow.
# examples, ETH for the beth examples and HYPE for the chype examples.
# Leave it unset to use the example's own default: 0.001 BTC, 0.01 ETH or
# 0.25 HYPE.
# The Bitcoin address that receives the BTC. cbtc_redeem_flow has no default.
DESTINATION_BTC_ADDRESS=
# The 0x address that receives the ETH. beth_redeem_flow has no default.
DESTINATION_ETH_ADDRESS=
# The ETH that beth_mint_flow builds a deposit for, in wei. It must be a
# whole multiple of 100000000. This value is 0.01 ETH.
DEPOSIT_AMOUNT_WEI=10000000000000000
WITHDRAW_AMOUNT=0.001
# The 0x HyperEVM address that receives the HYPE. chype_redeem_flow has no
# default.
DESTINATION_HYPE_ADDRESS=
# The ETH or HYPE that beth_mint_flow or chype_mint_flow builds a deposit
# for, in wei. It must be a whole multiple of 100000000. Leave it unset to
# use the example's own default: 0.01 ETH or 0.25 HYPE.
# DEPOSIT_AMOUNT_WEI=10000000000000000
# WITHDRAW_AMOUNT=0.001

# Transfers.
TRANSFER_AMOUNT=0.1
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ jobs:
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: Check the deployed BitSafe API shapes
# Devnet and testnet do not serve the BETH routes yet. Remove a
# network from the list when its deployment serves them.
# The listed networks do not serve the asset's routes yet. Remove a
# network from a list when its deployment serves them.
env:
BETH_LIVE_API_SKIP: devnet,testnet
CHYPE_LIVE_API_SKIP: testnet,mainnet
run: cargo test --lib live_api -- --ignored
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
A release of this crate is not finished until the public docs describe it.
Each supported asset has its own docs space at
[docs.bitsafe.finance](https://docs.bitsafe.finance). The supported assets
are the modules in `src/tokens/` (today `cbtc` and `beth`). After you cut a
release, you and the pilot update the docs of every one of them.
are the modules in `src/tokens/` (today `cbtc`, `beth` and `chype`). After
you cut a release, you and the pilot update the docs of every one of them.

The docs live in GitBook, and docs.bitsafe.finance publishes them. Work on
them through the GitBook API. The API needs a GitBook access token, which
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- `tokens::chype`: CHYPE, HYPE bridged from HyperEVM, with the BETH API
shape. It holds the registrar and the bridge of each network, the account,
mint and burn flows, and the credential filters. Devnet and testnet use
HyperEVM testnet (chain 998); mainnet uses HyperEVM (chain 999).
- CHYPE refuses a withdraw destination that never gets a payout: the zero
address, a HyperEVM system address or a CHYPE bridge proxy.
`create_withdraw_account` checks the address, and `submit_withdraw` checks
the account's address again before the burn.
- The testnet and mainnet BitSafe APIs do not serve the CHYPE routes yet. On
those networks, a party cannot open a CHYPE account or burn CHYPE.
- The `chype` 0.1.0 DAR in `dars/chype/`, and `dars/upload_dars.sh chype`.
- The `chype_credentials`, `chype_mint_flow` and `chype_redeem_flow`
examples, and `chype` as an `ASSET` value of the Token Standard examples.

### Changed

- `.env.example` leaves `DEPOSIT_AMOUNT_WEI` and `WITHDRAW_AMOUNT` unset, so
each example uses its own default amount.
- The localnet suite uses the sandbox image `cbtc-6689a6a`, which holds the
CHYPE packages, and runs a CHYPE phase.

## [0.3.0] - 2026-10-21

### Fixed
Expand Down
14 changes: 13 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "bitsafe-token"
version = "0.3.0"
edition = "2024"
description = "Client library for BitSafe bridged assets on Canton: CBTC, BETH"
description = "Client library for BitSafe bridged assets on Canton: CBTC, BETH, CHYPE"
license = "MIT"
repository = "https://github.com/DLC-link/bitsafe-token-lib"
publish = false
Expand Down Expand Up @@ -158,6 +158,18 @@ path = "examples/beth/mint_flow.rs"
name = "beth_redeem_flow"
path = "examples/beth/redeem_flow.rs"

[[example]]
name = "chype_credentials"
path = "examples/chype/credentials.rs"

[[example]]
name = "chype_mint_flow"
path = "examples/chype/mint_flow.rs"

[[example]]
name = "chype_redeem_flow"
path = "examples/chype/redeem_flow.rs"

[profile.release]
opt-level = 3
strip = "debuginfo"
Expand Down
62 changes: 46 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# bitsafe-token

A Rust client library for BitSafe's bridged assets on Canton Network: CBTC
(Bitcoin) and BETH (Ether). One API shape serves both assets. The library
also re-exports the Canton Token Standard operations of
(Bitcoin), BETH (Ether) and CHYPE (HYPE). One API shape serves every asset.
The library also re-exports the Canton Token Standard operations of
[canton-lib](https://github.com/DLC-link/canton-lib), so you can hold, send
and receive both assets.
and receive every asset.

**Status: 0.3.0.** The API can change in any 0.x release. The crate is not on
crates.io; you add it as a git dependency. It needs Rust 1.94 or newer
Expand Down Expand Up @@ -50,8 +50,8 @@ You need these, for the network you use:
| Term | Meaning |
|---|---|
| Registrar | The party that issues an asset on one network. Each asset module knows its registrar for each network |
| Minter credential | A credential from the registrar with the claim `hasCBTCRole` or `hasBETHRole` = `Minter`. The mint and burn calls need it |
| Deposit account | A contract that ties your party to a deposit: a BTC address for CBTC, a deposit id for BETH |
| Minter credential | A credential from the registrar with the claim `hasCBTCRole`, `hasBETHRole` or `hasCHYPERole` = `Minter`. The mint and burn calls need it |
| Deposit account | A contract that ties your party to a deposit: a BTC address for CBTC, a deposit id for BETH and CHYPE |
| Withdraw account | A contract that holds your payout address and your pending (burned) balance |
| Withdraw request | The payout record. The attestors create it after a burn and archive it after the payout |
| Holding | One unit of an asset that your party owns, like a UTXO |
Expand Down Expand Up @@ -203,9 +203,39 @@ need Sepolia ETH. Mainnet BETH runs on Ethereum mainnet (chain 1). The
library does not read the bridge's live `depositLimits()` or `paused()`;
check both with your Ethereum provider before you send.

## Quick start: CHYPE

CHYPE has the same calls as BETH, under `tokens::chype`. The CHYPE bridge
is the BETH bridge contract, deployed on HyperEVM. It takes HYPE through the
same `depositETH` function, so `chype::mint::deposit_call` builds the same
kind of transaction.

**Units.** HYPE has 18 decimals, so CHYPE uses the BETH units.
`deposit_call` takes wei as a `U256`. `redeem::submit_withdraw` takes HYPE
as a `DamlDecimal`, such as `0.25`.

**Chains.** Devnet and testnet CHYPE run on HyperEVM testnet (chain 998).
Mainnet CHYPE runs on HyperEVM (chain 999).

**Limits.** The mainnet bridge takes deposits and pays out withdrawals from
0.25 HYPE. The library does not read the bridge's live `depositLimits()`,
`withdrawLimits()` or `paused()`. Check them with your HyperEVM provider
before you deposit or burn.

**Destinations.** The library refuses a CHYPE payout address that never
gets a payout. It refuses the zero address, the HyperEVM system addresses
and the CHYPE bridge proxies. `redeem::create_withdraw_account` checks the
address, and `redeem::submit_withdraw` checks it again before the burn.

**BitSafe API.** The devnet BitSafe API serves the CHYPE routes. The testnet
and mainnet APIs do not serve them yet. On those networks, a party cannot
open a CHYPE account or burn CHYPE. `get_account_contract_rules` fails with a parse error, because the API
redirects the request. `submit_withdraw` fails in the same way. The calls
that only list contracts on the ledger work.

## Hold and send

The re-exported `TokenClient` reads balances and sends either asset. The
The re-exported `TokenClient` reads balances and sends every asset. The
asset module gives it the right configuration for each network:

```rust
Expand Down Expand Up @@ -256,11 +286,11 @@ V2 where both exist.
`Network` is a plain enum: `Devnet`, `Testnet`, `Mainnet`. Each asset module
maps a `Network` to its own registrar, so you pass only the network.

| Network | Utility registry | BitSafe API | BETH chain |
| --- | --- | --- | --- |
| devnet | https://api.utilities.digitalasset-dev.com | https://api.devnet.bitsafe.finance | Sepolia, 11155111 |
| testnet | https://api.utilities.digitalasset-staging.com | https://api.testnet.bitsafe.finance | Sepolia, 11155111 |
| mainnet | https://api.utilities.digitalasset.com | https://api.mainnet.bitsafe.finance | Ethereum, 1 |
| Network | Utility registry | BitSafe API | BETH chain | CHYPE chain |
| --- | --- | --- | --- | --- |
| devnet | https://api.utilities.digitalasset-dev.com | https://api.devnet.bitsafe.finance | Sepolia, 11155111 | HyperEVM testnet, 998 |
| testnet | https://api.utilities.digitalasset-staging.com | https://api.testnet.bitsafe.finance | Sepolia, 11155111 | HyperEVM testnet, 998 |
| mainnet | https://api.utilities.digitalasset.com | https://api.mainnet.bitsafe.finance | Ethereum, 1 | HyperEVM, 999 |

## What the library does not do

Expand All @@ -271,13 +301,13 @@ maps a `Network` to its own registrar, so you pass only the network.
after the payout, so a paid request no longer appears.
- **It does not check the network of a BTC address.** Use an address of the
Bitcoin network that your Canton network pays out on.
- **It reads no Ethereum state.** It reads no bridge limits, no pause state
and no deposit events.
- **It reads no EVM state.** It reads no bridge limits, no pause state and
no deposit events, on Ethereum or on HyperEVM.

## Examples

[`examples/README.md`](examples/README.md) lists 30 runnable examples, for
both assets: credentials, mint, burn, transfers, allocations and batch
[`examples/README.md`](examples/README.md) lists 33 runnable examples, for
every asset: credentials, mint, burn, transfers, allocations and batch
distribution. Copy [`.env.example`](.env.example) to `.env`, fill it in, and
run `cargo run --example <name>`.

Expand All @@ -295,7 +325,7 @@ cargo test
are crate-private building blocks. `tokens` may use `flows` and `kits`,
`flows` may use `kits`, and nothing imports upward; review checks this.

The localnet suite runs the CBTC and BETH flows against a local Canton
The localnet suite runs the CBTC, BETH and CHYPE flows against a local Canton
sandbox. It needs Docker:

```sh
Expand Down
9 changes: 7 additions & 2 deletions dars/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ or burn (redeem) an asset.
| `dependencies/` | The Splice and Canton Network Utility DARs that every asset uses |
| `cbtc/` | The `cbtc` DARs from 1.0.0 to 1.2.1 |
| `beth/` | The `beth` 0.2.0 DAR |
| `chype/` | The `chype` 0.1.0 DAR |

The asset DARs are the released `cbtc` and `beth` packages. The dependency
DARs are the Splice and Canton Network Utility packages that they use.
The asset DARs are the released `cbtc`, `beth` and `chype` packages. The
dependency DARs are the Splice and Canton Network Utility packages that they
use.

Each asset DAR has this main package id and this SHA-256 checksum:

Expand All @@ -22,6 +24,7 @@ Each asset DAR has this main package id and this SHA-256 checksum:
| `cbtc-1.2.0.dar` | `f240dd5d1a98079f37c0f93272cf5b28d4523027c42d0003c4c7a530eed6c313` | `4519ada05678f13cd10c3953b07e625a3f36e4fac186f8cf80e6b095a3c3a82d` |
| `cbtc-1.2.1.dar` | `3484f3214004982cc14315f7835d8722af9b141aebfc3ddcc605b2bee338f1bd` | `b6f82dcf721e94fb1b0d930dc6707ee15a7a6f82e88b4cbb1abc9a40ce2a7a76` |
| `beth-0.2.0.dar` | `99a39f943ce8fcb39159f8ed4fabab8c71da14db932347cddcf88bf0ac6e521f` | `f61e84e38a51e54855b20210d20acb32b1b566fb30a5a92ac4d163323d079c9c` |
| `chype-0.1.0.dar` | `601dd547300817b9532108638b2cd22190f3a0216996393705d2b97edcc3dfe3` | `b333300ab951dbbddba54690747a98e3daa351e5ce6acb5c90b902bab6e11aec` |

The utility DARs come from Digital Asset. The file
`dependencies/Terms.and.Conditions.for.Canton.Network.Utility.txt` sets the
Expand All @@ -37,6 +40,7 @@ participant. `ASSET` names the asset, and
```bash
ASSET=cbtc cargo run --example check_dars
ASSET=beth cargo run --example check_dars
ASSET=chype cargo run --example check_dars
```

A library caller does the same with `bitsafe_token::check_dars`. Its `root`
Expand All @@ -60,6 +64,7 @@ export jwt_token="<participant admin token>" # optional
export canton_admin_api_url="localhost:5002" # optional
dars/upload_dars.sh cbtc
dars/upload_dars.sh beth
dars/upload_dars.sh chype
```

The script stops at the first DAR that fails to upload. Canton skips a DAR
Expand Down
Binary file added dars/chype/chype-0.1.0.dar
Binary file not shown.
6 changes: 3 additions & 3 deletions dars/upload_dars.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# own DARs.
#
# Usage: dars/upload_dars.sh <asset>
# <asset> is cbtc or beth.
# <asset> is cbtc, beth or chype.
#
# Environment:
# jwt_token the participant admin token. Leave it unset when the
Expand All @@ -17,9 +17,9 @@ set -euo pipefail

asset="${1:-}"
case "${asset}" in
cbtc | beth) ;;
cbtc | beth | chype) ;;
*)
echo "Usage: $0 <asset>, where <asset> is one of: cbtc, beth" >&2
echo "Usage: $0 <asset>, where <asset> is one of: cbtc, beth, chype" >&2
exit 2
;;
esac
Expand Down
49 changes: 43 additions & 6 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ Run every example from the project root with `cargo run --example <name>`.
**Token Standard examples** live in `examples/`. They work for any asset, and
`ASSET` in your `.env` picks the asset. There is no default: an example that
runs on the wrong asset reads a zero balance or sends the wrong token. The
values are `cbtc` and `beth`.
values are `cbtc`, `beth` and `chype`.

**Bridge examples** live per asset, in `examples/<asset>/`. They cover the
mint and redeem flows of one asset and ignore `ASSET`. Cargo registers each
one as `<asset>_<name>`. The CBTC bridge examples are in `examples/cbtc/`, for
example `cargo run --example cbtc_mint_flow`. The BETH bridge examples are in
`examples/beth/`.
`examples/beth/`, and the CHYPE bridge examples are in `examples/chype/`.

| Token Standard example | What it does |
|---|---|
Expand Down Expand Up @@ -83,7 +83,7 @@ cargo run --example check_dars
```

The example scans the DAR files in `dars/dependencies/` and in the asset's
folder, `dars/cbtc/` or `dars/beth/`. It compares the newest package of each
folder, `dars/cbtc/`, `dars/beth/` or `dars/chype/`. It compares the newest package of each
DAR with the packages uploaded to the participant, and it exits non-zero
when one is missing. It reads no registry and no BitSafe API, so it needs
neither `ENVIRONMENT` nor `PARTY_ID`. To upload the missing packages, see
Expand Down Expand Up @@ -185,6 +185,42 @@ builds the call, after it finds or creates the account. The library does not
read the bridge's live `depositLimits()` or `paused()`; check both with your
Ethereum provider before you send.

### CHYPE Bridge Examples

The CHYPE examples need a Minter credential issued by the CHYPE registrar.
They work like the BETH examples, on HyperEVM instead of Ethereum. Run them
in this order:

1. **`chype_credentials`**: checks for a CHYPE Minter credential and accepts
a pending offer if there is one.
2. **`chype_mint_flow`**: finds or creates a deposit account and prints the
`depositETH` transaction for `DEPOSIT_AMOUNT_WEI`. The bridge takes HYPE
through this function.
3. **`chype_redeem_flow`**: finds or creates a withdraw account for
`DESTINATION_HYPE_ADDRESS`, burns `WITHDRAW_AMOUNT` CHYPE and lists the
withdraw requests.

```bash
cargo run --example chype_credentials
cargo run --example chype_mint_flow
cargo run --example chype_redeem_flow
```

`chype_mint_flow` sends nothing. You sign and send the printed transaction
with your own HyperEVM wallet on the printed chain. The amount checks are
the BETH checks: a whole multiple of 100000000 wei, above zero and inside the
deposit account's own limits. The mainnet bridge takes deposits and pays out
withdrawals from 0.25 HYPE. The library does not read the bridge's live
`depositLimits()`, `withdrawLimits()` or `paused()`; check them with your
HyperEVM provider first.

`chype_redeem_flow` refuses a destination that never gets a payout: the zero
address, a HyperEVM system address or a CHYPE bridge proxy.

The testnet and mainnet BitSafe APIs do not serve the CHYPE routes yet. On
those networks, `chype_mint_flow` works only with an existing deposit
account, and `chype_redeem_flow` cannot burn.

### Check Balance

Check your balance and UTXO count for `ASSET`:
Expand Down Expand Up @@ -633,7 +669,7 @@ Required for every example that touches a network:

Required for every Token Standard example:

- `ASSET` - The asset to work on: `cbtc` or `beth`.
- `ASSET` - The asset to work on: `cbtc`, `beth` or `chype`.

`check_dars` reads `ASSET` but not `ENVIRONMENT`. Two examples read neither
`ENVIRONMENT` nor `ASSET` and need no network configuration:
Expand All @@ -648,8 +684,9 @@ Mint and redeem:

- `DESTINATION_BTC_ADDRESS` - Payout address for `cbtc_redeem_flow`. It has no default.
- `DESTINATION_ETH_ADDRESS` - Payout address for `beth_redeem_flow`. It has no default.
- `DEPOSIT_AMOUNT_WEI` - The deposit `beth_mint_flow` builds, in wei (default: `10000000000000000`, 0.01 ETH)
- `WITHDRAW_AMOUNT` - Amount to burn, in the asset's unit (default: `0.001` for `cbtc_redeem_flow`, `0.01` for `beth_redeem_flow`)
- `DESTINATION_HYPE_ADDRESS` - Payout address for `chype_redeem_flow`. It has no default.
- `DEPOSIT_AMOUNT_WEI` - The deposit `beth_mint_flow` or `chype_mint_flow` builds, in wei (default: `10000000000000000`, 0.01 ETH, for `beth_mint_flow`, and `250000000000000000`, 0.25 HYPE, for `chype_mint_flow`)
- `WITHDRAW_AMOUNT` - Amount to burn, in the asset's unit (default: `0.001` for `cbtc_redeem_flow`, `0.01` for `beth_redeem_flow`, `0.25` for `chype_redeem_flow`)

Transfers:

Expand Down
2 changes: 1 addition & 1 deletion examples/accept_transfers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
///
/// Make sure to set up your .env file with the required configuration.
///
/// Set ASSET (cbtc or beth) and ENVIRONMENT (devnet, testnet or mainnet).
/// Set ASSET (cbtc, beth or chype) and ENVIRONMENT (devnet, testnet or mainnet).
/// examples/README.md lists the other variables.
use std::env;
mod shared;
Expand Down
2 changes: 1 addition & 1 deletion examples/allocate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
///
/// Make sure to set up your .env file with the required configuration.
///
/// Set ASSET (cbtc or beth) and ENVIRONMENT (devnet, testnet or mainnet).
/// Set ASSET (cbtc, beth or chype) and ENVIRONMENT (devnet, testnet or mainnet).
/// examples/README.md lists the other variables.
use std::env;
mod shared;
Expand Down
Loading
Loading