Exercise 2: Automated Real Estate Lending
Day 1 Recap
To recap, so far, we've created the ERC-1155 smart contract, connected it with the Zillow's API using Chainlink Functions to create a fractionalized real estate token. In the next two exercises, we will build use cases for that fractionalized real world asset:
RWA Lending & Borrowing
Selling fractionalized RWA on an English Auction

Use-case 1) RWA Lending & Borrowing
For this use-case we are going to create the RwaLending.sol smart contract in which Alice would lock certain amount of ERC-1155 tokens that represent her real estate in order to get a loan in USDC tokens in return. She can also loan a certain percentage of the real estate, because if you remember, if we issue her 20 RealEstateToken tokens and she loans only 5 of them, that means that she loaned the 25% of the real estate token representation.
To calculate the price of the real estate we will rely on the getPriceDetails function. If you remember, yesterday we've set up Chainlink Automation to periodically update real estate price details - in US Dollars ($). Then we will calculate the real estate token valuation directly on-chain using the following formula:
Where W stands for weight.
Once Alice repays her debt in USDC she gets her ERC-1155 tokens in return. If a value of an real estate drops below liquidation threshold, anyone can liquidate this position and Alice loses all of hers ERC-1155 tokens.
Create RWALending.sol
Inside the ./use-cases folder create the RWALending.sol file.
Let's analyze important parts of the code
Let's analyze some important parts of this smart contract.
IERC1155Receiver
To be able to receive ERC-1155 tokens, this smart contract must implement the IERC1155Receiver interface. The most important check is inside the onERC1155Received and onERC1155ReceivedBatch functions from that interface. Specifically here we ensure that msg.sender is our RealEstateToken.sol smart contract.
Initial and Liquidation Thresholds
These to values are hard-coded in this example to 60% and 75% for code simplicity reasons. That means that if Alice's real estate worths 100$ she will get 60 USDC in return as a loan. If at some point the value of her real estate drops below 75$, anyone can liquidate its position and she will lose all of hers ERC-1155 tokens. She will keep USDC though.
Slippage protection
During the borrow function Alice also needs to provide minLoanAmount and maxLiquidationThreshold values for her own protection against slippage. Since loanAmount and liquidationThreshold are calculated on-chain dynamically, Alice needs to set a boundary values that she is comfortable with, otherwise the transaction will revert.
$1 is not equal to 1 USDC
In general case, $1 is not equal to 1 USDC. The value can vary between $0.99-something and $1.01-something, therefore it is extremely dangerous to hard-code US Dollar values to 1 USDC. We must use USDC/USD Chainlink Price Feed.
Working with Chainlink Data Feeds - Decimals
The USDC/USD feed has 8 decimals, while the USDC ERC-20 token itself has 6 decimals. For instance, the feed might return 99993242, which means 1 USDC = $0.99993242. Now, we need to convert those $100 to exact amount of USDC tokens we will actually sent to/from. For that we are using the getValuationInUsdc function.
Working with Chainlink Data Feeds - Price update frequency
It isn't practical to push price updates to the blockchain with every block. Therefore, there are two triggers (which can be seen in the "Trigger parameters" section on data.chain.link): Price Deviation Threshold and Heartbeat. These vary from feed to feed, and developers need to be mindful of them. Essentially, DONs constantly calculate new prices and compare them with the latest one. If the price falls below or rises above the Deviation Threshold, a new report is pushed on-chain. Additionally, if the Heartbeat is, for example, 1 hour long and no new reports have been generated, a new one will be pushed regardless. Why is this important for developers? Using stale prices for on-chain actions is risky. Therefore, developers must:
Use the
latestRoundData()function instead oflatestAnswer().Compare the
updatedAtvariable against ausdcUsdFeedHeartbeatof their choice.
As a sanity check we would also want to validate that the returned roundId is greater than zero.
Deploy RWALending.sol to Avalanche Fuji
To deploy the RWALending.sol token to Avalanche Fuji we will need to provide the following information to constructor:
realEstateTokenAddress: The address of the
RealEstateToken.solsmart contract we previously deployedusdc:
0x5425890298aed601595a70AB815c96711a31Bc65usdcUsdAggregatorAddress:
0x97FE42a7E96640D932bbc0e1580c73E705A8EB73usdcUsdFeedHeartbeat:
86400
Last updated