Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: decentralised interest rate application #148

Open
mikehearn opened this issue Oct 30, 2019 · 2 comments
Open

Feature request: decentralised interest rate application #148

mikehearn opened this issue Oct 30, 2019 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@mikehearn
Copy link
Contributor

mikehearn commented Oct 30, 2019

This is a draft design document for interest rates support in the tokens SDK.

Overview

Some users want to apply interest rates to their tokens.

This feature can be used to implement different kinds of monetary policy. For instance, an unbacked token with a positive interest rate that decreases to zero over time could be used to implement a form of monetary distribution similar to what Satoshi implemented for Bitcoin, but without the special privileges awarded to miners. Such coins would just grow in your hands until the total monetary limit is reached.

More conventionally, commercial banks may use the feature to share investment returns with users, or even share investment failures with users by applying a negative interest rate. And central bank issued tokens may attempt to socially engineer particular outcomes, typically GDP growth, by forcing people to spend their savings or lose them. Charging negative interest is a more direct and thus more easily measured and understood mechanism than inflating the currency, which inherently creates distortions in the economy.

Problem statement. The tokens SDK does not implement interest rates. An oft-proposed approach is to periodically bring tokens back to the issuer for value adjustment. This creates problematic privacy, scaling, availability and incentive problems. In particular holders of tokens are not incentivised to return to the issuer if they'd face a negative interest rate, even if they're using tokens where they previously agreed to such negative rates e.g. because the token represents a share in an investment fund. We'd like a better approach.

Commentary. Negative interest rates have historically been seen as impossible or obviously absurd, due partly to lack of enforcement ability. They are deeply controversial and unpopular. We are not unaware of this unpopularity (in fact Switzerland has -0.75% rates today). But even in a world where everyone used Tokens SDK tokens as a replacement for cash, Corda is a general platform. An attempt to force people to use tokens with negative rates would result in people creating their own tokens, and building purely digital FX/OTC markets for them, as we've seen in the cryptocurrency world. Negative rates are most often talked about as a way to force people to spend money, given the apparent contemporary difficulty of creating inflation, thus boosting GDP. As GDP is the primary metric by which economists and politicians are judged this is seen as inherently good. But economic activity for the sake of gaming the measurement criteria of certain social classes is the fallacy of a planned economy. Policymakers who want to use them should consider campaigning for political leadership to be judged by other metrics instead. A focus on GDP growth at any cost will lead to either abandonment of CB managed currencies in favour of privately issued tokens e.g. Libra, or the totalitarianism required to avoid it.

Goals

  • Small extension of the existing code: demonstrate the cut lines of the feature, not implement full blown support.
  • No dependence on an issuer node, thus avoiding scaling bottlenecks.
  • Issuers should not get to see the chain of custody transactions (even if protected by enclaves or cryptography).
  • Incentive compatible: users should not be able to avoid negative rates if imposed.

Non-goals

  • Management tools, GUIs or other infrastructure to manage the setting of rates.
  • Support for very rapidly changing rates. We assume for scaling reasons that rates are adjusted only rarely, as today.
  • Solving dust limits.

Design

Design outline

The core idea is to make tokens self-inflating or deflating via the contract logic. Currently the smart contract enforces that during a payment the outputs sum to the value of the inputs. There's no requirement this be so, which is why the contract has to enforce it in the first place.

A new type of linear state can be defined which contains a list of interest rate changes over time (this is the source of the "no constant rate changes" non-goal). Only the issuer of the token may update this state. The rates state is included as a reference state into all transactions that spend the tokens, this is enforced by the token contract.

Each token state contains a timestamp of when the token last had interest applied.

The token contract then examines the timestamp window in the transaction header and takes the start of the time window (NOT the midpoint, as that'd allow arbitrary inflation). It then walks back through the history of rate changes in the ref state, from the tx timestamp until the "last applied" timestamp. It thus obtains a record of what rates were in force during the time this token was static, and can then apply the calculations to verify the final value.

Using tokens from other apps

The token state object should expose a utility method to do this calculation. This logic is of course used in the payment flows, which can invoke it to calculate the expected value during token movement. It should also be used by any other app that wishes to inspect the value of a token state and calculate its "true" value, e.g. if another app allows tokens to be used as reference states as a proof of solvency. Failure to use the interest-applied rate would be a critical bug in the other apps, so, as part of this feature, it may be desirable to make the "true" value of the token private and expose only a getter as a way to calculate the value of the token, however, this would probably be API incompatible. It's possible a new token type should be created, but, the details of that are left for the real design doc (this GitHub issue is only a starting point).

Calculating the monetary base

If the issuer wants to know how many tokens are in circulation at a given moment it can just apply the rate history to all issued tokens to arrive at how much would exist, if all tokens moved at that instant. From an economics perspective this should be sufficient as it's not the historical amount on the ledger that matters but rather how much is actually available to spend.

Time-varying balances in the API

The current Corda API doesn't directly expose any notion of balance. The Tokens SDK should expose such a notion but add support for querying "my expected balance at time T" which would use the new code on the state to apply the rates.

Dust limits

A negative rate erodes tokens such that their value trends to zero without ever actually hitting it.

At some point the value of a token is so low that it doesn't really make sense to store or work with it anymore. This is especially true if there are transaction fees of any sort. In the Bitcoin world we called this "dust" and it could be a significant problem. With time-varying transaction fees, the dust limit is itself variable.

Solving the problem of dust is a non-goal for three reasons:

  1. The obvious approach of letting an issuer set their own dust limit and then forcing erasure of any token states that fall below that value is wide open to hacking and errors destroying money incorrectly. It could also be used maliciously as another way to try and force people to spend their tokens, by progressively raising the limit.
  2. It's unclear how transaction fees in Corda will shake out, if at all. It very much depends on policies selected by token issuers, wallet developers and notary coalitions. The dust limit may in fact vary between users.
  3. Dust was a problem in Bitcoin primarily because of very high per-byte tx fees. If fees aren't levied per-byte or per-input, then the cost of aggregating lots of tiny outputs may be low or zero, meaning dust isn't really a problem unless a wallet itself runs out of funds.

Conclusion

This issue lays out a design for applying interest rates to tokens in a decentralised, privacy-preserving manner. Tokens never need to be returned to the issuer for value adjustment, yielding large scaling and availability benefits. Tokens representing shared investments may distribute the gains or losses in equally privacy preserving and decentralised manners.

With this power comes responsibility. Tokens that force people to spend them, in order to generate artificial activity for political/marketing reasons, can and should find themselves outcompeted in the market. Corda's transaction and multi-app interop features enable low trust discovery and OTC trading of tokens, and the cryptocurrency community has done many experiments with building truly decentralised trading venues. Such venues would be much easier to build with the facilities of the flow framework.

@RyanGled
Copy link

RyanGled commented Oct 30, 2019

This has been a topic of discussion for some time at Ivno Towers, so some points that may or may not be helpful:

  • We've been considering the concept of market cut-offs, and how this could (should) differ to the tradition central/commercial bank model.
    Our earliest design was to choose an arbitrary time and apply rate changes to the token within this time window. The problem you have here is that if the timewindow was everyday at 00:00, in a negative interest rate environment there would be an influx of outgoing transactions at 23:59, and/or responding parties wouldn't accept transactions until 00:01, meaning an unnecessary load on-ledger.
    Mike, I think your concept of 'walking the rate changes' and using an contract-adhered reference state largely fixes this. We assumed a regularly occuring timewindow here. IE - if you hold a cash token for 7 days, is it 7 x 1 day(s) interest applied, or is it better to apply on the next transaction in a more intricate fashion. Expanded below:

  • Is the interest calculated and applied upon the next state transition of the token (like you say, last applied -> tx timestamp)?

  • Can the 'change' be used in the initial transaction? Any appreciation is rightfully the owners to use at the time of transacting I expect.

  • In a negative environment, presumably we will need to check the 'real' value of the token quantity prior to using said tokens in any transaction to ensure users aren't left with a negative balance AFTER a transaction completes (unless this is by design, of course).

  • All of the above points naturally lead to a synchronous or blocking flow, prior to the intended token transaction taking place. Is there a potential bottleneck/DoS vector when requesting up-to-date reference states? If, say they were used for high-frequency trading, will there be a rush on the Issuer to request the ref state and thus the new rate?

Just a jumbled brain dump as I don't have a great deal of time - I'll try to expand on these thoughts a bit more eloquently when possible. Overall I think this is an exceptional start, and thanks for starting the discussion Mike!

@mikehearn
Copy link
Contributor Author

In a negative environment, presumably we will need to check the 'real' value of the token quantity prior to using said tokens in any transaction to ensure users aren't left with a negative balance AFTER a transaction completes (unless this is by design, of course).

I guess you can't end up with negative token amounts, that'd be an obligation wouldn't it. The contract should prevent that from happening: the tx would be invalid if there aren't enough tokens to make the payment after interest rates are applied.

However you don't want to discover that at tx verification time, so the vault/SDK needs some notion of balance with rates applied. I think if there's a getter method like this on token states, it could be used:

fun applyInterest(interestRateHistory: InterestRateHistory): Amount<T>

But of course software has to know to use it in preference to the current value, and there has to be a way to actually get the interest rate history easily. Perhaps the SDK should provide canned vault queries for that.

WRT requesting reference states - good question. How people get informed about rate changes in undefined, but the ref states work we did offers an answer: you have to do wrap your spend inside a loop that catches the notary exception thrown when a ref state is invalid, fetches the latest version from the issuer and then retries. There's a system provided flow that handles this for you:

https://docs.corda.net/api/kotlin/corda/net.corda.core.flows/-with-referenced-states-flow/index.html

This design does indeed mean the provider could be slammed with requests for the new data the moment it starts to apply. Good point and good catch. Corda isn't really designed for HFT so we have a cheap-ass "get out clause", but, it'd be nice to have a better solution. This feels like an incremental sub-unit of work on the path to implementing full DDGs. One possible solution is to for the issuer to pre-push the new rate state changing tx to known high priority customers. This won't work today because that tx wouldn't have a notary signature, but with some vault work we could store such an invalid tx such that when it does get notarised, the notary can just provide its signature that the tx has been committed in the error response saying the ref state was consumed. The node can then apply that sig to its local copy of the tx and send it down the usual recordTransaction codepath. We assume notaries can keep up with the load implicitly already.

Of course that takes us to the direction of duplicate copies of the same reference data on each notary, which the API doesn't assist with today. More work would be useful there to flesh out the multi-notary+ref states story.

None of this is actually much coding work. It's all very incremental and just needs careful design.

Thanks for the feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants