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.
Install command
npx @skill-hub/cli install openclaw-skills-streme-launcher
Repository
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 repositoryBest 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
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}×tamp=${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": []
}
```