Fractional Auction Listing for Real Estate Investing
This is the follow-up from my previous article Using Assets and Smart Contracts in Real Estate. Here, I will describe new concepts including stateless and stateful smart contracts, atomic transfers and we will go through the implementation of the FAL (Fractional Auction Listing) Application using the Algorand Blockchain and
goal CLI. This solution is intended for learning purposes only. It does not cover error checking and other edge cases therefore, should not be used as a production application.
FAL - Fractional Auction Listing
If you already read my previous article, you know that fractional ownership or fractional investing is a way to buy partial shares, securities or units of an asset. Instead of waiting until you have the total amount necessary to buy the entire asset (a house for example) you are interested in the seller or the brokerage can split that security among other investors. Doing so, you can maximize your portfolio’s rate of return (RoR) while providing steady income. Investors in Real Estate Fractional Investing can buy, hold, and sell fractional ownership in real estate assets, similar to trading stocks or cryptocurrencies. These assets can range from apartments, houses, multifamily units to commercial real estate, hospitals, malls, and more. Moreover, Real Estate Fractional Ownership gives investors all the benefits of real estate classic investing like stable dividends from rent and capital appreciation, diversification in recessions, above-average returns without the hassle of property management.
FAL - Prerequisites
Now let’s go through the prerequisites that our FAL app will need in order to function properly.
FAL - listingID
First, the Owner needs to specify the property (asset) for the Fractional Auction Listing. For consistency we will use as
listingID, the asset ID we created in the previous tutorial. We can refer to this ASA available on the Algorand blockchain listingID=71054280.
FAL - targetPrice, startAuctionDate, endAuctionDate
The owner will need to specify information such as the target listing price and the Start and End Auction date. The
startAuctionDatedefines when the Auction for that property becomes open for investments. The
targetPriceis the price the Owner is willing to sell his asset and if the target price is reached. The owner can decide to terminate the Auction early otherwise the Auction will conclude when the
Each Fractional Auction will need an escrow account (
escrowAccount) to hold the payments collected from the investors. The escrow account will accumulate and hold the investments from when the Auction starts until the Auction end date. This account, will run a stateless smart contract and will allow any accounts to send Algos or other Assets to the escrow using the Atomic Transfers.
The FAL Application will use a stateful smart contract because we need to persist some application values (Global Storage) and some user-specific values (Local Storage) for each account participating in the contract.
FAL - Functionalities
The following Use Case diagrams explain the common scenarios for the Owner and the Investor using the FAL Application. From these diagrams you can see that Atomic refers to those operations that will involve a call to the stateful smart contract and a payment or asset transaction.
The Owner should be able to:
Create FAL: The Owner needs to set the
receiverAddressalso need to be stored. The
ownerAddressis stored only to allow that address to modify or delete the smart contract.
Update FAL: In order to link the stateful smart contract to the escrow account, the owner needs to update the stateful smart contract after its creation with the
escrowAddress. In particular, you will need to use the
applicationIDreturned from the stateful smart contract creation and modify the escrow account code to add the specific value. This will return the
escrowAddressthat needed for the Update function.
Withdraw Funds: After
endDate, if the
targetPriceis met, the
receiverAddressshould be able to receive the total funds from the
escrowAddress. This will be possible with a payment transaction from the
Delete FAL Application: After the
closeDate, the owner will need to delete the terminated FAL and all funds in the
escrowAddressshould be transfered to the
The Investors should be able to:
Optin and Invest in a FAL: Before an investor starts funding in the FAL Application, the account must first opt into the application and the investment can be accepted after the
startDateand not after the
Reclaim Investment: Investors should be able to recover their investment after the
targetPricehas not been met.
For the purpose of this solution, we will use
goal command line to create, update, send transaction and delete the Application. As an exercise, you could try to replicate the following solution using the SDK provided.
Create FAL Application
To create our first FAL Application, we will use the
goal app create command which creates a transaction to the blockchain, and it will return the applicationID that we will need to pass during the Update function to link the escrow account. Before creating our stateful smart contract, the code for the ApprovalProgram and the ClearStateProgram should be written. These two programs are responsible for the The Lifecycle of our Stateful Smart Contract. You can find and download them from this github repo . Please refer to TEAL Reference Guide and TEAL Opcodes to understand how to write TEAL and the opcodes available. There is also an example of Boilerplate for Stateful Smart Contract for you to have a look.
export DATE=`date "+%Y%m%d-%H%M%S"` # get timestamp in seconds for the startDate export FALSD=$(DATE '+%s') # we allow 30min for investors to place their bid invs=1800 invss=2500 # FAL endDate export FALED=$(( $FALSD + $invs )) # FAL closeDate export FALCD=$(( $FALED + $invss )) # FAL listingID https://algoexplorer.io/asset/71054280 export LISTINGID="71054280" export ADDR_CREATOR="YOURACCOUNTIDENTIFIERGOESHERE" export TEAL_APPROVAL_PROG="approval_program.teal" export TEAL_CLEAR_PROG="clear_state_program.teal" export GLOBAL_BYTESLICES=3 export GLOBAL_INTS=6 export LOCAL_BYTESLICES=0 export LOCAL_INTS=1 goal app create --creator $ADDR_CREATOR \ --approval-prog $TEAL_APPROVAL_PROG \ --clear-prog $TEAL_CLEAR_PROG \ --global-byteslices $GLOBAL_BYTESLICES \ --global-ints $GLOBAL_INTS \ --local-byteslices $LOCAL_BYTESLICES \ --local-ints $LOCAL_INTS \ --app-arg "int:$LISTINGID" \ --app-arg "int:$FALSD" \ --app-arg "int:$FALED" \ --app-arg "int:1000000" \ --app-arg "addr:$ADDR_CREATOR" \ --app-arg "int:$FALCD" \ -d ~/node/data
ADDR_CREATOR is the account that is creating the application and this transaction is signed by this account.
For stateful smart contracts, there is a limit of 64 key-value pairs that can be used by the contract for global storage and 16 key-value pairs that can be used for local storage. Remember that when creating the smart contract the amount of storage can never be changed once the contract is created.
Here we are defining nine global variables (three byte slices and six integers) and one local storage variable (integer). The byte slices store the addresses while the global integers store the timestamps for the start and end dates, the listing ID, target price, and current fund total. The local integer stores the amount of a specific investor.
Once this command is run the result will be the app ID which can then be used to make ApplicationCall transactions to the smart contract and update the our Application.
Created app with app index 1111
Update FAL Application
Anyone at any time can Update the Stateful Smart Contract. In our application however we want only the original Owner to be able to update the program and in this case some additional code must be added to our ApprovalProgram to handle this situation.
export APP_ID="1111" export ESCROW_ADDR="ESCROWADDRESSACCOUNT" goal app update --app-id=$APP_ID \ --from $ADDR_CREATOR \ --approval-prog $TEAL_APPROVAL_PROG \ --clear-prog $TEAL_CLEAR_PROG \ --app-arg "addr:$ESCROW_ADDR"
With this command, we are updating the global state of our application and adding the escrow account. In the ApprovalProgram we will need to add the logic to verify that:
- the Owner of the stateful smart contract is making the update call,
- one parameter is passed in (the escrow address),
- And it will store the address in the application’s global state (
Please refer to Update Stateful Smart Contract for more information about this command and the TEAL ApprovalProgram.
Optin and Invest
Because our application is using local state, any account including the creator of the smart contract, before start making Application Transaction calls that use local state, it must optin first to the smart contract. This can be done with the
export INVESTOR_ADDR="INVESTORADDRESSACCOUNT" goal app optin --app-id $APP_ID \ --from $INVESTOR_ADDR
The ApprovalProgram will check the Transaction Type to verify it is optin. Please refer to the official documentation for all different transaction types.
After optin into the application it will be possible to invest. The invest operation requires two transactions. The first one is the stateful smart contract call using the string parameter containing the word “invest”, and the second is the payment transaction to the escrow fund.
goal app call --app-id $APP_ID \ --app-arg "str:invest" \ --from=$INVESTOR_ADDR \ --out=unsignedtransaction1.tx \ -d ~/node/data goal clerk send --from=$INVESTOR_ADDR \ --to=$ESCROW_ADDR \ --amount=500000 \ --out=unsignedtransaction2.tx \ -d ~/node/data cat unsignedtransaction1.tx unsignedtransaction2.tx > combinedtransactions.tx goal clerk group -i combinedtransactions.tx -o groupedtransactions.tx goal clerk sign -i groupedtransactions.tx -o signout.tx goal clerk rawsend -f signout.tx
Please refer to Atomic Transfers for more information on how to create and group transactions atomically.
endDate has passed, it will be possible for the Owner to claim the investments and send the fund to the
receiverAddress if the
targetPrice is reached. If that’s the case, the receiver can then submit a payment transaction from the escrow to their account using the following
goal command line.
export TEAL_ESCROW_PROG="fal_escrow.teal" export RECEIVER_ADDR="RECEIVERADDRESSACCOUNT" goal app call --app-id $APP_ID \ --app-arg "str:claim" \ --from $RECEIVER_ADDR \ --out=unsignedtransaction1.tx \ -d ~/node/data goal clerk send --to=$RECEIVER_ADDR \ --close-to=$RECEIVER_ADDR \ --from-program=$TEAL_ESCROW_PROG \ --amount=0 \ --out=unsignedtransaction2.tx \ -d ~/node/data cat unsignedtransaction1.tx unsignedtransaction2.tx > combinedtransactions.tx goal clerk group -i combinedtransactions.tx -o groupedtransactions.tx goal clerk split -i groupedtransactions.tx -o split.tx goal clerk sign -i split-0.tx -o signout-0.tx cat signout-0.tx split-1.tx > signout.tx goal clerk rawsend -f signout.tx
The first part is the call to the Stateful Smart Contract passing the string argument “claim”.
The second transaction is the payment transaction from the escrow account to the receiver and it is not signed as it is a Stateless TEAL contract.
It should have an amount of 0 and must set the
--close-to attribute to the receiver. This will empty the escrow funds into the receiver’s account.
targetPrice is not met and the
endDate has passed, the Investors can reclaim their investment fund. The
goal CLI will be:
export TEAL_ESCROW_PROG="fal_escrow.teal" goal app call --app-id $APP_ID \ --app-account=$ESCROW_ADDR \ --app-arg "str:reclaim" \ --from $INVESTOR_ADDR \ --out=unsignedtransaction1.tx # reclaim amount less the transaction fee goal clerk send --to=$INVESTOR_ADDR \ --close-to=$INVESTOR_ADDR \ --from-program=$TEAL_ESCROW_PROG \ --amount=499000 \ --out=unsignedtransaction2.tx cat unsignedtransaction1.tx unsignedtransaction2.tx > combinedtransactions.tx goal clerk group -i combinedtransactions.tx -o groupedtransactions.tx goal clerk split -i groupedtransactions.tx -o split.tx goal clerk sign -i split-0.tx -o signout-0.tx cat signout-0.tx split-1.tx > signout.tx goal clerk rawsend -f signout.tx
The amount is different from the initial investment because of the transaction fee is paid by the escrow.
closeDate has passed, the Owner which is also the creator of the FAL, should be able to delete the Application if the escrow account has been emptied. The
goal command line will be:
goal app delete --app-id $APP_ID --from $ADDR_CREATOR --app-account=$ESCROW_ADDR
We pass the
escrow account in as the value for
app-account to check if it is empty. This will be handled in the TEAL ApprovalProgram logic.
With this article, we have demonstrated how to create a Fractional Auction Listing Application that is decentralized, secure and automated. This is one of the many use cases of Algorand’s layer-1 features and as I have shown there is no central authority that manages the FAL Escrow account. The stateful TEAL application takes care of the investments and automates the Fractional Ownership of the asset.