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

# xStocks Launches

> Create an ERC-20-quoted launch against a supported xStocks wrapper on Ink.

xStocks launches are quoted in an xStocks wrapper instead of native ETH. Each supported asset has its own hook, wrapper, raise limits, deployment proof, and release identity.

<Warning>
  Do not use the native Ink hook for an xStocks launch. Do not hardcode one xStocks hook for every stock.
</Warning>

## What is different

| Native launch                       | xStocks launch                                              |
| ----------------------------------- | ----------------------------------------------------------- |
| Quote asset is ETH                  | Quote asset is the asset's wrapper ERC-20                   |
| Optional prebuy is `msg.value`      | Optional prebuy is `quotePrebuy` pulled with `transferFrom` |
| Call `createLaunch(params)`         | Call `createLaunchWithQuotePrebuy(params, quotePrebuy)`     |
| No quote-token approval             | Approve the exact per-asset hook to spend the wrapper       |
| Native hook comes from Capabilities | Hook and wrapper come from xStocks Quote Assets             |

The wrapper is the curve and pool quote asset. The rebasing underlying is a different token. Never substitute the underlying address for the wrapper address.

## 1. Load assets from the registry

```bash theme={null}
curl "https://inkypump.com/api/xstocks/quote-assets?chainId=57073&page=1&pageSize=100"
```

This endpoint is available for Ink only. Call it from your server.

For a new launch, require all of these:

```ts theme={null}
const asset = response.assets.find((item) => item.symbol === "NVDAx")

if (!asset) throw new Error("Asset is not in the current release")
if (!asset.canCreate) throw new Error("Creation is disabled for this asset")
if (!asset.deployment?.active) throw new Error("Asset hook is not active")
if (!asset.wrapperAddress) throw new Error("Wrapper address is missing")
```

Do not require `valuation` to create a launch. USD valuation is display evidence; it is not part of the on-chain curve call. Keep its `status`, `source`, and `observedAt` next to any USD number you show.

## 2. Validate amounts in wrapper units

All fields below are integer strings in the wrapper's smallest unit:

* `asset.config.minRaise`
* `asset.config.maxRaise`
* `asset.config.minBuy`
* `asset.config.buybackFlushThreshold`

```ts theme={null}
const targetRaise = BigInt(userTargetRaiseRaw)
const prebuy = BigInt(userPrebuyRaw)

if (targetRaise < BigInt(asset.config.minRaise)) throw new Error("Raise is too small")
if (targetRaise > BigInt(asset.config.maxRaise)) throw new Error("Raise is too large")
if (prebuy !== 0n && prebuy < BigInt(asset.config.minBuy)) {
  throw new Error("Prebuy is below the minimum")
}
```

Use `parseUnits(displayAmount, asset.decimals)` for user input. Do not use JavaScript floating-point math for contract amounts. A prebuy that reaches the remaining curve capacity can fill only that capacity and return the unused wrapper amount; show and verify the refund from the receipt.

## 3. Approve only the prebuy amount

No wrapper approval is needed when `quotePrebuy` is zero. Otherwise, approve the exact hook and amount.

```ts theme={null}
const hook = asset.deployment.hookAddress as `0x${string}`
const wrapper = asset.wrapperAddress as `0x${string}`

if (prebuy > 0n) {
  const allowance = await publicClient.readContract({
    address: wrapper,
    abi: ERC20_ABI,
    functionName: "allowance",
    args: [account, hook],
  })

  if (allowance < prebuy) {
    const approvalRequest = await publicClient.simulateContract({
      account,
      address: wrapper,
      abi: ERC20_ABI,
      functionName: "approve",
      args: [hook, prebuy],
    })
    const approvalHash = await walletClient.writeContract(approvalRequest.request)
    const approvalReceipt = await publicClient.waitForTransactionReceipt({
      hash: approvalHash,
    })
    if (approvalReceipt.status !== "success") throw new Error("Approval reverted")
  }
}
```

## 4. Create the launch

The parameter tuple is the same as a native launch, but `targetRaise` is wrapper-denominated. Send no native value.

```ts theme={null}
const XSTOCKS_CREATE_ABI = [
  {
    type: "function",
    name: "createLaunchWithQuotePrebuy",
    stateMutability: "nonpayable",
    inputs: [
      {
        name: "params",
        type: "tuple",
        components: [
          { name: "name", type: "string" },
          { name: "ticker", type: "string" },
          { name: "description", type: "string" },
          { name: "imageUrl", type: "string" },
          { name: "telegram", type: "string" },
          { name: "twitter", type: "string" },
          { name: "website", type: "string" },
          { name: "creatorFeeSplitBps", type: "uint16" },
          { name: "gainBps", type: "uint32" },
          { name: "targetRaise", type: "uint96" },
          { name: "antiSnipeDuration", type: "uint32" },
          { name: "startTime", type: "uint64" },
        ],
      },
      { name: "quotePrebuy", type: "uint256" },
    ],
    outputs: [{ name: "launchId", type: "uint256" }],
  },
  {
    type: "event",
    name: "LaunchCreated",
    anonymous: false,
    inputs: [
      { name: "launchId", type: "uint256", indexed: true },
      { name: "creator", type: "address", indexed: true },
      { name: "token", type: "address", indexed: false },
      { name: "targetRaise", type: "uint96", indexed: false },
    ],
  },
] as const

const params = {
  name: "NVIDIA Community",
  ticker: "NVIDIAC",
  description: "An InkyPump token quoted in NVDAx",
  imageUrl: "https://cdn.example.com/nvidiac.png",
  telegram: "",
  twitter: "",
  website: "",
  creatorFeeSplitBps: 5_000,
  gainBps: 50_000,
  targetRaise,
  antiSnipeDuration: 0,
  startTime: 0n,
} as const

const { request } = await publicClient.simulateContract({
  account,
  address: hook,
  abi: XSTOCKS_CREATE_ABI,
  functionName: "createLaunchWithQuotePrebuy",
  args: [params, prebuy],
})

const transactionHash = await walletClient.writeContract(request)
```

Use the same receipt checks as the [Launchpad Quickstart](/integrations/launchpad-quickstart): one `LaunchCreated` log from `hook`, creator equals the signing wallet, and target equals the signed target.

## Release evidence

The registry may return assets from more than one release. Use the selected asset's `asset.release`, not the response's top-level primary release. Store these fields with your cached asset record:

* `snapshotVersion`
* `release.leafScheme`
* `release.contentHash`
* `release.releaseBinding`
* `config.metadataHash`
* `deployment.configurationHash`
* `deployment.runtimeCodeHash`

Refresh the record before a write. If its release, hook, wrapper, or configuration changed after the user reviewed the launch, stop and ask the user to review the new plan.

## USD prices and 24/7 execution

The on-chain curve quotes token amounts in wrapper units. It does not need a USD mark to launch, buy, or sell. USD fields are separate display and accounting evidence.

An external ETH or stablecoin payment path still needs an executable conversion route into the wrapper. A valid stock mark does not create that liquidity. For the simplest reliable partner flow, require the user to hold the wrapper and trade the curve directly.

## Asset state

| Field                 | Meaning                                                             |
| --------------------- | ------------------------------------------------------------------- |
| `canCreate`           | InkyPump currently allows new launches for this exact deployment    |
| `deployment.active`   | The per-asset hook is active                                        |
| `isTradingHalted`     | Upstream issuer/provider halt signal; surface it to the user        |
| `supportsAtomicSwaps` | Upstream atomic conversion capability, not a promise of route depth |
| `valuation`           | Optional USD display evidence; never use it as an on-chain amount   |

The asset count and set can change. Never write a fixed list into your application.
