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

# IB20Factory.createB20

> Creates a B20 token of a given variant at a deterministic address, seals its identity, and runs optional bootstrap calls in the same transaction.

## Signature

```solidity IB20Factory.sol theme={null}
function createB20(B20Variant variant, bytes32 salt, bytes calldata params, bytes[] calldata initCalls) external payable returns (address token);
```

| Field               | Value                                    |
| ------------------- | ---------------------------------------- |
| Selector            | `0x62975e6a`                             |
| Canonical signature | `createB20(uint8,bytes32,bytes,bytes[])` |

## Description

Creates a B20 token of the given `variant` at the deterministic address derived from `(variant, msg.sender, salt)`. The Factory encodes the variant choice into the token address: byte `[0]` is `0xB2`, byte `[10]` is the variant discriminant (`0x00` for Asset, `0x01` for Stablecoin). The Factory then plants a `0xef` bytecode stub at that address, the stub the node reads to recognize a live B20, seals the token's identity (name, symbol, decimals, and variant-specific fields), emits `B20Created`, grants the initial admin role (skipped when `address(0)` is passed), and dispatches each entry in `initCalls` on the new token. Returns the token address.

The type is chosen once. After `createB20` returns, the variant encoded in the address cannot change. The Factory retains no persisted access after the call returns.

During the `createB20` call, factory-originated calls bypass the token's role gates and its transfer-side policy gates (`TRANSFER_SENDER_POLICY`, `TRANSFER_RECEIVER_POLICY`, `TRANSFER_EXECUTOR_POLICY`). This lets `initCalls` perform admin setup, `grantRole`, `updatePolicy`, `updateSupplyCap`, bootstrap transfers, without the Factory holding any role. The bypass is not total:

* **`MINT_RECEIVER_POLICY` is always enforced**, including for factory-originated mints. An `initCalls` bundle that sets a restrictive `MINT_RECEIVER_POLICY` and then mints to a non-authorized account reverts `PolicyForbids(MINT_RECEIVER_POLICY, ...)`, bubbled out of `createB20`.
* **Pause is never bypassed.** Pause defaults to nothing-paused at creation. To start paused, sequence the `pause(...)` call last among `initCalls`.
* **Token invariants are never bypassed.** Supply-cap math and balance accounting always apply.

The window closes when `createB20` returns.

## Parameters

| Name        | Type                   | Description                                                                                                                                                                                                                                                        |
| ----------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `variant`   | `B20Variant` (`uint8`) | Which variant to create: `ASSET` (`0x00`) or `STABLECOIN` (`0x01`). Determines which `params` struct to decode and which native logic the node dispatches to.                                                                                                      |
| `salt`      | `bytes32`              | Caller-chosen salt for deterministic address derivation.                                                                                                                                                                                                           |
| `params`    | `bytes`                | ABI-encoded variant-specific creation struct, leading with a `version` byte (currently `1`). For Asset: `B20AssetCreateParams` (name, symbol, `initialAdmin`, `decimals`). For Stablecoin: `B20StablecoinCreateParams` (name, symbol, `initialAdmin`, `currency`). |
| `initCalls` | `bytes[]`              | Bootstrap calls invoked on the new token after identity is sealed. May be empty.                                                                                                                                                                                   |

## Returns

| Name    | Type      | Description                         |
| ------- | --------- | ----------------------------------- |
| `token` | `address` | Address of the newly created token. |

## Reverts

| Error                  | Condition                                                                                                                   |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `NonPayable`           | ETH is attached to the call.                                                                                                |
| `FeatureNotActivated`  | The variant feature (`B20Asset` or `B20Stablecoin`) is not activated in the Activation Registry.                            |
| `InvalidVariant`       | `variant` is outside the `B20Variant` range.                                                                                |
| `UnsupportedVersion`   | The leading `version` byte in `params` is unrecognized for the given `variant`.                                             |
| `MissingRequiredField` | A required string field is empty: for example, Stablecoin `currency`.                                                       |
| `InvalidCurrency`      | Stablecoin `currency` is non-empty but contains a byte outside `A`–`Z`.                                                     |
| `InvalidDecimals`      | Asset `decimals` is outside `[B20Constants.MIN_ASSET_DECIMALS, B20Constants.MAX_ASSET_DECIMALS]` (i.e., outside `[6, 18]`). |
| `TokenAlreadyExists`   | A token already exists at the derived address. Reusing `(variant, sender, salt)` always hits this.                          |
| `InitCallFailed`       | An entry in `initCalls` reverted. The inner reason is bubbled when available.                                               |

## Access Control

No role required. Any caller may invoke `createB20`. The caller's address is part of the address derivation `(variant, msg.sender, salt)`.

## Policy Interaction

No direct policy interaction at the Factory level. Policy gates on the new token are enforced during `initCalls` as described in the bootstrap window rules above.

## Example

```solidity Usage Example theme={null}
address token = StdPrecompiles.B20_FACTORY.createB20(variant, salt, params, initCalls);
```
