Impossibility of DeFi Risk-Free Rates
This paper explores the idea of risk-free rates in trustless DeFi systems. The main result is that it is impossible, under a clearly stated set of conditions, to generate conventional risk-free rates. Here we are going to explore that by:
- Defining a DeFi risk-free rate
- Summarizing some key computer science results
- Proving DeFi risk-free rates are impossible
- Covering some basic implications
The technical treatment is in the paper. This is stylistic ‘cause it’s, you know, a blog.
First, let’s be clear we are limiting the scope of this discussion to trustless environments: tokens on decentralized permissionless blockchains, handed out via some randomized process. The precise details of that process do not really matter. As we discuss in the paper, randomness and decentralization are the essential features.
For such a token in an ideal DeFi system what is a risk-free rate? It’s a rate on a liability that will surely be paid without needing to trust anything beyond the system itself. This is going to be a smart contract — or collection of smart contacts — that never defaults so long as the system is running.
In the traditional finance world the analogy is a domestic currency government bond. The government can print whatever currency is required to always pay local currency debts. And this, in turn, requires trust the government won’t print “too much” currency and the like. We are not getting into a philosophical discussion about how governments can default on domestic debt or inflation or any of that. Read the paper for a clear and detailed presentation.
Proof in a decentralized permissionless environment means a public smart contract that validates risklessness. You pass in code and it tells you whether there is a risk of default. As all you can trust is “the system” this is the only available meaning. It doesn’t matter if this is 1 function or 10 — it’s all “the system” and conceptually one big program. That’s the idea behind the world computer.
Further, remember that if we are going to try to do dynamic-replication finance we need a construct that admits borrowing and lending at similar rates. For government bonds this is, approximately, repo. Leaving tokens at rest on-chain at zero is a non-starter as that doesn’t admit borrowing.
As we are talking about properties of smart contracts we need a bit of computer science theory. Most smart contract languages are what is known as Turing Complete. That’s a fancy way of saying they are normal, full-power, programming languages.
An important fact about Turing Complete programming languages is that we can’t prove many properties about arbitrary code. The famous Halting Problem result tells us that we cannot determine if an arbitrary piece of code will halt or run forever. This is not just saying it is difficult! The question is well-posed but no program can be written to answer it. A more general theorem by Rice extends this idea to many properties including questions like “does it use more than X memory while running?” or “is this function called more than Y times while running?” Any non-trivial property is what is called undecidable.
Yes, fees mean that real-world smart contacts aren’t truly Turing Complete. We will come back to that. Intuitively, the problem is that losing all your money in gas costs is the same as losing it in a default — it’s still gone and still represents risk.
We focus here on “arbitrary smart contact code” because it’s a decentralized permissionless system. If your smart contract interacts with the outside world it’s interacting with arbitrary code.
Now consider any piece of smart contract code. Let’s write a very simple function:
function ModifyContract(code, address)
for all lines where code can terminate do
InsertCodeBefore("b = CurrentBalance(address)")
InsertCodeBefore("TransferFrom(address, b+1, x)")
And compose that with our risk-free verifier:
newcode = ModifyContract(code, x)
Now we have a problem. The ModifyContract function is fine — it just scans the code and inserts a few lines. But this second function, that’s not allowed. It isn’t possible to build SolveHalting. Consequently, RiskFreeVerifier cannot exist.
This is a standard technique in computer science where we assume the existence of some function, write a bunch of unexceptional code around it, and show the composition of the assumed thing and the code we wrote violates a known theorem. It’s a proof by contradiction and, again, bog-standard computer science from an intro theory course.
But fees limit the runtime! Sure. Except that when you hit the gas limit and fail a) no loan occurs and b) you still pay the gas fees. A contract that might spend all your money proving it won’t lose it in a different way…that’s not risk-free. And any scheme where you collude with the validator to avoid leaking gas on failures — that’s either trusted (i.e. you control all the validators) or still risky (i.e you don’t).
Non-Turing Complete Languages
Now we could try to do this with a non-Turing-Complete language. Three issues pop up. First, it’s harder to construct such a language then you think. Second, having a construct which is limited still runs into Rice’s theorem. And third, it’s not clear what useful services can be built as the world generally runs on Turing-Complete languages.
Even awk and LaTeX are Turing-complete. So is Excel. Whether you can rebuild something like Uniswap in Python’s re language is a fascinating intellectual question. But it’s probably not a good homework assignment or business plan. Someone will surely try (as they should).
Can we fix this with some sort of money-printing contract? Short answer: no. Let’s say we have a function that prints tokens. That function is either open to all or restricted somehow.
If it’s open to all that means anyone can create an account, print some money, and transfer it anywhere. Everyone can have any bank balance at any time. That’s not an economic system. Recall: we can’t rely on trust.
If it’s restricted to a certain group of users then we have to trust them. This is a “central bank” and not trustless. Yes we can choose to “trust the DAO” — but that is decidedly different from relying only on the code. And there is clearly risk if that trust is violated.
Lastly, it might be open to all but capped. Rice’s theorem tells us, by a similar argument to the one above, that we cannot reliably check for code that will hit the cap and then default. Writing those wrapper functions is left as an exercise for the reader.
DeFi Is Incomplete
The tokens discussed here do not have risk-free rates. A more precise technical version of that statement is made in the paper . This means, in a formal sense, the market is incomplete. Further, even if you are trading trusted tokens which do not themselves have this property, you are probably paying fees in a native token which does. All activity on decentralized permissionless blockchains where fees are paid in native tokens touches this problem.
This has strong implications for financial engineering in DeFi. Traditional-finance-style derivatives trading won’t work the same way. More results are coming on that front and some progress can surely be made. But just like other impossibility results, we need to accept this limitation before we can begin to work around it.
Lastly, this is not directed at any particular token or protocol. What math does not permit will not be done. The goal of this, and other related research, is to move the state of the art forward by laying down clear boundaries. Finance, and science in general, deals with this all the time going back to the days of alchemy.
Financial engineering in DeFi will not look exactly like a copy-paste of TradFi, in part because of this result. More innovation — more technical derivative-finance innovation — is required and the destination remains a bit hazy. That’s fine. It’s also unavoidable.