Back to skills
SkillHub ClubRun DevOpsFull StackDevOps

streme-launcher

Launch tokens on Streme (streme.fun) - the streaming token platform on Base. Use when deploying SuperTokens with built-in staking rewards, Uniswap V3 liquidity, and optional vesting vaults. Triggers on "launch token on streme", "deploy streme token", "create supertoken", or any Streme token deployment task.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,124
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B73.6

Install command

npx @skill-hub/cli install openclaw-skills-streme-launcher

Repository

openclaw/skills

Skill path: skills/clawrencestreme/streme-launcher

Launch tokens on Streme (streme.fun) - the streaming token platform on Base. Use when deploying SuperTokens with built-in staking rewards, Uniswap V3 liquidity, and optional vesting vaults. Triggers on "launch token on streme", "deploy streme token", "create supertoken", or any Streme token deployment task.

Open repository

Best for

Primary workflow: Run DevOps.

Technical facets: Full Stack, DevOps.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install streme-launcher into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding streme-launcher to shared team environments
  • Use streme-launcher for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: streme-launcher
description: Launch tokens on Streme (streme.fun) - the streaming token platform on Base. Use when deploying SuperTokens with built-in staking rewards, Uniswap V3 liquidity, and optional vesting vaults. Triggers on "launch token on streme", "deploy streme token", "create supertoken", or any Streme token deployment task.
---

# Streme Token Launcher

Deploy SuperTokens on Base via Streme's V2 contracts. Tokens include automatic Uniswap V3 liquidity, Superfluid streaming staking rewards, and optional vesting vaults.

## Quick Start

```typescript
import { createWalletClient, http, parseEther, encodeAbiParameters } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

// See references/contracts.md for full ABIs
const DEPLOYER = '0x8712F62B3A2EeBA956508e17335368272f162748';

const tokenConfig = {
  _name: 'My Token',
  _symbol: 'MYTOKEN',
  _supply: parseEther('100000000000'), // 100B
  _fee: 10000, // 10%
  _salt: '0x0...', // from generateSalt()
  _deployer: walletAddress,
  _fid: 0n, // Farcaster FID or 0
  _image: 'https://example.com/image.png',
  _castHash: 'deployment',
  _poolConfig: {
    tick: -230400,
    pairedToken: '0x4200000000000000000000000000000000000006', // WETH
    devBuyFee: 10000
  }
};

// Deploy with 10% staking (1 day lock, 365 day stream)
const stakingAlloc = createStakingAllocation(10, 1, 365);
await deployWithAllocations(tokenConfig, [stakingAlloc]);
```

## Contract Addresses (Base Mainnet)

| Contract | Address |
|----------|---------|
| STREME_PUBLIC_DEPLOYER_V2 | `0x8712F62B3A2EeBA956508e17335368272f162748` |
| STREME_SUPER_TOKEN_FACTORY | `0xB973FDd29c99da91CAb7152EF2e82090507A1ce9` |
| STREME_ALLOCATION_HOOK | `0xC907788f3e71a6eC916ba76A9f1a7C7C19384c7B` |
| LP_FACTORY | `0xfF65a5f74798EebF87C8FdFc4e56a71B511aB5C8` |
| MAIN_STREME (for salt) | `0x5797a398fe34260f81be65908da364cc18fbc360` |
| WETH (Base) | `0x4200000000000000000000000000000000000006` |

## Deployment Flow

1. **Generate Salt** - Call `generateSalt()` to get deterministic token address
2. **Upload Image** - Host token image (see Image Hosting below)
3. **Build Config** - Create tokenConfig and allocations
4. **Deploy** - Call `deployWithAllocations()`

## Image Hosting

Token images must be publicly accessible URLs. Options:

### IPFS (Recommended)
```typescript
// Using Pinata
const pinata = new PinataSDK({ pinataJwt: PINATA_JWT });
const { IpfsHash } = await pinata.pinFileToIPFS(fileStream);
const imageUrl = `https://gateway.pinata.cloud/ipfs/${IpfsHash}`;
```

### Cloudinary
```typescript
import { v2 as cloudinary } from 'cloudinary';

const result = await cloudinary.uploader.upload(imagePath, {
  folder: 'tokens',
  transformation: [{ width: 400, height: 400, crop: 'fill' }]
});
const imageUrl = result.secure_url;
```

### Direct URL
Any publicly accessible image URL works:
```typescript
const imageUrl = 'https://example.com/my-token.png';
```

### Requirements
- Format: PNG, JPG, GIF, WebP
- Size: < 5MB (< 1MB recommended)
- Dimensions: Square preferred (400x400 ideal)

### Upload Script
```bash
# IPFS via Pinata
PINATA_JWT=xxx npx ts-node scripts/upload-image.ts pinata ./token.png

# Cloudinary
CLOUDINARY_CLOUD_NAME=xxx CLOUDINARY_API_KEY=xxx CLOUDINARY_API_SECRET=xxx \
  npx ts-node scripts/upload-image.ts cloudinary ./token.png

# imgBB (free)
npx ts-node scripts/upload-image.ts imgbb ./token.png
```

## Allocations

### Staking Allocation (Type 1)
Streams tokens to stakers over time.

```typescript
function createStakingAllocation(
  percentage: number,    // % of supply (e.g., 10)
  lockDays: number,      // min stake duration
  flowDays: number,      // reward stream duration
  delegate?: string      // optional admin address
) {
  const lockSec = lockDays * 86400;
  const flowSec = flowDays * 86400;
  
  return {
    allocationType: 1,
    admin: delegate || '0x0000000000000000000000000000000000000000',
    percentage: BigInt(percentage),
    data: encodeAbiParameters(
      [{ type: 'uint256' }, { type: 'int96' }],
      [BigInt(lockSec), BigInt(flowSec)]
    )
  };
}
```

### Vault Allocation (Type 0)
Locked tokens with optional vesting.

```typescript
function createVaultAllocation(
  percentage: number,     // % of supply
  beneficiary: string,    // recipient address
  lockDays: number,       // lockup (min 7 days)
  vestingDays: number     // vesting after lock
) {
  const lockSec = Math.max(lockDays, 7) * 86400;
  const vestSec = vestingDays * 86400;
  
  return {
    allocationType: 0,
    admin: beneficiary,
    percentage: BigInt(percentage),
    data: encodeAbiParameters(
      [{ type: 'uint256' }, { type: 'uint256' }],
      [BigInt(lockSec), BigInt(vestSec)]
    )
  };
}
```

### Allocation Rules
- Staking + Vault percentages must be ≤100%
- Remaining % goes to Uniswap V3 LP
- Vault lock minimum: 7 days
- Standard config: 10% staking, 90% LP

## Token Config Defaults

| Parameter | Value |
|-----------|-------|
| Supply | 100,000,000,000 (100B) |
| Creator Fee | 10000 (10%) |
| Dev Buy Fee | 10000 (10%) |
| Tick | -230400 |
| Paired Token | WETH |

## API Endpoints

```bash
# Get tokens by deployer
GET https://api.streme.fun/api/tokens/deployer/{address}

# Search all tokens
GET https://api.streme.fun/api/tokens

# Token details
GET https://api.streme.fun/api/tokens/{address}
```

## Full Implementation

See `scripts/deploy-token.ts` for complete deployment script.

See `references/contracts.md` for full ABIs and type definitions.

## Common Patterns

### Standard Launch (10% staking)
```typescript
const allocations = [createStakingAllocation(10, 1, 365)];
```

### With Team Vault (10% staking + 10% vested)
```typescript
const allocations = [
  createStakingAllocation(10, 1, 365),
  createVaultAllocation(10, teamAddress, 30, 365)
];
```

### Max Liquidity (no allocations)
```typescript
const allocations = [];
// 100% goes to Uniswap V3 LP
```


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/contracts.md

```markdown
# Streme Contract Reference

## Contract Addresses (Base Mainnet, Chain ID: 8453)

```typescript
export const CONTRACTS = {
  STREME_PUBLIC_DEPLOYER_V2: '0x8712F62B3A2EeBA956508e17335368272f162748',
  STREME_SUPER_TOKEN_FACTORY: '0xB973FDd29c99da91CAb7152EF2e82090507A1ce9',
  STREME_ALLOCATION_HOOK: '0xC907788f3e71a6eC916ba76A9f1a7C7C19384c7B',
  LP_FACTORY: '0xfF65a5f74798EebF87C8FdFc4e56a71B511aB5C8',
  MAIN_STREME: '0x5797a398fe34260f81be65908da364cc18fbc360',
  WETH: '0x4200000000000000000000000000000000000006',
  STAKING_FACTORY_V2: '0xC749105bc4b4eA6285dBBe2E3A36C2B899233d02c0',
  STREME_VAULT: '0xDa902C1F73160daDE69AB3c3355110442359EB70',
} as const;
```

## ABIs

### STREME_DEPLOY_V2_ABI

```typescript
export const STREME_DEPLOY_V2_ABI = [
  {
    inputs: [
      { name: '_symbol', type: 'string' },
      { name: '_requestor', type: 'address' },
      { name: '_tokenFactory', type: 'address' },
      { name: '_pairedToken', type: 'address' },
    ],
    name: 'generateSalt',
    outputs: [
      { name: 'salt', type: 'bytes32' },
      { name: 'token', type: 'address' },
    ],
    stateMutability: 'view',
    type: 'function',
  },
  {
    inputs: [
      { name: 'tokenFactory', type: 'address' },
      { name: 'postDeployHook', type: 'address' },
      { name: 'liquidityFactory', type: 'address' },
      { name: 'postLPHook', type: 'address' },
      {
        name: 'preSaleTokenConfig',
        type: 'tuple',
        components: [
          { name: '_name', type: 'string' },
          { name: '_symbol', type: 'string' },
          { name: '_supply', type: 'uint256' },
          { name: '_fee', type: 'uint24' },
          { name: '_salt', type: 'bytes32' },
          { name: '_deployer', type: 'address' },
          { name: '_fid', type: 'uint256' },
          { name: '_image', type: 'string' },
          { name: '_castHash', type: 'string' },
          {
            name: '_poolConfig',
            type: 'tuple',
            components: [
              { name: 'tick', type: 'int24' },
              { name: 'pairedToken', type: 'address' },
              { name: 'devBuyFee', type: 'uint24' },
            ],
          },
        ],
      },
      {
        name: 'allocationConfigs',
        type: 'tuple[]',
        components: [
          { name: 'allocationType', type: 'uint8' },
          { name: 'admin', type: 'address' },
          { name: 'percentage', type: 'uint256' },
          { name: 'data', type: 'bytes' },
        ],
      },
    ],
    name: 'deployWithAllocations',
    outputs: [
      { name: 'token', type: 'address' },
      { name: 'liquidityId', type: 'uint256' },
    ],
    stateMutability: 'payable',
    type: 'function',
  },
] as const;
```

## TypeScript Types

```typescript
interface PoolConfig {
  tick: number;           // -230400 for standard
  pairedToken: `0x${string}`;  // WETH address
  devBuyFee: number;      // 10000 = 10%
}

interface TokenConfig {
  _name: string;
  _symbol: string;
  _supply: bigint;        // parseEther('100000000000')
  _fee: number;           // 10000 = 10%
  _salt: `0x${string}`;
  _deployer: `0x${string}`;
  _fid: bigint;           // Farcaster FID or 0n
  _image: string;
  _castHash: string;
  _poolConfig: PoolConfig;
}

interface AllocationConfig {
  allocationType: 0 | 1;  // 0=Vault, 1=Staking
  admin: `0x${string}`;
  percentage: bigint;
  data: `0x${string}`;
}
```

## Allocation Encoding

### Staking (Type 1)

```typescript
import { encodeAbiParameters } from 'viem';

// Encodes [lockDuration, streamDuration] in seconds
const data = encodeAbiParameters(
  [{ type: 'uint256' }, { type: 'int96' }],
  [BigInt(lockSeconds), BigInt(streamSeconds)]
);
```

### Vault (Type 0)

```typescript
// Encodes [lockupDuration, vestingDuration] in seconds
const data = encodeAbiParameters(
  [{ type: 'uint256' }, { type: 'uint256' }],
  [BigInt(lockupSeconds), BigInt(vestingSeconds)]
);
```

## RPC Endpoints

```typescript
const RPC_ENDPOINTS = [
  'https://mainnet.base.org',
  'https://base.meowrpc.com',
  'https://1rpc.io/base',
];
```

## Superfluid Integration

Streme tokens are Superfluid SuperTokens. Key Superfluid addresses on Base:

```typescript
export const SUPERFLUID = {
  HOST: '0x4C073B3baB6d8826b8C5b229f3cfdC1eC6E47E74',
  CFA_V1: '0x19ba78B9cDB05A877718841c574325fdB53601bb',
  CFA_V1_FORWARDER: '0xcfA132E353cB4E398080B9700609bb008eceB125',
  GDA_V1_FORWARDER: '0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08',
} as const;
```

## Post-Deployment

After deployment, the token will have:

1. **Uniswap V3 Pool** - Paired with WETH at tick -230400
2. **Staking Pool** (if configured) - Streams rewards to stakers
3. **Vault** (if configured) - Locked tokens with vesting schedule

Query deployed tokens via:
```
GET https://api.streme.fun/api/tokens/deployer/{deployerAddress}
```

```

### scripts/upload-image.ts

```typescript
/**
 * Image Upload Helpers for Streme Token Deployment
 * 
 * Provides multiple upload options: IPFS (Pinata), Cloudinary, or use existing URL.
 */

import * as fs from 'fs';
import * as path from 'path';

// ============ IPFS via Pinata ============

interface PinataResponse {
  IpfsHash: string;
  PinSize: number;
  Timestamp: string;
}

export async function uploadToIPFS(
  filePath: string,
  pinataJwt: string
): Promise<string> {
  const formData = new FormData();
  const file = fs.readFileSync(filePath);
  const blob = new Blob([file]);
  formData.append('file', blob, path.basename(filePath));

  const response = await fetch('https://api.pinata.cloud/pinning/pinFileToIPFS', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${pinataJwt}`,
    },
    body: formData,
  });

  if (!response.ok) {
    throw new Error(`Pinata upload failed: ${response.statusText}`);
  }

  const data = (await response.json()) as PinataResponse;
  return `https://gateway.pinata.cloud/ipfs/${data.IpfsHash}`;
}

// ============ Cloudinary ============

interface CloudinaryResponse {
  secure_url: string;
  public_id: string;
}

export async function uploadToCloudinary(
  filePath: string,
  cloudName: string,
  apiKey: string,
  apiSecret: string
): Promise<string> {
  const file = fs.readFileSync(filePath);
  const base64 = file.toString('base64');
  const mimeType = filePath.endsWith('.png') ? 'image/png' : 'image/jpeg';
  
  const timestamp = Math.floor(Date.now() / 1000);
  const folder = 'streme-tokens';
  
  // Generate signature
  const crypto = await import('crypto');
  const signatureString = `folder=${folder}&timestamp=${timestamp}${apiSecret}`;
  const signature = crypto.createHash('sha1').update(signatureString).digest('hex');

  const formData = new FormData();
  formData.append('file', `data:${mimeType};base64,${base64}`);
  formData.append('api_key', apiKey);
  formData.append('timestamp', timestamp.toString());
  formData.append('signature', signature);
  formData.append('folder', folder);
  formData.append('transformation', 'w_400,h_400,c_fill');

  const response = await fetch(
    `https://api.cloudinary.com/v1_1/${cloudName}/image/upload`,
    {
      method: 'POST',
      body: formData,
    }
  );

  if (!response.ok) {
    throw new Error(`Cloudinary upload failed: ${response.statusText}`);
  }

  const data = (await response.json()) as CloudinaryResponse;
  return data.secure_url;
}

// ============ imgBB (Free, no API key needed for basic) ============

interface ImgBBResponse {
  data: {
    url: string;
    display_url: string;
  };
  success: boolean;
}

export async function uploadToImgBB(
  filePath: string,
  apiKey?: string
): Promise<string> {
  const file = fs.readFileSync(filePath);
  const base64 = file.toString('base64');

  const formData = new FormData();
  formData.append('image', base64);
  if (apiKey) {
    formData.append('key', apiKey);
  }

  const url = apiKey
    ? `https://api.imgbb.com/1/upload?key=${apiKey}`
    : 'https://api.imgbb.com/1/upload';

  const response = await fetch(url, {
    method: 'POST',
    body: formData,
  });

  if (!response.ok) {
    throw new Error(`imgBB upload failed: ${response.statusText}`);
  }

  const data = (await response.json()) as ImgBBResponse;
  if (!data.success) {
    throw new Error('imgBB upload failed');
  }
  
  return data.data.display_url;
}

// ============ Main CLI ============

async function main() {
  const [, , provider, filePath] = process.argv;

  if (!filePath) {
    console.log(`
Usage: npx ts-node upload-image.ts <provider> <file-path>

Providers:
  pinata     - IPFS via Pinata (requires PINATA_JWT)
  cloudinary - Cloudinary (requires CLOUDINARY_* vars)
  imgbb      - imgBB (optional IMGBB_API_KEY)

Environment variables:
  PINATA_JWT           - Pinata JWT token
  CLOUDINARY_CLOUD_NAME
  CLOUDINARY_API_KEY
  CLOUDINARY_API_SECRET
  IMGBB_API_KEY        - Optional
`);
    process.exit(1);
  }

  if (!fs.existsSync(filePath)) {
    console.error(`File not found: ${filePath}`);
    process.exit(1);
  }

  let imageUrl: string;

  switch (provider) {
    case 'pinata':
      const pinataJwt = process.env.PINATA_JWT;
      if (!pinataJwt) throw new Error('PINATA_JWT required');
      imageUrl = await uploadToIPFS(filePath, pinataJwt);
      break;

    case 'cloudinary':
      const cloudName = process.env.CLOUDINARY_CLOUD_NAME;
      const apiKey = process.env.CLOUDINARY_API_KEY;
      const apiSecret = process.env.CLOUDINARY_API_SECRET;
      if (!cloudName || !apiKey || !apiSecret) {
        throw new Error('CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET required');
      }
      imageUrl = await uploadToCloudinary(filePath, cloudName, apiKey, apiSecret);
      break;

    case 'imgbb':
      imageUrl = await uploadToImgBB(filePath, process.env.IMGBB_API_KEY);
      break;

    default:
      console.error(`Unknown provider: ${provider}`);
      process.exit(1);
  }

  console.log(`✅ Image uploaded: ${imageUrl}`);
  console.log(`\nUse in deployment:`);
  console.log(`  TOKEN_IMAGE="${imageUrl}"`);
}

main().catch(console.error);

```

### scripts/deploy-token.ts

```typescript
/**
 * Streme Token Deployment Script
 * 
 * Deploy SuperTokens on Base via Streme V2 contracts.
 * 
 * Usage:
 *   npx ts-node deploy-token.ts
 * 
 * Environment:
 *   PRIVATE_KEY - Deployer wallet private key
 *   TOKEN_NAME - Token name
 *   TOKEN_SYMBOL - Token symbol (without $)
 *   TOKEN_IMAGE - Image URL (optional)
 *   STAKING_PERCENT - Staking allocation % (default: 10)
 *   STAKING_LOCK_DAYS - Lock duration (default: 1)
 *   STAKING_FLOW_DAYS - Stream duration (default: 365)
 */

import {
  createPublicClient,
  createWalletClient,
  http,
  parseEther,
  encodeAbiParameters,
  type Hex,
} from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

// ============ CONTRACTS ============

const CONTRACTS = {
  DEPLOYER: '0x8712F62B3A2EeBA956508e17335368272f162748' as const,
  TOKEN_FACTORY: '0xB973FDd29c99da91CAb7152EF2e82090507A1ce9' as const,
  ALLOCATION_HOOK: '0xC907788f3e71a6eC916ba76A9f1a7C7C19384c7B' as const,
  LP_FACTORY: '0xfF65a5f74798EebF87C8FdFc4e56a71B511aB5C8' as const,
  MAIN_STREME: '0x5797a398fe34260f81be65908da364cc18fbc360' as const,
  WETH: '0x4200000000000000000000000000000000000006' as const,
};

// ============ ABI ============

const DEPLOY_ABI = [
  {
    inputs: [
      { name: '_symbol', type: 'string' },
      { name: '_requestor', type: 'address' },
      { name: '_tokenFactory', type: 'address' },
      { name: '_pairedToken', type: 'address' },
    ],
    name: 'generateSalt',
    outputs: [
      { name: 'salt', type: 'bytes32' },
      { name: 'token', type: 'address' },
    ],
    stateMutability: 'view',
    type: 'function',
  },
  {
    inputs: [
      { name: 'tokenFactory', type: 'address' },
      { name: 'postDeployHook', type: 'address' },
      { name: 'liquidityFactory', type: 'address' },
      { name: 'postLPHook', type: 'address' },
      {
        name: 'preSaleTokenConfig',
        type: 'tuple',
        components: [
          { name: '_name', type: 'string' },
          { name: '_symbol', type: 'string' },
          { name: '_supply', type: 'uint256' },
          { name: '_fee', type: 'uint24' },
          { name: '_salt', type: 'bytes32' },
          { name: '_deployer', type: 'address' },
          { name: '_fid', type: 'uint256' },
          { name: '_image', type: 'string' },
          { name: '_castHash', type: 'string' },
          {
            name: '_poolConfig',
            type: 'tuple',
            components: [
              { name: 'tick', type: 'int24' },
              { name: 'pairedToken', type: 'address' },
              { name: 'devBuyFee', type: 'uint24' },
            ],
          },
        ],
      },
      {
        name: 'allocationConfigs',
        type: 'tuple[]',
        components: [
          { name: 'allocationType', type: 'uint8' },
          { name: 'admin', type: 'address' },
          { name: 'percentage', type: 'uint256' },
          { name: 'data', type: 'bytes' },
        ],
      },
    ],
    name: 'deployWithAllocations',
    outputs: [
      { name: 'token', type: 'address' },
      { name: 'liquidityId', type: 'uint256' },
    ],
    stateMutability: 'payable',
    type: 'function',
  },
] as const;

// ============ HELPERS ============

function daysToSeconds(days: number): bigint {
  return BigInt(days * 24 * 60 * 60);
}

function createStakingAllocation(
  percentage: number,
  lockDays: number,
  flowDays: number,
  delegate?: string
) {
  const data = encodeAbiParameters(
    [{ type: 'uint256' }, { type: 'int96' }],
    [daysToSeconds(lockDays), daysToSeconds(flowDays)]
  );

  return {
    allocationType: 1 as const,
    admin: (delegate || '0x0000000000000000000000000000000000000000') as Hex,
    percentage: BigInt(percentage),
    data,
  };
}

function createVaultAllocation(
  percentage: number,
  beneficiary: string,
  lockDays: number,
  vestingDays: number
) {
  const data = encodeAbiParameters(
    [{ type: 'uint256' }, { type: 'uint256' }],
    [daysToSeconds(Math.max(lockDays, 7)), daysToSeconds(vestingDays)]
  );

  return {
    allocationType: 0 as const,
    admin: beneficiary as Hex,
    percentage: BigInt(percentage),
    data,
  };
}

// ============ MAIN ============

async function main() {
  // Config from environment
  const privateKey = process.env.PRIVATE_KEY as Hex;
  const tokenName = process.env.TOKEN_NAME || 'My Token';
  const tokenSymbol = (process.env.TOKEN_SYMBOL || 'MYTOKEN').replace('$', '');
  const tokenImage = process.env.TOKEN_IMAGE || '';
  const stakingPercent = parseInt(process.env.STAKING_PERCENT || '10');
  const stakingLockDays = parseInt(process.env.STAKING_LOCK_DAYS || '1');
  const stakingFlowDays = parseInt(process.env.STAKING_FLOW_DAYS || '365');

  if (!privateKey) {
    throw new Error('PRIVATE_KEY environment variable required');
  }

  // Setup clients
  const account = privateKeyToAccount(privateKey);
  const publicClient = createPublicClient({
    chain: base,
    transport: http('https://mainnet.base.org'),
  });
  const walletClient = createWalletClient({
    account,
    chain: base,
    transport: http('https://mainnet.base.org'),
  });

  console.log(`Deploying token: ${tokenName} ($${tokenSymbol})`);
  console.log(`Deployer: ${account.address}`);

  // Generate salt
  console.log('Generating salt...');
  const [salt, predictedToken] = await publicClient.readContract({
    address: CONTRACTS.MAIN_STREME,
    abi: DEPLOY_ABI,
    functionName: 'generateSalt',
    args: [
      tokenSymbol,
      account.address,
      CONTRACTS.TOKEN_FACTORY,
      CONTRACTS.WETH,
    ],
  });

  console.log(`Predicted token address: ${predictedToken}`);

  // Build token config
  const tokenConfig = {
    _name: tokenName,
    _symbol: tokenSymbol,
    _supply: parseEther('100000000000'), // 100B
    _fee: 10000, // 10%
    _salt: salt,
    _deployer: account.address,
    _fid: 0n,
    _image: tokenImage,
    _castHash: 'streme-launcher deployment',
    _poolConfig: {
      tick: -230400,
      pairedToken: CONTRACTS.WETH,
      devBuyFee: 10000,
    },
  };

  // Build allocations
  const allocations = [];
  if (stakingPercent > 0) {
    allocations.push(
      createStakingAllocation(stakingPercent, stakingLockDays, stakingFlowDays)
    );
    console.log(`Staking: ${stakingPercent}% (${stakingLockDays}d lock, ${stakingFlowDays}d stream)`);
  }

  const lpPercent = 100 - stakingPercent;
  console.log(`Liquidity: ${lpPercent}%`);

  // Deploy
  console.log('Deploying token...');
  const hash = await walletClient.writeContract({
    address: CONTRACTS.DEPLOYER,
    abi: DEPLOY_ABI,
    functionName: 'deployWithAllocations',
    args: [
      CONTRACTS.TOKEN_FACTORY,
      CONTRACTS.ALLOCATION_HOOK,
      CONTRACTS.LP_FACTORY,
      '0x0000000000000000000000000000000000000000', // postLPHook
      tokenConfig,
      allocations,
    ],
  });

  console.log(`Transaction: ${hash}`);
  console.log('Waiting for confirmation...');

  const receipt = await publicClient.waitForTransactionReceipt({ hash });

  if (receipt.status === 'success') {
    console.log('\n✅ Token deployed successfully!');
    console.log(`Token: ${predictedToken}`);
    console.log(`TX: https://basescan.org/tx/${hash}`);
    console.log(`View: https://streme.fun/token/${predictedToken}`);
  } else {
    console.error('❌ Deployment failed');
    process.exit(1);
  }
}

main().catch(console.error);

```



---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "owner": "clawrencestreme",
  "slug": "streme-launcher",
  "displayName": "Streme Token Launcher",
  "latest": {
    "version": "1.0.0",
    "publishedAt": 1769961399774,
    "commit": "https://github.com/clawdbot/skills/commit/63b71f204be62b10bc2a1114dbe5eb9738722445"
  },
  "history": []
}

```

streme-launcher | SkillHub