> For the complete documentation index, see [llms.txt](https://docs.astralbeam.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.astralbeam.io/smart-contracts/casper-token-factory.md).

# Casper TokenFactory

The TokenFactory contract manages CEP-18 token operations on Casper Network for cross-chain bridging.

## Overview

| Property       | Value                  |
| -------------- | ---------------------- |
| Language       | Rust (Odra Framework)  |
| License        | MIT                    |
| Token Standard | CEP-18                 |
| Security       | M-of-N Multi-signature |

## Core Functions

### mint\_with\_signatures

Mint CEP-18 tokens based on EVM lock event attestation.

```rust
pub fn mint_with_signatures(
    &mut self,
    source_chain_id: u64,
    eth_block_number: u64,
    eth_tx_index: u64,
    eth_log_index: u32,
    erc20_token: H160,
    sender: H160,
    amount: U256,
    casper_recipient_type: u8,
    casper_recipient: H256,
    nonce: u64,
    receipts_root: H256,
    signatures: Vec<Vec<u8>>,
)
```

**Parameters:**

| Name                    | Type      | Description                                                                         |
| ----------------------- | --------- | ----------------------------------------------------------------------------------- |
| `source_chain_id`       | u64       | Source EVM chain ID                                                                 |
| `eth_block_number`      | u64       | Block containing lock event                                                         |
| `eth_tx_index`          | u64       | Transaction index in block                                                          |
| `eth_log_index`         | u32       | Log index in transaction                                                            |
| `erc20_token`           | H160      | ERC-20 token address on source chain                                                |
| `sender`                | H160      | Original sender address on EVM                                                      |
| `amount`                | U256      | Amount to mint                                                                      |
| `casper_recipient_type` | u8        | 0 = account hash, 1 = contract package hash                                         |
| `casper_recipient`      | H256      | Recipient account hash on Casper                                                    |
| `nonce`                 | u64       | EVM locker's stable, monotonically increasing deposit nonce from the `Locked` event |
| `receipts_root`         | H256      | Receipts root from block header                                                     |
| `signatures`            | Vec\<Vec> | Relayer signatures                                                                  |

**Process:**

1. Verify block header exists in EthClient
2. Verify M-of-N signatures on attestation
3. Check event not already processed — replay protection is keyed by `(source_chain_id, nonce)`, the locker's stable deposit identifier, not by positional block/tx/log-index fields (positional fields can change if a deposit is re-anchored after a reorg, which would enable double-mint)
4. Mint CEP-18 tokens to recipient

**Events:**

```rust
struct TokensMinted {
    token: Address,
    recipient: Address,
    amount: U256,
    source_chain_id: u64,
    eth_block_number: u64,
    eth_tx_index: u64,
}
```

***

### burn

Burn CEP-18 tokens to unlock on EVM chain.

```rust
pub fn burn(
    &mut self,
    cep18_address: Address,
    amount: U256,
    eth_recipient: H160,
    target_chain_id: u64,
)
```

**Parameters:**

| Name              | Type    | Description                   |
| ----------------- | ------- | ----------------------------- |
| `cep18_address`   | Address | CEP-18 token contract address |
| `amount`          | U256    | Amount to burn                |
| `eth_recipient`   | H160    | Recipient address on EVM      |
| `target_chain_id` | u64     | Target EVM chain ID           |

**Requirements:**

* Caller must have sufficient balance
* Contract must not be paused
* Bridge fee must be paid (in CSPR)

**Events:**

```rust
struct TokensBurned {
    token: Address,
    sender: Address,
    amount: U256,
    eth_recipient: H160,
    target_chain_id: u64,
    nonce: u64,
}
```

**Example:**

```rust
// Burn 100 USDC to unlock on Sepolia
token_factory.burn(
    usdc_cep18_address,
    U256::from(100_000_000), // 100 USDC (6 decimals)
    eth_recipient_h160,
    11155111, // Sepolia chain ID
);
```

***

### lock\_native

Lock Casper-native CEP-18 tokens for bridging to EVM (mints wrapped tokens on EVM).

```rust
pub fn lock_native(
    &mut self,
    cep18_address: Address,
    amount: U256,
    eth_recipient: H160,
    target_chain_id: u64,
)
```

**Parameters:**

| Name              | Type    | Description          |
| ----------------- | ------- | -------------------- |
| `cep18_address`   | Address | CEP-18 token to lock |
| `amount`          | U256    | Amount to lock       |
| `eth_recipient`   | H160    | Recipient on EVM     |
| `target_chain_id` | u64     | Target chain ID      |

**Requirements:**

* Caller must have sufficient token balance
* Contract must not be paused

**Events:**

```rust
struct NativeTokenLocked {
    cep18_address: Address,
    sender: Address,
    amount: U256,
    eth_recipient: H160,
    target_chain_id: u64,
    nonce: u64,
}
```

***

### unlock\_native\_with\_signatures

Unlock Casper-native CEP-18 tokens based on EVM burn attestation.

```rust
pub fn unlock_native_with_signatures(
    &mut self,
    source_chain_id: u64,
    eth_block_number: u64,
    eth_tx_index: u64,
    eth_log_index: u32,
    wrapped_token: H160,
    cep18_contract_hash: H256,
    sender: H160,
    amount: U256,
    casper_recipient: H256,
    nonce: u64,
    receipts_root: H256,
    signatures: Vec<Vec<u8>>,
)
```

**Parameters:**

| Name                  | Type      | Description                      |
| --------------------- | --------- | -------------------------------- |
| `source_chain_id`     | u64       | Source EVM chain ID              |
| `eth_block_number`    | u64       | Block containing burn event      |
| `eth_tx_index`        | u64       | Transaction index in block       |
| `eth_log_index`       | u32       | Log index in transaction         |
| `wrapped_token`       | H160      | Wrapped token address on EVM     |
| `cep18_contract_hash` | H256      | CEP-18 contract hash to unlock   |
| `sender`              | H160      | Sender address on EVM            |
| `amount`              | U256      | Amount to unlock                 |
| `casper_recipient`    | H256      | Recipient account hash on Casper |
| `nonce`               | u64       | Burn nonce from EVM              |
| `receipts_root`       | H256      | Receipts root from block header  |
| `signatures`          | Vec\<Vec> | Relayer signatures               |

**Process:**

1. Verify M-of-N signatures
2. Check event not already processed
3. Transfer CEP-18 tokens to recipient

**Events:**

```rust
struct NativeTokenUnlocked {
    cep18_address: Address,
    recipient: Address,
    amount: U256,
    eth_burn_nonce: u64,
}
```

***

## Admin Functions

### deploy\_token

Deploy a new CEP-18 wrapped token.

```rust
pub fn deploy_token(
    &mut self,
    chain_id: u64,
    erc20_address: H160,
    name: String,
    symbol: String,
    decimals: u8,
) -> Address
```

**Access:** Admin only

**Events:**

```rust
struct TokenDeployed {
    erc20_address: H160,
    cep18_address: Address,
    name: String,
    symbol: String,
    decimals: u8,
}
```

***

### register\_token\_mapping

Register mapping between EVM token and CEP-18.

```rust
pub fn register_token_mapping(
    &mut self,
    chain_id: u64,
    erc20_address: H160,
    cep18_address: Address,
)
```

**Access:** Admin only

**Events:**

```rust
struct TokenMappingRegistered {
    erc20_address: H160,
    cep18_address: Address,
}
```

***

### register\_native\_token

Register a Casper-native CEP-18 token for bridging to EVM.

```rust
pub fn register_native_token(
    &mut self,
    cep18_address: Address,
    chain_id: u64,
    wrapped_token: H160,
    name: String,
    symbol: String,
    decimals: u8,
)
```

**Access:** Admin only

**Reverts** with `InvalidDecimals` (60049) if `decimals > 36`.

**Events:**

```rust
struct NativeTokenRegistered {
    cep18_address: Address,
    chain_id: u64,
    wrapped_token: H160,
}
```

***

### set\_eth\_client

Update the EthClient contract reference.

```rust
pub fn set_eth_client(&mut self, eth_client: Address)
```

**Access:** Admin only

***

### set\_bridge\_fee

Update the bridge fee.

```rust
pub fn set_bridge_fee(&mut self, fee: U512)
```

**Access:** Admin only

**Reverts** with `FeeExceedsMaximum` (60050) if the fee exceeds 10,000 CSPR (`MAX_BRIDGE_FEE_MOTES`) — a hard ceiling against fat-fingered values that would make every `burn`/`lock_native` revert until corrected. The same ceiling applies to `set_fee_parameters` and `repair_fee_config`.

> **Zero-fee mode:** when the fee is 0, transactions must attach NO CSPR — `collect_fee` reverts with `UnexpectedAttachedValue` (60048) instead of silently absorbing attached value into the contract purse.

***

### pause / unpause

Emergency pause mechanism.

```rust
pub fn pause(&mut self)
pub fn unpause(&mut self)
```

**Access:** Admin only

***

## View Functions

### get\_total\_bridged

Get total bridged amount for a token.

```rust
pub fn get_total_bridged(&self, erc20_address: H160) -> U256
```

### get\_locked\_per\_chain

Get locked amount per source chain.

```rust
pub fn get_locked_per_chain(&self, chain_id: u64, erc20_address: H160) -> U256
```

### is\_event\_processed

Check if an event has been processed.

```rust
pub fn is_event_processed(&self, event_hash: H256) -> bool
```

### get\_burn\_nonce

Get current burn nonce.

```rust
pub fn get_burn_nonce(&self) -> u64
```

### get\_bridge\_fee

Get current bridge fee.

```rust
pub fn get_bridge_fee(&self) -> U512
```

### get\_cep18\_for\_chain

Get CEP-18 token for a chain/EVM token pair.

```rust
pub fn get_cep18_for_chain(&self, chain_id: u64, erc20_address: H160) -> Option<Address>
```

### is\_native\_token\_for\_chain

Check if a token is a registered Casper-native token on a specific EVM chain.

```rust
pub fn is_native_token_for_chain(&self, cep18_address: Address, chain_id: u64) -> bool
```

***

## Error Codes

| Error                          | Code  | Description                                                                                                                                                                         |
| ------------------------------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Unauthorized`                 | 60021 | Caller not authorized (not admin)                                                                                                                                                   |
| `Paused`                       | 60022 | Contract is paused                                                                                                                                                                  |
| `TokenAlreadyExists`           | 60023 | Token already registered for this chain                                                                                                                                             |
| `TokenNotFound`                | 60024 | Token mapping not found                                                                                                                                                             |
| `EventNotAttested`             | 60025 | Event attestation failed verification                                                                                                                                               |
| `EventAlreadyProcessed`        | 60026 | Event already processed                                                                                                                                                             |
| `InvalidAmount`                | 60027 | Invalid token amount (zero or overflow)                                                                                                                                             |
| `MintFailed`                   | 60028 | CEP-18 token minting failed                                                                                                                                                         |
| `BurnFailed`                   | 60029 | CEP-18 token burning failed                                                                                                                                                         |
| `InvalidAttestation`           | 60030 | Attestation failed M-of-N signature verification                                                                                                                                    |
| `ReceiptsRootMismatch`         | 60031 | Receipts root in attestation doesn't match EthClient                                                                                                                                |
| `InsufficientSignatures`       | 60032 | Not enough valid signatures provided                                                                                                                                                |
| `BlockNotFound`                | 60033 | Block header not found in EthClient                                                                                                                                                 |
| `EthClientNotSet`              | 60034 | EthClient contract not configured                                                                                                                                                   |
| `InsufficientBridgeFee`        | 60035 | Insufficient bridge fee provided                                                                                                                                                    |
| `InvalidFeeRecipient`          | 60036 | Invalid fee recipient address                                                                                                                                                       |
| `NativeTokenAlreadyRegistered` | 60037 | Native token already registered for chain                                                                                                                                           |
| `NativeTokenNotRegistered`     | 60038 | Native token not registered for chain                                                                                                                                               |
| `TransferFailed`               | 60039 | CSPR transfer failed (lock/unlock)                                                                                                                                                  |
| `InsufficientChainLiquidity`   | 60040 | Not enough liquidity on target chain for unlock                                                                                                                                     |
| `DecimalMismatch`              | 60041 | Token decimal configuration mismatch                                                                                                                                                |
| `InvalidAdmin`                 | 60042 | Invalid admin address                                                                                                                                                               |
| `InvalidAddress`               | 60043 | Invalid (zero) address argument                                                                                                                                                     |
| `ChainNameNotSet`              | 60044 | Chain name not configured (required for EIP-712 domain)                                                                                                                             |
| `Erc20LockerNotSet`            | 60045 | No ERC20Locker configured for the source chain — seed via `admin casper-set-erc20-locker` (common after an in-place v7 upgrade, which leaves the mapping empty)                     |
| `AttestedAssetMismatch`        | 60046 | The signed attestation's `cep18_contract_hash` does not match the live wrapped→native mapping — the unlock is refused rather than releasing an asset the relayers never attested to |

***

## Storage Schema

```rust
struct TokenFactory {
    // Administration
    admin: AccountHash,
    eth_client: Option<Address>,
    erc20_locker: Option<H160>,
    bridged_token_factory: Option<Address>,
    paused: bool,

    // Token mappings (EVM-native tokens)
    erc20_to_cep18: Mapping<String, Address>,   // chain_erc20_key → cep18
    cep18_to_erc20: Mapping<String, (u64, H160)>, // cep18_chain_key → (chain_id, erc20)

    // Native token mappings (Casper-native tokens)
    native_to_wrapped: Mapping<Address, (u64, H160)>,  // cep18 → (chain_id, wrapped)
    wrapped_to_native: Mapping<String, Address>,       // wrapped_native_key → cep18

    // State tracking
    processed_events: Mapping<H256, bool>,      // event_hash → processed
    nonces: Mapping<String, u64>,               // nonce keys
    totals: Mapping<String, U256>,              // total keys → amount

    // Fees (packed into single Odra field to stay within 15-field module limit)
    fee_config: FeeConfig,  // { fee: U512, recipient: Option<Address>, collected: U512 }
}
```

***

## Integration Examples

### TypeScript (via bridge-cli)

```typescript
import { CasperClient } from './casper';

const client = new CasperClient(config);

// Deploy a new wrapped token
await client.deployToken(
    11155111, // Sepolia
    '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', // USDC on Sepolia
    'Bridged USDC',
    'bUSDC',
    6
);

// Register token mapping
await client.registerTokenMapping(
    11155111,
    '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
    cep18Address
);

// Query bridged totals
const total = await client.getTotalBridged(erc20Address);
```

### Rust (Direct Contract Call)

```rust
use odra::host::Deployer;

// Burn tokens
let token_factory = TokenFactoryRef::at(token_factory_address);
token_factory.burn(
    cep18_address,
    U256::from(1000000), // 1 USDC
    eth_recipient_h160,
    11155111, // Sepolia
);
```

***

## Security Considerations

1. **Signature Verification**: All mints require M-of-N valid signatures
2. **Event Hash Tracking**: Prevents replay attacks via unique event hashes
3. **Chain ID Validation**: Prevents cross-chain replay
4. **Liquidity Checks**: Ensures sufficient locked tokens for unlocks
5. **Pause Mechanism**: Emergency stop capability


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.astralbeam.io/smart-contracts/casper-token-factory.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
