Bonding Curve In Developers' Perspective

How to find the reserve/price/fdv from the circulating supply of a token?

Option1: Read from the Chain

You can directly read the information about a token through the getTokenV2 call to the on chain contract.

/// @notice Get token state
/// @param token  The address of the token
/// @return state  The state of the token
function getTokenV2(address token) external view returns (TokenStateV2 memory state);


/// @dev Token version
/// Which token implementation is used
enum TokenVersion {
    TOKEN_LEGACY_MINT_NO_PERMIT,
    TOKEN_LEGACY_MINT_NO_PERMIT_DUPLICATE, // for historical reasons, both 0 and 1 are the same: TOKEN_LEGACY_MINT_NO_PERMIT
    TOKEN_V2_PERMIT,
    TOKEN_GOPLUS
}
/// @notice the status of a token
/// The token has 4 statuses:
//    - Tradable: The token can be traded(buy/sell)
//    - InDuel: (obsolete) The token is in a battle, it can only be bought but not sold.
//    - Killed: (obsolete) The token is killed, it can not be traded anymore. Can only be redeemed for another token.
//    - DEX: The token has been added to the DEX
enum TokenStatus {
    Invalid, // The token does not exist
    Tradable,
    InDuel, // obsolete
    Killed, // obsolete
    DEX
}

/// @notice the state of a token (with dex related fields)
struct TokenStateV2 {
    TokenStatus status; // the status of the token
    uint256 reserve; // the reserve of the token
    uint256 circulatingSupply; // the circulatingSupply of the token
    uint256 price; // the price of the token
    TokenVersion tokenVersion; // the version of the token implementation this token is using
    uint256 r; // the r of the curve of the token
    uint256 dexSupplyThresh; // the cirtulating supply threshold for adding the token to the DEX
}

Option 2: Calculate them from the current supply

Check Bonding Curves On Different Chains for the r of each deployment

Whenever a user buys or sells token on the bonding curve, the following event would be emitted:

/// @notice emitted when the circulating supply of a token changes
/// @param token The address of the token
/// @param newSupply The new circulating supply
event FlapTokenCirculatingSupplyChanged(address token, uint256 newSupply);

You can simply index this event to get the latest circulating supply of any token. With the circulating supply of the token, you can get the reserve, price and FDV with the following typescript snippet:

import { Decimal } from "decimal.js";

const BILLION: Decimal = new Decimal("1000000000");

export class CDPV1 {
    // the initial virtual reserve
    private r: number;

    constructor(r: number) {
        this.r = r;
    }

    totalSupply(reserve: string): Decimal {
        //  (1e9 - supply) * (reserve + r) = r * 1e9
        if (!reserve) return new Decimal(0);
        return new Decimal(BILLION).sub(
            new Decimal(this.r * 1e9).div(new Decimal(reserve).add(this.r))
        );
    }

    totalReserve(amount: string): Decimal {
        //  (1e9 - supply) * (reserve + r) = r * 1e9
        if (!amount) return new Decimal(0);
        return new Decimal(this.r * 1e9)
            .div(new Decimal(1e9).sub(new Decimal(amount)))
            .sub(this.r);
    }

    mc(reserve: string): Decimal {
        return this.fdv(this.totalSupply(reserve).toString());
    }

    price(supply: string): Decimal {
        // r * 1e9 /((1e9 - supply)^2)
        const diff = new Decimal(1e9).sub(new Decimal(supply || 0));
        return new Decimal(this.r * 1e9).div(diff.pow(2));
    }

    fdv(supply: string): Decimal {
        return this.price(supply).mul(new Decimal(1e9));
    }
}

Last updated