The problem statement is simple; the relative instability of crypto prices makes using them for ledger-based authorizations hard to deal with.
With ledger-based authorizations (LBA) we leverage in-app purchase (IAP) payments made, to authorize for features in apps. When the value of these payments fluctuate in some currencies (ethers or bitcoins) versus others (dollars), it’s very difficult to maintain fair prices for access across all currencies and necessary checks and balances of whether sufficient payments were made.
We do not want app-developers to continuously update prices in their apps for the various IAPs.
In-fact, constantly adjusting prices of in-app purchases (IAPs) breaks ledger-based authorizations (LBA). LBA’s core mechanism is to allow authorizations for features be based on money transactions made from the user to the developer as they appear on public ledgers: so as not to force the developer to code up a complex system of who paid for what (although with LBA they can still do that if they choose to; with an address per IAP SKU).
Assume an app allows access to some extra features if a user paid $2 USD within the last 7 days. If a user paid $2 USD on Monday, they should expect access to said features on the following Thursday and Saturday.
Now, consider the following historical prices of ethers and bitcoins against the US dollar several weeks back:
|Monday, April 12, 2021 @ 10pm PST||$2||.000033||.00092|
|Thursday, April 15, 2021 @ 10pm PST||$2||.000031||.00081|
|Saturday, April 17, 2021 @ 10pm PST||$2||.000035||.00091|
Assume the developer sets the prices of the IAP on Monday. If a user comes on Monday and makes the purchase, they’re charged either
0.000033 bitcoins or
0.00092 ethers. After payment they’re allowed access.
On Thursday the prices of both bitcoins and ethers shot up. If the developer does not adjust the IAP cost in ethers and bitcoins, they’ll be overcharging versus the US dollar. Customers paying in US dollars on Thursday will still only pay $2. Customers paying in bitcoins should really pay
0.000031 bitcoins, but will be paying
0.000033 bitcoins. Same problem faces customers paying in ethers.
Now, should the developer react to fluctuations and do the extra work to adjust the prices on Thursday, then everything is OK, until Saturday. The new customers paying on Thursday pay the right value. The customers who paid on Monday paid more bitcoins and ethers than is expected on Thursday, they’ll continue to be able to access the extra features.
Come Saturday, however, unless the developer adjusts the IAP prices for ethers and bitcoins once more, they’ll be providing a discount in those currencies versus the US dollar. But if the developer adjusts the IAP prices for the cryptos, they’ll deny access of customers from Monday and Thursday. The developer would break the promise of allowing access to the extra features to anyone who paid up $2 USD worth (in any currency) within the last week. So although customers from Monday paid
0.000033 bitcoins and customers from Thursday paid
0.000031 bitcoins, neither would meet the new Saturday price of
0.000035 bitcoins; hence being denied access to features they thought they paid for.
In ledgers.js starting with version
4.2.0 we’ve added two new APIs:
Both APIs allow the app developer to configure IAPs in US dollars, yet easily collect cryptos as payment.
To support the new APIs and flows a new overhide-ex-rate service was added:
Furthermore, the ethers and bitcoins services had a
tally-dollars query parameter added to their
GET /get-transactions APIs:
Keep in mind that what we’re after is for a customer to pay a developer sufficient cryptos such that after converting to dollars, the amount in dollars covers the dollar-cost of being allowed to use an app-feature, the IAP.
Towards this end, the overhide-ex-rate service keeps track of exchange rates between cryptos and US dollars, on the hour.
When it’s invoked to convert a dollar amount to cryptos (getFromDollars), it looks at the last 3 hours for the lowest dollars/cryptos rate — highest cryptos yield — and returns it.
When used to convert some number of transactions from cryptos to dollars (getTallyDollars), it looks at the last 3 hours prior to each transaction for the highest dollars/cryptos rates (highest dollars yield) and returns those.
We do not try to use some perfect rate at a given time.
It takes time for wallets to process transactions and we do not need to be extremely precise.
Letting the customer pay the developer the highest amount of cryptos — after conversion from dollars over last several hours at time of purchase — and letting the code check for coverage of the cost of an IAP using the highest amount of dollars over those same hours, means every purchase will get covered despite rate fluctuations over time.
Let’s try to illustrate the discussion:
Imagine the customer was to pay for a $2 IAP (transaction 1) and then wanted to add $3 (transaction 2) to have access to a $5 IAP.
The customer chose to pay in ethers.
Consider the blue line in the diagram to be the exchange rate at the time.
Each transaction looks at exchange rates over some lookback period, indicated by the blue shadows.
When the customer is paying for each transaction, we want to charge the highest amount of ethers per dollar over the lookback period — the red arrows.
When the system checks whether the customer has made sufficient payments to satisfy ledger-based authorizations for the $5 IAP, we want to check for the highest amount of dollars paid over the lookback periods, the green arrows.
As such, the customer here pays:
The total amount of ethers does not matter — it fluctuates anyways. All that matters are ethers paid at a given time.
When the app checks for sufficient payments it sees these payments in ethers but calculates the dollar amount at the lowest rates (highest dollar yield) — the green arrows:
When we tally the US dollar amounts we see that the customer paid $5.05, which sufficiently covers the $5 IAP authorization cost.