LandX Smart Contracts Documentation

Architecture Overview

The repository for the LandX Protocol can be found on Github here

alt_text

LandX Smart Contract Architecture

LandX is built on the Ethereum blockchain, meaning all transactions reach consensus through a peer-to-peer system. All logic is implemented as a group of smart contracts that can interact with each other. They can be divided by two groups:

  • Internal contracts
  • Contracts that users can interact with

Internal Contracts: xTokenRouter.sol, OraclePrices.sol, KeyProtocolVariables.sol. Contract xTokenRouter.sol is used for storing actual xToken/cToken Pair. OraclePrices.sol provides actual prices for commodities and xTokens for executing internal calculations. KeyProtocolVariables.sol contains such protocol key parameters as fees percentages, the order of fee distributions, system wallets addresses.

Contracts that users can interact with: LandXNFT.sol, xToken.sol, cToken.sol, xBasket.sol, RentFoundation.sol. LandX NFTis an ERC1155 compatible contract, it represents landowner’s crop share agreement as a non-fungible token.

Each supported commodity type requires a deployed own version of the xToken/cToken pair. They are ERC20 compatible tokens. For example for SOY we should deploy xToken.sol/cToken.sol contracts as xSOY and cSOY, xToken.sol contract provide functionality to convert LNDX NFT to supported xTokens and stake/unstake feature for xToken owners. Staked xTokens generate cTokens. cToken.sol is usual ERC20 token and do not provide additional features except converting cTokens to USDC. It happens when the owner burns his tokens. At the beginning LandX protocol support four agricultural commodities: Wheat, Soy, Corn & Rice, so there are four xTokens/cTokens pairs: xWHEAT/cWHEAT, xSOY/cSOY, xCORN, cCORN and xRICE/cRICE.

xBasket.sol is an ERC20 and ERC4626 compatible contract. xBasket contract accepts deposits of all four xTokens and mints another ERC20 which acts as an index fund of them. User is allowed to convert his xBasket to xTokens back.

RentFoundation.sol is responsible to account rent payments for NFT that were converted to xTokens. Lanowners should make rent payments using payRent() method

Such contracts as xToken.sol and xBasket can interract with Uniswap for trading.

Detailed information about contract's methods and functions including who can call them is here.

Deployment steps

  1. Deploy KeyProtocolVariables.sol
  2. Deploy nft.sol and set gnosis safe address as contract owner
  3. Deploy lndx.sol
  4. Deploy RentFoundation.sol. Use USDC contract address, LNDX deployed contract address and Key Protocol Variables deployed contract address as constructor parameters
  5. Deploy xTokenRouter.sol
  6. Deploy cToken.sol for each crop type(SOY, WHEAT, RICE, CORN). Use xTokenRouter and rentFoundation contract addresses as constructor parameters
  7. Deploy xToken.sol for each crop type(SOY, WHEAT, RICE, CORN). Use NFT, lndx, USDC, xTokenRouter, rentFoundation and Key Protocol Variables contract addresses as constructor parameters
  8. Deploy OraclePrices.sol. Use xTokens and Key Protocol Variables contract addresses as constructor parameters
  9. On OraclePrices contract grant PRICE_SETTER_ROLEfor contract who will be allowed to update commodities prices
  10. Set xToken/cToken pairs in xTokenRouterContract by usingsetToken function
  11. Deploy xBasket.sol. Use xTokenRouter and Oracle Prices contract addresses as constructor parameters
  12. For each xToken set xBasketContract address usingchangeXBasketAddressfunction
  13. For NFT contract set xTokenRouter contract address usingsetXTokenRouterfunction
  14. For rentFoundation contract set xTokenRouter, oraclePrices and NFT contract addresses usingsetXTokenRouter, setGrainPrices, changeLandXNFTAddressfunctions
  15. For each deployed xToken contract set oraclePrices usingsetGrainPricesfunction

Build and test

Test coverage report

Copy-paste the env-sample to .env and replace the private keys & api keys accordingly.

Run:

npm install

Start ganache. check the RPC server that it uses (usually HTTP://127.0.0.1:7545)

Run:

npm run test

All test should pass

Publish on some blockchain (check package.json scripts):

npm run deploy_t:rinkeby
npm run deploy_v:mainnet

Contracts Under Review

contracts/LandXNFT.sol

LandXNFT is an ERC1155 compatible contract and represents landowner’s crop share agreement as a non-fungible token. Each NFT contains information on how much of xTokens the NFT is allowed to mint. Each NFT contains:

  • landArea, total land area in m2
  • tillableArea, tillable area in m2
  • cropShare, crop share in kg/ha
  • lienAgreementHash, hash of lien documents (byte32 word)

contracts/xToken.sol

XToken is an ERC20 compatible contract. It presents perpetual commodity vault that pays out 1 cToken per year. It accepts landxNFT and mints xTokens. It also provides logic for stake/unstake functionality. A user stakes xTokens to receive cTokens.

contracts/cToken.sol

CToken is an ERC20 compatible contract, 1 cToken represents 1 KG of crop. It can always be exchanged to USDC for prices to be updated via OraclePrices.sol that uses real world trading pricing data from traditional commodity exchanges. CTokens can be only minted by xToken contracts.

contracts/xBasket.sol

XBasket is an ERC20 and ERC4626 compatible contract. xBasket contract accepts deposits of all four xTokens and mints another ERC20 which acts as an index fund of them. It stakes all deposited xToken and receives cTokens. It then sells cTokens and buys more xTokens, creating self-compounding mechanism.

contracts/RentFoundation.sol

This contract is responsible for accepting crop share payments. Contains logic for accounting of crop share payments and exchange of cTokens for USDC

contracts/OraclePrices.sol

It provides current commodities and xTokens prices. It is deployed with initial prices. Provides a smart contract function which allows an authorized oracle address to update the values.

contracts/xTokenRouter.sol

This contract is used for getting correct xToken/cTokens contract addresses by others contracts.

contracts/KeyProtocolVariables.sol

It contains key Landx Protocol values like fees and commission rates, max allowable cropshare and other parameters. Its values can be changed based on the recommended DAO vote.

Contracts functions description

contracts/LandXNFT.sol

setDetailsAndMint

function setDetailsAndMint(
       uint256 _index,
       uint256 _landArea,
       uint256 _tillableArea,
       uint256 _cropShare,
       address _validator,
       uint256 _validatorFee
       bytes32 _lienAgreementHash,
       string memory _crop,
       address _to,
       string memory _uri
   ) public onlyOwner

Mint new NFT and set NFT details.

Parameters:

Name Type Description
_index uint256 NFT’s ID
_landArea uint256 Land area, m2
_tillableArea uint256 Tillable land area, m2
_cropShare uint256 Crop share, kg/Ha
_validator address Validator wallet address
_validatorFee uint256 Validator's fee
_lienAgreementHash bytes32 Lien documents hash value
_crop string Crop type (WHEAT, SOY etc)
_to address Receiver’s wallet address
_uri string NFT uri

contracts/xToken.sol

getShards

function getShards(uint256 _id) external

Deposit NFT, mint and distribute xTokens. Requires allowance to use NFT. Amount of xTokens is calculated by formula:

xTokens = landXNFT.tillableArea(_id) * (landXNFT.cropShare(_id)) / 10000

Parameters:

Name Type Description
_id uint256 NFT’s ID

The function emit event:

event Sharded(uint256 nftID, uint256 amount, string name);

getTheNFT

function getTheNFT(uint256 _id) external

Redeem the NFT. A caller should be a depositor of the NFT and has to have a full xTokens amount. xTokens will be burned.

Parameters:

Name Type Description
_id uint256 NFT’s ID

The function emit event:

event BuyOut(uint256 nftID, uint256 amount, string name);

getTheNFTPreview

function getTheNFTPreview(uint256 _id) public view

Calculates xTokens amount required to redeem NFT with provided ID

Parameters:

Name Type Description
_id uint256 NFT’s ID

stake

function stake(uint256 amount) public

Stake xTokens. Staked xTokens generate cTokens.

Parameters:

Name Type Description
amount uint256 xToken amount to satke

The function emit event:

 event TokenStaked(address staker, uint256 amount);

unstake

function unstake(uint256 amount) public

Unstake xTokens. This function also call claim() function so a caller also get all cTokens that were generated by this time.

Parameters:

Name Type Description
amount uint256 xToken amount to unstake

The function emit event:

event Unstaked(address staker, uint256 amount);

claim

function claim() public

Send all generated cTokens to a caller.

availableToClaim

function availableToClaim(address account) public view returns(uint256)

Returns cTokens amount available to claim by a staker.

Parameters:

Name Type Description
account address Staker’s address

The function emit event:

event YieldClaimed(address staker, uint256 amount);

Return Value:

Type Description
uint256 cTokens amount

totalAvailableToClaim

function totalAvailableToClaim() public view returns(uint256)

Returns all cTokens amount available to claim

Return Value:

Type Description
uint256 cTokens amount

preview

function preview(uint256 id) public view returns(uint256, uint256, uint256, uint256)

Returns xTokens amount will be minted and how they will be distributed

Parameters:

Name Type Description
id uint256 NFT’s ID

Return Values:

Type Description
uint256 total xTokens amount will be minted
uint256 xTokens amount to pay fee
uint256 xTokens amount to security deposit and to prepay annual rent
uint256 xTokens amount will be sent to NFT depositor

xBasketTransfer

function xBasketTransfer(address _from, uint256 amount) external

Service method that can be used only by xBasket contract. Implemented to avoid extra allowances during xBasket mining

Parameters:

Name Type Description
_from address xBasket minter address
amount uint256 xToken amount

changeXBasketAddress

function changeXBasketAddress(address _newAddress) public onlyOwner

Service method to change xBasket contract address. Only contract owner can use it

Parameters:

Name Type Description
_newAddress address xBasket contract address

setXTokenRouter

function setXTokenRouter(address _router) public onlyOwner

Service method to change xTokenRouter contract address. Only contract owner can use it

Parameters:

Name Type Description
_router address xTokenRouter contract address

previewNonDistributedYield

function previewNonDistributedYield() external view returns(uint256)

Returns non-distributed yield (generated by not staked xTokens) in cTokens

getNonDistributedYield

 function getNonDistributedYield() external returns(uint256)

Returns non-distributed yield (generated by not staked xTokens) in cTokens and reset counters. It is used only by RentFoundation contract to withdraw surplus

contracts/cToken.sol

mint

function mint(address account, uint256 amount) public

Mints cTokens. Only xToken contract can use it

Parameters:

Name Type Description
address address Receiver of cTokens
amount uint256 cTokens amount to mint

burn

function burn(uint256 amount) public override

Send USDC equivalent to caller and burn cTokens (Implemented selling for USDC logic).

Parameters:

Name Type Description
amount uint256 cTokens amount to burn

setRentFoundation

function setRentFoundation(address _address) public onlyOwner

Service method to change RentFoundation contract address. Only contract owner can use it

Parameters:

Name Type Description
_address address Rent foundation contract address

setXTokenRouter

function setXTokenRouter(address _router) public onlyOwner

Service method to change xTokenRouter contract address. Only contract owner can use it

Parameters:

Name Type Description
_router address xTokenRouter contract address

contracts/xBasket.sol

asset

function asset() public view override returns (address)

Returns underlying asset contract address. As xBasket has 4 underlying assets and total assets amount can be represented in USDC it returns USDC contract address

Return Value:

Type Description
address USDC contract address

totalAssets

function totalAssets() public view override returns (uint256)

Returns total assets amount represented in USDC

Return Value:

Type Description
uint256 Total assets amount represented in USDC

convertToShares

function convertToShares(uint256 assets) public view override returns (uint256)

Returns amount of xBasket that can be minted with provided amount of each xTokens

Parameters:

Name Type Description
assets uint256 Amount of each xToken

Return Value:

Type Description
uint256 Total xBasket amount

convertToAssets

function convertToAssets(uint256 shares) public view override returns (uint256)

Returns amount of each xTokens amount xBaskets will be converted to

Parameters:

Name Type Description
shares uint256 Amount of xBasket

Return Value:

Type Description
uint256 Amount of each xTokens will be converted to

maxDeposit

function maxDeposit(address receiver) public view virtual override returns (uint256)

Returns max amount of each xTokens that can be deposited

Parameters:

Name Type Description
receiver address xToken owner’s address

Return Value:

Type Description
uint256 Max amount of each xTokens that can be deposited

maxMint

function maxMint(address receiver) public view virtual override returns (uint256)

Returns max amount of xBasket that can be minted

Parameters:

Name Type Description
receiver address xToken owner’s address

Return Value:

Type Description
uint256 Max amount of xbasket that can be minted

maxWithdraw

function maxWithdraw(address owner) public view virtual override returns (uint256)

Returns max amount of each xToken that xBaskets owner can receive

Parameters:

Name Type Description
owner address xBasket owner’s address

Return Value:

Type Description
uint256 Max amount of each xToken that can be withdrawn

maxRedeem

function maxRedeem(address owner) public view virtual override returns (uint256)

Returns max amount of xBasket available to redeem (balanceOf)

Parameters:

Name Type Description
owner address xBasket owner’s address

Return Value:

Type Description
uint256 max amount of xBasket available to redeem (balanceOf)

previewDeposit

function previewDeposit(uint256 assets) public view virtual override returns (uint256)

Calculate xBasket amount that can be received for provided amount of each xToken

Parameters:

Name Type Description
assets uint256 amount of each xTokens to deposit

Return Value:

Type Description
uint256 xBasket amount that can be received for provided amount of each xToken

previewMint

function previewMint(uint256 shares) public view virtual override returns (uint256)

Returns required amount of each xToken for minting provided amount of xBaskets

Parameters:

Name Type Description
shares uint256 amount of xBasket to mint

Return Value:

Type Description
uint256 Required amount of each xToken

previewWithdarw

function previewWithdraw(uint256 assets) public view virtual override returns (uint256)

Returns required amount of xBasket to receive provided amount of each xTokens

Parameters:

Name Type Description
assets uint256 amount of each xToken

Return Value:

Type Description
uint256 required amount of xBasket

previewRedeem

function previewRedeem(uint256 shares) public view virtual override returns (uint256)

Returns amount of each xTokens that can be received for redeem provided amount of xBasket

Parameters:

Name Type Description
shares uint256 amount of xBasket

Return Value:

Type Description
uint256 amount of each xToken to receive

deposit

function deposit(uint256 assets, address receiver) public virtual override returns (uint256)

Deposit each xToken, mint xBasket and send them to received address

Parameters:

Name Type Description
assets uint256 amount of each xTokens
receiver address xBasket receiver’s address

Return Value:

Type Description
uint256 amount of minted xBaskets

mint

function mint(uint256 shares, address receiver) public virtual override returns (uint256)

Deposit required amount of each xToken, mint provided amount of xBasket and send them to received address

Parameters:

Name Type Description
shares uint256 required amount xBasket
receiver address xBasket receiver’s address

Return Value:

Type Description
uint256 amount of each deposited xTokens

withdraw

function withdraw(uint256 assets, address receiver, address owner) public virtual override returns (uint256)

Withdraw provided amount of each xTokens and send them to receiver address

Parameters:

Name Type Description
assets uint256 required amount of each xTokens
receiver address xToken receiver’s address
owner address Xbasket owner’s address

Return Value:

Type Description
uint256 amount of xBasket to redeem

redeem

function redeem(uint256 shares, address receiver, address owner) public virtual override returns (uint256)

Redeem provided amount of xBasket and send xTokens them to receiver address

Parameters:

Name Type Description
shares uint256 xBasket amount to redeem
receiver address xToken receiver’s address
owner address Xbasket owner’s address

Return Value:

Type Description
uint256 amount of each xTokens to send receiver

calculateYield

function calculateYield() public view returns(uint256)

Calculate the value of the contracts cToken holdings in USDC

Return Value:

Type Description
uint256 amount of cTokens presented in USDC available for xBasket contract

calculateTVL

function calculateTVL() public view returns(uint256)

Calculate the value of the contracts holdings in USDC

Return Value:

Type Description
uint256 value of the contracts holdings (sum of deposited xTokens and available cTokens) in USDC

pricePerToken

function pricePerToken() public view returns(uint256)

Calculate xBasket price in USDC

Return Value:

Type Description
uint256 xBasket token price

autoCompoundRewards

function autoCompoundRewards() public

Claims cTokens, sell them for USDC, buy xTokens and stakes them.

contracts/OraclePrices.sol

setGrainPrice

function setGrainPrice(string memory grain, uint256 price) public

Set commodity price in USDC (per megatone). Used by ChainLink oracle. Only setter with PRICE_SETTER_ROLE can set prices

Parameters:

Name Type Description
grain string commodity name (SOY, RICE etc)
price uint256 commodity price

The function emit event:

event AutoCompounded(uint256 xWheat, uint256 xSoy, uint256 xRice, uint256 xCorn);

setXTokenPrice

function setXTokenPrice(address xToken, uint256 price) public

Set xToken price in USDC. This price is used when there are no Uniswap pools. Only setter with PRICE_SETTER_ROLE can set prices

Parameters:

Name Type Description
xToken address xTokem contract address
price uint256 xToken price

getXTokenPrice

function getXTokenPrice(address xToken) public view returns(uint256)

get xToken price in USDC. If there isUniswap pool it returns the spot price from Uniswap pool. If no, xToken price was set in this contract is returned

Parameters:

Name Type Description
xToken address xToken contract address

Return Value:

Type Description
uint256 xToken price

contracts/RentFoundation.sol

payRent

function payRent(uint256 tokenID, uint256 amount) public

It is used to pay rent for the nft. Rent can be paid only for sharded NFT.

The function emit event:

event rentPaid(uint256 tokenID, uint256 amount);

Parameters:

Name Type Description
tokenID uint256 LandX NFT id
amount uint256 Rent amount in USDC

payInitialRent

function payInitialRent(uint256 tokenID, uint256 amount) external

It is used only by the xToken contract to apply annual rent during getting depositing NFT and getting xTokens.

The function emit event:

event initialRentPaid(uint256 tokenID, uint256 amount);

Parameters:

Name Type Description
tokenID uint256 LandX NFT id
amount uint256 Rent amount in USDC

getDepositBalance

function getDepositBalance(uint256 tokenID) public view returns(int256)

Returns paid rent balance for NFT by its ID, can be a negative value. Negative value means there is a debt

Parameters:

Name Type Description
tokenID uint256 LandX NFT id

Return Value:

Type Description
int256 Paid rent balance

sellCToken

function sellCToken(address account, uint256 amount) public

Used only by cToken contracts. Convert burning cToken amount to USDC and send USDC to account

Parameters:

Name Type Description
account address USDC receiver’s address
amount uint256 burning amount of cToken

setGrainPrices

function setGrainPrices(address _grainPrices) public onlyOwner

Service method to change OraclePrices contract address. Only contract owner can use it

Parameters:

Name Type Description
_grainPrices address Oracle Prices contract address

setXTokenRouter

function setXTokenRouter(address _router) public onlyOwner

Service method to change xTokenRouter contract address. Only contract owner can use it

Parameters:

Name Type Description
_router address xTokenRouter contract address

buyOutPreview

function buyOutPreview(uint256 tokenID) external view returns(bool, uint256)

Calculates remaining rent, if there is a debt returns false

Parameters:

Name Type Description
tokenID uint256 NFT ID

buyOut

function buyOut(uint256 tokenID) external returns(uint256)

Sends remaining rent to xToken contract during redeem of LandXNFT, reverts if there is a debt.

Parameters:

Name Type Description
tokenID uint256 NFT ID

previewSurplusUSDC

 function previewSurplusUSDC() public view returns(uint256)

Calculates surplus amount for all not staked xTokens (for all of 4 kinds of xTokens)

withdrawSurplusUSDC

 function withdrawSurplusUSDC(uint _amount) public

Withdraws surplus amount for all not staked xTokens. Funds are sent to distributor address

Parameters:

Name Type Description
_amount uint Amount to withdraw

updateDistributor

 function updateDistributor(address _distributor) public onlyOwner

Updates distributor address.

Parameters:

Name Type Description
_distributor address New distributor's address

updateCrops

 function updateCrops(string[] memory _crops) public onlyOwner

Updates crops list.

Parameters:

Name Type Description
_crops string[] New crops list

changeLandXNFTAddress

function changeLandXNFTAddress(address _newAddress) public onlyOwner

Service method to change LandX NFT contract address. Only contract owner can use it

Parameters:

Name Type Description
_newAddress address LandX NFT contract address

contracts/KeyProtocolVariables.sol

updateXTokenMintFee

function updateXTokenMintFee(uint256 _fee) public

Updates xToken mint fee. Default value 300(3%)

Parameters:

Name Type Description
_fee uint256 xToken mint fee percentage

updateCTokenSellFee

function updateCTokenSellFee(uint256 _fee) public

Updates cToken sell fee. Default value 1000(10%)

Parameters:

Name Type Description
_fee uint256 cToken sell fee percentage

updateValidatorCommission

  function updateValidatorCommission(uint256 _fee) public

Updates validator's commision. Default value 25(0.25%)

Parameters:

Name Type Description
_fee uint256 Validator's commission

updateMaxValidatorFee

  function updateMaxValidatorFee(uint256 _fee) public

Updates max validator's fee. Default value 1000(10%)

Parameters:

Name Type Description
_fee uint256 Max validator's fee

updateSellXTokenSlippage

function updateSellXTokenSlippage(uint256 _slippage) public

Updates sell xToken slippage. Default value 300(3%)

Parameters:

Name Type Description
_slippage uint256 slippage percentage

updateBuyXTokenSlippage

function updateBuyXTokenSlippage(uint256 _slippage) public

Updates buy xToken slippage. Default value 300(3%)

Parameters:

Name Type Description
_slippage uint256 slippage percentage

updatePayRentFee

function updatePayRentFee(uint256 _fee)public

Updates pay rent fee. Default value 150(1.5%)

Parameters:

Name Type Description
_fee uint256 pay rent fee percentage

updateHedgeFundAllocation

function updateHedgeFundAllocation(uint256 _allocation) public

Updates hedge fund allocation percentage. Default value 1500(15%). This parameter define which part of rent payments send to hedge fund wallet

Parameters:

Name Type Description
_allocation uint256 Hedge fund allocation percentage

updateSecurityDepositMonths

function updateSecurityDepositMonths(uint8 _months) public

Updates securityDepositMonth parameter. Id defines payment of how many month rent goes to the security deposit wallet during deposit NFT to mint xTokens. Default value is 12 months

Parameters:

Name Type Description
_months uint8 months count

updateFeeDistributionPercentage

function updateFeeDistributionPercentage(uint256 _lndxHoldersPercentage, uint256 _landxOperationPercentage) public

Updates fee distribution percentage.

lndxHoldersPercentage defines what part of fees will be shared between LNDX stakers. Default value is 6500 (65%)

landXOpertationsPercentage what part of fee sends to Landx Operational wallet. Default value is 3000 (30%)

landXChoicePercentage = 10000 - landXOpertationsPercentage - lndxHoldersPercentage. Default value is 500 (5%)

Parameters:

Name Type Description
_lndxHoldersPercentage uint256 LNDX holders percentage
landxOperationPercentage uint256 landX operation percentage

updateHedgeFundWallet

function updateHedgeFundWallet(address _wallet) public

Updates hedge fund wallet address.

Parameters:

Name Type Description
_wallet address hedge fund wallet address

updateLandxOperationalWallet

function updateLandxOperationalWallet(address _wallet) public

Updates Landx opertainal wallet address.

Parameters:

Name Type Description
_wallet address landx operational wallet address

updateLandxChoiceWallet

function updateLandxChoiceWallet(address _wallet) public

Updates landx choice wallet address.

Parameters:

Name Type Description
_wallet address landx choice wallet address

updateXTokensSecurityWallet

function updateXTokensSecurityWallet(address _wallet) public

Updates xTokens security wallet address.

Parameters:

Name Type Description
_wallet address xTokens security wallet address

updateValidatorCommisionWallet

function updateValidatorCommisionWallet(address _wallet) public

Updates validator commission wallet address.

Parameters:

Name Type Description
_wallet address validators commissions wallet address

launch

function launch() public

Disables pre-launch mode. It can be done only once and pre-launch mode can’t be switched on again.

contracts/xTokenRouter.sol

setToken

function setToken(string memory crop, address xToken, address cToken) public onlyOwner

Set xToken/cToken pair for given crop type.

Parameters:

Name Type Description
crop string crop type (SOY, RICE etc)
xToken address xToken contract address
cToken address cToken contract address

getXtoken

function getXToken(string memory crop) external view returns(address)

Returns xToken contract address by crop type

Parameters:

Name Type Description
crop string crop type (SOY, RICE etc)

Return Value:

Type Description
address xToken contract address

getCtoken

function getCToken(string memory crop) external view returns(address)

Returns cToken contract address by crop type

Parameters:

Name Type Description
crop string crop type (SOY, RICE etc)

Return Value:

Type Description
address cToken contract address

Oracles

Overview

LandX has partnered with Chainlink and Matrixed.Link to provide an oracle service to bring commodity price data on-chain.

The price data is derived from a commodities API which delivers it directly from CME, CBOT, NYMEX and COMEX. The data is pulled from the API by a decentralized network of nodes and sent via a transaction to our smart contracts on the Ethereum mainnet.

Contract

The chainlink adapter is here:

https://github.com/LandXit/land-x-smart-contracts/blob/develop/contracts/OracleMulti.sol

Multiple queries are called from a single transaction to fetch API data and bring that data into the OraclePrices.sol contract which makes it available throughout.

https://github.com/LandXit/land-x-smart-contracts/blob/develop/contracts/OraclePrices.sol

This adapter is hosted by Matrixed.link and is called by Chainlink Automation (formerly Chainlink keepers) more information is available here: \ https://docs.chain.link/docs/chainlink-automation/introduction/?_ga=2.75182097.2031120419.1665842779-312568758.1658466725

The Chainlink automation cron job is set to update 5 times a week when traditional finance markets are open. Further details are available here:

https://automation.chain.link/goerli/71649092462618195074524583505042249501464488159377840087759832747240961126361

Frontrunning & Flashloans

Oracle price data affects the USD value of cTokens which are exchanged for USDC internally. This is available via the public sellCTokenfunction in RentFoundation.sol

https://github.com/LandXit/land-x-smart-contracts/blob/develop/contracts/RentFoundation.sol#L180

cTokens are not expected to trade on external exchanges and pricing is not affected by trade volume which mitigates the risk of a flashloan attack.

xTokens are traded on decentralized exchanges and their price may find a fair market correlation to the price of the underlying commodities. However the commodity data would be available directly from tradfi exchanges before it becomes available on chain. There may be an informational advantage to trading xTokens based on the underlying commodity prices but that is for the market to decide.

A technical user could potentially maximize their returns from xToken holdings by selling cTokens at the best price over two days.

In theory a user could monitor the mempool for the incoming oracle transaction and then front run or wait for that transaction. If commodity prices continued to go up they could hold until there is a down turn and then sell. This is not a significant risk to the protocol and the same goal could be achieved by casually monitoring the price of commodities on traditional finance exchanges.