Core Concepts
Where the Money Goes

Where the Money Goes

Every AE that enters a community token trade ends up in one of four places: the bonding curve reserve, the community's DAO treasury, the affiliation chain, or the network as gas. This page gives the full accounting, on both sides of a trade.

The buy side

On every community-token buy:

Buyer pays AE
  ├── 99.0%  → Bonding curve reserve (redeemable by sellers)
  ├──  0.5%  → Community DAO treasury (governed by token holders)
  └──  0.5%  → Affiliation system
                ├── 0.300% → Level 1 referrer
                ├── 0.125% → Level 2 referrer
                ├── 0.050% → Level 3 referrer
                └── 0.025% → Level 4 referrer
                (if no referrer: burned)

Buyer also receives:
  └── ProtocolDAO tokens = 1,000 × AE value of the buy

The 1% total spread is the difference between the buy curve and the sell curve. It is not charged as a separate fee; it is built into the two curves. See Bonding Curves for the math.

The exact split

Write C for the curve cost of the slice you are buying: the integral of the buy curve from the current supply to the supply after your purchase:

C = integral of buy(x) dx, from supply to supply + amount
    where buy(x) = 0.001 * e^(0.00000001 * x) - 0.0009999

The contract evaluates this curve as a Maclaurin expansion of e^x in integer arithmetic (curve_type() returns "TAYLOR_EXPONENTIAL_V1"), terminating at 100 terms or when a term rounds to zero:

function exp_helper(x : int, term : int, sum : int, i : int, scale : int) : int =
  if (i > 100 || term < 1) sum
  else
    let next_term = (term * x) / (i * scale)
    exp_helper(x, next_term, sum + next_term, i + 1, scale)

The series matches the closed form to well below one aetto per token. Use the closed form to reason about the shape; use price(count) when a number has to be exact.

The sell curve is sell(x) = buy(x) * 0.995, and that 0.5% gap funds the DAO. The sale contract adds a further 0.5% affiliation fee on top of the curve price, so the total spread between buy and sell price is 1%.

price(count) is the all-in figure, fee included. It is the number you quote against:

entrypoint price(count : int) : int =
  require(count > 0, "COUNT_NOT_POSITIVE")
  let bonding_curve_price = state.bonding_curve.calculate_buy_price(state.token_contract.total_supply(), count)
  let affiliation_amount = affiliation_amount(bonding_curve_price)
  bonding_curve_price + affiliation_amount

price(n) already equals 1.005 * C; do not multiply it by 1.005 again. buy uses the same arithmetic and requires Call.value >= total_price, refunding any excess with Chain.spend(Call.caller, overpaid_refund). That is why the agent CLI can attach price * 1.03 and get the difference back.

The affiliation fee rate is read from the treasury at call time: get_affiliation_fee_percentage() returns 500 and get_affiliation_fee_precision() returns 10^5, so 500 / 100,000 = 0.5%.

The buyer's gross is 1.005 * C, and it splits exactly:

DestinationAmountShare of what the buyer pays
Bonding curve reserve0.995 * C99.005%
Community DAO treasury0.005 * C0.4975%
Affiliation chain (or burned)0.005 * C0.4975%
Total1.005 * C100%

0.995 + 0.005 + 0.005 = 1.005, with no remainder. The 99.0 / 0.5 / 0.5 figures above are this split rounded to one decimal place.

The four affiliation levels are percentages of the transaction value, not of the fee, which is why they sum to 0.5% rather than to 100%. The transaction value handed to the treasury is C, the bare curve price, so level 1 receives 0.300% of C, not of 1.005 * C.

How the split is executed

buy_with_affiliation_inner moves the money in this order:

StepCallAmount
1affiliation_treasury.record_sale_transaction(...)affiliation_amount = 0.005 * C
2Chain.spend(Call.caller, overpaid_refund)whatever you attached above 1.005 * C
3token_contract.mint(Call.caller, count)your tokens
4factory.mint_protocol_dao_token(Call.value - overpaid_refund, Call.caller)ProtocolDAO tokens
5dao_contract.record_sale_transaction(...)Call.value - overpaid_refund - affiliation_amount - reserve

The DAO's cut in step 5 is a residual, not a percentage. reserve is calculate_sell_return(total_supply_after_mint, count), which is 0.995 * C: exactly what a seller of that same slice could immediately redeem. Subtracting it and the affiliation fee from 1.005 * C leaves 0.005 * C for the DAO. The sale contract keeps precisely the sell-side obligation and forwards the rest, which is what makes the solvency guarantee structural.

Both treasury calls are made with protected = true, so a failure in the DAO or the affiliation treasury cannot block a buy.

The sell side

Selling is not the buy flow in reverse.

It is two transactions, not one. AEX-9 has no transfer-from without prior approval, so you first grant the sale contract an allowance over your tokens, then call sell:

1. create_allowance(sale_account, count)      on the community AEX-9 token
   (or change_allowance(sale_account, delta) if an allowance already exists)

2. sell(count, minimal_return_required)       on the token sale contract

minimal_return_required is your slippage floor: if the curve has moved against you between quote and execution, the call reverts rather than paying out less. The web app shows the two steps as a progress indicator; the agent CLI runs them back to back. The allowance is granted to the sale contract's address rewritten from ct_ to ak_ form.

The payout is the sell-curve integral. Quote it before you sign with the read-only sell_return(count) entrypoint on the sale contract:

return = integral of sell(x) dx, from supply - amount to supply
       = 0.995 * (integral of buy(x) dx over the same interval)

Nothing is deducted at sell time.

Destination on a sellAmount
Sellerthe full sell_return(count) payout
Community DAO treasurynothing
Affiliation chainnothing
ProtocolDAO tokens mintednone

The 0.5% gap relative to the buy curve is not a sell fee. It was taken when those tokens were bought. The reserve grows by 0.995 * C per buy, which is exactly the sell-curve integral over the same slice, so the reserve at supply S is always integral of sell(x) from 0 to S: precisely enough to redeem the entire supply. Selling the entire supply back to the curve is always possible.

Your tokens are burned. Community tokens are minted on buy and burned on sell; the token contract's Burn event on the sell receipt carries the amount destroyed.

sell does five things, in order:

  1. Reads total_supply and the current unit price.
  2. return = bonding_curve.calculate_sell_return(total_supply, count).
  3. require(return >= minimal_return_required, "MINIMAL_RETURN_NOT_MEET").
  4. token_contract.transfer_allowance(Call.caller, Contract.address, count) then token_contract.burn(count).
  5. Chain.spend(Call.caller, return), then emits PriceChange and Sell.

The minimum tradable amount is enforced one level down: calculate_price requires count >= minimum_count, where minimum_count is 10^12 aettos (10^-6 tokens).

The sale contract's trading entrypoints:

EntrypointSignatureNotes
sell_returnsell_return(count: int) -> intRead-only quote
sellsell(count: int, minimal_return_required: int) -> intStateful, not payable, returns the AE paid out
priceprice(count: int) -> intThe buy-side counterpart
buybuy(count: int) -> unitStateful, payable
buy_with_affiliationbuy_with_affiliation(count: int, affiliation_rewardee: address) -> unitStateful, payable

There is a buy_with_affiliation and no sell_with_affiliation: referral rewards accrue on buys only. Likewise the factory's mint_protocol_dao_token(int, address) is called on buys only. See the contract reference.

Event arguments

EventArgument 0Argument 1Argument 2
Buytotal_price: all-in AE, fee includedaffiliation_amounttotal_supply before the mint
Sellreturn: AE paid to the sellertotal_supply before the burnn/a
PriceChangeprevious_pricenext_pricen/a

Buy and Sell omit count; take the token amount from the decoded call arguments, not the event. Both unit prices in PriceChange come from calculate_unit_price(), which is price(10^18): the all-in cost of one whole token at that moment, affiliation fee included.

A worked example

A token at supply zero. You buy a slice worth 10 AE of curve cost, which on this curve is about 1,400,993 tokens.

LineAmount
Curve cost C10.000 AE
Affiliation fee added on top (0.5% of C)0.050 AE
You send10.050 AE (plus gas)
→ bonding curve reserve9.950 AE
→ community DAO treasury0.050 AE
→ affiliation chain0.050 AE
You receive≈ 1,400,993 tokens

If your buy is attributed to a referrer, that 0.050 AE splits down the invite chain:

LevelRate on the 10 AE transaction valueAmount
10.300%0.0300 AE
20.125%0.0125 AE
30.050%0.0050 AE
40.025%0.0025 AE
Total0.500%0.0500 AE

A level that does not exist (nobody invited your inviter) contributes nothing to anyone.

Now sell all 1,400,993 tokens straight back, before anyone else trades:

LineAmount
Curve value of the slice10.000 AE
Sell curve factor× 0.995
You receive9.950 AE (minus gas, on two transactions)

Round trip: you paid 10.050 AE and got back 9.950 AE. The 0.100 AE difference is 0.995% of what you sent: the 1% spread, all of it collected on the way in. Gas is extra, and a sell costs two transactions' worth of it.

Slippage

None of the figures above account for other people trading between your quote and your transaction. That is what slippage protection is for, and the three clients default differently:

ClientDefault toleranceMechanism
Web app, community token trade card1%Stored as tokenTrade:slippage, editable in the trade card
Web app, DEX swap5%Stored as dex:slippage
Agent CLI (superhero-token-swap.mjs)3%Buy sends price * 1.03; sell passes sell_return * 0.97 as minimal_return_required

On a buy, the tolerance is the extra AE you are willing to attach; unused AE is refunded, but treat the tolerance as a ceiling on your cost. On a sell it is a hard floor: the transaction reverts rather than executing below it. See Fees & Slippage.

Gas

Gas is a separate line item paid to the network in AE, never to Superhero, and never recoverable. Count transactions, not trades:

ActionTransactions
Post or comment1
Buy a token1
Sell a token2: allowance, then sell
Create a token1 (deploys token, curve, sale, DAO and management contracts together)
Open a DAO vote1, plus a 555 AE payment to the DAO
Create a governance poll2: deploy, then register
Claim rewards1; a small gas fee applies

Gas for every transaction follows the network's gas price at execution; æScan (opens in a new tab) shows the fee paid on each transaction.

What "burned" means

When a buyer has no inviter, the affiliation portion is burned. Mechanically, this is retention in a contract with no withdrawal path, not a transfer to an unspendable address.

The sale contract forwards the fee as Call.value on record_sale_transaction, so the AE lands in the treasury's balance. update_inviters then walks the affiliation tree upward, crediting payout_periods[period][inviter] at 300, 125, 50 and 25 parts in 100,000 for levels 1 to 4. When a level does not exist, get_direct_inviter returns None and the recursion stops:

switch(get_direct_inviter(invitee))
  None => ()
  Some(inviter) =>
    update_inviter_balance(inviter, (transaction_value * affiliation_percentage) / affiliation_fee_precision)
    update_inviters(inviter, buyer, transaction_value, remaining_affiliation_fee_percentages)

No entry is credited for a missing level. The only way AE leaves the treasury is withdraw(), which pays get_accumulated_rewards(Call.caller), the sum of that caller's own ledger entries. There is no owner, no admin entrypoint and no sweep, so uncredited AE stays in the contract balance permanently. (Creating a collection, by contrast, sends its 555 AE fee to the burn address ak_11111111111111111111111111111111273Yts.)

Two further amounts burn the same way, both consequences of withdraw():

  • Rewards older than two payout periods. get_accumulated_rewards sums only the current period and the one before it. A payout period is Chain.timestamp / 2592000000 (30 days in milliseconds), so anything credited more than roughly 30 to 60 days ago can no longer be withdrawn.
  • Rewards belonging to an inviter who has not qualified. withdraw() requires state.unique_invitees[...] == ThresholdReached, and aborts with MINIMUM_ACCOUNTS_THRESHOLD_NOT_REACHED otherwise. Reaching that state needs unique_invitee_count_threshold = 4 distinct invitees who have each bought at least unique_invitee_buy_amount_threshold = 10 AE (10 * 10^18 aettos), counted cumulatively per invitee. Rewards accrued before qualifying expire on the same 30-day clock.

ProtocolDAO tokens

Every buy also mints ProtocolDAO tokens to the buyer (a separate platform-wide AEX-9 token, not the community token you bought) at 1,000× the AE value of the buy, issued to the buyer's address at the time of purchase. Its governance functionality is not yet implemented.

The factory holds the multiplier as a single constant:

// mints protocol DAO tokens at a rate of 1000 times the buy value.
let protocol_dao_token_multiplier = 1000

stateful entrypoint mint_protocol_dao_token(buy_value : int, receiver : address) =
  require(Set.member(Call.caller, state.known_token_sales), "NOT_KNOWN_TOKEN_SALE")
  state.protocol_dao_token.mint(receiver, buy_value * protocol_dao_token_multiplier)

The sale contract passes Call.value - overpaid_refund as buy_value: the all-in amount debited, 1.005 * C, affiliation fee included. A buy whose curve cost is 10 AE costs 10.05 AE and mints 10,050 ProtocolDAO tokens. Only a sale the factory itself deployed can mint (known_token_sales). During create_community the factory mints the initial buy's ProtocolDAO tokens directly, at the same 1,000× rate.

A buy receipt carries two Mint events: one on the community token and one on the ProtocolDAO token contract.

The minted amount is 1,000× the AE debited; the Mint event on your own transaction is the record.

Related