CenturionDEX
Launch App

Reading Asset Balance

Last modified:

As noted in Best Practices, the AssetSink's available asset balance is observed in three places:

For example, the releasable USDC balance is USDC.balanceOf(address(assetSink)) + sum of CenturionV3Pool.protocolFees() + sum of CenturionV2Pair.burn() for each USDC-paired pool


CenturionDEX v3 Pool Protocol Fees

Reading available CenturionDEX v3 Pool protocol fees requires calling .protocolFees() on each CenturionV3Pool contract

import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {ICenturionV3Pool} from "@centurion-dex/v3-core/contracts/interfaces/pool/ICenturionV3Pool.sol";
import {IAssetSink} from "@centurion-dex/phoenix-fees/src/interfaces/IAssetSink.sol";
 
contract Example {
    IAssetSink assetSink = IAssetSink(0x0);
 
    function releaseableBalance(address token, address[] calldata pools)
        external
        view
        returns (uint256)
    {
        return IERC20(token).balanceOf(address(assetSink)) // [!code hl]
            + _getV3ProtocolFeesUnclaimed(token, pools); // [!code hl]
    }
 
    function _getV3ProtocolFeesUnclaimed(address token, address[] calldata pools)
        internal
        view
        returns (uint256 feesUnclaimed)
    {
        uint128 token0Unclaimed;
        uint128 token1Unclaimed;
        for (uint256 i; i < pools.length; i++) {
            (token0Unclaimed, token1Unclaimed) = ICenturionV3Pool(pools[i]).protocolFees(); // [!code hl]
            
            // determine if the requested `token` parameter is `pool.token0()` or `pool.token1()`
            feesUnclaimed += pool.token0() == token
                ? token0Unclaimed
                : pool.token1() == token
                ? token1Unclaimed
                : 0;
        }
    }
}

CenturionDEX v3 does not support native CTN tokens. Protocol fees in CTN are accrued as Wrapped CTN (WCTN).

Because unclaimed tokens are stored in CenturionDEX v3 Pool contracts, integrators should use offchain indexing to track which pools contain the asset of interest. For example, USDC protocol fees are accrued in many different pools:

To track which pools contain the asset of interest, we recommend to index the PoolCreated event emitted by the CenturionV3Factory contract

CenturionDEX v2 Pool Protocol Fees

CenturionDEX v2 protocol fees are automatically "pushed" to the AssetSink so no additional calls are required to make the assets releasable. However, CenturionDEX v2 protocol fees are accrued in the form of liquidity tokens (LP tokens) which are redeemable for underlying assets. Ownership of the LP token represents the proportional share of the pool's assets.

math

(LP Token Balance / LP Token Total Supply) * Pool Reserves

solidity

IERC20 lpToken;
 
uint256 amount0 = (lpToken.balanceOf(address(assetSink)) * IERC20(lpToken.token0()).balanceOf(address(lpToken))) / lpToken.totalSupply();
uint256 amount1 = (lpToken.balanceOf(address(assetSink)) * IERC20(lpToken.token1()).balanceOf(address(lpToken))) / lpToken.totalSupply();

To access the underlying assets, integrators should call ICenturionV2Pair.burn()

(uint256 amount0, uint256 amount1) = ICenturionV2Pair(pool).burn(recipient);