Teller Protocol Diamond

Structure

This is the main diamond contract where all facets of the protocol can talk to each other through a shared storage interface. The ITellerDiamond contract itself works by importing all of it's facets as dependencies. See below:

abstract contract ITellerDiamond is
    SettingsFacet,
    PlatformSettingsFacet,
    AssetSettingsDataFacet,
    AssetSettingsFacet,
    PausableFacet,
    PriceAggFacet,
    ChainlinkAggFacet,
    LendingFacet,
    CollateralFacet,
    CreateLoanFacet,
    LoanDataFacet,
    RepayFacet,
    SignersFacet,
    NFTFacet,
    EscrowClaimTokensFacet,
    CompoundFacet,
    UniswapFacet,
    IDiamondCut,
    IDiamondLoupe
{}

In the Teller Protocol, each Facet contains function helpers that come from its respective Library or libraries. Each Library contains not only function helpers to assist the facets, but also a storage function caller. Here's an example of our LoanDataFacet

Note: this example does not resemble our actual file on the Teller protocol, but rather a simplified version.

In this example, our LoanDataFacet uses 2 functions that call from the LibLoans and the LibEscrow library, respectively:

  • getLoan directly calls the LibLoans storage function s() which gets our loan data back after we pass our loanID

  • getLoanEscrowValue directly calls the LibEscrow library function calculateTotalValue to calculate the loan escrow value using loanID

Next, we'll look at how storage works.

Storage

The way diamond storage works is that we add or read data to a struct that is stored in a hashed position slot by calling a function. Let's call this function store(). We shall take a look at our market.sol storage file, since it's the most popular one in our Teller protocol.

This file, like the previous file, has been compressed for ease of understanding.

  • Our MARKET_STORAGE_POS is the hash of our position string

  • The store() function in the MarketStorageLib returns our MarketStorage at the position we initialized before

  • The MarketStorage is a heavy struct with multiple mappings to interfaces, primitive data types and other structs

So, now that we understand this, how do we call this function to update or read data? Well, it's simple really! Let's head to a simple function in our LibLoans library called loan(), which simply returns our loan data:

Let's go through this step by step

  • loan() function takes in the loanID as a parameter and returns a struct of type Loan (defined in market.sol) with the help of our s() function

  • the s() function calls our MarketStorageLib.store(), which if you remember it returns our MarketStorage struct stored at our hashed slot

  • Now that our MarketStorage is returned via s(), we also return the specific loan by adding .loans[loanID]

That's really our Diamond Structure and Storage in a nutshell! Since our Diamond pulls in all of its Facets via Inheritance, calling any of our facet is still calling our Diamond Contract's address.

Last updated

Was this helpful?