> For the complete documentation index, see [llms.txt](https://docs.rh.fun/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rh.fun/for-developers/creating-a-coin.md).

# Creating a Coin

This guide covers coin creation through the **RH Factory** contract.

The create flow now uses struct-based APIs. Standard and advanced creation are unified under the same create params.

## Create Coin

To create a coin, call `createRHToken`.

### Method Interface

```solidity
function createRHToken(CreateParams calldata params)
    external
    returns (address token);
```

### CreateParams

```solidity
struct CreateParams {
    // Metadata / Auth
    string name;                   // Token name
    string symbol;                 // Token symbol
    string tokenURI;               // Metadata URI (commonly IPFS)
    uint256 nonce;                 // Signature nonce
    bytes signature;               // Backend authorization signature
    bytes32 tokenSalt;             // Deployment salt (bytes32(0) for auto-generate)

    // Recipients
    address payoutRecipient;       // Creator reward recipient
    address marketPayoutRecipient; // Tax market-bucket recipient (must be address(0) when using vault)

    // Market Vault (optional, for tax tokens)
    address marketVaultFactory;    // Vault factory address (address(0) to disable)
    bytes marketVaultData;         // Vault-specific initialization data

    // Market Config
    address collateralToken;       // Collateral asset, address(0) for native ETH
    uint256 targetRaise;           // Target raise amount (0 = use per-collateral default)

    // Lock Config (enabled when lockBps > 0)
    uint16 lockBps;                // Percentage of supply to lock (bps, 0-10000)
    uint64 lockupDuration;         // Lock period before vesting starts (seconds)
    uint64 vestingDuration;        // Vesting duration after lockup (seconds)
    address lockAdmin;             // Lock allocation admin address

    // Tax Config (enabled when taxRateBps > 0)
    uint16 taxRateBps;             // Tax rate on buys/sells (bps)
    uint64 taxDuration;            // Tax active duration (seconds)
    uint64 antiFarmerDuration;     // Anti-farmer window (seconds)
    uint16 processorMarketBps;     // Share to market vault/recipient (bps)
    uint16 processorDeflationBps;  // Share to deflation/burn (bps)
    uint16 processorLpBps;         // Share to LP (bps)
    uint16 processorDividendBps;   // Share to holder dividend (bps)
    uint256 minimumShareBalance;   // Minimum balance for dividend eligibility
}
```

### Mode Switches (Important)

* Standard mode: `targetRaise == 0` (uses per-collateral defaults)
* Advanced mode: `targetRaise > 0`
* Lock enabled: `lockBps > 0`
* Tax enabled: `taxRateBps > 0`

Supported collateral assets are chain-config driven. On Robinhood Chain, current options are native ETH (`address(0)`) and USDG (`0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168`, 6 decimals).

### Creation Events

Creation emits `NewRHToken`, and also emits parameter snapshot events depending on token mode:

* `NewRHTokenCurveParams`
* `NewRHTokenDynamicParams`
* `NewRHTaxTokenParams` (tax market only)

See ABI for full field definitions.

***

## Create and Buy Coin

To create and do an exact-in first buy in one transaction, call `createRHTokenAndBuy`.

### Method Interface

```solidity
function createRHTokenAndBuy(
    CreateParams calldata params,
    BuyParams calldata buy
)
    external
    payable
    returns (address token, uint256 tokensOut);
```

### Payment Notes

* Native collateral market (`collateralToken == address(0)`): `msg.value` must equal `buy.collateralAmountIn`.
* ERC20 collateral market: `msg.value` must be `0`, and caller must approve the Factory for `buy.collateralAmountIn`.

On successful first buy, the Factory emits `Buy`.

***

## Basic Create (Standard / Non-tax / Non-lock)

For the simplest create flow, call `createRHTokenBasic`.

```solidity
function createRHTokenBasic(BasicCreateParams calldata params)
    external
    returns (address token);
```

This entrypoint is a convenience wrapper for standard mode only.

***

## Creating a Tax Token with Vault

Tax tokens can be paired with a Market Vault by setting `marketVaultFactory` and `marketVaultData` in `CreateParams`. The vault receives the market-bucket portion of tax revenue instead of a static `marketPayoutRecipient` address.

> **Important:** When using a vault, `marketPayoutRecipient` must be set to `address(0)`. The transaction will revert with `MarketPayoutRecipientMustBeZeroInVaultMode()` otherwise.

### Relevant CreateParams Fields

```solidity
struct CreateParams {
    // ... other fields ...

    /// Market vault factory address (set to address(0) to disable vault).
    address marketVaultFactory;
    /// Vault-specific initialization data (opaque bytes passed to the vault factory).
    bytes marketVaultData;

    // Tax config (vault requires taxRateBps > 0)
    uint16 taxRateBps;
    uint16 processorMarketBps;   // share directed to market vault
    // ... other tax fields ...
}
```

When `marketVaultFactory != address(0)`, the Factory internally calls:

```solidity
IVaultFactory(marketVaultFactory).newVault(tokenAddress, quoteToken, msg.sender, marketVaultData);
```

The resulting vault address replaces `marketPayoutRecipient` as the tax revenue destination for the market bucket.

On success, the Factory emits:

```solidity
event MarketVaultCreated(
    address indexed token,
    address indexed vaultFactory,
    address vault,
    bytes marketVaultData
);
```

### Vault Factory Addresses

| Vault Type   | Factory Address                              |
| ------------ | -------------------------------------------- |
| SnowBall     | `0x02836df426F73142A9860578Bc9E0aAbcB2AEef8` |
| BurnDividend | `0xB2414df84a9551B374D0d2f5B76f242ca911BEAE` |
| Gift         | `0xcDE778F62D40d40fd61b51f07714BD9f52F438E6` |
| Split        | `0x3830723F569cF9f36B25c291367eD1ddB4Ac76F7` |

### `marketVaultData` Encoding by Vault Type

Each vault factory decodes `marketVaultData` differently. All vaults currently only support native quote (`quoteToken == address(0)`).

For detailed descriptions of each Vault type, see: [SnowBall](/vaults/snowball.md) | [BurnDividend](/vaults/burndividend.md) | [Gift](/vaults/gift.md) | [Split](/vaults/splitvault.md)

#### SnowBall Vault

```solidity
bytes memory marketVaultData = abi.encode(keeper);
// keeper (address): account granted SNOWBALL_ROLE, responsible for calling snowball()
```

| Field    | Type      | Description                                                                     |
| -------- | --------- | ------------------------------------------------------------------------------- |
| `keeper` | `address` | Fixed platform Keeper Bot address: `0xdD90b6E098E0c0756721D2bec83fDbDA14bB6eF9` |

#### BurnDividend Vault

```solidity
bytes memory marketVaultData = abi.encode(keeper);
// keeper (address): account granted OPERATOR_ROLE, responsible for calling buyback()
```

| Field    | Type      | Description                                                                     |
| -------- | --------- | ------------------------------------------------------------------------------- |
| `keeper` | `address` | Fixed platform Keeper Bot address: `0xdD90b6E098E0c0756721D2bec83fDbDA14bB6eF9` |

#### Gift Vault

```solidity
// VaultData struct defined in GiftVaultFactory:
// struct VaultData { string xHandle; }

bytes memory marketVaultData = abi.encode(
    GiftVaultFactory.VaultData({ xHandle: "elonmusk" })
);
```

| Field     | Type     | Description                                                                                                                |
| --------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| `xHandle` | `string` | X (Twitter) handle of the gift recipient. **Without `@` prefix, lowercase only.** Must not be empty. Example: `"elonmusk"` |

Encoding example (ABI tuple):

```solidity
// The struct is encoded as a tuple containing a single string:
marketVaultData = abi.encode("elonmusk");
// This is equivalent since VaultData only has one string field
```

#### Split Vault

```solidity
// Recipient struct defined in SplitVault:
// struct Recipient { address recipient; uint16 bps; }

SplitVault.Recipient[] memory recipients = new SplitVault.Recipient[](3);
recipients[0] = SplitVault.Recipient({ recipient: addr1, bps: 5000 }); // 50%
recipients[1] = SplitVault.Recipient({ recipient: addr2, bps: 3000 }); // 30%
recipients[2] = SplitVault.Recipient({ recipient: addr3, bps: 2000 }); // 20%

bytes memory marketVaultData = abi.encode(recipients);
```

| Field        | Type          | Description                                  |
| ------------ | ------------- | -------------------------------------------- |
| `recipients` | `Recipient[]` | Array of `{ address recipient, uint16 bps }` |

Constraints:

* 1–10 recipients
* `bps` values must sum to `10000` (100%)
* No duplicate or zero addresses

***

## Additional Notes

* `tokenURI`: points to metadata (commonly IPFS).
* `tokenSalt`: if set to `bytes32(0)`, factory auto-generates deployment salt; otherwise uses the provided deterministic salt.
* `signature`: signature checks depend on factory configuration. Integrators should follow the active backend signing policy.
