Launch on Telau Bot
You can simply launch in the bot conversation using the following template.
/launch
n: token name
$: ticker
b: initial buy (0.1 default)
d: description (optionnal)
x: x.com/ (optionnal)
t: t.me/ (optionnal)
w: website (optionnal)
l: launchpad (pump | bonk - pump.fun default)Code Blocks (Some)
import fs from 'fs';
import path from 'path';
interface EnvConfig {
[key: string]: string;
}
/**
* Get environment variable with fallback to .env file
* @param key The environment variable key
* @returns The environment variable value or undefined if not found
*/
export function getEnvVar(key: string): string | undefined {
// First try to get from system environment
const systemValue = process.env[key];
if (systemValue && systemValue.trim() !== '') {
return systemValue;
}
// If not found or empty, try loading from .env file
const envConfig = loadEnvFile();
const envValue = envConfig[key];
if (envValue && envValue.trim() !== '') {
return envValue;
}
// Return undefined if not found
return undefined;
}
/**
* Load configuration from .env file
* @returns Configuration object
*/
function loadEnvFile(): EnvConfig {
const config: EnvConfig = {};
// Try to load from .env file in parent directory
const envPath = path.join(__dirname, '../../.env');
try {
const envContent = fs.readFileSync(envPath, 'utf8');
// Parse .env file
const lines = envContent.split('\n');
for (const line of lines) {
const trimmedLine = line.trim();
// Skip empty lines and comments
if (!trimmedLine || trimmedLine.startsWith('#')) {
continue;
}
// Split key=value
const [key, ...valueParts] = trimmedLine.split('=');
if (!key || valueParts.length === 0) {
continue;
}
let value = valueParts.join('=').trim();
// Remove surrounding quotes
if (value.length >= 2 &&
((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'")))) {
value = value.slice(1, -1);
}
config[key.trim()] = value;
}
} catch (error) {
console.log(error);
}
return config;
}import {
Connection,
Keypair,
PublicKey,
SendTransactionError
} from '@solana/web3.js';
import BN from 'bn.js'
import bs58 from 'bs58';
import crypto from 'crypto';
import bodyParser from 'body-parser';
import express, { Request, Response } from 'express';
import { pumpLaunch } from './pump';
import { bonkLaunch } from './bonk';
import { getEnvVar } from './env';
const app = express();
app.use(bodyParser.json({ limit: '4mb' }));
app.use((req: Request, res: Response, next: any) => {
const ip = req.ip || req.connection.remoteAddress || req.socket.remoteAddress || 'unknown';
const allowedIPs = ['127.0.0.1', '::1', '::ffff:127.0.0.1'];
if (!allowedIPs.includes(ip)) {
console.log(`Access denied for IP: ${ip}`);
return res.status(403).send('Forbidden - Access restricted to localhost');
}
next();
});
const SOL_NODE: string = getEnvVar('SOL_NODE') || (() => { throw new Error('SOL_NODE must be set'); })();
const ENCRYPTION_KEY_B64: string = getEnvVar('ENCRYPTION_KEY') || (() => { throw new Error('ENCRYPTION_KEY must be set'); })();
const ENCRYPTION_KEY: Buffer = Buffer.from(ENCRYPTION_KEY_B64, 'base64');
const connection = new Connection(SOL_NODE);
function keypairFromAny(secret: string): Keypair {
try {
const decoded = bs58.decode(secret);
if (decoded.length === 64) return Keypair.fromSecretKey(decoded);
if (decoded.length === 32) return Keypair.fromSeed(decoded);
} catch (_) { }
throw new Error('Invalid FEES_COLLECTOR_KEY');
}
const FEES_COLLECTOR_KEY: string =
getEnvVar('FEES_COLLECTOR_KEY') || (() => { throw new Error('FEES_COLLECTOR_KEY must be set'); })();
const feesCollectorKeypair = keypairFromAny(FEES_COLLECTOR_KEY);
const feesCollector: PublicKey = feesCollectorKeypair.publicKey;
function decrypt(encryptedB64: string, key: Buffer): string {
const combined = Buffer.from(encryptedB64, 'base64');
if (combined.length < 12 + 16) throw new Error('Ciphertext too short');
const nonce = combined.slice(0, 12);
const tag = combined.slice(combined.length - 16);
const ciphertext = combined.slice(12, combined.length - 16);
const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);
decipher.setAuthTag(tag);
let decrypted = decipher.update(ciphertext);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString('utf8');
}
app.post('/create-token', async (req: Request, res: Response) => {
try {
const { launchpad, name, ticker, desc, website, x, tg, devbuy, image, user_privkey, mint_privkey } = req.body;
const decryptedPrivkey = decrypt(user_privkey, ENCRYPTION_KEY);
const userPrivkeyBytes: number[] = JSON.parse(decryptedPrivkey);
const userKeypair = Keypair.fromSecretKey(Uint8Array.from(userPrivkeyBytes));
const mintPrivkeyBytes: number[] = JSON.parse(mint_privkey);
const mintKeypair = Keypair.fromSecretKey(Uint8Array.from(mintPrivkeyBytes));
if (launchpad === "pump") {
await pumpLaunch(
connection,
userKeypair,
mintKeypair,
feesCollector,
name,
ticker,
desc || '',
website || '',
x || '',
tg || '',
devbuy,
image
);
} else {
await bonkLaunch(
connection,
userKeypair,
mintKeypair,
feesCollector,
name,
ticker,
desc || '',
website || '',
x || '',
tg || '',
devbuy,
image
);
}
res.status(200).send(mintKeypair.publicKey.toBase58());
} catch (err: any) {
console.error('main error:', err);
let logs: string[] = [];
let message: string = '';
let resError = '';
if (err instanceof SendTransactionError) {
message = err.message || '';
if (typeof err.getLogs === 'function') {
try {
logs = await err.getLogs(connection);
} catch (logErr) {
console.error('failed to get simulation logs:', logErr);
}
}
} else {
if (err && typeof err === 'object' && 'message' in err) {
message = err.message || '';
}
if (err && typeof err === 'object') {
if ('transactionLogs' in err && Array.isArray(err.transactionLogs)) {
logs = err.transactionLogs;
} else if ('logs' in err && Array.isArray(err.logs)) {
logs = err.logs;
}
}
}
if ((message.toLowerCase().includes('insufficient lamports') ||
logs.some(line => line.toLowerCase().includes('insufficient lamports'))) ||
(message.toLowerCase().includes('insufficient funds') ||
logs.some(line => line.toLowerCase().includes('insufficient funds')))) {
resError = 'insufficient';
} else if (message.toLowerCase().includes('block height exceeded') ||
logs.some(line => line.toLowerCase().includes('block height exceeded'))) {
resError = 'exceeded';
} else {
resError = 'unknown';
}
res.status(500).send(resError);
}
});
const PORT = getEnvVar('PORT') || '3000';
app.listen(parseInt(PORT), '127.0.0.1', () => {
console.log(`Launchpad token creation microservice running on port ${PORT}`);
});Last updated
