> ## Documentation Index
> Fetch the complete documentation index at: https://compact-by-example.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Minting Tokens

> Mint tokens in Compact with admin-gated authentication, total-supply overflow checks, and explicit disclosure of minted amounts.

<Warning>
  Mint authority is gated by the witness-derived admin keypair from
  [Access Control](/basics/access-control). The admin proves knowledge of a
  witness secret whose hash matches the stored `_admin` public key.
</Warning>

## The Contract

<Accordion title="View Contract Code">
  ```compact theme={null}
  pragma language_version >= 0.23;

  import CompactStandardLibrary;

  // Admin keypair (witness-derived)
  struct AdminSecretKey { bytes: Bytes<32>; }
  struct AdminPublicKey { bytes: Bytes<32>; }
  witness getAdminSecret(): AdminSecretKey;

  // User keypair (witness-derived) — used as a balance index
  struct UserSecretKey { bytes: Bytes<32>; }
  struct UserPublicKey { bytes: Bytes<32>; }
  witness getUserSecret(): UserSecretKey;

  // Ledger state
  export ledger _admin: AdminPublicKey;
  export ledger _balances: Map<UserPublicKey, Uint<128>>;
  export ledger _totalSupply: Uint<128>;

  constructor(initialAdmin: AdminPublicKey) {
      _admin = disclose(initialAdmin);
  }

  // Key derivation
  export circuit deriveAdminPublicKey(sk: AdminSecretKey): AdminPublicKey {
      return AdminPublicKey {
          bytes: persistentHash<Vector<2, Bytes<32>>>([
              pad(32, "myapp:admin:v1"),
              sk.bytes
          ])
      };
  }

  export circuit deriveUserPublicKey(sk: UserSecretKey): UserPublicKey {
      return UserPublicKey {
          bytes: persistentHash<Vector<2, Bytes<32>>>([
              pad(32, "myapp:user:v1"),
              sk.bytes
          ])
      };
  }

  // Read total supply
  export circuit getTotalSupply(): Uint<128> {
      return _totalSupply;
  }

  // Mint — admin only
  export circuit mint(account: UserPublicKey, amount: Uint<128>): [] {
      assert(
          _admin == deriveAdminPublicKey(getAdminSecret()),
          "Only admin may mint"
      );
      _mint(account, amount);
  }

  // Internal mint logic
  circuit _mint(account: UserPublicKey, amount: Uint<128>): [] {
      const MAX_UINT128: Uint<128> = 340282366920938463463374607431768211455 as Uint<128>;

      // Check total supply won't overflow
      assert(_totalSupply <= MAX_UINT128 - amount, "Total supply overflow");
      _totalSupply = disclose((_totalSupply + amount) as Uint<128>);

      // Check recipient's balance won't overflow
      const currentBalance = getBalance(account);
      assert(currentBalance <= MAX_UINT128 - amount, "Balance overflow");
      _balances.insert(
          disclose(account),
          disclose((currentBalance + amount) as Uint<128>)
      );
  }

  // Helper
  circuit getBalance(account: UserPublicKey): Uint<128> {
      if (!_balances.member(disclose(account))) { return 0; }
      return _balances.lookup(disclose(account));
  }
  ```
</Accordion>

## How It Works

### Admin authentication

```compact theme={null}
assert(
    _admin == deriveAdminPublicKey(getAdminSecret()),
    "Only admin may mint"
);
```

The contract stores the admin's *public* key. To mint, the caller must
produce a ZK proof that they know a witness secret whose hash equals that
public key. Reading `_admin` off chain gives an attacker the hash, not the
secret — preimage resistance means they cannot forge the proof.

### Total supply invariant

```compact theme={null}
assert(_totalSupply <= MAX_UINT128 - amount, "Total supply overflow");
_totalSupply = disclose((_totalSupply + amount) as Uint<128>);
```

`sum(all balances) == _totalSupply` is maintained by always updating both
sides together. Minting increases both; burning ([Burning](/basics/burning))
decreases both; transferring preserves both.

### Cast back to `Uint<128>` on store

```compact theme={null}
_totalSupply = disclose((_totalSupply + amount) as Uint<128>);
```

Arithmetic widens; after the overflow assertion we cast back to `Uint<128>`
before writing. See [Overflow Protection](/basics/overflow-protection).

## Privacy Note

<Warning>
  Each mint discloses `account` and `amount` on the public ledger. The full
  participant set and amount of every mint is observable to anyone reading the
  chain. This contract is suitable for transparent registries (game items,
  public rewards) but not for private finance.
</Warning>

## What's Next

<CardGroup cols={2}>
  <Card title="Burning Tokens" icon="fire" href="/basics/burning">
    Learn how to destroy tokens
  </Card>

  <Card title="ERC20 Token" icon="coins" href="/applications/erc20-token">
    Complete token with minting
  </Card>
</CardGroup>
