Contractless/docs/TOKEN_SWAPS.md

504 lines
17 KiB
Markdown
Raw Permalink Normal View History

2026-07-12 22:01:00 +00:00
# Tokens and Swaps
Contractless supports native fungible tokens and native two-party swaps. Token creation, additional issuance, token burns, token lookup, and swap creation are handled by CLI tools that create or inspect native transaction types.
This guide covers:
- Creating tokens with `create_tokens_tx`
- Issuing more tokens with `create_issue_token_tx`
- Burning tokens with `create_burn_tx`
- Looking up tokens with `lookup_token` and `lookup_token_list`
- Creating and second-signing swaps with `create_swap_tx` and `verify_sign_swap_tx`
On Windows, add `.exe` to each command name.
When a tool asks for a wallet path or transaction file path, press `<Tab>` to search and auto-complete files and folders.
## Important Token Model
Contractless token creation tools mint tokens directly to the wallet that creates the token transaction.
These are not smart-contract tokens. They are not released by programmable vesting rules, bonding curves, administrator contracts, or contract-controlled supply schedules. When a token creation transaction confirms, the full initial supply is credited to the creator wallet. When an issue-more transaction confirms, the additional supply is credited directly to the original creator wallet.
If a creator wants a timed release, public sale, treasury distribution, or external business rule, that must be handled outside the token creation transaction. The chain records the native token supply and balances; it does not run token-sale contract logic.
Token amounts are entered in display units but stored in atomic units. One display token equals `100000000` atomic units.
Example:
```text
1 token = 100000000 atomic units
1000 tokens = 100000000000 atomic units
```
The CLI tools usually ask for display units and then write atomic units into the saved transaction JSON.
## CLI Tools
| Tool | Purpose |
| --- | --- |
| `create_tokens_tx` | Creates and signs a new token creation transaction. |
| `create_issue_token_tx` | Creates and signs an additional-issuance transaction for an existing token. |
| `create_swap_tx` | Creates the first-signed side of a two-party swap. |
| `verify_sign_swap_tx` | Lets the counterparty verify terms, sign the second side, and save the completed swap. |
| `create_burn_tx` | Creates and signs a token or NFT burn transaction. |
| `lookup_token` | Looks up one token by ticker/name. |
| `lookup_token_list` | Lists known tokens from the connected node. |
Creation tools save signed transaction JSON under:
```text
./transactions/<hash>.json
```
Saving a transaction file does not broadcast it. Submit saved transactions with `broadcast_transaction` or with the GUI wallet import/broadcast flow.
## Token Creation
Use `create_tokens_tx` to create a new fungible token.
Usage:
```text
create_tokens_tx
```
The transaction type is `3`.
### Token Creation Fields
| Field | Size | Meaning |
| --- | ---: | --- |
| `txtype` | 1 byte | Transaction type. For token creation this is `3`. |
| `time` / `timestamp` | 4 bytes | UTC timestamp when the transaction is created. |
| `creator` | 22 bytes | Creator short address. The initial supply is credited here. |
| `ticker` | 15 bytes | Unique token ticker/name, padded to 15 bytes. |
| `number` | 8 bytes | Initial token supply in atomic units. |
| `hard_limit` | 1 byte | `1` means hard capped forever; `0` means the creator may issue more later. |
| `txfee` | 8 bytes | Base-currency transaction fee. Minimum is `500` CLC or CLTC. |
| `signature` | 666 bytes | Creator signature. |
### Prompts
`create_tokens_tx` asks for:
| Prompt | What To Enter |
| --- | --- |
| Ticker / token name | A unique 3 to 15 character alphanumeric token name. |
| Amount to create | Initial supply in display tokens, such as `1`, `1000`, or `100000`. |
| Hard cap | `1` for yes, `0` for no. |
| Fee | Minimum `500` CLC or CLTC. |
| Wallet path | Path to the creator wallet file. |
| Wallet key | Creator wallet decryption key. |
Token names are normalized to lowercase alphanumeric identifiers and stored in a fixed 15-byte field. The name must be globally unique. The first confirmed transaction for a ticker owns that ticker.
The base coin ticker is reserved and cannot be created as a custom token.
### Hard Cap
The hard cap choice is permanent.
If `hard_limit = 1`, no future `create_issue_token_tx` transaction can issue more supply for that token.
If `hard_limit = 0`, only the original creator wallet may issue more supply later.
### Output Shape
The saved JSON includes a `hash` field so the file can be named and later broadcast:
```json
{
"txtype": 3,
"timestamp": 1780000000,
"creator": "creator_short_address.cltc",
"ticker": "example ",
"number": 100000000000,
"hard_limit": 0,
"txfee": 50000000000,
"hash": "transaction_hash",
"signature": "creator_signature"
}
```
In this example, `number = 100000000000` means `1000` display tokens.
## Issuing More Tokens
Use `create_issue_token_tx` to issue more units of an existing token.
Usage:
```text
create_issue_token_tx
```
The transaction type is `11`.
Additional issuance is only valid when:
- The token already exists.
- The token was created with `hard_limit = 0`.
- The signing wallet is the original token creator.
- The creator has enough base currency for the issue-token fee.
When the transaction confirms, the newly issued tokens are credited directly to the original creator wallet.
### Issue More Fields
| Field | Size | Meaning |
| --- | ---: | --- |
| `txtype` | 1 byte | Transaction type. For issue-more this is `11`. |
| `time` / `timestamp` | 4 bytes | UTC timestamp when the transaction is created. |
| `creator` | 22 bytes | Original creator short address. New supply is credited here. |
| `ticker` | 15 bytes | Existing token ticker/name, padded to 15 bytes. |
| `number` | 8 bytes | Additional supply in atomic units. |
| `txfee` | 8 bytes | Base-currency transaction fee. Minimum is `100` CLC or CLTC. |
| `signature` | 666 bytes | Creator signature. |
### Prompts
`create_issue_token_tx` asks for:
| Prompt | What To Enter |
| --- | --- |
| Ticker / token name | Existing token name. |
| Additional tokens | Amount to add in display tokens. |
| Fee | Minimum `100` CLC or CLTC. |
| Wallet path | Path to the original creator wallet file. |
| Wallet key | Creator wallet decryption key. |
### Output Shape
```json
{
"txtype": 11,
"timestamp": 1780000000,
"creator": "creator_short_address.cltc",
"ticker": "example ",
"number": 50000000000,
"txfee": 10000000000,
"hash": "transaction_hash",
"signature": "creator_signature"
}
```
In this example, `number = 50000000000` means `500` additional display tokens.
## Burning Tokens
Use `create_burn_tx` to permanently destroy a token or NFT balance.
Usage:
```text
create_burn_tx
```
The transaction type is `10`.
The base coin cannot be burned with this transaction type.
### Burn Fields
| Field | Size | Meaning |
| --- | ---: | --- |
| `txtype` | 1 byte | Transaction type. For burn this is `10`. |
| `time` / `timestamp` | 4 bytes | UTC timestamp when the transaction is created. |
| `address` | 22 bytes | Wallet address burning the asset. |
| `coin` | 15 bytes | Token or NFT base name, padded to 15 bytes. |
| `nft_series` | 4 bytes | `0` for fungible tokens or one-of-one NFTs; series item number for numbered NFTs. |
| `value` | 8 bytes | Amount to burn in atomic units. NFT burns must use exactly `100000000`. |
| `txfee` | 8 bytes | Base-currency transaction fee. Minimum is `0.0001` CLC or CLTC. |
| `signature` | 666 bytes | Burner signature. |
### Prompts
`create_burn_tx` asks for:
| Prompt | What To Enter |
| --- | --- |
| Token or NFT name | Asset name to burn. Base coin is rejected. |
| NFT series number | `0` for standard tokens or one-of-one NFTs; item number for collection NFTs. |
| Burn amount | Token amount in display units. Use `1.0` for NFTs. |
| Fee | Minimum `0.0001` CLC or CLTC. |
| Wallet path | Path to the wallet that owns the asset. |
| Wallet key | Wallet decryption key. |
For fungible tokens, `value` may be any positive amount the wallet owns.
For NFTs, the burn must destroy exactly one full NFT unit. The CLI prompt says to use `1.0`; internally that becomes `100000000`.
## Token Lookup
Use `lookup_token` to inspect one token by name.
Usage:
```text
lookup_token <token_name>
```
Example:
```text
lookup_token example
```
The tool asks for a wallet path and wallet key for authenticated RPC handshake. The lookup does not spend funds.
Expected output:
```json
{
"token_name": "example",
"genesis": "creation_transaction_hash",
"creator": "creator_short_address.cltc",
"token_count": 1500.0,
"token_spread": "2 addresses",
"hard_limit": false,
"issued_hashes": [
"issue_transaction_hash"
],
"burned_hashes": [
"burn_transaction_hash"
]
}
```
Field meanings:
| Field | Meaning |
| --- | --- |
| `token_name` | Token ticker/name. |
| `genesis` | Token creation transaction hash. |
| `creator` | Original creator wallet. |
| `token_count` | Current supply after issuance and burns, displayed in whole-token units. |
| `token_spread` | Number of addresses holding the token. |
| `hard_limit` | Whether additional issuance is permanently blocked. |
| `issued_hashes` | Confirmed issue-more transaction hashes. |
| `burned_hashes` | Confirmed burn transaction hashes. |
## Token List
Use `lookup_token_list` to list known tokens from the connected node.
Usage:
```text
lookup_token_list
```
The tool asks for a wallet path and wallet key for authenticated RPC handshake. The lookup does not spend funds.
Expected output:
```json
{
"tokens": [
{
"token": "example",
"hash": "creation_transaction_hash"
}
]
}
```
If the connected node has no token entries, the output is:
```json
{
"tokens": []
}
```
## Swaps
Contractless swaps are native two-party transactions. A swap has one shared unsigned transaction body and two signatures:
- `signature1` from `sender1`
- `signature2` from `sender2`
There is no automatic match-making service in the CLI tools. Before creating a swap, the two parties must already agree on the trade terms off-chain. The first signer creates the offer, saves the transaction file, and sends that file to the counterparty. The counterparty verifies the terms, signs the second half, and then the completed transaction can be broadcast.
The CLI does not find counterparties for you.
The transaction type is `6`.
## Creating a Swap Offer
Use `create_swap_tx` to create the first-signed swap offer.
Usage:
```text
create_swap_tx
```
The active wallet becomes `sender1`.
### Swap Fields
| Field | Size | Meaning |
| --- | ---: | --- |
| `txtype` | 1 byte | Transaction type. For swaps this is `6`. |
| `timestamp` | 4 bytes | UTC time when the offer is created. |
| `offer_expiration` | 4 bytes | UTC expiration timestamp. Must not be earlier than `timestamp` or more than 30 days later. |
| `ticker1` | 15 bytes | Asset offered by `sender1`. |
| `nft_series1` | 4 bytes | `0` for fungible assets and one-of-one NFTs; numbered NFT item for series NFTs. |
| `value1` | 8 bytes | Amount offered by `sender1`, in atomic units. |
| `ticker2` | 15 bytes | Asset expected from `sender2`. |
| `nft_series2` | 4 bytes | `0` for fungible assets and one-of-one NFTs; numbered NFT item for series NFTs. |
| `value2` | 8 bytes | Amount expected from `sender2`, in atomic units. |
| `sender1` | 22 bytes | First signer short address. |
| `sender2` | 22 bytes | Counterparty short address. |
| `tip1` | 8 bytes | Miner tip paid from `sender1` asset side. |
| `tip2` | 8 bytes | Miner tip paid from `sender2` asset side. |
| `txfee1` | 8 bytes | Base-currency fee paid by `sender1`. Minimum is `1` CLC or CLTC. |
| `txfee2` | 8 bytes | Base-currency fee paid by `sender2`. Minimum is `1` CLC or CLTC. |
| `signature1` | 666 bytes | Sender1 signature. |
| `signature2` | 666 bytes | Sender2 signature. Present only after the counterparty signs. |
### Swap Prompts
`create_swap_tx` asks for:
| Prompt | What To Enter |
| --- | --- |
| Coin or token to send | Base coin or token/NFT name offered by `sender1`. |
| NFT series number to send | `0` for coins/tokens/one-of-one NFTs; item number for series NFTs. |
| Amount to send | Amount in display units. Use `1` for NFTs. |
| Coin or token to receive | Base coin or token/NFT name expected from `sender2`. |
| NFT series number to receive | `0` for coins/tokens/one-of-one NFTs; item number for series NFTs. |
| Amount to receive | Amount in display units. Use `1` for NFTs. |
| Wallet path | Path to sender1 wallet. |
| Wallet key | Sender1 wallet decryption key. |
| Counterparty address | Sender2 short address or vanity address. |
| First miner tip | Tip paid from sender1 asset side. |
| Second miner tip | Tip paid from sender2 asset side. |
| Fee you will pay | Sender1 base-currency fee. Minimum `1`. |
| Fee other party will pay | Sender2 base-currency fee. Minimum `1`. |
| Hours until offer expires | Expiration window in hours. Maximum effective window is 30 days. |
### Swap Fees and Tips
Each party pays:
- A base-currency swap fee of at least `1` CLC or CLTC.
- A miner tip for their offered asset side.
For fungible assets, the tip must be at least 1% of the offered amount. The tip is paid in the asset being offered by that side.
For NFT sides, the tip must be `0` because NFTs cannot be fractionally tipped.
Each party must have enough balance for:
- The offered amount.
- The offered-side tip.
- The base-currency transaction fee.
### Swap Expiration
Swap offers expire. The expiration timestamp must be:
- Not earlier than the creation timestamp.
- Not more than 30 days after the creation timestamp.
- Still in the future when the completed transaction is broadcast.
The transaction timestamp must also be within the normal 30-day transaction window.
### Output Shape
`create_swap_tx` creates a partially signed transaction:
```json
{
"txtype": 6,
"timestamp": 1780000000,
"offer_expiration": 1780259200,
"ticker1": "example ",
"nft_series1": 0,
"value1": 100000000000,
"ticker2": "CLTC ",
"nft_series2": 0,
"value2": 5000000000,
"sender1": "sender1_short_address.cltc",
"sender2": "sender2_short_address.cltc",
"tip1": 1000000000,
"tip2": 50000000,
"txfee1": 100000000,
"txfee2": 100000000,
"hash": "swap_hash",
"signature1": "sender1_signature"
}
```
This file is not ready to broadcast yet because it has no `signature2`.
## Counterparty Signing
The counterparty uses `verify_sign_swap_tx` to inspect and sign the offer.
Usage:
```text
verify_sign_swap_tx <path/to/file.json>
```
The tool:
1. Loads the swap JSON file.
2. Loads the counterparty wallet.
3. Confirms the active wallet matches `sender2`.
4. Shows the received amount, sent amount, fee, and tip.
5. Asks yes/no verification questions.
6. Recomputes the swap hash.
7. Signs only if the included hash matches the transaction body.
8. Saves a completed transaction JSON with both `signature1` and `signature2`.
The completed file is saved under:
```text
./transactions/<hash>.json
```
After both signatures exist, either party can broadcast the transaction.
## Swap Safety Checklist
Before signing the second half of a swap, the counterparty should verify:
- The wallet address is their wallet address.
- The asset they receive is correct.
- The amount they receive is correct.
- The asset they send is correct.
- The amount they send is correct.
- The fee they pay is acceptable.
- The tip they pay is acceptable.
- The offer has not expired.
- The file came from the expected counterparty.
Because there is no match-making service, the transaction file must be exchanged manually. Common methods include email, direct message, file sharing, or another off-chain communication channel.
## Broadcasting
All creation tools in this guide create transaction JSON files. They do not mine or confirm the transaction by themselves.
To finish a transaction:
1. Create and sign the JSON file.
2. For swaps, have the counterparty verify and second-sign the JSON file.
3. Broadcast the completed file with `broadcast_transaction` or the GUI wallet.
4. Wait for confirmation.
## Common Problems
| Problem | Likely Cause |
| --- | --- |
| Token creation rejected | Ticker already exists, ticker is reserved, creator wallet is not registered, or fee is below `500`. |
| Issue-more rejected | Token is hard capped, token does not exist, signer is not the original creator, amount is zero, or fee is below `100`. |
| Burn rejected | Asset does not exist, base coin was selected, wallet lacks balance, NFT value is not exactly `1.0`, or fee is below `0.0001`. |
| Swap rejected | Missing second signature, bad signature, insufficient balance, expired offer, bad asset name, missing token/NFT, fee below `1`, or tip below the required amount. |
| Counterparty cannot sign swap | The active wallet does not match `sender2`, or the transaction hash no longer matches the file contents. |