Developers Docs
Search
⌃K

Understanding Smart Contracts

Subgraph is a framework to automate the process of indexing smart contract events with some extra features that are quite useful. Before jumping into the smart contracts code we need to develop an idea of what we are looking for in the smart contracts. We don't need to understand whole smart contracts, we need to understand just enough to be able to capture data for interactions discussed in previous article Understanding The Protocol.
After developing subgraphs for almost dozens of protocols our team has come up with certain steps to understand only relevant information from smart contracts. You don't need to follow these steps if you prefer but we highly recommend following these steps if you are not one of the developers of the smart contracts. It will save you time and help you avoid common mistakes while developing the subgraph.

Find the core contract

Most of the protocols are complex decentralized application and need to be developed as a collection of smart contracts that talk to each other to achieve the desired functionality within limitations of EVM and blockchain execution context. In almost all cases there is always a core contract that implements methods to update state on user interaction. Other smart contracts are more or less implementations of user friendly external functions.
SushiSwap protocol also has one core smart contract UniswapV2Pair.sol. For those of you who are not aware SushiSwap is a fork of Uniswap V2. This UniswapV2Pair.sol is the one that keeps market reserves and liquidity provider token balances.

How is the core contract deployed?

Some protocols deploy the core contract manually and some has a factory contract that deploys these core contracts. SushiSwap also has a UniswapV2Factory.sol which deploys UniswapV2Pair.sol.

Is it one market each instance of core contract or all markets in one instance of core contract?

In most of the protocols there are multiple instances of core contract are deployed, each with a different configuration which represents an individual market. In this case we say that every market has a different smart contract address. SushiSwap exchanges UniswapV2Pair.sol represents one market for each instance deployed.
In some cases protocols one instance of the core contract is deployed and this contract itself has functions to add or remove markets by updating it's internal state variables. One example of such protocol is SushiSwap Farms.

Find events emitted by the core contract on core interactions

We need to go through code of methods implementing core user interactions and find events emitted by them. Some protocols design these events carefully and include all the required data in event arguments and some don't include all the required data in these event arguments. Unfortunately protocol developers design events to fulfill their indexing needs which is mostly collecting statics on market like daily volume, total locked value. Therefore in most of the protocols these events don't have all the required data points for our subgraph.
In case we find that events don't include all the required data then we need to find ways to collect that info from method arguments or return values of the core interaction method or other methods that this core interaction method calls on other supporting smart contracts.
SushiSwap core smart contract UniswapV2Pair.sol emits following events -
  1. 1.
    Mint(address indexed sender, uint amount0, uint amount1)
  2. 2.
    Burn(address indexed sender, uint amount0, uint amount1, address indexed to)
  3. 3.
    Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to)
  4. 4.
    Sync(uint112 reserve0, uint112 reserve1)
Looking at the code of mint , burn and swap methods we find that Sync event is fired in every time there is a change in reserves of the market. Mint and Burn events are emitted every time a user invests in the market and redeems from the market respectively.
Sync event has required data in the arguments to call updateMarket function of SimpleFi subgraph mapping library code but Mint and Burn events don't have all the required data points for calling investInMarket and redeemFromMarket function of library code.

How to get missing data points for Mint event?

We see that mint method calls _mint method which is implemented in UniswapV2ERC20.sol which emits Transfer event. Then it calls _update method which emits Sync event and then finally emits Mint event. Let's look at all these events in the order they are emitted with their arguments -
  1. 1.
    Transfer(address indexed from, address indexed to, uint value)
  2. 2.
    Sync(uint112 reserve0, uint112 reserve1)
  3. 3.
    Mint(address indexed sender, uint amount0, uint amount1)
We can get amount of positional token minted from Transfer event last argument value.The Mint event arguments amount0 and amount1 can be used as amount of assets that are deposited by the sender in the market. The Sync already includes arguments to tell us about change in reserves of the market.
Now question arises that there are a lot of Transfer events then how do we find out if a specific instance of the Transfer event is part of this mint call?
_mint method emits Transfer event with from argument as address(0) which means we can easily recognize if a Transfer event is part of a mint method call or not.

How to get missing data points for Burn event?

burn method of UniswapV2Pair.sol also emits following events in order -
  1. 1.
    Transfer(address indexed from, address indexed to, uint value)
  2. 2.
    Sync(uint112 reserve0, uint112 reserve1)
  3. 3.
    Burn(address indexed sender, uint amount0, uint amount1, address indexed to)
We can get amount of positional token minted from Transfer event last argument value.The Burn event arguments amount0 and amount1 can be used as amount of assets that are deposited by the sender in the market. The Sync already includes arguments to tell us about change in reserves of the market.
The problem with using Transfer event for burn method is that we can not be sure that every Transfer event with to argument as address(0) is part of burn method because a user or a smart contract can accidentally send their LP tokens to address(0) but this manual send to zero address is not going to change total supply or reserves of the market. It will only increase balance of zero address. To handle this specific case we will need to use an attribute that will keep track of last transfer to zero, which may or may not be part of a burn call.