Settling by token price

The following is an example of a settlement contract which determines the outcome of an Ante based on an asset price fetched from a Chainlink oracle.

The settle function takes some data that is decoded to a Chainlink oracle address (can be found here) and a price threshold. You need to make sure the threshold value takes into account the asset decimals.

 function settle(bytes memory data) external view returns (WinningSide) {
        (address feedAddr, int priceThreshold) = abi.decode(data, (address, int));

This data value passed as a parameter when you create the Ante. This value doesn't get changed after creation and the AnteMetaPool smart contract will use it to call the settlement contract when the time comes.

// Extracted from AnteMetaPool.settle function
address settler = commitment.settler;
bytes memory settlerData = commitment.settlerData;
...
ParticipantSide winningSide = ParticipantSide(uint8(IAnteSettlement(settler).settle(settlerData)));

If the fetched price is equal to the set threshold, the Ante will be marked as having no winner. At this point both parties can withdraw their initial stake.

If the fetched price is greater than the set threshold, A side is considered the winner.

If the fetched price is less than the set threshold, B side is considered the winner.

if (price == priceThreshold) {
    return WinningSide.NONE;
} else if (price > priceThreshold) {
    return WinningSide.A;
} else {
    return WinningSide.B;
}

IMPORTANT! If you are the Ante author, you will automatically be assigned to side A. In order to stake behind a claim saying that an asset will be under a threshold, you will have to update the condition block accordingly.

link to repo

Full contract code

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.21;

/// @title The interface for a AnteSettlement smart contract
interface IAnteSettlement {
    enum WinningSide {
        NONE,
        A,
        B
    }

    /// @notice Settles the outcome of a given commitment
    /// @param data Arbitrary data used to determine the outcome
    /// @return the winning side
    function settle(bytes memory data) external returns (WinningSide);
}

// Chainlink Aggragator interface
// import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface AggregatorV3Interface {
    function latestRoundData()
        external
        view
        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

/**
 * Contract used for settling a commitment with a given Chainlink feed and
 * a given price threshold.
 * These values are set when the commitment is created.
 */
contract AnteSettlementByTokenPrice is IAnteSettlement {
    function settle(bytes memory data) external view returns (WinningSide) {
        (address feedAddr, int priceThreshold) = abi.decode(data, (address, int));

        AggregatorV3Interface dataFeed = AggregatorV3Interface(feedAddr);
        // prettier-ignore
        (
            /* uint80 roundID */,
            int price,
            /*uint startedAt*/,
            /*uint timeStamp*/,
            /*uint80 answeredInRound*/
        ) = dataFeed.latestRoundData();

        if (price == priceThreshold) {
            return WinningSide.NONE;
        } else if (price > priceThreshold) {
            return WinningSide.A;
        } else {
            return WinningSide.B;
        }
    }
}

Last updated