Constant Rate Issuance Sales Protocol

01.25.2022|Dave WhiteFrankieJustin Roiland

Introduction

This paper introduces the Constant Rate Issuance Sales Protocol, or CRISP, a pricing mechanism that aims to sell NFTs at a targeted rate over time.

If we want to sell 100 NFTs per day but are on pace to sell only 10, CRISP will slowly decay the "buy it now" price. If we want to sell 100 NFTs per day but are on pace to sell 200, CRISP will rapidly increase the “buy it now” price with every new sell.

We provide a Python notebook modeling the mechanism's behavior, as well as a reference Solidity implementation.

Motivation

Imagine you have an unlimited set of NFTs that you want to sell at a constant rate — say, 100 per day.

You might design an auction system to achieve this goal. You could sell all 100 in a single auction, or perhaps hold 100 different auctions of one NFT each.

However, the user experience of an auction can be quite unwieldy — auctions cost gas, and we want users to be able to buy one of these NFTs at any time, without having to wait for an auction to terminate.

Mechanism

Overview

CRISP tracks the rate at which NFTs are being sold, and compares it to a target rate.

When NFTs are being sold too quickly relative to the target rate, we want to be able to adjust prices quickly. The higher the sales rate compared to the target rate, the faster we want to raise prices.

On the other hand, when NFTs are being sold too slowly relative to the target rate, we do not want to be too hasty to lower prices. After all, there had been sufficient demand to support the current price at some point in the past. As a result, we decay prices slowly over time.

Sales Rate

We measure the sales rate using an Exponential Moving Sum, or EMS.

The EMS is an adaptation of the Exponential Moving Average that is commonly used in quantitative trading to measure the accumulation of some quantity over a recency-weighted window of time. It is cheap to calculate and requires little storage.

The CRISP EMS in particular tracks the number of NFTs sold over a recent time period defined by sale averaging halflife. A sale averaging halflife of 100 would mean that a sale 100 blocks ago would add only

12\frac{1}{2}
to the current EMS.

The EMS at block 

bb
is defined recursively as:

EMSb=21sale_averaging_halflifeEMSb1+SbEMS_b = 2^{\frac{-1}{sale\_averaging\_halflife}}EMS_{b-1} + S_b

where

SbS_b
is a variable indicating the number of sales that have occurred in block
bb
.

Given two blocks,

b1b_1
and
b2b_2
, and assuming no sales occurred between the blocks, we have

EMSb2=2(b2b1)sale_averaginghalflifeEMSb1+Sb2EMS_{b2} = 2^{\frac{-(b_2-b_1)}{sale\_averaging_halflife}}EMS_{b1} + S{b_2}

We can translate a target sales rate to a target EMS using the above formula. Assuming we are targeting a rate of 1 sale every

nn
blocks, the target EMS should be

EMStarget=112nsale_averaging_halflifeEMS_{target} = \frac{1}{1-2^{\frac{-n}{sale\_averaging\_halflife}}}

(see Appendix for proof).

Raising Prices

If the current EMS is above the target, the sales rate is by definition too high. As a result, we want to charge more for the next NFT, because that will (presumably) reduce demand, or, at the very least, increase revenue.

The faster we are selling NFTs relative to the desired rate, the more quickly we should update prices. So, we define a variable

mismatch_ratio=EMScurrentEMStargetmismatch\_ratio = \frac{EMS_{current}}{EMS_{target}}

and then set

price=price(1+mismatch_ratioprice_increase_speed)price = price \cdot (1 + mismatch\_ratio \cdot price\_increase\_speed)

where price increase speed controls how quickly price reacts to differences between the target and observed rates.

In this example, we model CRISP over a period of 200 blocks. We are targeting one sale per 100 blocks, and using a sale halflife of 700 blocks. In the given period, we see purchases happening every 50 blocks, which is above our target. This pushes the EMS upward on every purchase, and price reacts accordingly.

Lowering prices

When the current EMS is below target, the sales rate is too low. As a result, we want to charge less for the next NFT, making it a more attractive purchase.

However, we want to decay prices slowly over time, because we managed to hit the target rate at previous prices and we don’t want to drop prices more than we have to.

Assuming the last sale happened on block

b1b_1
at
priceb1price_{b_1}
, the price on block
b2b_2
is then given by:

priceb2=priceb1e(b2b1)price_decay_halflifeprice_{b2} = price_{b1} \cdot e^{\frac{-(b_2 - b_1)}{price\_decay\_halflife}}

where price decay halflife controls the rate of decay.

Because we only want to decay price when the sales rate is below the target, if the current sale is the first since the sales rate dropped below the target price, we calculate decay starting from the block when the rate dropped below the target, not from time since the last sale.

In this example, we model CRISP over a period of 300 blocks. Again, we target one sale every 100 blocks. In the given period, only one purchase happens, on the 200th block. We see that the current EMS slowly falls over the first 200 blocks, but price does not start falling until around the 100th block, when the current EMS falls below the target. Since after the purchase, the EMS is still below target, price does not increase.

Full Example

An example of CRISP over a longer time period. At first, purchase rate is too high, so price increases with every purchase. After a period with no purchases, price and purchase rate roughly stabilize.

Code

A Python notebook and Solidity implementation are available at https://github.com/FrankieIsLost/CRISP.

Conclusion

We hope CRISP will unlock a host of cool and interesting NFT dynamics.

If you spot any problems or think of any improvements, we'd love to hear from you! You can reach us at @Dave__White, @FrankieIsLost, and @justinroiland on Twitter.

Appendix

Translating Target Sales Rate to Target EMS: Proof

Assume we are targeting a sales rate of 1 sale every nth block. Then, using formula (1), the EMS on the block of the 

kthk^{th}
sale is:

EMSk=2nsale_averaging_halflifeEMSk1+1EMS_k = 2^{\frac{-n}{sale\_averaging\_halflife}}EMS_{k-1} +1
=22nsale_averaging_halflifeEMSk2+2nsale_averaging_halflife+1= 2^{\frac{-2n}{sale\_averaging\_halflife}}EMS_{k-2} + 2^{\frac{-n}{sale\_averaging\_halflife}} +1
\vdots
=i=1k(2nsale_averaging_halflife)i= \sum_{i=1}^{k}(2^{\frac{-n}{sale\_averaging\_halflife}})^i

This is a geometric series which converges to

112nsale_averaging_halflife\frac{1}{1-2^\frac{-n}{sale\_averaging\_halflife}}

Hence, we can translate between target sales rates and target EMS.

Written by

Dave WhiteFrankieJustin Roiland

Disclaimer: This post is for general information purposes only. It does not constitute investment advice or a recommendation or solicitation to buy or sell any investment and should not be used in the evaluation of the merits of making any investment decision. It should not be relied upon for accounting, legal or tax advice or investment recommendations. This post reflects the current opinions of the authors and is not made on behalf of Paradigm or its affiliates and does not necessarily reflect the opinions of Paradigm, its affiliates or individuals associated with Paradigm. The opinions reflected herein are subject to change without being updated.

Copyright © 2024 Paradigm Operations LP All rights reserved. “Paradigm” is a trademark, and the triangular mobius symbol is a registered trademark of Paradigm Operations LP