# Smart Contracts

This page documents the WAX Duel smart contracts deployed on the WAX blockchain.

***

## stf.duel Contract <a href="#stf-duel" id="stf-duel"></a>

The main Duel smart contract is deployed at [stf.duel](https://waxblock.io/account/stf.duel) on WAX mainnet.

### Overview

The stf.duel contract manages:

* Game creation and lifecycle
* Token deposits and prize distribution
* Team validation and hash commitment
* Battle execution using nonce-based randomness
* Player and NFT statistics

### Game Actions

#### creategame

Player 1 creates a game with a hashed team (commit phase).

| Parameter     | Type        | Description                             |
| ------------- | ----------- | --------------------------------------- |
| `player`      | name        | P1 account                              |
| `gamemode_id` | uint64\_t   | Game mode to play                       |
| `team_hash`   | checksum256 | SHA256(nonce:asset\_id1,asset\_id2,...) |
| `bet_amount`  | asset       | Bet in FIGHT tokens                     |

#### joingame

Player 2 joins with their revealed team.

| Parameter   | Type               | Description          |
| ----------- | ------------------ | -------------------- |
| `player`    | name               | P2 account           |
| `game_id`   | uint64\_t          | Game to join         |
| `nonce`     | uint64\_t          | P2's team randomness |
| `asset_ids` | vector\<uint64\_t> | P2's NFT asset IDs   |

#### reveal

Player 1 reveals their team; battle executes immediately using combined nonces.

| Parameter   | Type               | Description                       |
| ----------- | ------------------ | --------------------------------- |
| `player`    | name               | P1 account (must be game creator) |
| `game_id`   | uint64\_t          | Game to reveal                    |
| `nonce`     | uint64\_t          | P1's nonce for hash verification  |
| `asset_ids` | vector\<uint64\_t> | P1's actual NFT IDs               |

#### fight

Legacy action for manual battle execution (rarely needed; battle now executes automatically during reveal).

| Parameter | Type      | Description   |
| --------- | --------- | ------------- |
| `game_id` | uint64\_t | Game to fight |

#### cancel

Player 1 cancels game before P2 joins.

| Parameter | Type      | Description    |
| --------- | --------- | -------------- |
| `player`  | name      | P1 account     |
| `game_id` | uint64\_t | Game to cancel |

#### claiminactive

Claim victory due to opponent timeout.

| Parameter | Type      | Description     |
| --------- | --------- | --------------- |
| `player`  | name      | Claiming player |
| `game_id` | uint64\_t | Game to claim   |

#### withdraw

Withdraw deposited tokens.

| Parameter | Type | Description        |
| --------- | ---- | ------------------ |
| `player`  | name | Player withdrawing |

### Key Tables

| Table     | Scope        | Description                         |
| --------- | ------------ | ----------------------------------- |
| config    | singleton    | Global contract settings            |
| gamemodes | contract     | Game mode configurations            |
| chars     | gamemode\_id | Character base attributes           |
| tmpls     | gamemode\_id | NFT-to-character mapping            |
| games     | contract     | Active game state                   |
| gameturns | game\_id     | Battle action log                   |
| players   | contract     | Lifetime player statistics          |
| assets    | contract     | Per-NFT statistics and leaderboards |
| deposits  | contract     | Token deposit pool for players      |

### Game Status Enum

| Value | Name              | Description                       |
| ----- | ----------------- | --------------------------------- |
| 0     | CREATED           | Game created, awaiting P1 deposit |
| 1     | P1\_DEPOSITED     | P1 deposited, awaiting P2         |
| 2     | ALL\_DEPOSITED    | Both deposited, awaiting P2 join  |
| 3     | ALL\_JOINED       | P2 joined, awaiting P1 reveal     |
| 4     | READY\_TO\_FIGHT  | P1 revealed, battle ready         |
| 5     | (unused)          | Reserved (legacy)                 |
| 6     | P1\_WIN           | Player 1 won                      |
| 7     | P2\_WIN           | Player 2 won                      |
| 8     | P1\_CANCELED      | P1 canceled                       |
| 9     | P1\_WIN\_INACTIVE | P1 won (P2 timeout)               |
| 10    | P2\_WIN\_INACTIVE | P2 won (P1 timeout)               |

### External Contracts

| Contract       | Purpose                    |
| -------------- | -------------------------- |
| `token.duel`   | FIGHT token contract       |
| `atomicassets` | NFT ownership verification |

***

## train.duel Contract <a href="#train-duel" id="train-duel"></a>

The Training smart contract is deployed at [train.duel](https://waxblock.io/account/train.duel) on WAX mainnet.

### Overview

The train.duel contract manages the non-custodial NFT training system:

* Individual asset registration for training
* Batched registration for large collections (50-100 assets per call)
* $TRAIN reward calculation and distribution
* Multi-collection support
* Configurable reward rates per rarity/powerscore combination

### Key Concepts

#### Non-Custodial Training

Unlike traditional staking, NFTs **never leave the user's wallet**. The contract:

1. Tracks individual registered assets in the `assetstrain` table
2. Aggregates counts by rarity/powerscore in the `training` table for reward calculation
3. Verifies current NFT ownership before paying rewards
4. Uses batched registration to handle large collections efficiently

#### Asset Registration

The contract tracks individual registered assets:

* Each asset is registered with its rarity and powerscore cached
* Ownership transfers are handled automatically (old owner's counts decremented)
* Batched registration allows processing 50-100 assets per transaction

### User Actions

#### regassets

Register assets for training. Supports batching for large collections. Automatically reconciles ownership changes and pays pending rewards before adding new assets.

| Parameter   | Type   | Description                             |
| ----------- | ------ | --------------------------------------- |
| `user`      | name   | Asset owner                             |
| `asset_ids` | vector | List of asset IDs to register (max 100) |

The `regassets` action:

1. **Reconciles existing state first:**
   * Removes stale `assetstrain` entries (NFTs user no longer owns)
   * Calculates and pays pending rewards for remaining NFTs
   * Updates `training` counts to match actual ownership
2. Verifies user owns each new asset via AtomicAssets
3. Checks collection is enabled and template is in cache
4. Handles ownership transfers (decrements old owner's counts)
5. Adds new assets to `assetstrain` table and updates `training` counts

#### claim

Claim accumulated $TRAIN rewards. Automatically reconciles ownership changes.

| Parameter | Type | Description           |
| --------- | ---- | --------------------- |
| `user`    | name | User claiming rewards |

The `claim` action:

1. **Reconciles ownership changes:**
   * Removes stale `assetstrain` entries (NFTs user no longer owns)
   * Updates `training` counts to match actual ownership
2. Calculates rewards using `min(old_count, actual_count)` to prevent overpaying
3. Updates last\_claim timestamps
4. Transfers accumulated $TRAIN rewards

> **Note:** Both `regassets` and `claim` handle ownership changes automatically. Users don't need to manually sync after buying or selling NFTs.

### Key Tables

| Table       | Scope            | Description                            |
| ----------- | ---------------- | -------------------------------------- |
| config      | singleton        | Manager, pause flag, reward pool       |
| collections | contract         | Enabled NFT collections                |
| rewardrates | collection\_name | Rates per rarity/powerscore            |
| tmplcache   | collection\_name | Cached template rarity/powerscore      |
| assetstrain | contract         | Individual registered assets           |
| training    | user account     | Aggregated counts by rarity/powerscore |

#### assetstrain Table Schema

| Field             | Type   | Description                         |
| ----------------- | ------ | ----------------------------------- |
| `asset_id`        | uint64 | AtomicAssets asset ID (primary key) |
| `owner`           | name   | Registered owner (secondary index)  |
| `template_id`     | int32  | Cached template ID                  |
| `collection_name` | name   | Cached collection for O(1) lookup   |
| `rarity`          | uint8  | Cached rarity (0-5)                 |
| `powerscore`      | uint8  | Cached powerscore (1-5)             |

#### rewardrates Table Schema

| Field             | Type   | Description                                              |
| ----------------- | ------ | -------------------------------------------------------- |
| `id`              | uint64 | (rarity << 8) \| powerscore                              |
| `rarity`          | uint8  | 0=Base, 1=Foil, 2=Battle, 3=Weld, 4=Action, 5=Collectors |
| `powerscore`      | uint8  | 1-5                                                      |
| `min_template_id` | int32  | First template in range                                  |
| `max_template_id` | int32  | Last template in range                                   |
| `hourly_rate`     | uint64 | $TRAIN per hour (raw units, 8 decimals)                  |

#### training Table Schema

| Field             | Type             | Description                                     |
| ----------------- | ---------------- | ----------------------------------------------- |
| `id`              | uint64           | Composite key from collection/rarity/powerscore |
| `collection_name` | name             | NFT collection                                  |
| `rarity`          | uint8            | 0-5                                             |
| `powerscore`      | uint8            | 1-5                                             |
| `count_assets`    | uint32           | Number of NFTs being trained                    |
| `last_claim`      | time\_point\_sec | Last claim timestamp                            |

### Reward Calculation

```
seconds_elapsed = now - last_claim
reward_count = min(traindata_count, actual_owned_count)
reward_raw = (hourly_rate * reward_count * seconds_elapsed) / 3600
```

Using `min(traindata_count, actual_owned_count)` prevents gaming:

* If user sold NFTs, rewards are based on current (lower) count
* If user bought NFTs but hasn't registered them, rewards are based on registered count
* New NFTs only earn rewards from the time they are registered

### stf.capcom Reward Rates

30 rates configured (6 rarities × 5 powerscores). Base hourly rates (PS5):

| Rarity      | $TRAIN/hour (PS5) | $TRAIN/day (PS5) |
| ----------- | ----------------- | ---------------- |
| Base        | 0.18939394        | 4.545            |
| Foil        | 0.33333333        | 8.0              |
| Battle      | 0.55555555        | 13.333           |
| Weld        | 0.83333333        | 20.0             |
| Action      | 1.66666666        | 40.0             |
| Collector's | 8.33333333        | 200.0            |

Powerscore multipliers: PS5=100%, PS4=50%, PS3=25%, PS2=12.5%, PS1=6.25%

### External Contracts

| Contract       | Purpose                    |
| -------------- | -------------------------- |
| `token.duel`   | TRAIN token contract       |
| `atomicassets` | NFT ownership verification |

***

## bank.duel Contract <a href="#bank-duel" id="bank-duel"></a>

The Token Bank smart contract is deployed at [bank.duel](https://waxblock.io/account/bank.duel) on WAX mainnet.

### Overview

The bank.duel contract provides in-app token exchange:

* Exchange $TRAIN for $FIGHT (and vice versa)
* Exchange $WAXP for $FIGHT
* Maintains reserves for all tokens
* Emergency pause mechanism

### Exchange Rates

| Direction     | Rate  | Example             |
| ------------- | ----- | ------------------- |
| TRAIN → FIGHT | 100:1 | 100 TRAIN = 1 FIGHT |
| FIGHT → TRAIN | 1:80  | 1 FIGHT = 80 TRAIN  |
| WAXP → FIGHT  | 1:1   | 1 WAXP = 1 FIGHT    |

The spreads create a natural fee structure preventing arbitrage.

### Exchange Flow

#### TRAIN -> FIGHT

1. User transfers TRAIN to bank.duel with memo: `exchange`
2. Contract validates:
   * Not paused
   * Token is TRAIN
   * Amount >= 100 TRAIN (minimum for 1 FIGHT output)
3. Calculates FIGHT output: `amount / train_to_fight_rate`
4. Verifies sufficient FIGHT reserve
5. Deducts from FIGHT reserve, adds to TRAIN reserve
6. Transfers FIGHT to user

#### FIGHT -> TRAIN

1. User transfers FIGHT to bank.duel with memo: `exchange`
2. Contract validates:
   * Not paused
   * Token is FIGHT
3. Calculates TRAIN output: `amount * fight_to_train_rate`
4. Verifies sufficient TRAIN reserve
5. Deducts from TRAIN reserve, adds to FIGHT reserve
6. Transfers TRAIN to user

#### WAXP -> FIGHT

1. User transfers WAXP to bank.duel with memo: `exchange`
2. Contract validates:
   * Not paused
   * Amount >= minimum for 1 FIGHT output
3. Calculates FIGHT output: `amount / waxp_to_fight_rate`
4. Verifies sufficient FIGHT reserve
5. Deducts from FIGHT reserve, adds to WAXP reserve
6. Transfers FIGHT to user

### Key Tables

| Table  | Scope     | Description                          |
| ------ | --------- | ------------------------------------ |
| config | singleton | Manager, pause flag, reserves, rates |

### Config Fields

| Field                  | Description                    |
| ---------------------- | ------------------------------ |
| manager                | Admin account                  |
| paused                 | Emergency pause flag           |
| train\_reserve         | Available TRAIN for exchange   |
| fight\_reserve         | Available FIGHT for exchange   |
| waxp\_reserve          | Available WAXP for exchange    |
| train\_to\_fight\_rate | TRAIN required per FIGHT (100) |
| fight\_to\_train\_rate | TRAIN paid per FIGHT (80)      |
| waxp\_to\_fight\_rate  | WAXP required per FIGHT (1)    |

### External Contracts

| Contract      | Purpose                        |
| ------------- | ------------------------------ |
| `token.duel`  | TRAIN and FIGHT token contract |
| `eosio.token` | WAXP token contract            |

***

## token.duel Contract

The token contract at [token.duel](https://waxblock.io/account/token.duel) hosts both $TRAIN and $FIGHT tokens.

### Token Details

| Token | Symbol | Precision  | Max Supply    |
| ----- | ------ | ---------- | ------------- |
| TRAIN | TRAIN  | 8 decimals | 1,000,000,000 |
| FIGHT | FIGHT  | 8 decimals | 1,000,000,000 |

### Token Links

* [$TRAIN on WAX Block](https://waxblock.io/tokens/TRAIN-wax-token.duel)
* [$FIGHT on WAX Block](https://waxblock.io/tokens/FIGHT-wax-token.duel)

***

## Contract Addresses Summary

| Contract   | Address                                                                  | Purpose                 |
| ---------- | ------------------------------------------------------------------------ | ----------------------- |
| stf.duel   | [waxblock.io/account/stf.duel](https://waxblock.io/account/stf.duel)     | Main game contract      |
| train.duel | [waxblock.io/account/train.duel](https://waxblock.io/account/train.duel) | NFT training            |
| bank.duel  | [waxblock.io/account/bank.duel](https://waxblock.io/account/bank.duel)   | Token exchange          |
| token.duel | [waxblock.io/account/token.duel](https://waxblock.io/account/token.duel) | TRAIN & FIGHT tokens    |
| duel       | [waxblock.io/account/duel](https://waxblock.io/account/duel)             | Reserved for future use |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://duel-2.gitbook.io/duel-white-paper/reference/smart-contracts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
