Build a Real Estate dApp With Chainlink Oracles

Smart contract developers can use Chainlink oracles to obtain real estate valuations directly on-chain, enabling new DeFi products and markets for the real estate industry.

Decentralized Finance (DeFi) has already shown how a wide range of cryptocurrencies, commodities, indices, stocks, and more can be represented on-chain as NFTs backed by real off-chain assets or collateralized synthetic tokens that provide exposure to underlying assets without actual ownership. Chainlink has been right at the heart of these DeFi markets, provisioning price oracles for each of these asset types. This has allowed new products and markets to be quickly launched in areas like lending/borrowing, derivatives, asset management, and more.

Chainlink is now bringing a new asset class on-chain: real estate. The real estate industry alone is vast, expected to grow from $2687.35 billion in 2020 to $3717.03 billion in 2025. Not only can real estate assets be digitized on blockchains as tokens, but hybrid smart contracts can apply logic to their usage on-chain, such as for trading against benchmarks, using as collateral for a loan, enabling prediction markets based on industry trends, or supporting passive yields through decentralized ETFs that serve as on-chain liquidity.

In the following tutorial, we showcase how developers can use Chainlink oracles today to get high-quality data on-chain regarding residential real estate valuations. This involves access to two premium data providers.

  • SmartZip — provides estimations of residential real estate values from their patented Automated Valuation Model (AVM).
  • ProspectNow — supplies data on the average price per square foot of residential real estate for the last quarter, given a specific ZIP Code.

The data from both SmartZip and ProspectNow can then be averaged to generate a multi-source valuation used to reliably price tokenized or synthetic real estate assets on-chain and enable new DeFi products and markets. To learn more about how hybrid smart contracts can disrupt the real estate industry, refer to our blog post How Blockchain Technology Is Transforming the Real Estate Industry.

Consuming SmartZip and ProspectNow Data

Contract Setup

We begin with the typical contract initialization for a contract that makes use of the Chainlink Any-API functionality. Import the ChainlinkClient contract in order to have access to the Chainlink request function and then define the contract as a ChainlinkClient along with its constructor.

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/master/evm-contracts/src/v0.6/ChainlinkClient.sol";

contract RealEstateDataConsumer is ChainlinkClient {
  
    uint256 oraclePayment;
  
    constructor(uint256 _oraclePayment) public {
        setPublicChainlinkToken();
        oraclePayment = _oraclePayment;
    }
    // Additional functions here:
  
}

SmartZip Data Request

The actual data request is performed using the Chainlink.Request struct, which is part of the ChainlinkClient contract that was imported previously. Using this request struct is straightforward, simply initialize the struct with the default buildChainlinkRequest function and then use the add method to add your desired parameters to the request. What parameter you add depends on which data you require and which API you’re using.

In the case of SmartZip’s API, the request parameter needed for retrieving valuation data is the property_id< of the property you wish to value. As such, this is the only parameter we need to add to our API request. Once added, we simply send it to the SmartZip oracle node along with the specified payment. Details for what values to use for the Job ID, oracle contract, and fee can be found on the SmartZip Real Estate AVM Oracle page.

function requestDataSmartZip
(
    address _oracle,
    bytes32 _jobId,
    string memory _propertyId
) 
    public 
    returns (bytes32 requestId)
{
    Chainlink.Request memory req = buildChainlinkRequest(_jobId, address(this), this.fulfillSmartZip.selector);
    req.add("property_id", _propertyId);
    return sendChainlinkRequestTo(_oracle, req, oraclePayment);
}

SmartZip Data Fulfillment

Once the request is sent, the SmartZip oracle node fulfilling the request will retrieve the data, format it, and return it to the callback function specified when the request was built. In this case, we’ve named that function fulfillSmartZip as specified by the this.fulfillSmartZip.selector parameter of the request building. In the case of SmartZip, the data is returned as a 256-bit unsigned integer, the value of the property. This fulfill function exists simply to accept the data. Once retrieved, the data is now on-chain and you’re free to use it as you please: record it, send it to another function to be processed, trigger another function based on the value, etc.

uint256 public smartZipData;

function fulfillSmartZip(bytes32 _requestId, uint256 _data)
    public
    recordChainlinkFulfillment(_requestId)
{
    smartZipData = _data;
}

ProspectNow Data Request

Now that we have SmartZip data in our smart contract, let’s also reach out and consume ProspectNow data so we can then use both sets of data to triangulate price information. We start off by creating another function to execute a request to the ProspectNow oracle, this time passing in a ZIP Code into the “propertyZip” parameter. This will be used to provide the average price per square foot of residential real estate for the last quarter of a specified ZIP Code. Once added, we simply send it to the ProspectNow oracle, along with the specified payment. Details for what values to use for the Job ID, oracle contract, and fee can be found on the ProspectNow Real Estate Data Oracle page in the Chainlink documentation.

function requestDataProspectNow
(
    address _oracle,
    bytes32 _jobId,
    string memory _propertyZip
) 
    public 
    returns (bytes32 requestId) onlyOwner  
{
    Chainlink.Request memory req = buildChainlinkRequest(_jobId, address(this), this.fulfillProspectNow.selector);
    req.add("propertyZip", _propertyZip);
    return sendChainlinkRequestTo(_oracle, req, oraclePayment);
}

PropertyNow Data Fulfillment

Once the request is sent, the ProspectNow oracle fulfilling the request will retrieve the data, format it, and return it to the callback function specified when the request was built. In this case, we’ve named that function fulfillProspectNow as specified by the this.fulfillProspectNow.selector parameter of the request. In the case of ProspectNow, the data is returned as an unsigned integer, the average price per square foot of residential real estate for the last quarter of the specified ZIP Code.

uint256 public prospectNowData;

function fulfillProspectNow(bytes32 _requestId, uint256 _data)
    public
    recordChainlinkFulfillment(_requestId)
{
    prospectNowData = _data;
}

Deploying and Testing the Contract

Now that we have our contract, we can deploy it to the Kovan test network and test it with some data. As both SmartZip and ProspectNow oracles have the same fee of 0.1 LINK specified in their respective pages in the Chainlink documentation, we pass in 100000000000000000 as the parameter to the constructor when we deploy the contract. Then once we’ve funded our contract with LINK, we simply execute both the requestDataSmartZip and requestDataProspectNow functions, passing in the required parameters.

Requesting data from SmartZip

Requesting data from PropectNow

Once the requests have been fulfilled, we can see the values returned by the SmartZip Oracle and the ProspectNow Oracle by executing the smartZipData and zipData functions. In the case of the ProspectNow data, the price per square foot has been multiplied by 100000000 to ensure there are no decimals in the result.

Viewing returned data from SmartZip

Viewing returned data from ProspectNow

Bringing the Data Together

Now that we have data in our smart contract from both SmartZip and ProspectNow, we can triangulate the data and come up with all sorts of useful and meaningful pieces of information that could be used as a basis for executing smart contract events and logic.

The data received from SmartZip provides a home valuation calculated by SmartZip’s Automated Valuation Model (AVM) and the data received from ProspectNow provides the average price per square foot of residential real estate for the last quarter of a specified ZIP Code. If we combine these two pieces of data for a property in a given ZIP Code, we can determine if the specified property’s valuation is above or below the average price over the past quarter, and then take some sort of action in our smart contract based on the result.

 function isPropertyOverAverage (uint _squareFootage) public view returns (bool) {
     //return true if property valuation is over the average 
     //price per sqft x given sqft
     return ((smartZipData * 10**8)  > (prospectNowData * _squareFootage));
  }
Calculating if the SmartZip Automated Valuation Model valuation is greater than the average for the given ZIP code for the given square footage
Calculating if the SmartZip Automated Valuation Model valuation is greater than the average for the given ZIP code for the given square footage

In addition to this, we can use the combined data to get a relative value, such as the average of the two prices, one being the predictive estimation and the other being the average based on square footage from ProspectNow.

  function getPropertyAverage (uint _squareFootage) public view returns (uint) {
      //return average of property value and ZIP code average x square footage
      return (((smartZipData * 10**8)  + (prospectNowData * _squareFootage)) / 2);
  }
Obtaining the average property valuation based on the two different pricing valuation models
Obtaining the average property valuation based on the two different pricing valuation models

Developers can then use these values to price real estate assets, settle prediction markets, check the collateralization of loans backed by real estate, set price benchmarks to trade against, and much more.

Additional Development Resources

In addition to the data providers above, developers can follow our External Adapter documentation to build a connection to any external API in order to fetch data or combine new datasets with the values above. https://docs.chain.link/docs/external-adapters/

Developers can reach out in our Discord with any technical questions as well as set up a call with the Chainlink Labs team to discuss more in-depth product offerings using the Chainlink Solutions Typeform.

To learn more about Chainlink, visit chain.link, subscribe to the Chainlink newsletter, and follow @chainlink on Twitter. To understand the full vision of the Chainlink Network, read the Chainlink 2.0 whitepaper.

Need Integration Support?
Talk to an expert
Faucets
Get testnet tokens
Read the Docs
Technical documentation