Module 07: Token Creation

Create and manage tokens on the BASIS factory. You set a creator fee of up to 1% on every trade of your token (it is 0 until you set it), and you receive 20% of the base part of loan-side fees on it, for the life of the token. Launching needs no liquidity; the creation fee is the factory's feeAmount() in ETH (0 today).

Prerequisites

Next steps after creation


Why Create a Token

Creating a token makes you a revenue-generating business on the platform, not just a trader.

What you get as creator:

  • A creator fee you set, for the life of the token: 0 to 1% of every buy and sell, by any user, paid to your wallet(s) in the same transaction. It is 0 until you set it (TAXES.setCreatorFee). You also receive 20% of the base part of loan-side fees on loans that use your token as collateral. Nothing is claimed.
  • No liquidity requirement: the creator deposits nothing to launch. The creation fee is feeAmount(), 0 today.
  • What the creator cannot do: the creator cannot mint, has no pool to pull (there is no separate LP) and cannot change the hybrid multiplier (there is no setter for it).
  • Presale control: set a presale of presaleTokens whole tokens, which can be zero; with frozen it is whitelist-only.
  • Holder rewards: an opt-in feature chosen at creation (rewardsEnabled): you set a rewards fee that is paid to every holder.
  • Fee control: set the creator fee (0 to 1%) and, on a token with holder rewards, the rewards fee.
  • Stacking foundation: your token is collateral-eligible. Buy your own token → borrow the pair asset → deploy elsewhere (see Strategy 4: Creator's Edge).

If your token does $10,000 in daily volume and your creator fee is 0.50%, you earn $50 that day, paid trade by trade. Volume compounds. Fees compound. The creator role is structural.


How It Works

Factory contract → creates the token → sets you as permanent dev → token trades on the DEX immediately.

Two-phase lifecycle:

  1. Presale (optional): set by presaleTokens, a number of whole tokens (presaleTarget = presaleTokens × 1e18). It runs until that many tokens have been bought (presaleSold reaches presaleTarget). The buy that completes it emits Bonded, sets presaleComplete() to true and lifts a freeze. There is no pair-asset threshold and no cap; on a reversed token (Meme+, Yolo+, Yolo) the presale may be at most half the launch supply.

  2. Standard AMM: trading continues on the same curve. The creator fee you set keeps applying.

Pitfall: Presale and AMM buys run the same curve: there is no special presale price. Once the presale is complete it never reopens.

Frozen launch: optionally start trading locked. Only whitelisted wallets can buy (sells are never gated) during the presale; the freeze lifts when the presale completes or when you call disableFreeze(). A frozen token needs a presale (presaleTokens > 0), else frozen needs presale. Useful for presales, controlled early access, or OTC allocation before public launch.

Mains and pair assets. BASIS can run several mains. Each has its own pair asset and its own vault: SWAP.pairCount(), pairList(i) and pairs(main) → (pairAsset, staking, active), or mains[] in /contracts.json. A token is paired with one main for life (token.quoteToken()), and what you pay or receive for it is in that main's pair asset. A paused pair (active false) refuses trades.


Actions

Create Token

Method: client.factory.createTokenWithMetadata(options)

Recommended over a bare factory call. Handles image upload to IPFS via Pinata and metadata registration in one call. Token symbols must be CAPITALISED (a dapp and SDK rule; the contract does not check).

The contract calls behind it:

// 1. the exact creation fee, in ETH fee = FACTORY.feeWhitelist(me) ? 0 : FACTORY.feeAmount() // 2. create (payable, msg.value = fee exactly, else "Wrong fee") FACTORY.createTokenFor(CreateParams{ mainToken, // a main from /contracts.json mains[] symbol, name, hybridMultiplier, // 1-100 frozen, // needs presaleTokens > 0 presaleTokens, // whole tokens; 0 = no presale startLP, // 1000-100000: launch depth; 10000 = standard; not deposited capital supplyMultiplier, // leave at 1 (the app's value) rewardsEnabled, // holder rewards: fixed for life autoVest, autoVestDuration, gradualAutovest }) { value: fee } // Meme+: FACTORY.createReversedTokenFor(same struct) { value: fee } // 3. the token address is in the TokenCreated(tokenAddress, name, symbol, creator) event of the receipt

There is no short form: createTokenFor(params) and createReversedTokenFor(params) take the whole struct, mainToken, supplyMultiplier and rewardsEnabled included. Holder rewards are fixed at creation, for good.

JavaScript:

const { BasisClient } = require("basis-sdk-js");

const client = await BasisClient.create({ privateKey: "0xYourPrivateKey..." });

const result = await client.factory.createTokenWithMetadata({
  symbol: "MYTKN",
  name: "My Awesome Token",
  hybridMultiplier: 50n,
  startLP: 10000n,         // launch depth: 10000 = the standard depth
  presaleTokens: 0n,       // whole tokens; 0 = no presale
  rewardsEnabled: true,    // holder rewards: fixed for life
  description: "My awesome DeFi token on Basis",
  imageUrl: "https://example.com/my-logo.png",
  website: "https://myproject.com",
});

console.log("Token:", result.tokenAddress);
console.log("Image:", result.imageUrl);
console.log("Metadata:", result.metadata.url);

Python:

from basis_sdk import BasisClient

client = BasisClient.create(private_key="0xYourPrivateKey...")

result = client.factory.create_token_with_metadata(
    symbol="MYTKN", name="My Awesome Token",
    hybrid_multiplier=50, start_lp=10000,  # start_lp: launch depth, 10000 = standard
    presale_tokens=0,                      # whole tokens; 0 = no presale
    rewards_enabled=True,                  # holder rewards: fixed for life
    description="My awesome DeFi token on Basis",
    image_url="https://example.com/my-logo.png",
    website="https://myproject.com",
)
print("Token:", result["token_address"])

Returns: { hash, receipt, tokenAddress, imageUrl, metadata }

Parameter Reference

ParameterRequiredLimitsDescription
symbolyesCAPITALISED onlyToken ticker. "MYTKN" not "mytkn".
nameyes-Token full name
mainnoa live mainThe main the token trades against (mainToken). Default: the default main
hybridMultiplieryes1–100Token type and stability. 100 = Stable+, 50–99 = Utility+, 1–49 = Floor+. With reversed: true the same dial makes Meme+ (1–50), Yolo+ (51–99) or Yolo (100). See decision table below.
startLPyes1,000–100,000Launch depth. 10,000 is the standard depth. NOT deposit capital and not a dollar amount: creator pays nothing for it. Higher value = deeper pool = less price movement per trade.
supplyMultiplierno1 to main.MAX_SUPPLY_MULTIPLIER(), default 1Leave at 1 (the app's value)
rewardsEnablednofixed for lifeTurns holder rewards on. Off unless you pass true
reversednodefault: falsetrue creates a reversed token, Meme+, Yolo+ or Yolo (createReversedTokenFor); its presale may be at most half the launch supply
descriptionno-Platform description text
imageUrlno-Auto-resized to 512×512 WebP
website / telegram / twitterxno-Social links: see Module 03 for X/Twitter linking
frozennodefault: falseIf true, only whitelisted wallets can buy during the presale, until disableFreeze() or until the presale completes. Needs presaleTokens > 0
presaleTokensno0 or more, whole tokensPresale size (presaleTarget = presaleTokens × 1e18). 0 = no presale. It is a token count, not a pair-asset amount.
autoVestnodefault: falseEvery buyer's presale purchases go into a vesting schedule for that buyer instead of the wallet. Nothing vests after the presale completes; with no presale it does nothing
autoVestDurationno1–990 days when autoVest is trueVesting period in days
gradualAutovestno-true = linear unlock over duration. false = cliff unlock at end.

Fee: the call is payable. msg.value must equal exactly feeWhitelist(you) ? 0 : feeAmount(), in ETH (0 today); any other value reverts Wrong fee. The SDK reads it and sends it. Requires: SIWE authentication (auto-handled by BasisClient.create: see Module 16).

Understanding startLP

startLP sets the price depth: how much capital is needed to move the price. It does not affect token type or the floor mechanism. Think of it as the zoom level on the price chart.

startLPLaunch depth
1,000The shallowest (the minimum)
2,500What Up/Down pool tokens use
10,000The standard depth, and what market tokens use
100,000The deepest (the maximum)

Higher is deeper: each trade moves the price less. There is no fixed dollar table. Preview any trade with SWAP.getAmountsOut.


Manage Token (Post-Creation)

Disable Freeze

Opens a frozen token to public trading. Irreversible: once called, freeze cannot be re-enabled. The freeze also lifts by itself when the presale completes.

await client.factory.disableFreeze(tokenAddress);

Whitelist Wallets (frozen tokens)

Add wallets that can buy while the token is frozen. Each wallet gets a cap in tokens: the most it may buy during the frozen presale (18 decimals). It is not a pair-asset amount.

await client.factory.setWhitelistedWallet(
  tokenAddress,
  ["0xWallet1...", "0xWallet2..."],
  maxTokensPerWallet,  // bigint, token units (18 decimals)
  "presale round 1"    // label/tag
);

A wallet that is already whitelisted is skipped, so a cap cannot be raised in place. Call removeWhitelist, then add the wallet again with a cap above what it has already bought (the bought counter is kept).

Remove from Whitelist

await client.factory.removeWhitelist(tokenAddress, "0xWallet...");

Claim Holder Rewards

Holder rewards exist only on a token created with rewardsEnabled = true (through createTokenFor or createReversedTokenFor; never on a market token). The token's dev sets a rewards fee; it is shared among all holders in proportion to their balance, follows the tokens when they are transferred, and is paid in the pair asset of the token's main. Read getClaimableRewards(holder) on the token; take it with claimRewards(). With rewards off the read is 0.

const { hash, receipt } = await client.factory.claimRewards(tokenAddress);

Note: claimRewards() pays the caller's holder rewards only. The creator fee is never claimed: it is paid to the dev wallets on every trade. With nothing owed the call succeeds and pays nothing, so read getClaimableRewards first. Creator income so far: TAXES.tokenDevEarnings(token, wallet) and TAXES.devTotalEarnings(wallet, pairAsset) (running totals of what was already paid).


Read a Token's Fees

Every trade pays a base fee: 0.60% today, or 0.54% when the wallet has an on-chain referrer. A factory token adds its creator fee (0 to 1%, set by the token's dev; 0 until set) and, only when the token was created with holder rewards, its rewards fee (0 up to maxRewardsFee: 0.5% at multiplier 100, rising to 10% at multiplier 1, always 10% on a reversed token (Meme+, Yolo+, Yolo)). A main pays the base only. A fee-exempt wallet pays nothing. The base rate is capped at 2%: read TAXES.baseRate(), do not hardcode it.

Read methods:

// What this wallet pays on this token, in basis points (0 for a fee-exempt wallet)
const rate = await client.taxes.getTaxRate(tokenAddress, userAddress);   // TAXES.getTaxRate(token, user)

// The parts: isMain, hybridMultiplier, rewardsEnabled, dev, baseRate, creatorFee, rewardsFee,
// totalRate, maxCreatorFee, maxRewardsFee, reversed
const info = await client.taxes.getTokenTaxInfo(tokenAddress);          // TAXES.getTokenTaxInfo(token)

// The platform base rate alone
const base = await client.taxes.getBaseRate();                         // TAXES.baseRate()

getAmountsOut() is the quote before fees. Take getTaxRate(token, you) basis points off the input on a buy and off the output on a sell before setting minOut.


Creator Fee and Rewards Fee

await client.taxes.setCreatorFee(tokenAddress, 30n);   // TAXES.setCreatorFee(token, bps): 0 to 100
await client.taxes.setRewardsFee(tokenAddress, 25n);   // TAXES.setRewardsFee(token, bps): 0 to maxRewardsFee
const info = await client.taxes.getTokenTaxInfo(tokenAddress);

Rules:

  • Only the token's dev may call (only dev); the creator of a market may set the creator fee on its market token.
  • Not on a main (not on MAIN).
  • The creator fee is at most 100 bps; the rewards fee at most maxRewardsFee(hybridMultiplier, reversed) (over max).
  • The rewards fee needs a token created with holder rewards (rewards off).
  • Each fee can change once per cooldown, 4 hours today; the first setting is free (fee cooldown).
  • addDevShare(token, wallet, basisPoints) splits your creator income across up to 10 wallets; removeDevShare(token, wallet); getDevWallets(token).

Read Methods

MethodReturnsDescription
client.factory.getTokenState(addr){ frozen, presaleComplete, presaleSold, presaleTarget, reversed, rewardsEnabled, hybridMultiplier, totalSupply, tokenPrice, pairPrice, main, pairAsset }Current token state. tokenPrice is in main units (getTokenPrice()), pairPrice in the main's pair asset (getPairPrice())
client.factory.getTokensByCreator(creator)string[]Standalone tokens the wallet created through the factory. It does not list the tokens of markets you created: the market host is their creator on the factory. See Module 10 for portfolio-wide queries.
client.factory.isEcosystemToken(addr)booleanIs this a valid BASIS token?
client.factory.getFloorPrice(addr)stringFloor in the main's pair asset (calculateFloor()); calculateTokenFloor() gives it in main units
client.factory.getClaimableRewards(addr, investor)bigintClaimable holder rewards, in the pair asset (0 when rewards are off)
client.factory.getFeeAmount()bigintCreation fee in wei of ETH (feeAmount()); pair it with feeWhitelist(you)
client.taxes.getTaxRate(addr, user)numberEffective tax rate for a user in basis points
client.taxes.getTokenTaxInfo(addr)structBase rate, creator fee, rewards fee and their caps for a token

Reading the token type on-chain:

const multiplier = await client.publicClient.readContract({
  address: tokenAddress,
  abi: [{"inputs":[],"name":"hybridMultiplier","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],
  functionName: 'hybridMultiplier',
});
const reversed = await client.publicClient.readContract({
  address: tokenAddress,
  abi: [{"inputs":[],"name":"reversed","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"}],
  functionName: 'reversed',
});
// reversed true: 1-50 = Meme+, 51-99 = Yolo+, 100n = Yolo.
// reversed false: 100n = Stable+ (or a market token / Up/Down pool token: FACTORY.creatorOf(token) is a market host
// or the Up/Down contract), 50-99 = Utility+, 1-49 = Floor+.

Choosing Your Token Type

The most important decision at creation. Pick the wrong type and your mechanics work against your goals.

GoalToken TypehybridMultiplierNotes
Maximum value accrual, price only rises (in pair-asset units)Stable+100Up-only mechanics, measured in the main's pair asset. 0.60% base fee like every token; rewards fee capped at 0.5%. Best for utility/service tokens with high transaction frequency.
Price discovery + a fast-rising floorUtility+50–99 (the app offers 50–90)Real price movement but the floor rises fast. Best for community/brand tokens.
Room to run with a rising floorFloor+1–49 (the app offers 1 and 10–40)More price action; the floor still rises, slowly toward 1. 1 is the app's default.
Memecoin moves, a floor that still growsMeme+1–50, reversed: true (the app offers 10–50)Created with createReversedTokenFor. Loans value it at its floor. Rewards fee up to 10%. Presale at most half the launch supply
Bigger swings, a slow floorYolo+51–99, reversed: true (the app offers 60–90)As Meme+, with less floor growth
A plain memecoinYolo100, reversed: trueClassic memecoin pricing with a fixed supply; the floor stays at the launch price
Prediction market tokenPredict+100 (Stable+ subtype)Created via prediction market flow, not standalone factory. Earns from market volume.

Every value from 1 to 100 is valid: on a normal token 100 = Stable+, 50 to 99 = Utility+, 1 to 49 = Floor+; on a reversed token 1 to 50 = Meme+, 51 to 99 = Yolo+, 100 = Yolo.

Stable+: The Utility Token

Best when users repeatedly buy to use something, then the agent/service sells back to the pair asset. The ratchet mechanic (slippage stays in the pool, so the price does not fall in its pair asset) rewards high transaction frequency.

Use when: Services, subscriptions, API access, pay-per-use tools.
Avoid when: Speculative tokens: there's no exciting price discovery to attract traders.

Floor+: The Community Token

Best for projects where holders need confidence against dumps. The floor rises on every buy-sell cycle. Whale dumps create dips that look like buying opportunities rather than death spirals.

Use when: Communities, brand tokens, fan tokens, loyalty programs.
Key window: Near launch, the gap between spot and floor is smallest: the highest leverage ratio and the smallest possible drop to the floor. Market your launch to coincide with this window.

Meme+, Yolo+ and Yolo: Memecoins With a Floor

reversed() is true. These trade like classic memecoins, and at setting 100 nothing is minted or burned at all. The price can fall, so "price can only go up" never applies to a Meme+ token. The floor still never goes below the launch price; at 100 it stays at the launch price. A presale may be at most half the launch supply.

Predict+: The Engagement Token

Created as part of a prediction market. The token earns from all market trading volume.

Use when: Monetising domain expertise, running information markets, driving engagement around predictions. See Module 13 for full creator strategy.


Fees

ActionFee
Token creationFACTORY.feeAmount() in ETH, sent as the exact msg.value: 0 today; 0 for a fee-whitelisted wallet
Trading (ongoing)base 0.60% (0.54% with a referrer) + your creator fee (0 to 1%) + the rewards fee if the token has holder rewards

A creator earns two things: the creator fee they set on their token, on every trade and bet, and 20% of the base part of loan-side fees on their token. Both are paid as they happen; there is nothing to claim. tokenDevEarnings(token, wallet) and devTotalEarnings(wallet, pairAsset) are running totals of what was already paid.


Errors

ErrorWhenFix
"invalid multiplier"hybridMultiplier out of rangeMust be 1 to 100
"invalid starting LP"startLP out of rangeMust be 1,000–100,000
"Wrong fee"msg.value is not exactly feeWhitelist(you) ? 0 : feeAmount()Read the fee and send exactly that
"frozen needs presale"frozen with presaleTokens = 0Set a presale or drop frozen
"auto-vest duration 1-990 days"autoVest with a duration out of rangeUse 1–990 days
"invalid supply multiplier"supplyMultiplier is 0 or above main.MAX_SUPPLY_MULTIPLIER()Use 1 to that cap
"unknown pair" / MainNotRegistered()The main is not an active, registered pairPick a main from /contracts.json mains[]
"presale above half the launch supply"Presale too large on a reversed token (Meme+, Yolo+, Yolo)Lower presaleTokens
"No WL for freeze"Buying a frozen token without whitelistCreator must call setWhitelistedWallet() first
"Overcapped on WL buying"Whitelisted wallet hit its capThe cap is in tokens; the creator removes the wallet and whitelists it again with a higher cap
"only dev"setCreatorFee / setRewardsFee by someone elseCall from the token's dev wallet
"over max"Fee above 100 bps (creator) or maxRewardsFee (rewards)Lower the fee
"fee cooldown"Second change within the cooldown (4 hours today)Wait for the cooldown
"rewards off"setRewardsFee on a token created without holder rewardsNot possible: rewards are fixed at creation
"not on MAIN"A fee setter called on a mainMains pay the base fee only

For the full alphabetical error index across all modules, see Module 18: SDK Reference.


What Next

After creating a token, the typical creator flow:

  1. If frozen: Call setWhitelistedWallet() for presale participants, then disableFreeze() when ready for public trading (or let the presale complete).
  2. Set your fees: setCreatorFee (up to 1%) and, with holder rewards on, setRewardsFee. Both start at 0.
  3. Buy during your own presale if you want an early position.
  4. Monitor state with getTokenState(): watch presaleComplete.
  5. Nothing to claim for the creator fee: it is paid on every trade. Holders claim rewards with claimRewards().
  6. Stack on top: Creator's Edge strategy: buy your own Floor+/Predict+ token → borrow the pair asset → deploy across Stable+, lending, and predictions. You earn your creator fee on other users' volume on top of your stacked positions. See Module 12 for the full stacking strategies module.

See Also