Mar 6, 2021 - A linear interpolation based liquidity pool

In my previous post I have briefly described my recent adventures in the DeFi space and how I’ve built an experimental decentralized options exchange on ethereum with solidity programming. If you haven’t read it yet, feel free to follow the link below for more context:

In this post I’m gonna talk about liquidity pools. More specifically about a linear interpolation based liquidity pool I have developed for my experimental options exchange, whose source code and brief documentation you can find in the project’s GitHub repository:

First we will recall what’s a liquidity pool and the purpose it serves (feel free to jump ahead if you’re already familiary with it). Then I’ll present my linear interpolation liquidity pool proposal and explain how it works, it’s advantages and disadvantages.

What’s a liquidity pool?

A liquidity pool is a smart contract that gathers funds from individuals denominated liquidity providers which are then used to facilitate decentralized trading. As the name suggests liquidity pools provide “liquidity” to the market, i.e., they make it possible for traders to quickly purchase or sell an asset without causing a drastic change in the asset’s price, and without subjecting traders to unfair prices, which would be one of the consequences of lack of liquidity.

DeFi liquidity pools emerged as an innovative and automated solution for addressing the liquidity challenge on decentralized exchanges. They replace the traditional order book model used in traditional exchanges (such as the NYSE) which is not applicable to most cryptocurrencies platforms mainly due to their highly mutable nature, i.e., in a matter of a couple of hundreds of milliseconds an entire order book can change as a result of orders being created, updated, fulfilled and cancelled, which would be extremely costly in a platform like ethereum on account of transaction fees.

One could say that achieving efficient pricing is among the biggest challenges for implementing a successful liquidity pool. Typically the price of an asset varies according to supply and demand pressures. If there’s too much supply prices will drop, since sellers will compete against each other for offering the most competitive price. Likewise if demand is up to the roof prices will rise, since buyers will fight amongst themselves to offer the best price for purchasing an asset.

Several models have been proposed and are being used in DeFi to address this challenge. Uniswap liquidity pools famously use the constant product formula to automatically adjust cryptocurrencies exchange prices upon each processed transaction. In this case market participants are resposible for driving exchange rates up/down by taking advantage of short-lived arbitrage opportunities that appear when prices distantiate from their ideal values.

Nonetheless a supply/demand based pricing model, such as Uniswap’s, is in my opinion unfit for pricing options, since an option price is not entirely the result of supply and demand pressures, but rather directly dependent on its underlying’s price. This observation motivated me to propose a linear interpolation based liquidity pool model, as we’ll see in the next section.

The linear interpolation liquidity pool

The diagram below illustrates how the linear interpolation liquidity pool fits in the options exchange trading environment, how market agents interact with it, and provides some context on the pool pricing model:

linear-liquidity-pool

Market Agents

On one side of the table we have options traders that interact with the pool by either buying options from it or selling options to it. The pool first calculates the target price for an option based on its internal pricing parameters (more on that latter) and then applies a fixed spread on top of it for deriving the buy price above the target price, and sell price below the target price. This spread can be freely defined by the pool operator and should be high enough for ensuring the pool is profitable, but not too high as to demotivate traders.

Below are the solidity function signatures available for traders to interact with the pool:

function queryBuy(string calldata symbol) external view returns (uint price, uint volume);

function querySell(string calldata symbol) external view returns (uint price, uint volume);

function buy(string calldata symbol, uint price, uint volume, address token)
    external
    returns (address addr);

function sell(string calldata symbol, uint price, uint volume) external;
  • The queryBuy function receives an option symbol and returns the spread-adjusted “buy” price and available volume for traders to buy from the pool
  • Similarly the querySell function receives an option symbol and returns the spread-adjusted “sell” price and available volume the pool is able to purchase from traders
  • Traders can then call the buy function to purchase option tokens specifying the option symbol, queried “buy” price, desired volume and the address of the stablecoin used as payment
  • Or call the sell function to receive payment for option tokens being sold to the pool specifying the option symbol, queried “sell” price and the pre-approved option token transfer volume

On the other side of the table we have liquidity providers. They interact with the pool by depositing funds into it which are used to both i) allocate collateral for writing new option tokens for selling to traders and ii) allocate a reserve of capital for buying option tokens from traders.

Below is the solidity function signature liquidity providers should call for providing funds to the pool:

function depositTokens(address to, address token, uint value) external;

Liquidity providers receive pool tokens in return for depositing compatible stablecoin tokens into the pool following a “post-money” valuation strategy, i.e., proportionally to their contribution to the total amount of capital allocated in the pool including the expected value of open option positions. This allows new liquidity providers to enter the pool at any time without harm to pre-existent providers.

Funds are locked in the pool until it reaches the pre-defined liquidation date, whereupon the pool ceases operations and profits are distributed to liquidity providers proportionally to their participation in the total supply of pool tokens.

Even so, since the pool is tokenized, liquidity providers are free to trade their pool tokens in the open market in case they need to recover their funds earlier.

Pricing Model

The pool holds a pricing parameters data structure for each tradable option, as shown below, which contains a discretized pricing curve calculated off-chain based on a traditional option pricing model (ex: Monte Carlo) that’s “uploaded” to the pool storage. The pool pricing function receives the underlying price (fetched from the underlying price feed) and the current timestamp as inputs, then it interpolates the discrete curve to obtain the desired option’s target price. That’s it, just simple math.

struct PricingParameters {
    address udlFeed;
    uint strike;
    uint maturity;
    OptionsExchange.OptionType optType;
    uint t0;
    uint t1;
    uint[] x;
    uint[] y;
    uint buyStock;
    uint sellStock;
}

Notice the t0 and t1 parameters, which define, respectively, the starting and ending timestamps for the interpolation. Also notice the x vector, which contains the underlying price points, and the y vector, which contains the pre-computed option price points for both the starting timestamp t0 and the ending timestamp t1 (see example snippet below). These four variables define the two-dimensional surface that the pool contract uses to calculate option prices.

 // underlying price points (US$)
x = [1350, 1400, 1450, 1500, 1550, 1600, 1650];

y = [
     // option price points for "t0" (US$)
    27, 42, 62, 87, 118, 152, 191,
    
    // option price points for "t1" (US$)
    22, 36, 56, 81, 111, 146, 185
];

This example snippet defines price points for a hypothetical ETH call option with strike price of US$ 1.500 and an interpolation period starting at 7 days to maturity and ending at 6 days to maturity, resulting in the pricing surface plotted below:

surface

By following this approach the more heavy math is performed off-chain, since it would be unfeasible/too damn expensive to run a Monte Carlo simulation or any other option pricing method on ethereum, and actually a waste of capital, as interpolating a preprocessed discretized curve achieves similar end results with much less on-chain computational effort.

Advantages

Below I provide a couple of reasons of why I believe this approach will appeal to both options traders and liquidity providers:

  • Changes to the underlying price are instantly reflected on the option price, meaning that the pool won’t be subject to arbitrage that would otherwise reduce its gains and that traders can rest assured they are getting fair, transparent prices when interacting with the pool.
  • Zero slippage, since options prices aren’t dependent on offer/demand pressures, making it simpler to trade larger option token volumes.
  • Lightweight pricing model, allowing a single pool to trade multiple symbols, which can potentially reduce the pool returns volatility due to the effects of diversification.

Disadvantages

I also see some operational/structural disadvantages of this design:

  • Necessity to update pricing parameters on a regular basis, possibly daily, to prevent pool prices from being calculated using an outdated pricing curve that would result in pricing inefficiencies.
  • Dependence on underlying price feed oracles. While the option price itself isn’t subject to direct manipulation one could try manipulating the underlying price feed instead, hence the importance of adopting trustworthy oracles.
  • Requirement of an operator for overseeing pool operations such as registering tradable options, updating pricing parameters and defining buy-sell spreads.

Closing thoughts

This linear interpolation liquidity pool design adds up to the decentralized options exchange environment presented in my previous blog post. It’s been implemented as a decoupled, independent component with the goals of pricing efficiency, operational flexibility and design extensibility in mind.

I believe that, once deployed, this pool will be attractive for both traders, which will have access to more efficient prices with zero slippage, and liquidity providers, which will experience less volatility in their returns considering that a diversified options offer is added to the pool.

Next steps for this project include: backtesting of the liquidity pool to further validate its model and to estimate the appropriate parameters for launching; optimizations to solidity code for reducing gas consumption; and the development of the dapp front-end to make the exchange accessible to non-developers. Stay tuned!

Feb 18, 2021 - Building a decentralized options exchange on ethereum

Decentralized finance (a.k.a. DeFi) is a relatively recent and fast growing field in the crypto space that is providing innovative implementations for financial instruments that rely on “smart contracts” (actual code files) instead of being subject to control by central financial intermediaries such as brokerages, exchanges, or banks.

I first came across DeFi about six months ago while browsing a hacker news thread on the subject, and became especially interested on the topic. Not much later major financial news portals reported that DeFi had already grown tenfold during the course of 2020, surpassing US$ 11 billion in deposited value with still a few months left to year end1,2, nothing less than staggering.

This context motivated me to invest my free time for studying this field more deeply, and since I learn better when I get my hands dirty I ended up developing an experimental project of a decentralized options exchange on ethereum which I describe briefly in this post. Also, feel free to browse the project’s source code on GitHub, which includes a short technical documentation: DeFiOptions.

I start with a functional overview of the project and then I get into more details on key DeFi concepts related to it. So don’t go away just yet if you feel overwhelmed by the vocabulary. Nonetheless, if you’re not familiar with options trading in traditional stock exchanges, I suggest you take a look here before proceeding.

Functional overview

So this experimental DeFi options exchange was implemented as a collection of smart contracts written in the solidity programming language. They enable trading of long and short positions for cash settable call and put european style options. The diagram below gives a glimpse on how traders interact with the exchange, and how components interact with one another.

regular-graphs

The exchange accepts stablecoin deposits as collateral for writing tokenized (ERC20) options, and a dynamic approach has been implemented for ensuring collateral in a more capital efficient way, making use of favorable writer’s open option positions for decreasing total required balance provided as collateral.

Decentralized price feeds provide the exchange on-chain underlying price and volatility updates, which is crucial for properly calculating options intrinsic values, collateral requirements, and performing settlements.

Because options are tokenized they can be freely traded/transferred between any two parties. Upon maturity each option contract is liquidated, cash settled by the credit provider contract and destroyed to prevent anyone from trading an expired asset. In case any option writer happens to be short on funds during settlement the credit provider will register a debt and cover payment obligations, essentially performing a lending operation.

Registered debt will accrue interest until it’s repaid by the borrower. Payment occurs either implicitly when any of the borrower’s open option positions matures and is cash settled (pending debt will be discounted from profits) or explicitly if the borrower makes a new stablecoin deposit in the exchange.

Exchange’s balances not allocated as collateral can be withdrawn by respective owners in the form of stablecoins. If there aren’t enough stablecoins available at the moment of the request due to operational reasons the solicitant will receive ERC20 credit tokens issued by the credit provider instead. These credit tokens are a promise of future payment, serving as a proxy for stablecoins since they can be redeemed for stablecoins at a 1:1 value conversion ratio, and are essential for keeping the exchange afloat during episodes of high withdrawal demand.

Holders of credit tokens can request to withdraw (and burn) their balance for stablecoins as long as there are sufficient funds available in the exchange to process the operation, otherwise the withdraw request will be FIFO-queued while the exchange gathers funds, accruing interest until it’s finally processed to compensate for the delay.

Phew, that’s it! While implementing the options exchange I came across several challenges, tried different approaches, reverted back and tried again until coming up with this solution. There’s still work to be done (see “Status & next steps” section below), but I’m confident this foundation is solid enough to support further developments.

DeFi glossary

Now, let’s look at some (not alphabetically ordered) key DeFi concepts that play an important role in this project. Feel free to jump ahead some of them if they seem too basic for you, they are included to offer newcomers a more complete introduction.

Smart contracts

If you’re new to ethereum development you must know that smart contracts constitute the source code of decentralized applications (dapp). It’s solidity code, simply put.

A smart contract defines functions with varying degrees of visibility that perform calculations, modify blockchain state and emit logs. External and public functions are the API of a dapp and can be called by any participant of the ethereum network. Internal and private functions on the other hand can only be called by the smart contract itself or its derivations in the case of the former.

Dapps live in the blockchain, i.e., their source code is stored in its blocks and ran upon demand, somewhat similar to the serverless computing model. Nonetheless the ethereum network guaranties atomicity, meaning that at any given moment only a single function is being executed as if it had the entire blockchain available for itself alone.

When smart contract functions are executed they potentially alter state. If so changes are definitive, persisted into the blockchain and available to be audited by any node in the network. Without getting into too much detail this model of execution is what gives ethereum its decentralized quality, anyone can execute code and anyone can audit executed code.

As I’ve pointed out before feel free to browse the options exchange source code in the project’s GitHub repository at any time for evaluating a range of smart contracts examples.

Tokenization

Tokenization is the process of converting physical and non-physical assets into digital tokens on the blockchain. It’s notably done by implementing the ERC20 interface which is nothing more than a definition of functions and events that once implemented allow any network participant to interact with such token for querying total token supply, querying an account’s token balance, transfering tokens between accounts, and approving token allowances.

By following the ERC20 standard newly created tokens can take advantage of numerous DeFi primitives already available in the blockchain. With that in mind I’ve implemented the options exchange to adopt tokenized options, allowing option writers to easily manage them, for instance for transfering options to a third-party willing to purchase them.

My take on tokenization was to incorporate a base ERC20 implementation into the project’s repository and make all smart contracts that I needed tokenized to inherit from it:

import "../utils/ERC20.sol";

contract OptionToken is ERC20 {

	// contract source code
	
}

contract CreditToken is ManagedContract, ERC20 {

	// contract source code
	
}

The base implementation allows derived contracts to override base functions definitions for implementing specific behavior such as the credit token interest rate accrual mechanism.

Stablecoins

Stablecoins are cryptocurrencies designed to minimize the volatility of the price of the stablecoin, relative to some “stable” asset or basket of assets. A stablecoin can be pegged to a cryptocurrency, fiat money, or to exchange-traded commodities.

This project adopts stablecoins pegged to the US dollar. Traders can deposit any of the accepted stablecoins as balance for writing options. It’s worth noting that these stablecoins are also ERC20 compliant, as to reinforce the importance of this standard. For reference, the table below depicts the market cap for the five biggest stablecoins at this time:

Name Code Market Cap
Theter USDT $ 30.76B
USD Coin USDC $ 7.28B
Multi-Collateral Dai DAI $ 2.07B
Binance USD BUSD $ 1.83B
Paxos Standard PAX $ 681.87M

I’ve decided to adopt stablecoins instead of other cryptocurrencies (such as ether itself) in the hopes of making the options exchange more palpable and appealing to traders that may not be insterested in being exposed to non stable cryptocurrencies while trading options. Also, this decision has helped to reduce code complexity by eliminating the need to constantly perform currencies value conversions between one another.

Collateralization

Collateralization is the use of a valuable asset to secure a liability. It is a heavily adopted concept in the DeFi space.

In this project every option is backed by a stablecoin deposit provided as collateral, and if an option writer defaults on his liability, the option holder may seize the asset to offset the loss. Collateralization of assets gives holders a sufficient level of reassurance against default risk.

You can get more details on the exchange’s collateralization requirements in the collateral allocation section of the repository documentation, in which I present the ad-hoc formula that’s being used to achieve improved capital efficiency.

Oracles

One of the drawbacks of dapps is that they are isolated from the real-world and are only able to read data that is already persisted in the blockchain. Relying on off-chain data would break the chain of trust, since it would be impossible for other network participants to audit such data to make sure it wasn’t forged.

Fortunately there’s a solution to this impediment, Oracles! An oracle is a third-party blockchain component that allows smart contracts within ethereum to receive external data from outside of their ecosystem. For this project decentralized price feed oracles are being used, which employ on-chain consensus protocols for providing tamper-resistant, high-quality, and up-to-date price readings.

regular-graphs

The options exchange takes advantage of these decentralized price feeds for fetching underlying prices updates for calculating options intrinsic values and collateral requirements.

Liquidity pools

A liquidity pool is a smart contract that gathers funds from individuals denominated liquidity providers which are then used to facilitate decentralized trading. As the name suggests liquidity pools provide “liquidity” to the market, i.e., they make it possible for traders to quickly purchase or sell an asset without causing a drastic change in the asset’s price, and without subjecting traders to unfair prices, which would be one of the consequences of lack of liquidity.

The options exchange itself is meaningless unless there’s enough liquidity to make options trading feasible. For instance, why would a trader write options if there were no one to buy them from him/her? and why would another trader buy options if his/hers strategy is dependant on selling these options on a short notice if there were a chance of not finding someone to sell them to? The answer is simple, there’s little reason to trade options in non-liquid markets. That’s why in the absence of organic liquidity there’s a need to deploy a liquidity pool to promote the exchange.

A liquidity pool should be designed to slightly favor its providers, as to incentivize them to allocate capital into the pool for increasing the supply and circulation of options in the market.

Particularly in the case of options trading the liquidity pool smart contract is required to implement a robust option pricing model in order to perform successfully and generate profits for its providers.

As of the time of this writing a linear interpolation model liquidity pool is being implemented for the options exchange that will be fed with parameters calculated from an empirical options pricing model I described in this blog a while ago.

Governance

Last but not least, governance defines a framework of on-chain rules and procedures that regulates the operation and evolution of a DeFi application. It’s through the governance framework that decisions such as modifying protocol parameters (ex: fees, interest rates, etc), issuing tokens, distributing profits and modifying protocol behaviors/functionality gets made.

Governance functionality is also defined in smart contracts, as every other aspect of dapps, and there are at least three levels of control according to who holds power to make decisions and take action:

  • Dictatorship
  • Council
  • Democracy

Usually a new protocol starts as a dictatorship of its main developer(s), then shifts to a council of early adopters and eventually reaches a democracy of anyone interested in participating and willing to invest in the protocol.

The options exchange project’s governance functionality is still incipient. Upon deployment it will be a dictatorship with a plan to distribute governance tokens to early adopters to shift towards a council as quickly as possible.

Status & next steps

We have gone through a functional overview of my decentralized options exchange project and cleared important DeFi concepts pertinent to better understanding it. Now you may be wondering what’s the current status of the project and possible next steps? see below for an answer.

This project is in alpha phase, and available on kovan testnet for evaluation (browse the documentation for more info on how to interact with it). There are a few major technical challenges that still need to get dealt with for this project to enter the beta phase and eventually be ready for deployment to mainnet:

  • Design and implementation of a liquidity pool, which will involve knowledge in finance and option pricing models (in progress)
  • Development of a dapp front-end application to make the exchange accessible to non-developers
  • Allow deposit/withdraw of underlying assets (ex: ETH, BTC) so they can be provided as collateral for writing options against them
  • Improvement of the incipient governance functionality

Closing thoughts

DeFi is a very innovative field. What I find most appealing is that some popular derivative protocols are yet inefficient in some ways, which means there is a lot of room for new solutions to come along.

I believe the advent of stablecoins and ingenious DeFi protocols are laying the foundations upon which more accessible and efficient solutions will be built, and its amazing that anyone with a software development and financial background can take part in this transformation.

My options exchange experimental project has been an edifying adventure, helping me get familiar with the solidity programming model and the overall DeFi ecosystem. There’s still a lot to learn, and I believe the best way will continue to be getting my hands dirty and keep improving this project, stay tuned.


Sources

[1] “Why ‘DeFi’ Utopia Would Be Finance Without Financiers: QuickTake”. Bloomberg. 2020-08-26. Retrieved 2020-10-06.

[2] Ehrlich, Steven. “Leading ‘Privacy Coin’ Zcash Poised For Growth Following Placement On Ethereum”. Forbes.

Jan 28, 2021 - Code fluency

More than a decade ago the Using FizzBuzz to Find Developers who Grok Coding blog post, by Imran Ghory, brought attention to the fact that most computer science graduates can’t code simple problems out of the box. If you haven’t heard of it I recommend reading it for more context.

Over the past few years as I started spending more time recruiting developers for my team, I was able to experience exactly what Imran describes in his blog post, having the opportunity to draw my own (additional) conclusions about it.

First, let me confirm what you already know and probably experienced yourself conducting interviews, it’s true, the vast majority of recent graduates struggles to complete our “screening test” which is comprised of four really basic questions (two FizzBuzz style questions, and two conceptual open-ended questions) that experienced developers take at most ten minutes to solve.

From my point of view this phenomenon is mainly a consequence of a lower code fluency level among young developers, i.e. the ability to read and produce code with speed, accuracy, and proper expression, which as with any language (or idiom) comes with constant practice and not necessarily indicates that a person isn’t a good fit for a position in software development.

To achieve code fluency in a programming language a developer must at the most basic level be familiarized with its syntax and know how to properly declare variables, use boolean and arithmetic operators, write conditional statements, for-loops, declare functions/methods, work with arrays, define classes and instantiate objects. If a developer doesn’t have this covered he/she will definitely struggle to produce working code, even if he/she understands the problem and knows a solution for it.

At this point we can raise some questions: are colleges in general providing enough practical programming classes? what exactly makes some candidates more fluent in code than others?

One trivial observation I made was that there’s a strong correlation between recent graduates who perform well and those that actively code in their free time. It could be a hobby project, coding katas, or learning new languages and frameworks. Of course, by practicing more they become better prepared to solve problems at interviews, and more fluent in code, but more than that it’s also an indication that they enjoy coding and are willing invest their free time (which recent graduates early in their lives more often than not have plenty) to improve their skills.

Another, more problematic, thing I noticed is that besides not being able to code problems most young developers aren’t able to read code properly as well. Take the following snippet, which I regularly bring up at entry level interviews:

Person a = new Person();
a.name = "Bob";

Person b = a;
b.name = "Jane";

print(a.name); // (1)
print(b.name); // (2)

a = null;

print(b.name); // (3)
print(a.name); // (4)

After presenting it and defining a base programming language (since some languages may handle variables differently than others according to their type) I ask what’s the expected outcome for (1), (2), (3) and (4). Sure, it’s a tricky question that messes with variables and references, but not hard at all, and it shouldn’t take more than thirty seconds for the average developer to answer it. Nevertheless I came to accept that most junior developers will fail this test at least partially.

I consider failing this and a few others code reading challenges more problematic, and not only a matter of lack of code fluency, because i) we developers spend an order of magnitude more time reading code (our own and from other developers) than writing and ii) it reveals a cognitive bias in the developer mental model of how their code will behave that has the potential to introduce furtive bugs in the codebase not always detectable by a compact test suite. Providing feedback in unsuccessful interviews is a subject of its own, be that as it may these misconceptions should be brought to light and dealt with as soon as possible for the benefit of the developer and the company he/she starts working for.

In sum achieving code fluency is the first step in the ladder for becoming an experienced software developer. A large portion of young developers haven’t taken this step yet, and are actually further behind due to misconceptions about how code behaves. In turn those who have are more likely to succeed at job interviews. Once this competency level is reached and a developer becomes fluent in code he/she can aim for higher grounds such as becoming proficient in data structures, algorithms, design patterns, systems architecture and so forth.