Skip to main content

What You Can Build

RektHub isn’t just another “token launchpad”, it’s infrastructure for the creator economy. Integrate our contracts to build:
  • Trading Interfaces: Cross-chain token trading UIs
  • Creator Dashboards: Fee tracking, analytics, community management
  • Portfolio Trackers: Multi-chain creator token portfolios
  • Trading Bots: Automated trading strategies
  • Aggregators: Cross-platform creator token discovery
Building something cool? Tag us @rekthub_io on X, we love seeing what the community creates.

Prerequisites

Before you start, make sure you have:
  • Node.js v16+ installed
  • ethers.js v6+ or viem v1+ (your choice)
  • A wallet provider (MetaMask, WalletConnect, etc.)
  • RPC endpoint for your target chain
  • Some native tokens for gas fees
Need testnet tokens? Check our Deployment Addresses page for faucet links.

Installation

npm install ethers@latest

Your First Buy Transaction

Let’s buy some creator tokens. This example shows the complete flow:
import { ethers } from 'ethers';

const FACTORY_ADDRESS = '0x...';
const TOKEN_ADDRESS = '0x...';

const FACTORY_ABI = [
	'function buy(address token, uint256 minTokensOut) payable returns (uint256)',
	'function getCurve(address token) view returns (address)',
	'event TokenPurchased(address indexed token, address indexed curve, address indexed buyer, uint256 nativeIn, uint256 tokensOut, uint256 totalFee, uint256 creatorFee, uint256 platformFee, uint256 newRealNativeReserves, uint256 newRealTokenReserves, uint256 newVirtualNativeReserves, uint256 newVirtualTokenReserves)',
];

const CURVE_ABI = [
	'function getBuyPrice(uint256 nativeIn) view returns (uint256 tokensOut, uint256 totalFee, uint256 creatorFee, uint256 platformFee)',
];

async function buyCreatorToken() {
	const provider = new ethers.BrowserProvider(window.ethereum);
	const signer = await provider.getSigner();

	const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, signer);

	const amountToSpend = ethers.parseEther('0.1');

	const curveAddress = await factory.getCurve(TOKEN_ADDRESS);
	const curve = new ethers.Contract(curveAddress, CURVE_ABI, provider);

	const [expectedTokens] = await curve.getBuyPrice(amountToSpend);

	const minTokensOut = (expectedTokens * 95n) / 100n;

	const tx = await factory.buy(TOKEN_ADDRESS, minTokensOut, {
		value: amountToSpend,
	});

	console.log('Transaction sent:', tx.hash);

	const receipt = await tx.wait();
	console.log('Transaction confirmed:', receipt.hash);

	const event = receipt.logs
		.map((log) => {
			try {
				return factory.interface.parseLog(log);
			} catch {
				return null;
			}
		})
		.find((e) => e?.name === 'TokenPurchased');

	if (event) {
		console.log('Tokens received:', ethers.formatEther(event.args.tokensOut));
		console.log('Creator earned:', ethers.formatEther(event.args.creatorFee));
	}

	return receipt;
}
Always implement slippage protection. Prices move between quote and execution, use minTokensOut to protect users.

Your First Sell Transaction

Selling tokens back to the curve:
import { ethers } from 'ethers';

const FACTORY_ADDRESS = '0x...';
const TOKEN_ADDRESS = '0x...';

const FACTORY_ABI = [
	'function sell(address token, uint256 tokenAmount, uint256 minNativeOut) returns (uint256)',
	'function getCurve(address token) view returns (address)',
	'event TokenSold(address indexed token, address indexed curve, address indexed seller, uint256 tokensIn, uint256 nativeOut, uint256 totalFee, uint256 creatorFee, uint256 platformFee, uint256 newRealNativeReserves, uint256 newRealTokenReserves, uint256 newVirtualNativeReserves, uint256 newVirtualTokenReserves)',
];

const TOKEN_ABI = [
	'function approve(address spender, uint256 amount) returns (bool)',
	'function balanceOf(address account) view returns (uint256)',
];

const CURVE_ABI = [
	'function getSellPrice(uint256 tokensIn) view returns (uint256 nativeOut, uint256 totalFee, uint256 creatorFee, uint256 platformFee)',
];

async function sellCreatorToken() {
	const provider = new ethers.BrowserProvider(window.ethereum);
	const signer = await provider.getSigner();

	const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, signer);
	const token = new ethers.Contract(TOKEN_ADDRESS, TOKEN_ABI, signer);

	const balance = await token.balanceOf(await signer.getAddress());
	const amountToSell = balance / 2n;

	const curveAddress = await factory.getCurve(TOKEN_ADDRESS);

	const approveTx = await token.approve(curveAddress, amountToSell);
	await approveTx.wait();
	console.log('Approval confirmed');

	const curve = new ethers.Contract(curveAddress, CURVE_ABI, provider);
	const [expectedNative] = await curve.getSellPrice(amountToSell);
	const minNativeOut = (expectedNative * 95n) / 100n;

	const tx = await factory.sell(TOKEN_ADDRESS, amountToSell, minNativeOut);
	console.log('Sell transaction sent:', tx.hash);

	const receipt = await tx.wait();
	console.log('Sell confirmed:', receipt.hash);

	return receipt;
}
Pro tip: Use sellPercentage() instead to sell a percentage without calculating exact amounts. Perfect for “Sell 25%” buttons.

Creating Your First Token

Launch a creator token in minutes. Here’s the complete flow from metadata to deployment:

Step 1: Prepare Your Metadata

Create a JSON file with your token info:
{
	"name": "Creator Coin",
	"symbol": "CRTR",
	"description": "Official token for [Your Community]. Join us!",
	"image": "ipfs://QmYourImageHash...",
	"external_url": "https://your-website.com",
	"social_links": {
		"twitter": "https://x.com/yourusername",
		"telegram": "https://t.me/yourchannel"
	}
}

Step 2: Upload to IPFS

import pinataSDK from '@pinata/sdk';

const pinata = new pinataSDK(
	process.env.PINATA_API_KEY,
	process.env.PINATA_SECRET
);

const upload = await pinata.pinJSONToIPFS(metadata);
const metadataURI = `ipfs://${upload.IpfsHash}`;

console.log('Metadata URI:', metadataURI);
Free IPFS Services: Pinata, NFT.Storage, or Web3.Storage all offer free tiers.

Step 3: Create the Token

import { ethers } from 'ethers';

const FACTORY_ADDRESS = '0x...';
const FACTORY_ABI = [
	'function createToken(string calldata name, string calldata symbol, string calldata tokenURI) payable returns (address, address)',
	'function getCreationFee() view returns (uint256)',
	'event TokenCreated(address indexed tokenAddress, address indexed curveAddress, address indexed creator, string name, string symbol, string uri, uint256 realNativeReserves, uint256 realTokenReserves, uint256 virtualNativeReserves, uint256 virtualTokenReserves, uint256 creationFee)',
];

async function createCreatorToken() {
	const provider = new ethers.BrowserProvider(window.ethereum);
	const signer = await provider.getSigner();

	const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, signer);

	const creationFee = await factory.getCreationFee();
	console.log('Creation fee:', ethers.formatEther(creationFee), 'ETH');

	const tx = await factory.createToken(
		'Creator Coin',
		'CRTR',
		'ipfs://QmYourHash...',
		{ value: creationFee }
	);

	console.log('Transaction sent:', tx.hash);
	const receipt = await tx.wait();

	const event = receipt.logs
		.map((log) => {
			try {
				return factory.interface.parseLog(log);
			} catch {
				return null;
			}
		})
		.find((e) => e?.name === 'TokenCreated');

	console.log('Token created!');
	console.log('Token address:', event.args.tokenAddress);
	console.log('Curve address:', event.args.curveAddress);
	console.log(
		'View on explorer:',
		`https://etherscan.io/token/${event.args.tokenAddress}`
	);

	return {
		token: event.args.tokenAddress,
		curve: event.args.curveAddress,
	};
}

Step 4: Verify on Block Explorer

After creation, verify your token was deployed correctly:
const token = new ethers.Contract(
	tokenAddress,
	[
		'function name() view returns (string)',
		'function symbol() view returns (string)',
		'function totalSupply() view returns (uint256)',
		'function tokenURI() view returns (string)',
	],
	provider
);

const [name, symbol, supply, uri] = await Promise.all([
	token.name(),
	token.symbol(),
	token.totalSupply(),
	token.tokenURI(),
]);

console.log('Name:', name);
console.log('Symbol:', symbol);
console.log('Supply:', ethers.formatEther(supply));
console.log('Metadata:', uri);
Token Supply: All RektHub tokens have a fixed supply of 1 billion tokens with 18 decimals. 850M are tradeable, 150M reserved for graduation liquidity.

Bonus: Create with Vanity Address

Want a custom token address like 0x000... or 0xdead...?
function mineVanitySalt(prefix, implementationAddress, factoryAddress) {
	let nonce = 0;
	while (true) {
		const salt = ethers.id(`vanity-${nonce}`);
		const predicted = ethers.getCreate2Address(
			factoryAddress,
			salt,
			ethers.keccak256(
				ethers.concat([
					'0x3d602d80600a3d3981f3363d3d373d3d3d363d73',
					implementationAddress,
					'0x5af43d82803e903d91602b57fd5bf3',
				])
			)
		);

		if (predicted.toLowerCase().startsWith(prefix.toLowerCase())) {
			return { salt, address: predicted };
		}
		nonce++;

		if (nonce % 10000 === 0) {
			console.log(`Tried ${nonce} combinations...`);
		}
	}
}

const { salt, address } = mineVanitySalt('0x0000', tokenImpl, factoryAddress);
console.log('Found vanity address:', address);

const tx = await factory.createTokenDeterministic(
	'Vanity Token',
	'VNTY',
	metadataURI,
	salt,
	{ value: creationFee }
);
Vanity Mining: Finding addresses with specific prefixes can take hours/days depending on length. Mine offchain, then deploy with the found salt.

Listening to Events

Track real-time activity across all creator tokens:
import { ethers } from 'ethers';

const FACTORY_ADDRESS = '0x...';
const FACTORY_ABI = [
	'event TokenPurchased(address indexed token, address indexed curve, address indexed buyer, uint256 nativeIn, uint256 tokensOut, uint256 totalFee, uint256 creatorFee, uint256 platformFee, uint256 newRealNativeReserves, uint256 newRealTokenReserves, uint256 newVirtualNativeReserves, uint256 newVirtualTokenReserves)',
	'event TokenSold(address indexed token, address indexed curve, address indexed seller, uint256 tokensIn, uint256 nativeOut, uint256 totalFee, uint256 creatorFee, uint256 platformFee, uint256 newRealNativeReserves, uint256 newRealTokenReserves, uint256 newVirtualNativeReserves, uint256 newVirtualTokenReserves)',
	'event TokenCreated(address indexed tokenAddress, address indexed curveAddress, address indexed creator, string name, string symbol, string uri, uint256 realNativeReserves, uint256 realTokenReserves, uint256 virtualNativeReserves, uint256 virtualTokenReserves, uint256 creationFee)',
];

async function listenToActivity() {
	const provider = new ethers.JsonRpcProvider('YOUR_RPC_URL');
	const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, provider);

	factory.on(
		'TokenCreated',
		(tokenAddress, curveAddress, creator, name, symbol) => {
			console.log(`New token launched: ${name} (${symbol})`);
			console.log(`   Creator: ${creator}`);
			console.log(`   Token: ${tokenAddress}`);
		}
	);

	factory.on(
		'TokenPurchased',
		(token, curve, buyer, nativeIn, tokensOut, totalFee, creatorFee) => {
			console.log(`Buy: ${ethers.formatEther(tokensOut)} tokens`);
			console.log(`   Spent: ${ethers.formatEther(nativeIn)}`);
			console.log(`   Creator earned: ${ethers.formatEther(creatorFee)}`);
		}
	);

	factory.on(
		'TokenSold',
		(token, curve, seller, tokensIn, nativeOut, totalFee, creatorFee) => {
			console.log(`Sell: ${ethers.formatEther(tokensIn)} tokens`);
			console.log(`   Received: ${ethers.formatEther(nativeOut)}`);
			console.log(`   Creator earned: ${ethers.formatEther(creatorFee)}`);
		}
	);
}

Common Integration Patterns

Building Trading UIs

async function getPriceQuote(tokenAddress, amountIn) {
	const curveAddress = await factory.getCurve(tokenAddress);
	const curve = new ethers.Contract(curveAddress, CURVE_ABI, provider);

	const [tokensOut, totalFee, creatorFee, platformFee] = await curve.getBuyPrice(
		amountIn
	);

	return {
		tokensOut,
		totalFee,
		creatorFee,
		platformFee,
		effectivePrice: amountIn / tokensOut,
	};
}

async function getTradeHistory(tokenAddress, fromBlock) {
	const filter = factory.filters.TokenPurchased(tokenAddress);
	const events = await factory.queryFilter(filter, fromBlock);

	return events.map((e) => ({
		timestamp: e.blockNumber,
		price: e.args.nativeIn / e.args.tokensOut,
		volume: e.args.tokensOut,
		buyer: e.args.buyer,
	}));
}

Building Aggregators

async function getTrendingTokens(fromBlock) {
	const createdFilter = factory.filters.TokenCreated();
	const tokens = await factory.queryFilter(createdFilter, fromBlock);

	const withVolume = await Promise.all(
		tokens.map(async (t) => {
			const buyFilter = factory.filters.TokenPurchased(t.args.tokenAddress);
			const trades = await factory.queryFilter(buyFilter, fromBlock);

			const volume = trades.reduce((sum, trade) => sum + trade.args.nativeIn, 0n);

			return {
				address: t.args.tokenAddress,
				name: t.args.name,
				symbol: t.args.symbol,
				creator: t.args.creator,
				volume: ethers.formatEther(volume),
			};
		})
	);

	return withVolume.sort((a, b) => parseFloat(b.volume) - parseFloat(a.volume));
}

Building Trading Bots

async function momentumBot(tokenAddress, thresholds) {
	const curve = await getCurveContract(tokenAddress);

	factory.on('TokenPurchased', async (token, _, __, nativeIn, tokensOut) => {
		if (token !== tokenAddress) return;

		const priceImpact = calculatePriceImpact(nativeIn, tokensOut);

		if (priceImpact > thresholds.buyThreshold) {
			await executeBuy(tokenAddress);
		}
	});
}
Trading bots carry risk. Always test thoroughly on testnets and use appropriate risk management.

Next Steps

Get Help