Skip to content

Commit

Permalink
Merge pull request #11 from uma-universal-money-address/feat/decimals…
Browse files Browse the repository at this point in the history
…details

Add more details to the description of the decimals field with examples.
  • Loading branch information
jklein24 authored Dec 19, 2023
2 parents f955495 + a8fe012 commit 56e4e6a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 16 deletions.
92 changes: 77 additions & 15 deletions umad-04-lnurlp-response.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,14 @@ The full structure of the LNURLP response is:
"symbol": string, // eg. "₱",
"minSendable": number,
"maxSendable": number,
// Estimated millisats per "unit" (eg. 1 cent in USD)
// Estimated millisats per "unit" (eg. 1 cent in USD). A double-precision floating point number.
"multiplier": number,
// Number of digits after the decimal point for display on the sender side. For example,
// in USD, by convention, there are 2 digits for cents - $5.95. in this case, `decimals`
// would be 2. Note that the multiplier is still always in the smallest unit (cents). This field
// is only for display purposes. The sender should assume zero if this field is omitted, unless
// they know the proper display format of the target currency.
"decimals": number,
},
{
"code": string, // eg. "BTC",
"name": string, // eg. "Bitcoin",
"symbol": string, // eg. "₿",
"minSendable": number,
"maxSendable": number,
"multiplier": 1 // estimated millisats per "unit" (eg. 1 cent in USD)
// Number of digits after the decimal point for display on the sender side, and to add clarity around what the
// "smallest unit" of the currency is. For example, in USD, by convention, there are 2 digits for cents - $5.95.
// In this case, `decimals` would be 2. Note that the multiplier is still always in the smallest unit (cents).
// In addition to display purposes, this field can be used to resolve ambiguity in what the multiplier
// means. For example, if the currency is "BTC" and the multiplier is 1000, really we're exchanging in SATs, so
// `decimals` would be 8.
"decimals": number,
},
],
Expand Down Expand Up @@ -65,3 +57,73 @@ The full structure of the LNURLP response is:

The signature here is over `sha256_hash(<receiver UMA> (eg. "[email protected]") + nonce + timestamp)`.
The receiving VASPs `signingPubKey` can be used by the sending VASP to verify the signature as described in [UMAD-02](/umad-02-keys-and-authentication.md).

## Currency examples

Here are some additional examples of the `currencies` field to illustrate how the `multiplier` and `decimals` fields work.

```json
{
"code": "USD",
"name": "US Dollars",
"symbol": "$",
"minSendable": 1,
"maxSendable": 1000000, // 1M
"multiplier": 23400,
"decimals": 2
}
```

In this case, the `decimals` field is 2, indicating that the smallest unit of the currency is cents (one hundredth of a dollar).
The `multiplier` field is 23400, indicating that there are 23,400 millisats per USD cent. This struct also indicates that
the receiving user can receive between 1 cent and $10,000 USD. If a sender wanted to send $5.95 USD, they would specify
`amount: 595, currency: USD` in their [payreq request](/umad-05-payreq-request.md), which should in turn create a Lightning
invoice for 13,923,000 millisats (595 * 23,400) plus applicable conversion fees.

```json
{
"code": "BTC",
"name": "Bitcoin",
"symbol": "",
"minSendable": 1,
"maxSendable": 100000000, // 100M
"multiplier": 1000,
"decimals": 8
},
```

In this case, the `decimals` field is 8, indicating that the smallest unit of the currency is SATs (one hundred millionth
of a BTC). The `multiplier` field is 1,000, indicating that there are 1,000 millisats per SAT. This struct also indicates
that the receiving user can receive between 1 SAT and 1 BTC. If a sender wanted to send 0.0000001 BTC (10 sats), they would
specify `amount: 10, currency: BTC` in their [payreq request](/umad-05-payreq-request.md), which should in turn create a
Lightning invoice for 10,000 millisats (10 * 1,000) plus applicable conversion fees.

```json
{
"code": "USDC",
"name": "USDC",
"symbol": "USDC",
"minSendable": 100000, // 100K
"maxSendable": 10000000000, // 10B
"multiplier": 2.34,
"decimals": 6
}
```

In this case, the `decimals` field is 6, indicating that the smallest unit of the currency is one USDC / 10^6.
The `multiplier` field is 2.466, indicating that there are 2.466 millisats per USDC/10^6. This struct also indicates that
the receiving user can receive between 1 USDCent and 100,000,000 USDCents. If a sender wanted to send 5.95 USDC, they would
specify `amount: 5950000, currency: USDC` in their [payreq request](/umad-05-payreq-request.md), which should in turn create
a Lightning invoice for 14,677,700 millisats (5,950,000 * 2.466) plus applicable conversion fees.

## Note for very small currency units

If the smallest unit of a currency is very small (eg. `multiplier` is .0001), it may be necessary to round up to a larger
unit when actually sending the payment so that the `amount` field in the [payreq request](/umad-05-payreq-request.md) is
can fit in an int64 and can be represented in millisats. For example, DAI has 18 decimals, so the smallest unit is 10^-18.
In this case, trying to send 20 DAI would result in an `amount` of 20 * 10^18, which is too large to fit in an int64. For
this reason, the maximum `decimals` allowed is 8. If a currency has more than 8 decimals, the `multiplier` should be
increased to reduce the number of decimals. For example, if a currency has 10 decimals, the `multiplier` should be
`100 * the number of millisats per the real smallest unit`, and you should set `decimals` to 8. Tweaking the `multiplier`
and `decimals` fields in this way should allow the smallest unit to be represented in millisats and fit in an int64,
although it may result in some loss of precision.
2 changes: 1 addition & 1 deletion umad-05-payreq-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The body of the request is a JSON object with the following fields:
// See LUD-18 for details.
<json payerdata>
},
// This is the amount in the smallest unit of the specified receiving currency (eg. cents for USD).
// An int64 - This is the amount in the smallest unit of the specified receiving currency (eg. cents for USD).
"amount": number,
// The currency code of the receiving currency (eg. "USD"). This must be one of the currencies returned in the
// LNURLP response.
Expand Down

0 comments on commit 56e4e6a

Please sign in to comment.