Tokens and markets

Deploy a new token or import an existing contract, set its fees and limits, then pair two active tokens into a tradable market with your own precision and maker/taker fees.

8 min readUpdated 3 September 2026tokens, markets, erc20, spl, fees, limits, network-fee

A market is two tokens. Both must exist, both must be active, and the assets behind them must be on a chain that is configured and has a funded master wallet. So tokens come first, in every sense.

What a token record is

ecosystem_token is the platform's definition of a tradable and withdrawable asset. It carries the contract address, the chain and network it lives on, its on-chain decimals, the display precision, its contractType, and two JSON blobs: fee and limits.

A token's currency symbol is what ties everything together. A user's ECO wallet is per currency, and the address map inside it gets one entry per chain that has an active token with that symbol. So USDT on ETH, BSC and TRON is three token rows and one wallet with three addresses.

There are two ways to create one, and they are not interchangeable.

Deploying a new token

Use this when the token does not exist yet and you want to issue it. The platform deploys a real contract on-chain, signed by the master wallet.

POST/api/admin/ecosystem/tokenpermission: create.ecosystem.token
Deploys a token contract and registers it
  1. Confirm the prerequisites. The chain must have <SYMBOL>_NETWORK set — deployment rejects with "Network not found for chain" otherwise. The vault must be unlocked. The master wallet must exist and hold enough native coin; a contract deployment is expensive relative to a transfer.

  2. Open Admin → Ecosystem → Trading → Tokens → Create.

  3. Fill in the token itself — name, currency symbol, chain, decimals.

  4. Set the supply. Three fields, with rules the endpoint enforces: initialSupply must be greater than zero, marketCap must be at least initialSupply, and neither may be negative. initialHolder is the address that receives the initial supply and is required.

  5. Set precision, fees and limits — see below.

  6. Deploy. On EVM chains this uses the bundled ERC20 contract, which supports permit, so the token is recorded as contractType: PERMIT. On Solana it deploys an SPL mint and queues the initial minting as a background task; if that minting fails, the token row is removed again.

The contract name recorded on the token follows the chain: ERC20 on Ethereum and most EVM chains, BEP20 on BSC, HRC20 on HECO, CRC20 on Cronos, SPL on Solana.

Importing an existing token

Use this for an asset that already exists — USDT, USDC, any third-party contract, or a chain's native coin.

POST/api/admin/ecosystem/token/importpermission: create.ecosystem.token
Registers an already-deployed token without deploying anything

You supply the contract address, chain, network, decimals and the contractType. That flag decides which withdrawal movers the token may use, never where deposits go — every EVM token deposits to the customer's own address. PERMIT is for a token that implements EIP-2612 permit, NO_PERMIT for one that does not. Getting it wrong costs a permit attempt that cannot be signed, or a permit option that is never offered; under the default auto mover the withdrawal still goes out by EIP-7702 or just-in-time gas either way. See Deposit wallets for the movers.

For a native coin, choose NATIVE and leave the contract blank. The endpoint substitutes the null-address sentinel 0x0000000000000000000000000000000000000000, which is what the seeded natives use and what the withdrawal path expects. A second native import on the same chain returns 409 with "already has a native token registered".

Adding a custom EVM chain backfills its native coin as a token automatically, because a native currency has no contract address and cannot go through the token import form. Do not create it by hand.

Fees, limits and precision

  1. An inactive token gets no address and no monitor

Both creation paths take the same three configuration blocks, and all three are editable afterwards from the token's edit screen.

PUT/api/admin/ecosystem/token/{id}permission: edit.ecosystem.token
Updates a token's precision, limits and fee

Fee is an object with min, percentage and an optional network. The platform fee charged is max(amount × percentage ÷ 100, min), always denominated in the token's own currency; min is what stops a 0.5% fee from being worthless on a small withdrawal. Network gas is not something this fee has to cover: with the network fee charged to the customer — the default — the estimated gas of an EVM token withdrawal is a separate line in the same currency, refunded down to the actual cost after confirmation. network is the flat fallback, in token units, charged instead of that estimate when the token or the chain's native coin has no USD price; leave it unset and such a withdrawal skips the network fee with a warning in the log. The mechanism is in Deposit wallets.

Limits is an object with deposit and withdraw, each having min and max. Minimums keep dust and spam out; maximums cap your exposure per transaction.

Precision is the number of decimal places users may enter. It is checked on withdrawal — an amount with more decimals than precision is rejected with a message naming the maximum — and it falls back to the token's on-chain decimals, then to 8, if unset.

Status is the master switch. An inactive token disappears from deposit and withdrawal options, cannot be used to create a market, and stops being considered when a user's addresses are generated.

PUT/api/admin/ecosystem/token/statuspermission: edit.ecosystem.token
Enables or disables a token

The token's icon is written to an icon cache on create and import. A failure there is logged but does not fail the operation — you get a token with a missing picture, not a missing token.

GET/api/admin/ecosystem/token/{id}/holderpermission: view.ecosystem.token
Lists the on-chain holders of a token contract

The holders view reads the contract's transfer list through the same explorer failover as transaction history, so on a chain with a keyless Blockscout or Routescan instance it works with no key at all. On a chain that has neither — BSC (56 and 97), Fantom (250 and 4002), Cronos (25), HECO (128 and 256) and Polygon Amoy (80002) — it still needs <CHAIN>_EXPLORER_API_KEY or ETHERSCAN_API_KEY, and without one it throws rather than returning an empty list. "This contract has no transfers" is a real answer and returns an empty list, not an error.

Creating a market

  1. Base asset — the left half of the symbol
  2. Quote asset — fees are always charged in this currency
POST/api/admin/ecosystem/marketpermission: create.ecosystem.market
Creates a market from two active tokens
  1. Go to Admin → Ecosystem → Trading → Markets → Create.

  2. Choose the base and quote assets. Both dropdowns list only tokens with status: true. An inactive token is not offered, and passing one anyway returns 404 "Currency token not found or inactive".

  3. Save. The pair must be unique — a second BTC/USDT returns 409. The market is created active.

  4. Configure it from the row's edit action: precision, limits, fees and the two promotional flags.

  5. Check it appears at /ecosystem, and that it opens at /trade?symbol=BTC-USDT&type=spot-eco.

Market configuration

Everything except the pair itself lives in the market's metadata object.

Field What it controls
precision.amount Decimal places allowed on the base asset — BTC in BTC/USDT
precision.price Decimal places allowed on the price, in quote units
limits.amount Minimum and maximum order size in the base asset
limits.price Minimum and maximum limit price
limits.cost Minimum and maximum total order value (amount × price)
maker Percentage fee charged to the resting side of a trade
taker Percentage fee charged to the side that crosses the spread

limits.cost is the one that does the real work. It is what stops orders too small to be worth settling, and it is enforced against the total rather than either component, so a user cannot evade it by splitting price and size.

Two flags sit outside metadata. Trending promotes the market in the market list, and Hot flags it for the promotional category used by the frontend and the mobile app. Neither affects trading.

PUT/api/admin/ecosystem/market/{id}permission: edit.ecosystem.market
Updates a market's metadata and flags
PUT/api/admin/ecosystem/market/{id}/statuspermission: edit.ecosystem.market
Enables or disables a market

Disabling a market hides it from users and keeps its configuration. It does not cancel resting orders — do that first if you intend to retire a pair rather than pause it.

What trades, and what does not

  1. The row opens /trade with type=spot-eco

The matching engine handles limit and market orders. Stop-limit and stop-market orders are accepted on the same endpoint but rest outside the engine until their trigger price is crossed, at which point they are activated. Anything else is rejected with 422.

POST/api/ecosystem/order
Places an order on an ecosystem market

Orders are also gated by the platform's KYC feature policy for trading, and by a per-user rate limiter tuned for active traders rather than one-shot checkout flows.

Candles, the ticker and the order book are all built from real orders. A freshly created pair shows nothing until someone trades it. If you need quoted markets from day one, that is what the AI Market Maker addon is for — and note that it enqueues into the matching engine's in-process queue, so it must run in the same process as the engine.