Skip to content
Open
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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
members = [
"lez-authority",
"programs/token/core",
"programs/token",
"programs/token/methods",
Expand Down
71 changes: 71 additions & 0 deletions artifacts/token-idl.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,66 @@
}
]
},
{
"name": "new_fungible_definition_with_authority",
"accounts": [
{
"name": "definition_target_account",
"writable": false,
"signer": false,
"init": false
},
{
"name": "holding_target_account",
"writable": false,
"signer": false,
"init": false
}
],
"args": [
{
"name": "name",
"type": "string"
},
{
"name": "initial_supply",
"type": "u128"
},
{
"name": "mint_authority",
"type": {
"array": [
"u8",
32
]
}
}
]
},
{
"name": "set_authority",
"accounts": [
{
"name": "definition_account",
"writable": false,
"signer": false,
"init": false
}
],
"args": [
{
"name": "new_authority",
"type": {
"option": {
"array": [
"u8",
32
]
}
}
}
]
},
{
"name": "print_nft",
"accounts": [
Expand Down Expand Up @@ -194,6 +254,17 @@
"type": {
"option": "account_id"
}
},
{
"name": "mint_authority",
"type": {
"option": {
"array": [
"u8",
32
]
}
}
}
]
},
Expand Down
208 changes: 208 additions & 0 deletions docs/LP-0013-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# LP-0013: Token Program Mint Authority

This document describes the mint authority model added to the LEZ Token program as part of LP-0013.

## Overview

The LEZ Token program now supports a mint authority model for fungible tokens:

- **Mint authority set at initialization** — create a token with a designated minter
- **Minting by the authority** — the authority can mint additional tokens at any time
- **Authority rotation** — transfer minting rights to a new key
- **Authority revocation** — permanently fix the supply by setting authority to `None`

The `lez-authority` crate provides a reusable, program-agnostic authority library (RFP-001).

## Architecture

### Authority Model

`mint_authority: Option<[u8; 32]>` is added to `TokenDefinition::Fungible`:
- `Some(key)` — the key holder can mint and rotate/revoke
- `None` — supply is permanently fixed, minting rejected

### New Instructions

| Instruction | Description |
|---|---|
| `NewFungibleDefinitionWithAuthority` | Create token with mint authority |
| `Mint` (updated) | Now authority-gated — rejects if authority is None |
| `SetAuthority` | Rotate or revoke mint authority |

### Atomicity

`SetAuthority` only mutates state after all checks pass. A failed authorization check returns an error before any write occurs, leaving the prior authority intact.

### Error Codes

| Condition | Message |
|---|---|
| Mint with revoked authority | Mint authority has been revoked; this token has a fixed supply |
| SetAuthority without authorization | Definition account authorization is missing |
| SetAuthority on already-revoked | Mint authority already revoked; supply is permanently fixed |

## Crate Structure

- `lez-authority/` — Agnostic AuthoritySlot library (RFP-001)
- `programs/token/core/` — TokenDefinition with mint_authority field
- `programs/token/src/mint.rs` — Authority-gated minting
- `programs/token/src/set_authority.rs` — Rotation and revocation handler
- `programs/token/src/new_definition.rs` — NewFungibleDefinitionWithAuthority handler
- `programs/token/methods/guest/src/bin/token.rs` — Guest binary dispatch

## Module/SDK

`token_core` provides the reusable types and instructions for building Logos modules. It is already consumed by `amm`, `ata`, `stablecoin`, and `integration_tests` in this workspace:

```toml
[dependencies]
token_core = { path = "programs/token/core" }
```

Key types:
- `TokenDefinition::Fungible { mint_authority, .. }` — token definition with authority
- `Instruction::NewFungibleDefinitionWithAuthority` — create with authority
- `Instruction::SetAuthority` — rotate or revoke

## RFP-001 Compliance

LP-0013 has a formal dependency on [RFP-001](https://github.com/logos-co/rfp/blob/master/RFPs/RFP-001-admin-authority-lib.md) — the standardised admin authority library. The `lez-authority` crate in this submission directly implements the approval pattern defined in RFP-001:

| RFP-001 Requirement | How `lez-authority` satisfies it |
|---|---|
| Self-sufficient, agnostic authority library | `lez-authority` has zero program-specific dependencies — it only uses `borsh` for serialisation |
| Authority slot abstraction | `AuthoritySlot` struct wraps `Option<[u8; 32]>` with `check`, `set`, and revocation semantics |
| Approval check | `AuthoritySlot::check(signer)` returns an error if the signer does not match or authority is revoked |
| Rotation | `AuthoritySlot::set(Some(new_key))` atomically rotates to a new authority |
| Permanent revocation | `AuthoritySlot::set(None)` permanently fixes the supply — subsequent `set` calls are rejected |
| Reusable by other programs | Any LEZ program can add `lez-authority` as a workspace dependency and use `AuthoritySlot` directly |

The `lez-authority` crate was also submitted as part of [RFP-001 PR #212](https://github.com/logos-co/spel/pull/212) (the `spel-admin-authority` library with the `#[require_admin]` macro). The two are complementary: `lez-authority` is the lightweight on-chain primitive; `spel-admin-authority` is the SPEL framework macro layer built on top of the same pattern.

## Deployment

### Program ID (LEZ localnet)
efdf86b1127c57c4653903e78bd2174b539fd688054331618c48f98c8fc057bd

### Build the guest binary

```bash
cargo risczero build --manifest-path programs/token/methods/guest/Cargo.toml
```

### Deploy to the sequencer

```bash
wallet deploy-program target/riscv-guest/token-methods/token-guest/riscv32im-risc0-zkvm-elf/release/token.bin
```

## Running Tests

```bash
# Authority unit tests
cargo test -p lez-authority --lib
cargo test -p token_program --lib

# Authority integration tests (zkVM, dev mode)
RISC0_DEV_MODE=1 cargo test -p integration_tests --test token -- token_new_fungible_definition_with_authority token_set_authority_revoke
```

## CLI Usage (via `spel`)

### Create token with mint authority

```bash
spel --idl artifacts/token-idl.json --program <token-binary> \
-- new-fungible-definition-with-authority \
--definition-target-account <DEF_ID> \
--holding-target-account <SUPPLY_ID> \
--name "MyToken" \
--initial-supply 1000000 \
--mint-authority <AUTHORITY_KEY_HEX>
```

### Mint tokens

```bash
spel --idl artifacts/token-idl.json --program <token-binary> \
-- mint \
--definition-account <DEF_ID> \
--user-holding-account <HOLDER_ID> \
--amount-to-mint 500000
```

### Rotate authority

```bash
spel --idl artifacts/token-idl.json --program <token-binary> \
-- set-authority \
--definition-account <DEF_ID> \
--new-authority <NEW_KEY_HEX>
```

### Revoke authority (fix supply permanently)

```bash
spel --idl artifacts/token-idl.json --program <token-binary> \
-- set-authority \
--definition-account <DEF_ID> \
--new-authority none
```

## Example Scripts

```bash
# Fixed supply token (creates with authority, then revokes)
bash scripts/examples/fixed_supply_token.sh

# Variable supply token (creates with authority, mints more, optionally rotates)
bash scripts/examples/variable_supply_token.sh
```

## End-to-End Demo

The demo script must be run from inside an `lgs` scaffold project directory (where the localnet and wallet live):

```bash
# 1. Set up an lgs scaffold (if you don't have one):
cargo install logos-scaffold
lgs new my-scaffold && cd my-scaffold
lgs setup
lgs localnet start
lgs wallet topup

# 2. Deploy the token program:
lgs deploy --program-path /path/to/lez-programs/target/riscv-guest/token-methods/token-guest/riscv32im-risc0-zkvm-elf/release/token.bin

# 3. Run the demo:
RISC0_DEV_MODE=0 bash /path/to/lez-programs/scripts/demo-full-flow.sh
```

The script will:
1. Verify the localnet is running
2. Fund the wallet
3. Create 3 token accounts (definition, supply holder, recipient)
4. Submit `NewFungibleDefinitionWithAuthority` (creates "DemoCoin" with 1M supply)
5. Submit `Mint` (mints 500K to recipient → total supply 1.5M)
6. Submit `SetAuthority` with `None` (permanently revokes minting)
7. Run unit tests to verify authority logic (60 tests)

## Compute Unit (CU) Costs

Measured on LEZ localnet with `RISC0_DEV_MODE=1` (execution only, no proof):

| Operation | Execution Time | Notes |
|---|---|---|
| `NewFungibleDefinitionWithAuthority` | ~11ms | Creates token with mint authority |
| `Mint` (with authority) | ~10ms | Authority-gated mint |
| `SetAuthority` (rotate) | ~8ms | Rotates to new key |
| `SetAuthority` (revoke) | ~8ms | Permanently revokes, sets None |

Note: With `RISC0_DEV_MODE=0`, full ZK proof generation takes 3–10 minutes per transaction on Apple M-series hardware. LEZ's per-transaction compute budget may change during testnet.

## References

- [lez-authority crate](../lez-authority/src/lib.rs)
- [SetAuthority handler](../programs/token/src/set_authority.rs)
- [Mint handler](../programs/token/src/mint.rs)
- [Solana SPL Token - Set Authority](https://solana.com/docs/tokens/basics/set-authority)
11 changes: 11 additions & 0 deletions lez-authority/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "lez-authority"
version = "0.1.0"
edition = "2024"
license = "MIT OR Apache-2.0"

[lints]
workspace = true

[dependencies]
borsh = { workspace = true, features = ["derive"] }
Loading