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.
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.
-
Confirm the prerequisites. The chain must have
<SYMBOL>_NETWORKset — 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. -
Open Admin → Ecosystem → Trading → Tokens → Create.
-
Fill in the token itself — name, currency symbol, chain, decimals.
-
Set the supply. Three fields, with rules the endpoint enforces:
initialSupplymust be greater than zero,marketCapmust be at leastinitialSupply, and neither may be negative.initialHolderis the address that receives the initial supply and is required. -
Set precision, fees and limits — see below.
-
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.
You supply the contract address, chain, network, decimals and — critically —
the contractType. Get that wrong and deposits go to the wrong kind of address:
marking a non-permit token as PERMIT means users are given their own address
for a token the platform will never be able to move out of it.
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
Both creation paths take the same three configuration blocks, and all three are editable afterwards from the token's edit screen.
Fee is an object with min and percentage. The withdrawal 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; set it to at least cover the network cost you expect to absorb,
because network gas is paid by the platform and recovered through this fee.
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.
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.
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
-
Go to Admin → Ecosystem → Trading → Markets → Create.
-
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". -
Save. The pair must be unique — a second
BTC/USDTreturns 409. The market is created active. -
Configure it from the row's edit action: precision, limits, fees and the two promotional flags.
-
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.
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
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.
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.
Related
- Blockchains — configure the chain before adding its tokens
- Master wallets — the wallet that signs deployments
- Deposit wallets — what
contractTypedecides - Admin console — every screen referenced here