# Addresses
Source: https://docs.kas.fun/contracts/addresses
Contract addresses and network configuration
## Network
| Parameter | Value |
| ------------------- | ------------------------------ |
| **Chain ID** | `202555` |
| **RPC URL** | `https://evmrpc.kasplex.org` |
| **Explorer** | `https://explorer.kasplex.org` |
| **Native Currency** | KAS (18 decimals) |
## Contract Addresses
| Contract | Address |
| ---------------------- | -------------------------------------------- |
| **MemeFactory** | `0xa58afB4Cfec744f70417d1424e2bb40B7902FB87` |
| **WKAS (Wrapped KAS)** | `0x2c2Ae87Ba178F48637acAe54B87c3924F544a83e` |
The BondingCurve contract address can be read from `MemeFactory.bondingCurve()`. The Council contract address is per-token — check each token's community page on [kas.fun](https://kas.fun).
## Network
| Parameter | Value |
| ------------------- | ------------------------------------------ |
| **Chain ID** | `167012` |
| **RPC URL** | `https://rpc.kasplextest.xyz` |
| **Explorer** | `https://explorer.testnet.kasplextest.xyz` |
| **Native Currency** | KAS (18 decimals) |
## Contract Addresses
| Contract | Address |
| ---------------------- | -------------------------------------------- |
| **MemeFactory** | `0x5F65Df9DCf7d764CA9d319Baf89611d289546A81` |
| **WKAS (Wrapped KAS)** | `0xC065C62a10fB363fD31CA394D632C4Df106566df` |
The BondingCurve contract address can be read from `MemeFactory.bondingCurve()`. The Council contract address is per-token — check each token's community page on [kas.fun](https://kas.fun).
Contract addresses may be updated. Check [kas.fun](https://kas.fun) for the latest addresses.
# Buy & Sell
Source: https://docs.kas.fun/contracts/buy-and-sell
Trading tokens on the KasFun bonding curve
The code examples on this page use a `bondingCurve` contract instance for price quotes. Get its address from `MemeFactory.bondingCurve()`. See [Contract Overview](/contracts/overview) for details.
## Buy Tokens
Send KAS to `MemeFactory.buy()` to receive tokens.
```solidity theme={null}
function buy(address token, uint256 minTokensOut) external payable;
```
| Parameter | Description |
| -------------- | ----------------------------------------------- |
| `token` | Token contract address |
| `minTokensOut` | Minimum tokens to receive (slippage protection) |
| `msg.value` | Amount of KAS to spend (wei) |
```javascript ethers.js theme={null}
const kasAmount = ethers.parseEther("100"); // 100 KAS
// 1. Get quote first
const tokensOut = await bondingCurve.calculateBuyReturnWithParams(
kasAmount, tokenReserves, kasReserves, vToken, vKas
);
// 2. Apply slippage (e.g., 20%)
const minTokensOut = tokensOut * 80n / 100n;
// 3. Execute buy
const tx = await factory.buy(tokenAddress, minTokensOut, {
value: kasAmount,
});
await tx.wait();
```
### Buy Event
```solidity theme={null}
event Buy(
address indexed token,
address indexed buyer,
uint256 kasAmount,
uint256 tokenAmount,
uint256 fee
);
```
## Sell Tokens
Sell tokens back for KAS via `MemeFactory.sell()`.
```solidity theme={null}
function sell(address token, uint256 tokenAmount, uint256 minKasOut) external;
```
| Parameter | Description |
| ------------- | -------------------------------------------- |
| `token` | Token contract address |
| `tokenAmount` | Amount of tokens to sell (wei) |
| `minKasOut` | Minimum KAS to receive (slippage protection) |
Before selling, you must **approve** the MemeFactory contract to spend your tokens.
```javascript ethers.js theme={null}
const tokenAmount = ethers.parseEther("1000000"); // 1M tokens
// 1. Approve MemeFactory to spend tokens
const tokenContract = new ethers.Contract(tokenAddress, [
"function approve(address spender, uint256 amount) returns (bool)",
], signer);
const approveTx = await tokenContract.approve(FACTORY_ADDRESS, tokenAmount);
await approveTx.wait();
// 2. Get quote
const kasOut = await bondingCurve.calculateSellReturnWithParams(
tokenAmount, tokenReserves, kasReserves, vToken, vKas
);
// 3. Apply slippage (e.g., 20%)
const minKasOut = kasOut * 80n / 100n;
// 4. Execute sell
const tx = await factory.sell(tokenAddress, tokenAmount, minKasOut);
await tx.wait();
```
### Sell Event
```solidity theme={null}
event Sell(
address indexed token,
address indexed seller,
uint256 tokenAmount,
uint256 kasAmount,
uint256 fee
);
```
## Slippage Protection
Always set `minTokensOut` (buy) or `minKasOut` (sell) to protect against price changes between quoting and execution.
| Slippage | Multiplier | Use Case |
| -------- | ------------------ | ------------------------------ |
| 5% | `quote * 95 / 100` | Low volatility |
| 20% | `quote * 80 / 100` | Normal (recommended) |
| 50% | `quote * 50 / 100` | High volatility / large orders |
KasFun website uses 20% default slippage. For programmatic trading, adjust based on the token's volatility and your order size relative to pool reserves.
## Complete Trading Flow
```javascript theme={null}
import { ethers } from "ethers";
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const FACTORY = "0x..."; // MemeFactory Contract Address
const factory = new ethers.Contract(FACTORY, [
"function buy(address token, uint256 minTokensOut) payable",
"function sell(address token, uint256 tokenAmount, uint256 minKasOut)",
"function getTokenInfo(address token) view returns (tuple(uint256 tokenId, address creator, address pool, uint256 tokenReserves, uint256 kasReserves, uint256 createdAt, bool fulfilled, bool graduated, string metadataUri, uint256 paramVersion))",
"function getTokenParamVersion(address token) view returns (tuple(uint256 graduationThreshold, uint256 virtualToken, uint256 virtualKas, uint160 sqrtPriceX96Token0, uint160 sqrtPriceX96Token1, bool active))",
"function bondingCurve() view returns (address)",
], signer);
// Get BondingCurve address
const bcAddress = await factory.bondingCurve();
const bc = new ethers.Contract(bcAddress, [
"function calculateBuyReturnWithParams(uint256,uint256,uint256,uint256,uint256) pure returns (uint256)",
"function calculateSellReturnWithParams(uint256,uint256,uint256,uint256,uint256) pure returns (uint256)",
], provider);
const TOKEN = "0x..."; // your token address
// Read current state
const info = await factory.getTokenInfo(TOKEN);
const params = await factory.getTokenParamVersion(TOKEN);
// --- BUY ---
const kasIn = ethers.parseEther("100");
const buyReturn = await bc.calculateBuyReturnWithParams(
kasIn,
info.tokenReserves,
info.kasReserves,
params.virtualToken,
params.virtualKas
);
const minTokens = buyReturn * 80n / 100n; // 20% slippage
const buyTx = await factory.buy(TOKEN, minTokens, { value: kasIn });
await buyTx.wait();
// --- SELL ---
const tokensIn = ethers.parseEther("500000");
const sellReturn = await bc.calculateSellReturnWithParams(
tokensIn,
info.tokenReserves,
info.kasReserves,
params.virtualToken,
params.virtualKas
);
const minKas = sellReturn * 80n / 100n; // 20% slippage
// Approve first
const token = new ethers.Contract(TOKEN, [
"function approve(address,uint256) returns (bool)",
], signer);
await (await token.approve(FACTORY, tokensIn)).wait();
const sellTx = await factory.sell(TOKEN, tokensIn, minKas);
await sellTx.wait();
```
Bonding curve trading is only available when the token is not yet fulfilled (`info.fulfilled === false`). Once fulfilled, buy/sell will revert.
# Create Token
Source: https://docs.kas.fun/contracts/create-token
How token creation works on KasFun
## Overview
Token creation on KasFun requires a **platform signature** — you cannot call `createToken()` directly without one. This is by design: all tokens should be created through the [kas.fun](https://kas.fun) website.
Token creation is designed to be done through the KasFun website at [kas.fun/create-token](https://kas.fun/create-token). The platform signature ensures metadata integrity and prevents spam.
## How It Works
The user fills in token details (name, symbol, icon, description) on kas.fun. The platform generates a signature authorizing the creation.
The user's wallet calls `MemeFactory.createToken(params)` with the signed parameters. This is a **payable** call — it requires a creation fee.
MemeFactory deploys an ERC-20 token, sets up the bonding curve pool, and emits a `Created` event.
## createToken Parameters
```solidity theme={null}
struct CreateTokenParams {
string name; // Token name
string symbol; // Token symbol
string metadataUri; // IPFS/S3 metadata URL
uint256 creatorBuyAmount; // Optional: buy tokens at creation (wei)
bytes32 salt; // For deterministic address (vanity address)
uint256 nonce; // Anti-replay
uint256 deadline; // Signature expiry (unix timestamp)
bytes signature; // Platform EIP-712 signature
}
```
## Creation Fee
The contract charges a creation fee in KAS. Query it via:
```javascript theme={null}
const fee = await factory.creationFee();
console.log("Creation fee:", ethers.formatEther(fee), "KAS");
```
If `creatorBuyAmount > 0`, the transaction value must be `creationFee + creatorBuyAmount`.
## Token Address
All KasFun tokens have addresses ending in `7777` (vanity address). The address is deterministic — computed from the salt and creator address:
```javascript theme={null}
const predictedAddress = await factory.computeTokenAddress(salt, creatorAddress);
```
## Created Event
```solidity theme={null}
event Created(
address indexed token,
address indexed creator,
uint256 indexed tokenId,
address pool,
string name,
string symbol
);
```
Listen for new token creations:
```javascript theme={null}
factory.on("Created", (token, creator, tokenId, pool, name, symbol) => {
console.log(`New token: ${name} (${symbol}) at ${token}`);
});
```
# Graduation
Source: https://docs.kas.fun/contracts/graduation
What happens when a token reaches its fundraising goal
## What is Graduation?
When a token's bonding curve pool accumulates enough KAS to reach the **graduation threshold**, the token "graduates" — it transitions from the internal bonding curve market to a DEX (Krokoswap).
## Graduation Flow
The `kasReserves` in the pool reaches `graduationThreshold`. The token becomes **fulfilled**.
```javascript theme={null}
const info = await factory.getTokenInfo(token);
// info.fulfilled === true, info.graduated === false
```
The platform automatically migrates liquidity from the bonding curve pool to Krokoswap DEX. No user action needed.
The token is now live on DEX. The `graduated` flag is set to `true`.
```javascript theme={null}
const info = await factory.getTokenInfo(token);
// info.fulfilled === true, info.graduated === true
```
Community Governance becomes available. Token holders can elect a Council and participate in proposals.
## Checking Progress
```javascript theme={null}
// Progress: 0-10000 (representing 0.00% - 100.00%)
const progress = await factory.getBondingCurveProgress(tokenAddress);
const percent = Number(progress) / 100;
console.log(`${percent}% to graduation`);
// Or check reserves directly
const info = await factory.getTokenInfo(tokenAddress);
const params = await factory.getTokenParamVersion(tokenAddress);
const remaining = params.graduationThreshold - info.kasReserves;
console.log(`${ethers.formatEther(remaining)} KAS remaining`);
```
## After Graduation
| Action | Bonding Curve | DEX (Krokoswap) |
| ------------ | ------------- | --------------- |
| Buy | Not available | Available |
| Sell | Not available | Available |
| Price source | N/A | Krokoswap pool |
Calling `buy()` or `sell()` on MemeFactory for a graduated token will **revert**.
## Community Governance (CTO)
After graduation, the token unlocks Community Take Over (CTO) features:
* **Council Election** — token holders vote to elect council members
* **Proposals** — council members create proposals
* **Community Voting** — token holders vote on proposals by locking tokens
* **Tax Configuration** — community can set token transaction tax via proposals
See the [Community Governance](/governance/overview) section for details.
# Contract Overview
Source: https://docs.kas.fun/contracts/overview
KasFun smart contract architecture
## Architecture
KasFun consists of three core contracts:
```mermaid theme={null}
graph TD
MF["MemeFactory
createToken() · buy() · sell()
getTokenInfo() · getCurrentPrice()"]
BC["BondingCurve
(pure math)
calculateBuyReturn · calculateSellReturn"]
C["Council V1
(per-token, after graduation)
Elections · Proposals · Voting"]
TA["Token A
(ERC-20)"]
TB["Token B
(ERC-20)"]
MF --> TA
MF --> TB
MF -- reads --> BC
TA -. graduated .-> C
TB -. graduated .-> C
```
## MemeFactory
The central contract. All token creation and bonding curve trading goes through MemeFactory.
| Function | Description |
| ------------------------------------- | ------------------------------------------------------------- |
| `createToken(params)` | Create a new token (payable, requires platform signature) |
| `buy(token, minTokensOut)` | Buy tokens with KAS (payable) |
| `sell(token, tokenAmount, minKasOut)` | Sell tokens for KAS (requires ERC-20 approval) |
| `getTokenInfo(token)` | Get token state (reserves, graduated, etc.) |
| `getCurrentPrice(token)` | Get current price in KAS |
| `getBondingCurveProgress(token)` | Get fundraising progress (0–10000 = 0–100%) |
| `getTokenParamVersion(token)` | Get bonding curve parameters (virtualToken, virtualKas, etc.) |
| `bondingCurve()` | Get the BondingCurve contract address |
Each token created by MemeFactory is **ERC-20 compatible**.
## BondingCurve
A stateless math contract. All functions are `pure` or `view` — they don't modify state. Used by MemeFactory internally and available for external price calculations.
The BondingCurve contract address is not fixed — read it from `MemeFactory.bondingCurve()`.
```javascript theme={null}
const bcAddress = await factory.bondingCurve();
```
| Function | Description |
| ------------------------------------ | ------------------------------------ |
| `calculateBuyReturnWithParams(...)` | KAS in → tokens out |
| `calculateSellReturnWithParams(...)` | Tokens in → KAS out |
| `calculateBuyCostWithParams(...)` | Desired tokens out → required KAS in |
## Council V1
Per-token governance contract, activated after a token graduates. Each graduated token can have its own Council with elected members, proposals, and voting.
| Feature | Description |
| -------------- | -------------------------------------------------- |
| **Elections** | Token holders vote to elect Council members |
| **Proposals** | Council members create proposals for the community |
| **Voting** | Token holders vote on proposals by locking tokens |
| **Tax Config** | Community can set token tax through proposals |
Council addresses are per-token. You can find a token's Council address on its community page at [kas.fun](https://kas.fun).
## Token Standards
* All tokens are **ERC-20** compatible (transfer, approve, balanceOf, etc.)
* Total supply: **1,000,000,000** (1 billion) tokens per token, all 18 decimals
* Tokens are minted entirely at creation. 80% goes into the bonding curve pool, 20% is reserved.
# Price Calculation
Source: https://docs.kas.fun/contracts/price-calculation
Understanding the bonding curve math
The BondingCurve contract address can be obtained from `MemeFactory.bondingCurve()`. See [Contract Overview](/contracts/overview) for details.
## Constant Product Formula
KasFun uses a **constant-product** bonding curve (similar to Uniswap V2), enhanced with **virtual reserves**:
```
(tokenReserves + virtualToken) * (kasReserves + virtualKas) = k
```
The virtual reserves set the initial price and curve shape without requiring seed liquidity.
## Getting Curve Parameters
Before calculating prices, fetch the token's current state and curve parameters:
```javascript theme={null}
// 1. Current reserves
const info = await factory.getTokenInfo(tokenAddress);
const { tokenReserves, kasReserves } = info;
// 2. Virtual parameters
const params = await factory.getTokenParamVersion(tokenAddress);
const { virtualToken, virtualKas, graduationThreshold } = params;
```
## Price Calculation Functions
The BondingCurve contract provides three pure calculation functions:
### Calculate Buy Return
How many tokens will I get for a given KAS amount?
```solidity theme={null}
function calculateBuyReturnWithParams(
uint256 kasIn,
uint256 tokenReserves,
uint256 kasReserves,
uint256 vToken,
uint256 vKas
) pure returns (uint256 tokensOut)
```
```javascript theme={null}
const kasIn = ethers.parseEther("100"); // 100 KAS
const tokensOut = await bondingCurve.calculateBuyReturnWithParams(
kasIn,
info.tokenReserves,
info.kasReserves,
params.virtualToken,
params.virtualKas
);
console.log("Tokens out:", ethers.formatEther(tokensOut));
```
### Calculate Sell Return
How much KAS will I get for selling a given amount of tokens?
```solidity theme={null}
function calculateSellReturnWithParams(
uint256 tokensIn,
uint256 tokenReserves,
uint256 kasReserves,
uint256 vToken,
uint256 vKas
) pure returns (uint256 kasOut)
```
```javascript theme={null}
const tokensIn = ethers.parseEther("1000000"); // 1M tokens
const kasOut = await bondingCurve.calculateSellReturnWithParams(
tokensIn,
info.tokenReserves,
info.kasReserves,
params.virtualToken,
params.virtualKas
);
console.log("KAS out:", ethers.formatEther(kasOut));
```
### Calculate Buy Cost
How much KAS do I need to spend to get a specific amount of tokens?
```solidity theme={null}
function calculateBuyCostWithParams(
uint256 tokensOut,
uint256 tokenReserves,
uint256 kasReserves,
uint256 vToken,
uint256 vKas
) pure returns (uint256 kasIn)
```
```javascript theme={null}
const desiredTokens = ethers.parseEther("1000000"); // I want 1M tokens
const kasNeeded = await bondingCurve.calculateBuyCostWithParams(
desiredTokens,
info.tokenReserves,
info.kasReserves,
params.virtualToken,
params.virtualKas
);
console.log("KAS needed:", ethers.formatEther(kasNeeded));
```
## Current Price
Get the current token price (KAS per token):
```javascript theme={null}
// Via MemeFactory (convenience)
const price = await factory.getCurrentPrice(tokenAddress);
// Via BondingCurve (from reserves)
const price = await bondingCurve.getCurrentPrice(
info.tokenReserves,
info.kasReserves
);
console.log("Price:", ethers.formatEther(price), "KAS per token");
```
## Price Impact
For large trades, the price impact can be significant. Calculate it by comparing the effective price with the current price:
```javascript theme={null}
const kasIn = ethers.parseEther("1000"); // 1000 KAS
const tokensOut = await bondingCurve.calculateBuyReturnWithParams(
kasIn, tokenReserves, kasReserves, vToken, vKas
);
const effectivePrice = kasIn * BigInt(1e18) / tokensOut; // KAS per token
const currentPrice = await factory.getCurrentPrice(tokenAddress);
const priceImpact = Number(effectivePrice - currentPrice) / Number(currentPrice) * 100;
console.log(`Price impact: ${priceImpact.toFixed(2)}%`);
```
When `kasIn` is very small relative to `kasReserves`, the price impact approaches zero and the effective price approaches the spot price.
## Graduation Threshold
Each token has a `graduationThreshold` in its curve parameters. When `kasReserves >= graduationThreshold`, the token graduates:
```javascript theme={null}
const params = await factory.getTokenParamVersion(tokenAddress);
const info = await factory.getTokenInfo(tokenAddress);
const remaining = params.graduationThreshold - info.kasReserves;
console.log("KAS until graduation:", ethers.formatEther(remaining));
```
# Token Lifecycle
Source: https://docs.kas.fun/contracts/token-lifecycle
The stages of a KasFun token from creation to DEX
## Overview
Every KasFun token goes through the following stages:
```mermaid theme={null}
graph LR
A["Created
Token deployed"] --> B["Trading
Bonding Curve
buy & sell"]
B --> C["Fulfilled
Waiting for
DEX migration"]
C --> D["Launched
DEX Trading"]
D --> E["CTO
Community
Governance"]
```
## Stages
### 1. Created
A token is deployed via `MemeFactory.createToken()`. At this point:
* Token ERC-20 contract is deployed
* 80% of supply is deposited into the bonding curve pool
* The token is immediately tradeable
```javascript theme={null}
const info = await factory.getTokenInfo(tokenAddress);
// info.fulfilled === false
// info.graduated === false
```
### 2. Trading (Bonding Curve)
Users buy and sell through `MemeFactory.buy()` and `MemeFactory.sell()`. The price follows a constant-product curve.
You can monitor progress:
```javascript theme={null}
// Returns 0-10000 (representing 0-100%)
const progress = await factory.getBondingCurveProgress(tokenAddress);
console.log(`${Number(progress) / 100}% funded`);
```
### 3. Fulfilled
When `kasReserves` reaches the `graduationThreshold`, the token becomes fulfilled:
```javascript theme={null}
const info = await factory.getTokenInfo(tokenAddress);
// info.fulfilled === true
// info.graduated === false
```
Once fulfilled, **buy and sell on the bonding curve are disabled**. The token is waiting for liquidity migration.
### 4. Launched (Graduated)
Liquidity is migrated to Krokoswap DEX. The token is now tradeable on the open market.
```javascript theme={null}
const info = await factory.getTokenInfo(tokenAddress);
// info.fulfilled === true
// info.graduated === true
```
After graduation, **Community Governance (CTO)** becomes available — token holders can elect a Council and vote on proposals.
## Checking Token Status
```javascript theme={null}
const info = await factory.getTokenInfo(tokenAddress);
if (info.graduated) {
console.log("Token has graduated - trade on DEX");
} else if (info.fulfilled) {
console.log("Token is fulfilled - waiting for DEX migration");
} else {
console.log("Token is trading on bonding curve");
}
```
## Events
Listen for lifecycle events emitted by MemeFactory:
| Event | When |
| ------------------------------------------------------ | -------------------- |
| `Created(token, creator, tokenId, pool, name, symbol)` | Token is created |
| `Buy(token, buyer, kasAmount, tokenAmount, fee)` | Someone buys tokens |
| `Sell(token, seller, tokenAmount, kasAmount, fee)` | Someone sells tokens |
# Election
Source: https://docs.kas.fun/governance/election
How council elections work on-chain
## Overview
Council elections allow token holders to vote for candidates. The top candidates (by vote amount) become council members. Voting requires **locking tokens** in the Council contract.
## Election Flow
An election is initiated (requires EIP-712 signature from the platform). The election has a fixed duration.
Token holders approve their tokens to the Council contract, then call `voteElection()` to vote for candidates. Tokens are locked until the election ends.
After `endTime`, anyone can call `claimElectionTokens()`. The first caller triggers finalization — top candidates become council members.
All voters call `claimElectionTokens()` to retrieve their locked tokens.
## Reading Election State
```javascript theme={null}
const council = new ethers.Contract(councilAddress, CouncilV1ABI, provider);
const state = await council.getElectionState(tokenAddress);
console.log("Active:", state.active);
console.log("End time:", new Date(Number(state.endTime) * 1000));
console.log("Finalized:", state.finalized);
console.log("Council size:", state.councilSize.toString());
console.log("Epoch:", state.epoch.toString());
```
### Election State Fields
| Field | Type | Description |
| ----------------- | ------- | ------------------------------------------------------- |
| `active` | bool | Whether an election is currently running |
| `endTime` | uint256 | Election end timestamp (unix seconds) |
| `lastElectionEnd` | uint256 | When the last election ended |
| `finalized` | bool | Whether the current/last election results are finalized |
| `councilSize` | uint256 | Number of council seats |
| `epoch` | uint256 | Election epoch counter |
## Voting in an Election
Before voting, you must **approve** the Council contract to transfer your tokens.
```javascript theme={null}
const tokenContract = new ethers.Contract(tokenAddress, [
"function approve(address spender, uint256 amount) returns (bool)",
], signer);
const council = new ethers.Contract(councilAddress, CouncilV1ABI, signer);
// 1. Approve tokens
const amount = ethers.parseEther("10000");
await (await tokenContract.approve(councilAddress, amount)).wait();
// 2. Vote for candidates
// You can split your tokens across multiple candidates
const votes = [
{ candidate: "0xCandidate1...", amount: ethers.parseEther("6000") },
{ candidate: "0xCandidate2...", amount: ethers.parseEther("4000") },
];
const tx = await council.voteElection(tokenAddress, votes);
await tx.wait();
```
## Checking Candidates
```javascript theme={null}
// Get top 20 candidates sorted by votes (descending)
const [candidates, voteAmounts] = await council.getTop20Candidates(tokenAddress);
for (let i = 0; i < candidates.length; i++) {
if (candidates[i] === ethers.ZeroAddress) break;
console.log(`${candidates[i]}: ${ethers.formatEther(voteAmounts[i])} votes`);
}
// Check a specific candidate's votes
const votes = await council.getCandidateVotes(tokenAddress, candidateAddress);
```
## Claiming Tokens After Election
After the election ends (`block.timestamp > endTime`):
```javascript theme={null}
// First caller triggers finalization + claims
// Subsequent callers just claim their tokens
const tx = await council.claimElectionTokens(tokenAddress);
await tx.wait();
```
## Reading Council Members
```javascript theme={null}
// After election is finalized
const members = await council.getCouncilMembers(tokenAddress);
console.log("Council members:", members);
// Check if an address is a council member
const isMember = await council.isCouncilMember(tokenAddress, someAddress);
```
## Events
| Event | Description |
| --------------------------------------------------------------- | -------------------------- |
| `ElectionStarted(token, endTime, councilSize)` | Election begins |
| `ElectionVoted(token, voter, totalLocked, candidates, amounts)` | A vote is cast |
| `ElectionFinalized(token, councilMembers)` | Election results finalized |
| `ElectionTokensClaimed(token, voter, amount)` | Voter claims locked tokens |
# Governance Overview
Source: https://docs.kas.fun/governance/overview
Community Take Over (CTO) — decentralized governance for graduated tokens
## What is CTO?
**Community Take Over (CTO)** is KasFun's on-chain governance system. After a token graduates from the bonding curve, its holders can:
1. **Elect a Council** — vote for council members who represent the community
2. **Create Proposals** — council members submit proposals for community decisions
3. **Vote on Proposals** — all token holders vote by locking their tokens
4. **Configure Token Tax** — set transaction tax parameters through proposals
## CTO Trigger Conditions
When market cap exceeds **\$800K** and holders exceed **2,000**, the community council will be activated.
## CTO Lifecycle
```mermaid theme={null}
graph TD
G["Token Graduates"] --> I["INITIALIZED
CTO created"]
I --> E["ELECTION
Voting in progress"]
E -->|"Success"| EN["ENABLED
Governance active"]
E -->|"No votes"| R["RESTART"]
R --> E
EN -->|"New election"| RE["RE-ELECTION"]
RE --> E
```
## Council Contract
Each graduated token has its own **Council V1** contract. The Council contract manages:
* **Elections** — periodic voting to select council members
* **Governance Rounds** — time-boxed proposal + voting phases
* **Proposals** — general proposals and tax configuration proposals
* **Token Locking** — voters lock tokens during elections/voting, claim them back after
The Council contract address is unique per token. You can find it on the token's community page at [kas.fun](https://kas.fun).
## Key Concepts
### Token Locking
When you vote in an election or on a proposal, your tokens are **locked** in the Council contract. You can claim them back after the election/proposal ends.
### Governance Phases
Each governance round has two phases:
| Phase | Who | What |
| ------------------ | ----------------- | ----------------- |
| **Proposal Phase** | Council members | Submit proposals |
| **Voting Phase** | All token holders | Vote on proposals |
### Proposal Types
| Type | Description |
| ----------- | ------------------------------------------------- |
| **General** | Community decisions — title, description, options |
| **Tax** | Set token transaction tax — rate, purpose, target |
## Interacting with CTO
How to vote in council elections
How to vote on proposals
The easiest way to participate in governance is through the [kas.fun](https://kas.fun) website. The contract interactions described in this documentation are for developers building integrations.
# Proposals & Voting
Source: https://docs.kas.fun/governance/proposals
How to vote on community proposals
## Overview
After a council is elected, council members can create proposals. All token holders can vote on proposals by locking their tokens. After the voting period ends, results are finalized and winning options are determined.
## Governance Rounds
Governance operates in rounds with two phases:
```mermaid theme={null}
graph LR
A["Proposal Phase
Council creates proposals"] --> B["Voting Phase
Token holders vote"]
B --> C["Finalized
Results determined"]
```
### Reading Governance State
```javascript theme={null}
const council = new ethers.Contract(councilAddress, CouncilV1ABI, provider);
const state = await council.getCouncilState(tokenAddress);
console.log("Phase:", state.governancePhase); // 0=Idle, 1=Proposal, 2=Voting
console.log("Proposal phase ends:", new Date(Number(state.proposalPhaseEnd) * 1000));
console.log("Voting phase ends:", new Date(Number(state.votingPhaseEnd) * 1000));
console.log("Current proposal ID:", state.currentProposalId.toString());
console.log("Treasury:", ethers.formatEther(state.treasuryBalance));
```
## Voting on a Proposal
Before voting, you must **approve** the Council contract to transfer your tokens.
```javascript theme={null}
const tokenContract = new ethers.Contract(tokenAddress, [
"function approve(address spender, uint256 amount) returns (bool)",
], signer);
const council = new ethers.Contract(councilAddress, CouncilV1ABI, signer);
// 1. Approve tokens
const amount = ethers.parseEther("10000");
await (await tokenContract.approve(councilAddress, amount)).wait();
// 2. Vote on proposal
// target: address(0) for general proposals
// optionIndex: index of the option you're voting for
// amount: tokens to allocate to this option
const votes = [
{
target: ethers.ZeroAddress,
optionIndex: 0, // first option
amount: ethers.parseEther("10000"),
},
];
const proposalId = 1; // on-chain proposal ID
const tx = await council.voteProposal(tokenAddress, proposalId, votes);
await tx.wait();
```
You can split your tokens across multiple options in a single vote transaction.
## Reading Proposal Details
```javascript theme={null}
// Get proposal info
const proposal = await council.getProposal(tokenAddress, proposalId);
console.log("Start:", new Date(Number(proposal.startTime) * 1000));
console.log("End:", new Date(Number(proposal.endTime) * 1000));
console.log("Finalized:", proposal.finalized);
console.log("Type:", proposal.proposalType); // 0=General, 1=Tax
console.log("Options:", proposal.optionCodes);
console.log("Winning option:", proposal.winningOption.toString());
// Get vote counts per option
const optionVotes = await council.getProposalOptionVotes(tokenAddress, proposalId);
optionVotes.forEach((votes, i) => {
console.log(`Option ${i}: ${ethers.formatEther(votes)} votes`);
});
// Get your own votes
const myVotes = await council.getVoterOptionVotes(tokenAddress, proposalId, myAddress);
// Check locked amount (claimable after proposal ends)
const locked = await council.getVoterLockedAmount(tokenAddress, proposalId, myAddress);
```
## Claiming Tokens After Voting
After the voting period ends:
```javascript theme={null}
// First caller triggers finalization + claims
// Subsequent callers just claim their tokens
const tx = await council.claimProposalTokens(tokenAddress, proposalId);
await tx.wait();
```
## Tax Configuration
Tax proposals set the token's transaction tax. After a tax proposal is finalized and the winning option is applied:
```javascript theme={null}
const taxConfig = await council.getTaxConfig(tokenAddress);
console.log("Rate:", taxConfig.rate.toString()); // in basis points
console.log("Purpose:", taxConfig.purpose); // 0=None, 1=Burn, 2=Transfer, 3=Treasury
console.log("Target:", taxConfig.target);
// Check if an address is tax exempt
const exempt = await council.isTaxExempt(tokenAddress, someAddress);
```
| Purpose | Value | Description |
| --------------- | ----- | ----------------------------------- |
| None | 0 | No tax |
| Burn | 1 | Tax tokens are burned |
| Transfer | 2 | Tax tokens sent to target address |
| CouncilTreasury | 3 | Tax tokens sent to council treasury |
## Events
| Event | Description |
| ----------------------------------------------------------------------------------------- | ------------------ |
| `ProposalCreated(token, proposalId, nonce, proposer, proposalType, optionCodes, endTime)` | Proposal created |
| `ProposalFinalized(token, proposalId, winningOption, winningVotes)` | Proposal finalized |
# Introduction
Source: https://docs.kas.fun/introduction
KasFun - Token launchpad on Kasplex with Bonding Curve trading
## What is KasFun?
KasFun is a token launchpad built on the **Kasplex** EVM chain. Anyone can create a token and trade it through a **Bonding Curve** mechanism. Once a token reaches its fundraising goal, liquidity is automatically migrated to [Krokoswap](https://krokoswap.io/) DEX.
## How It Works
Anyone can launch a new token via the MemeFactory contract. Each token starts with an internal Bonding Curve market.
Users buy and sell the token using KAS. The price follows a constant-product curve — early buyers get lower prices.
When the KAS reserves in the pool reach the graduation threshold, the token "graduates". Trading on the internal market stops.
Liquidity is automatically migrated to Krokoswap DEX for open market trading.
## Core Concepts
A constant-product formula (`x * y = k`) determines the token price. As more KAS flows in, the price rises.
Each token has a fundraising target. Once reached, the bonding curve is complete and liquidity moves to DEX.
After graduation, token holders can elect a Council, create proposals, and vote on community decisions.
Token creation, trading, elections, and voting are all executed through smart contracts on Kasplex.
## Contract Architecture
KasFun uses three core contracts:
| Contract | Purpose |
| ---------------- | ---------------------------------------------------- |
| **MemeFactory** | Token creation, buy/sell trading, token info queries |
| **BondingCurve** | Price calculation (pure math functions) |
| **Council V1** | Community governance — elections, proposals, voting |
All amounts in the contracts use **18 decimals** (wei). `1 KAS = 1e18 wei`.
# Quick Start
Source: https://docs.kas.fun/quickstart
Connect to Kasplex and interact with KasFun contracts
Before you start, make sure you have the network and contract addresses configured. See [Addresses](/contracts/addresses) for details.
## Quick Example: Read Token Info
```javascript ethers.js theme={null}
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://evmrpc.kasplex.org");
const FACTORY = "0x..."; // MemeFactory Contract Address
const FACTORY_ABI = [
"function getTokenInfo(address token) view returns (tuple(uint256 tokenId, address creator, address pool, uint256 tokenReserves, uint256 kasReserves, uint256 createdAt, bool fulfilled, bool graduated, string metadataUri, uint256 paramVersion))",
"function getCurrentPrice(address token) view returns (uint256)",
"function getBondingCurveProgress(address token) view returns (uint256)",
];
const factory = new ethers.Contract(FACTORY, FACTORY_ABI, provider);
const TOKEN = "0x..."; // token address
const info = await factory.getTokenInfo(TOKEN);
const price = await factory.getCurrentPrice(TOKEN);
const progress = await factory.getBondingCurveProgress(TOKEN);
console.log("Token ID:", info.tokenId.toString());
console.log("Reserves:", ethers.formatEther(info.kasReserves), "KAS");
console.log("Price:", ethers.formatEther(price), "KAS");
console.log("Progress:", Number(progress) / 100, "%");
console.log("Graduated:", info.graduated);
```
```python web3.py theme={null}
from web3 import Web3
w3 = Web3(Web3.HTTPProvider("https://evmrpc.kasplex.org"))
FACTORY = "0x..." # MemeFactory Contract Address
# Use full ABI from the Contract Reference section
factory = w3.eth.contract(address=FACTORY, abi=FACTORY_ABI)
TOKEN = "0x..." # token address
info = factory.functions.getTokenInfo(TOKEN).call()
price = factory.functions.getCurrentPrice(TOKEN).call()
progress = factory.functions.getBondingCurveProgress(TOKEN).call()
print(f"Reserves: {w3.from_wei(info[4], 'ether')} KAS")
print(f"Price: {w3.from_wei(price, 'ether')} KAS")
print(f"Progress: {progress / 100}%")
print(f"Graduated: {info[7]}")
```
## Quick Example: Buy a Token
```javascript ethers.js theme={null}
import { ethers } from "ethers";
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const FACTORY = "0x..."; // MemeFactory Contract Address
const FACTORY_ABI = [
"function buy(address token, uint256 minTokensOut) payable",
];
const factory = new ethers.Contract(FACTORY, FACTORY_ABI, signer);
const TOKEN = "0x...";
const kasAmount = ethers.parseEther("100"); // 100 KAS
const minTokensOut = 0n; // set proper slippage in production!
const tx = await factory.buy(TOKEN, minTokensOut, { value: kasAmount });
await tx.wait();
console.log("Buy tx:", tx.hash);
```
Always set a proper `minTokensOut` for slippage protection. Using `0` means no slippage protection and is only safe for testing.
## Next Steps
Understand the contract architecture
Learn how to trade tokens with slippage protection
Understand the bonding curve math
Full contract ABI reference
# BondingCurve
Source: https://docs.kas.fun/reference/bonding-curve
BondingCurve contract ABI reference
## Contract Info
| Property | Value |
| ----------- | ------------------------------------------------------------------------------------------------------ |
| **Address** | Read from `MemeFactory.bondingCurve()` (see [Addresses](/contracts/addresses) for MemeFactory address) |
| **Network** | Kasplex (see [Addresses](/contracts/addresses) for chain details) |
All calculation functions are `pure` — they don't read or modify state. You can call them off-chain for gas-free price quotes.
## Functions
### calculateBuyReturnWithParams
Calculate how many tokens you get for a given KAS amount.
```solidity theme={null}
function calculateBuyReturnWithParams(
uint256 kasIn,
uint256 tokenReserves,
uint256 kasReserves,
uint256 vToken,
uint256 vKas
) external pure returns (uint256 tokensOut)
```
| Parameter | Type | Description |
| --------------- | ------- | -------------------------------------------- |
| `kasIn` | uint256 | KAS amount to spend (wei) |
| `tokenReserves` | uint256 | Current token reserves from `getTokenInfo()` |
| `kasReserves` | uint256 | Current KAS reserves from `getTokenInfo()` |
| `vToken` | uint256 | Virtual token from `getTokenParamVersion()` |
| `vKas` | uint256 | Virtual KAS from `getTokenParamVersion()` |
***
### calculateSellReturnWithParams
Calculate how much KAS you get for selling tokens.
```solidity theme={null}
function calculateSellReturnWithParams(
uint256 tokensIn,
uint256 tokenReserves,
uint256 kasReserves,
uint256 vToken,
uint256 vKas
) external pure returns (uint256 kasOut)
```
| Parameter | Type | Description |
| --------------- | ------- | -------------------------------------------- |
| `tokensIn` | uint256 | Token amount to sell (wei) |
| `tokenReserves` | uint256 | Current token reserves from `getTokenInfo()` |
| `kasReserves` | uint256 | Current KAS reserves from `getTokenInfo()` |
| `vToken` | uint256 | Virtual token from `getTokenParamVersion()` |
| `vKas` | uint256 | Virtual KAS from `getTokenParamVersion()` |
***
### calculateBuyCostWithParams
Calculate how much KAS you need to get a desired amount of tokens.
```solidity theme={null}
function calculateBuyCostWithParams(
uint256 tokensOut,
uint256 tokenReserves,
uint256 kasReserves,
uint256 vToken,
uint256 vKas
) external pure returns (uint256 kasIn)
```
| Parameter | Type | Description |
| --------------- | ------- | -------------------------------------------- |
| `tokensOut` | uint256 | Desired token amount (wei) |
| `tokenReserves` | uint256 | Current token reserves from `getTokenInfo()` |
| `kasReserves` | uint256 | Current KAS reserves from `getTokenInfo()` |
| `vToken` | uint256 | Virtual token from `getTokenParamVersion()` |
| `vKas` | uint256 | Virtual KAS from `getTokenParamVersion()` |
***
### getCurrentPrice
Get the current spot price.
```solidity theme={null}
function getCurrentPrice(
uint256 tokenReserves,
uint256 kasReserves
) external view returns (uint256 price)
```
***
### virtualToken / virtualKas
```solidity theme={null}
function virtualToken() external view returns (uint256)
function virtualKas() external view returns (uint256)
```
Default virtual reserves configured in the BondingCurve contract. Note: individual tokens may use different values via `getTokenParamVersion()`.
***
### curveType
```solidity theme={null}
function curveType() external view returns (uint256)
```
Returns the curve type identifier.
***
## Full ABI (JSON)
```json theme={null}
[
{
"inputs": [{"internalType": "uint256", "name": "kasIn", "type": "uint256"}, {"internalType": "uint256", "name": "tokenReserves", "type": "uint256"}, {"internalType": "uint256", "name": "kasReserves", "type": "uint256"}, {"internalType": "uint256", "name": "vToken", "type": "uint256"}, {"internalType": "uint256", "name": "vKas", "type": "uint256"}],
"name": "calculateBuyReturnWithParams",
"outputs": [{"internalType": "uint256", "name": "tokensOut", "type": "uint256"}],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [{"internalType": "uint256", "name": "tokensOut", "type": "uint256"}, {"internalType": "uint256", "name": "tokenReserves", "type": "uint256"}, {"internalType": "uint256", "name": "kasReserves", "type": "uint256"}, {"internalType": "uint256", "name": "vToken", "type": "uint256"}, {"internalType": "uint256", "name": "vKas", "type": "uint256"}],
"name": "calculateBuyCostWithParams",
"outputs": [{"internalType": "uint256", "name": "kasIn", "type": "uint256"}],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [{"internalType": "uint256", "name": "tokensIn", "type": "uint256"}, {"internalType": "uint256", "name": "tokenReserves", "type": "uint256"}, {"internalType": "uint256", "name": "kasReserves", "type": "uint256"}, {"internalType": "uint256", "name": "vToken", "type": "uint256"}, {"internalType": "uint256", "name": "vKas", "type": "uint256"}],
"name": "calculateSellReturnWithParams",
"outputs": [{"internalType": "uint256", "name": "kasOut", "type": "uint256"}],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [{"internalType": "uint256", "name": "tokenReserves", "type": "uint256"}, {"internalType": "uint256", "name": "kasReserves", "type": "uint256"}],
"name": "getCurrentPrice",
"outputs": [{"internalType": "uint256", "name": "price", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "virtualToken",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "virtualKas",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "curveType",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
}
]
```
# Council V1
Source: https://docs.kas.fun/reference/council-v1
Council V1 contract ABI reference — elections, proposals, voting
## Contract Info
| Property | Value |
| ----------- | ---------------------------------------------------------------------- |
| **Address** | Per-token (check token's community page on [kas.fun](https://kas.fun)) |
| **Network** | Kasplex (see [Addresses](/contracts/addresses) for chain details) |
Each graduated token has its own Council contract address. The address is not global — query it from the token's community page.
## Election Functions
### startElection
Start a council election. Requires platform EIP-712 signature.
```solidity theme={null}
function startElection(address token, bytes signature) external
```
***
### voteElection
Vote for candidates. Tokens are locked until the election ends.
```solidity theme={null}
function voteElection(address token, ElectionVoteEntry[] votes) external
```
**ElectionVoteEntry:**
| Field | Type | Description |
| ----------- | ------- | ------------------------------ |
| `candidate` | address | Candidate address |
| `amount` | uint256 | Token amount to allocate (wei) |
***
### claimElectionTokens
Claim locked tokens after election ends. First caller triggers finalization.
```solidity theme={null}
function claimElectionTokens(address token) external
```
***
## Election Read Functions
### getElectionState
```solidity theme={null}
function getElectionState(address token) external view returns (ElectionState)
```
**Returns:**
| Field | Type | Description |
| ----------------- | ------- | ---------------------------- |
| `active` | bool | Election is running |
| `endTime` | uint256 | End timestamp (unix seconds) |
| `lastElectionEnd` | uint256 | Previous election end time |
| `finalized` | bool | Results have been finalized |
| `councilSize` | uint256 | Number of seats |
| `epoch` | uint256 | Election epoch counter |
***
### getCouncilMembers
```solidity theme={null}
function getCouncilMembers(address token) external view returns (address[])
```
***
### isCouncilMember
```solidity theme={null}
function isCouncilMember(address token, address account) external view returns (bool)
```
***
### getTop20Candidates
```solidity theme={null}
function getTop20Candidates(address token) external view returns (address[] candidates, uint256[] voteAmounts)
```
Returns candidates sorted by votes descending. Empty entries padded with `address(0)`.
***
### getCandidateVotes
```solidity theme={null}
function getCandidateVotes(address token, address candidate) external view returns (uint256)
```
***
## Governance Functions
### startGovernance
Start a governance round. Only callable by contract owner/manager.
```solidity theme={null}
function startGovernance(address token, uint256 proposalPhaseEnd, uint256 votingPhaseEnd) external
```
***
### createProposal
Create a proposal. Requires platform EIP-712 signature.
```solidity theme={null}
function createProposal(
address token,
bytes32 nonce,
bytes signature,
uint256[] optionCodes,
uint256 endTime,
uint8 proposalType
) external
```
| Parameter | Type | Description |
| -------------- | ---------- | -------------------- |
| `token` | address | Token address |
| `nonce` | bytes32 | Unique nonce |
| `signature` | bytes | Platform signature |
| `optionCodes` | uint256\[] | Option identifiers |
| `endTime` | uint256 | Voting end timestamp |
| `proposalType` | uint8 | 0 = General, 1 = Tax |
***
### voteProposal
Vote on a proposal by locking tokens.
```solidity theme={null}
function voteProposal(address token, uint256 proposalId, VoteEntry[] votes) external
```
**VoteEntry:**
| Field | Type | Description |
| ------------- | ------- | ---------------------------------- |
| `target` | address | `address(0)` for general proposals |
| `optionIndex` | uint8 | Option index to vote for |
| `amount` | uint256 | Token amount to allocate (wei) |
***
### finalizeProposal
Finalize a proposal after voting ends.
```solidity theme={null}
function finalizeProposal(address token, uint256 proposalId) external
```
***
### claimProposalTokens
Claim locked tokens after proposal ends. First caller triggers finalization.
```solidity theme={null}
function claimProposalTokens(address token, uint256 proposalId) external
```
***
## Governance Read Functions
### getCouncilState
```solidity theme={null}
function getCouncilState(address token) external view returns (CouncilState)
```
**Returns:**
| Field | Type | Description |
| ---------------------- | ------- | ---------------------------------- |
| `currentProposalId` | uint256 | Latest proposal ID |
| `treasuryBalance` | uint256 | Treasury balance (wei) |
| `governancePhase` | uint8 | 0 = Idle, 1 = Proposal, 2 = Voting |
| `proposalPhaseEnd` | uint256 | Proposal phase end timestamp |
| `votingPhaseEnd` | uint256 | Voting phase end timestamp |
| `roundFirstProposalId` | uint256 | First proposal ID in current round |
***
### getProposal
```solidity theme={null}
function getProposal(address token, uint256 proposalId) external view returns (Proposal)
```
**Returns:**
| Field | Type | Description |
| --------------- | ---------- | ----------------------- |
| `startTime` | uint256 | Start timestamp |
| `endTime` | uint256 | End timestamp |
| `finalized` | bool | Whether finalized |
| `executed` | bool | Whether executed |
| `proposalType` | uint8 | 0 = General, 1 = Tax |
| `nonce` | bytes32 | Unique nonce |
| `optionCount` | uint256 | Number of options |
| `winningOption` | uint256 | Winning option index |
| `optionCodes` | uint256\[] | Option code identifiers |
***
### getProposalOptionVotes
```solidity theme={null}
function getProposalOptionVotes(address token, uint256 proposalId) external view returns (uint256[])
```
Returns vote counts per option (array index = option index).
***
### getVoterOptionVotes
```solidity theme={null}
function getVoterOptionVotes(address token, uint256 proposalId, address voter) external view returns (uint256[])
```
Returns a voter's allocated tokens per option.
***
### getVoterLockedAmount
```solidity theme={null}
function getVoterLockedAmount(address token, uint256 proposalId, address voter) external view returns (uint256)
```
Returns total tokens locked by a voter in a proposal. Claimable after proposal ends.
***
## Tax Functions
### setTaxConfig
```solidity theme={null}
function setTaxConfig(address token, uint256 rate, uint8 purpose, address target) external
```
Only callable by owner/manager. Purpose: 0=None, 1=Burn, 2=Transfer, 3=CouncilTreasury.
***
### getTaxConfig
```solidity theme={null}
function getTaxConfig(address token) external view returns (TaxConfig)
```
**Returns:**
| Field | Type | Description |
| --------- | ------- | -------------------------------------- |
| `rate` | uint256 | Tax rate (basis points) |
| `purpose` | uint8 | 0=None, 1=Burn, 2=Transfer, 3=Treasury |
| `target` | address | Tax recipient address |
***
### isTaxExempt
```solidity theme={null}
function isTaxExempt(address token, address account) external view returns (bool)
```
***
## Events
### Election Events
```solidity theme={null}
event ElectionStarted(address indexed token, uint256 endTime, uint256 councilSize)
event ElectionVoted(address indexed token, address indexed voter, uint256 totalLocked, address[] candidates, uint256[] amounts)
event ElectionFinalized(address indexed token, address[] councilMembers)
event ElectionTokensClaimed(address indexed token, address indexed voter, uint256 amount)
```
### Proposal Events
```solidity theme={null}
event ProposalCreated(address indexed token, uint256 indexed proposalId, bytes32 indexed nonce, address proposer, uint8 proposalType, uint256[] optionCodes, uint256 endTime)
event ProposalFinalized(address indexed token, uint256 indexed proposalId, uint256 winningOption, uint256 winningVotes)
```
## Full ABI (JSON)
```json theme={null}
[
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "councilSize", "type": "uint256"}, {"internalType": "uint256", "name": "minInterval", "type": "uint256"}, {"internalType": "uint256", "name": "duration", "type": "uint256"}], "name": "initElectionConfig", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "bytes", "name": "signature", "type": "bytes"}], "name": "startElection", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"components": [{"internalType": "address", "name": "candidate", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "internalType": "struct ICouncil.ElectionVoteEntry[]", "name": "votes", "type": "tuple[]"}], "name": "voteElection", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "claimElectionTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalPhaseEnd", "type": "uint256"}, {"internalType": "uint256", "name": "votingPhaseEnd", "type": "uint256"}], "name": "startGovernance", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "bytes32", "name": "nonce", "type": "bytes32"}, {"internalType": "bytes", "name": "signature", "type": "bytes"}, {"internalType": "uint256[]", "name": "optionCodes", "type": "uint256[]"}, {"internalType": "uint256", "name": "endTime", "type": "uint256"}, {"internalType": "uint8", "name": "proposalType", "type": "uint8"}], "name": "createProposal", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalId", "type": "uint256"}, {"components": [{"internalType": "address", "name": "target", "type": "address"}, {"internalType": "uint8", "name": "optionIndex", "type": "uint8"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "internalType": "struct ICouncil.VoteEntry[]", "name": "votes", "type": "tuple[]"}], "name": "voteProposal", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalId", "type": "uint256"}], "name": "finalizeProposal", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalId", "type": "uint256"}], "name": "claimProposalTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "rate", "type": "uint256"}, {"internalType": "uint8", "name": "purpose", "type": "uint8"}, {"internalType": "address", "name": "target", "type": "address"}], "name": "setTaxConfig", "outputs": [], "stateMutability": "nonpayable", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "getElectionState", "outputs": [{"components": [{"internalType": "bool", "name": "active", "type": "bool"}, {"internalType": "uint256", "name": "endTime", "type": "uint256"}, {"internalType": "uint256", "name": "lastElectionEnd", "type": "uint256"}, {"internalType": "bool", "name": "finalized", "type": "bool"}, {"internalType": "uint256", "name": "councilSize", "type": "uint256"}, {"internalType": "uint256", "name": "epoch", "type": "uint256"}], "internalType": "struct ICouncil.ElectionState", "name": "", "type": "tuple"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "getCouncilMembers", "outputs": [{"internalType": "address[]", "name": "", "type": "address[]"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "address", "name": "account", "type": "address"}], "name": "isCouncilMember", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "getTop20Candidates", "outputs": [{"internalType": "address[]", "name": "candidates", "type": "address[]"}, {"internalType": "uint256[]", "name": "voteAmounts", "type": "uint256[]"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "address", "name": "candidate", "type": "address"}], "name": "getCandidateVotes", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "getCouncilState", "outputs": [{"components": [{"internalType": "uint256", "name": "currentProposalId", "type": "uint256"}, {"internalType": "uint256", "name": "treasuryBalance", "type": "uint256"}, {"internalType": "uint8", "name": "governancePhase", "type": "uint8"}, {"internalType": "uint256", "name": "proposalPhaseEnd", "type": "uint256"}, {"internalType": "uint256", "name": "votingPhaseEnd", "type": "uint256"}, {"internalType": "uint256", "name": "roundFirstProposalId", "type": "uint256"}], "internalType": "struct ICouncil.CouncilState", "name": "", "type": "tuple"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalId", "type": "uint256"}], "name": "getProposal", "outputs": [{"components": [{"internalType": "uint256", "name": "startTime", "type": "uint256"}, {"internalType": "uint256", "name": "endTime", "type": "uint256"}, {"internalType": "bool", "name": "finalized", "type": "bool"}, {"internalType": "bool", "name": "executed", "type": "bool"}, {"internalType": "uint8", "name": "proposalType", "type": "uint8"}, {"internalType": "bytes32", "name": "nonce", "type": "bytes32"}, {"internalType": "uint256", "name": "optionCount", "type": "uint256"}, {"internalType": "uint256", "name": "winningOption", "type": "uint256"}, {"internalType": "uint256[]", "name": "optionCodes", "type": "uint256[]"}], "internalType": "struct ICouncil.Proposal", "name": "", "type": "tuple"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalId", "type": "uint256"}], "name": "getProposalOptionVotes", "outputs": [{"internalType": "uint256[]", "name": "", "type": "uint256[]"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalId", "type": "uint256"}, {"internalType": "address", "name": "voter", "type": "address"}], "name": "getVoterOptionVotes", "outputs": [{"internalType": "uint256[]", "name": "", "type": "uint256[]"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "proposalId", "type": "uint256"}, {"internalType": "address", "name": "voter", "type": "address"}], "name": "getVoterLockedAmount", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}], "name": "getTaxConfig", "outputs": [{"components": [{"internalType": "uint256", "name": "rate", "type": "uint256"}, {"internalType": "uint8", "name": "purpose", "type": "uint8"}, {"internalType": "address", "name": "target", "type": "address"}], "internalType": "struct ICouncil.TaxConfig", "name": "", "type": "tuple"}], "stateMutability": "view", "type": "function"},
{"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "address", "name": "account", "type": "address"}], "name": "isTaxExempt", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", "type": "function"},
{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "endTime", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "councilSize", "type": "uint256"}], "name": "ElectionStarted", "type": "event"},
{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": false, "internalType": "address[]", "name": "councilMembers", "type": "address[]"}], "name": "ElectionFinalized", "type": "event"},
{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": true, "internalType": "address", "name": "voter", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "totalLocked", "type": "uint256"}, {"indexed": false, "internalType": "address[]", "name": "candidates", "type": "address[]"}, {"indexed": false, "internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}], "name": "ElectionVoted", "type": "event"},
{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": true, "internalType": "address", "name": "voter", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "ElectionTokensClaimed", "type": "event"},
{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": true, "internalType": "uint256", "name": "proposalId", "type": "uint256"}, {"indexed": true, "internalType": "bytes32", "name": "nonce", "type": "bytes32"}, {"indexed": false, "internalType": "address", "name": "proposer", "type": "address"}, {"indexed": false, "internalType": "uint8", "name": "proposalType", "type": "uint8"}, {"indexed": false, "internalType": "uint256[]", "name": "optionCodes", "type": "uint256[]"}, {"indexed": false, "internalType": "uint256", "name": "endTime", "type": "uint256"}], "name": "ProposalCreated", "type": "event"},
{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": true, "internalType": "uint256", "name": "proposalId", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "winningOption", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "winningVotes", "type": "uint256"}], "name": "ProposalFinalized", "type": "event"}
]
```
# MemeFactory
Source: https://docs.kas.fun/reference/meme-factory
MemeFactory contract ABI reference
## Contract Info
| Property | Value |
| ----------- | ----------------------------------------------------------------- |
| **Address** | See [Addresses](/contracts/addresses) |
| **Network** | Kasplex (see [Addresses](/contracts/addresses) for chain details) |
## Write Functions
### createToken
Create a new token. Requires a platform signature obtained through [kas.fun](https://kas.fun).
```solidity theme={null}
function createToken(CreateTokenParams params) external payable returns (uint256 tokenId, address token)
```
**CreateTokenParams:**
| Field | Type | Description |
| ------------------ | ------- | --------------------------------- |
| `name` | string | Token name |
| `symbol` | string | Token symbol |
| `metadataUri` | string | Metadata URI |
| `creatorBuyAmount` | uint256 | Optional initial buy amount (wei) |
| `salt` | bytes32 | Salt for deterministic address |
| `nonce` | uint256 | Anti-replay nonce |
| `deadline` | uint256 | Signature expiry timestamp |
| `signature` | bytes | Platform EIP-712 signature |
**Value:** `creationFee + creatorBuyAmount`
***
### buy
Buy tokens with KAS.
```solidity theme={null}
function buy(address token, uint256 minTokensOut) external payable
```
| Parameter | Type | Description |
| -------------- | ------- | ----------------------------------------------- |
| `token` | address | Token to buy |
| `minTokensOut` | uint256 | Minimum tokens to receive (slippage protection) |
**Value:** Amount of KAS to spend (wei)
***
### sell
Sell tokens for KAS. Requires prior ERC-20 approval.
```solidity theme={null}
function sell(address token, uint256 tokenAmount, uint256 minKasOut) external
```
| Parameter | Type | Description |
| ------------- | ------- | -------------------------------------------- |
| `token` | address | Token to sell |
| `tokenAmount` | uint256 | Amount of tokens to sell (wei) |
| `minKasOut` | uint256 | Minimum KAS to receive (slippage protection) |
***
## Read Functions
### getTokenInfo
```solidity theme={null}
function getTokenInfo(address token) external view returns (TokenInfo)
```
**Returns (TokenInfo):**
| Field | Type | Description |
| --------------- | ------- | ------------------------------- |
| `tokenId` | uint256 | Token ID (0 if not found) |
| `creator` | address | Token creator |
| `pool` | address | Pool address |
| `tokenReserves` | uint256 | Token reserves in pool (wei) |
| `kasReserves` | uint256 | KAS reserves in pool (wei) |
| `createdAt` | uint256 | Creation timestamp |
| `fulfilled` | bool | Bonding curve threshold reached |
| `graduated` | bool | Liquidity migrated to DEX |
| `metadataUri` | string | Metadata URI |
| `paramVersion` | uint256 | Curve parameter version |
***
### getCurrentPrice
```solidity theme={null}
function getCurrentPrice(address token) external view returns (uint256)
```
Returns the current price in KAS per token (18 decimals).
***
### getBondingCurveProgress
```solidity theme={null}
function getBondingCurveProgress(address token) external view returns (uint256)
```
Returns progress from `0` to `10000` (representing 0.00% to 100.00%).
***
### getTokenParamVersion
```solidity theme={null}
function getTokenParamVersion(address token) external view returns (ParamVersion)
```
**Returns (ParamVersion):**
| Field | Type | Description |
| --------------------- | ------- | ------------------------------------ |
| `graduationThreshold` | uint256 | KAS amount needed to graduate (wei) |
| `virtualToken` | uint256 | Virtual token reserve for curve |
| `virtualKas` | uint256 | Virtual KAS reserve for curve |
| `sqrtPriceX96Token0` | uint160 | Uniswap V3 sqrt price (token0) |
| `sqrtPriceX96Token1` | uint160 | Uniswap V3 sqrt price (token1) |
| `active` | bool | Whether this param version is active |
***
### computeTokenAddress
```solidity theme={null}
function computeTokenAddress(bytes32 salt, address creator) external view returns (address)
```
Predict the token contract address before creation.
***
### bondingCurve
```solidity theme={null}
function bondingCurve() external view returns (address)
```
Returns the BondingCurve contract address.
***
### creationFee
```solidity theme={null}
function creationFee() external view returns (uint256)
```
Returns the token creation fee in KAS (wei).
***
### authorizedSigner
```solidity theme={null}
function authorizedSigner() external view returns (address)
```
Returns the platform's authorized signer address.
***
## Events
### Created
```solidity theme={null}
event Created(
address indexed token,
address indexed creator,
uint256 indexed tokenId,
address pool,
string name,
string symbol
)
```
### Buy
```solidity theme={null}
event Buy(
address indexed token,
address indexed buyer,
uint256 kasAmount,
uint256 tokenAmount,
uint256 fee
)
```
### Sell
```solidity theme={null}
event Sell(
address indexed token,
address indexed seller,
uint256 tokenAmount,
uint256 kasAmount,
uint256 fee
)
```
## Full ABI (JSON)
```json theme={null}
[
{
"inputs": [{"components": [{"internalType": "string", "name": "name", "type": "string"}, {"internalType": "string", "name": "symbol", "type": "string"}, {"internalType": "string", "name": "metadataUri", "type": "string"}, {"internalType": "uint256", "name": "creatorBuyAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "salt", "type": "bytes32"}, {"internalType": "uint256", "name": "nonce", "type": "uint256"}, {"internalType": "uint256", "name": "deadline", "type": "uint256"}, {"internalType": "bytes", "name": "signature", "type": "bytes"}], "internalType": "struct IMemeFactory.CreateTokenParams", "name": "params", "type": "tuple"}],
"name": "createToken",
"outputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}, {"internalType": "address", "name": "token", "type": "address"}],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "minTokensOut", "type": "uint256"}],
"name": "buy",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [{"internalType": "address", "name": "token", "type": "address"}, {"internalType": "uint256", "name": "tokenAmount", "type": "uint256"}, {"internalType": "uint256", "name": "minKasOut", "type": "uint256"}],
"name": "sell",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{"internalType": "address", "name": "token", "type": "address"}],
"name": "getTokenInfo",
"outputs": [{"components": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}, {"internalType": "address", "name": "creator", "type": "address"}, {"internalType": "address", "name": "pool", "type": "address"}, {"internalType": "uint256", "name": "tokenReserves", "type": "uint256"}, {"internalType": "uint256", "name": "kasReserves", "type": "uint256"}, {"internalType": "uint256", "name": "createdAt", "type": "uint256"}, {"internalType": "bool", "name": "fulfilled", "type": "bool"}, {"internalType": "bool", "name": "graduated", "type": "bool"}, {"internalType": "string", "name": "metadataUri", "type": "string"}, {"internalType": "uint256", "name": "paramVersion", "type": "uint256"}], "internalType": "struct IMemeFactory.TokenInfo", "name": "", "type": "tuple"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{"internalType": "address", "name": "token", "type": "address"}],
"name": "getCurrentPrice",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{"internalType": "address", "name": "token", "type": "address"}],
"name": "getBondingCurveProgress",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{"internalType": "address", "name": "token", "type": "address"}],
"name": "getTokenParamVersion",
"outputs": [{"components": [{"internalType": "uint256", "name": "graduationThreshold", "type": "uint256"}, {"internalType": "uint256", "name": "virtualToken", "type": "uint256"}, {"internalType": "uint256", "name": "virtualKas", "type": "uint256"}, {"internalType": "uint160", "name": "sqrtPriceX96Token0", "type": "uint160"}, {"internalType": "uint160", "name": "sqrtPriceX96Token1", "type": "uint160"}, {"internalType": "bool", "name": "active", "type": "bool"}], "internalType": "struct IMemeFactory.ParamVersion", "name": "", "type": "tuple"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{"internalType": "bytes32", "name": "salt", "type": "bytes32"}, {"internalType": "address", "name": "creator", "type": "address"}],
"name": "computeTokenAddress",
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bondingCurve",
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "creationFee",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "authorizedSigner",
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": true, "internalType": "address", "name": "creator", "type": "address"}, {"indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256"}, {"indexed": false, "internalType": "address", "name": "pool", "type": "address"}, {"indexed": false, "internalType": "string", "name": "name", "type": "string"}, {"indexed": false, "internalType": "string", "name": "symbol", "type": "string"}],
"name": "Created",
"type": "event"
},
{
"anonymous": false,
"inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": true, "internalType": "address", "name": "buyer", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "kasAmount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "tokenAmount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "fee", "type": "uint256"}],
"name": "Buy",
"type": "event"
},
{
"anonymous": false,
"inputs": [{"indexed": true, "internalType": "address", "name": "token", "type": "address"}, {"indexed": true, "internalType": "address", "name": "seller", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "tokenAmount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "kasAmount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "fee", "type": "uint256"}],
"name": "Sell",
"type": "event"
}
]
```