Verify Stablecoin Collateral With Chainlink Proof of Reserve

The Chainlink Fall 2021 Hackathon kicks off October 22. Sign up today.

Decentralized finance (DeFi) is about economic transparency and changing the fundamental trust philosophy of how financial transactions are conducted. Through smart contracts, transparency and trustlessness have been achieved at the base protocol layer, but as exotic new financial instruments continue to emerge across the DeFi space, our ecosystem needs increasingly robust infrastructure for securing these protocols and the data feeding in and out of them. This is where Chainlink comes in, the blockchain agnostic, secure, decentralized off-chain service layer for smart contracts.

One DeFi instrument that is already benefiting from Chainlink’s high-quality data feeds are stablecoins, digital assets backed by either off-chain or cross-chain collateral. Stablecoins provide users the ability to transact in a non-volatile currency, while still offering the permissionless nature of blockchain-based smart contracts and the high yield that continues to attract new users to DeFi. With Chainlink Proof of Reserve, developers and users can now trustlessly verify that backed assets like wrapped tokens and stablecoins are fully backed by the collateral they claim to be. Proof of Reserve also provides a higher level of reliability and transparency around collateralized loans, credit default swaps, cross-chain token swaps, and more.

As with all Chainlink Data Feeds, ease of access is a priority, making it simple for developers to integrate pre-aggregated, reliable off-chain data into their dApp. In this guide, we’ll go over how to quickly leverage Chainlink Proof of Reserve to prove the collateralization of a stablecoin, specifically TrustToken’s TUSD.

Initialize the Feeds

The first step with any Chainlink data feed is importing the aggregator interface, and then initializing the feeds with the correct address in the constructor.

import "https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";

contract ProofOfReserve {

    AggregatorV3Interface internal supplyTUSD;
    AggregatorV3Interface internal reservesTUSD;

    /**
     * Aggregator: TUSD reserve and TUSD supply
     * Reserves Address: 0x478f4c42b877c697C4b19E396865D4D533EcB6ea
     * Supply Address: 0x807b029DD462D5d9B9DB45dff90D3414013B969e
     */
    constructor() public {
        supplyTUSD = AggregatorV3Interface(0x807b029DD462D5d9B9DB45dff90D3414013B969e);
        reservesTUSD = AggregatorV3Interface(0x478f4c42b877c697C4b19E396865D4D533EcB6ea);
    }

In this case, we have two feeds, one showing the current reserves backing TUSD and one providing the current supply of TUSD. We need both to be able to determine if the reserve is sufficient for the supply that has been issued.

Retrieve Values

Once the feeds are initialized, we need two functions to retrieve the values from them.

   //Returns the latest Supply info
    function getLatestSupply() public view returns (int) {
        (
            uint80 roundID, 
            int answer,
            uint startedAt,
            uint updatedAt,
            uint80 answeredInRound
        ) = supplyTUSD.latestRoundData();
        return answer;
    }
    
    //Returns the latest Reserves info
    function getLatestReserves() public view returns (int) {
        (
            uint80 roundID, 
            int answer,
            uint startedAt,
            uint updatedAt,
            uint80 answeredInRound
        ) = reservesTUSD.latestRoundData();
        return answer;
    }

Since the data is already aggregated and committed on-chain by the network of Chainlink nodes, we only need a simple view function to access the data so there is no gas cost. There are some other fields like the ID and time of the aggregation round in which the data was retrieved, but in this case, it’s only the answer we care about: the value of the supply and reserves.

Check Reserves Against Supply

Finally, once we have this data, we simply need to check that the reserve outnumbers the supply, meaning the stablecoin is fully collateralized and in a healthy state.

//Determines if supply has exceeded reserves
    function isTUSDHealthOK() public view returns (bool) {
        return getLatestReserves() >= getLatestSupply();
    }

If this function were to return false, it would mean the supply is greater than the reserves and TUSD is not adequately backed. In this case, you may wish to trigger a circuit breaker in your dApp calling this function to close any associated loans or temporarily halt trading to prevent any cascading market risk. If the function is true, TUSD is healthy, overcollateralized, and your dApp can continue operating as normal.

Conclusion

DeFi and smart contracts are built upon the principles of transparency and verifiability. This is a powerful shift in design from existing systems which are often undercollateralized and opaque. To meet DeFi’s standards around transparency and to reduce risk for both the user and the larger market, it’s critical that protocols are held to these principles end-to-end. Chainlink Proof of Reserve is the solution for maintaining end-to-end transparency for any platform utilizing backed or wrapped assets, and it’s easier than ever to leverage in your dApp today on mainnet.

If you’re a developer and want to integrate Chainlink Proof of Reserve into your smart contract applications, check out the Chainlink developer documentation or reach out to an expert.

More on This Topic