diff --git a/umad-04-lnurlp-response.md b/umad-04-lnurlp-response.md index 9ef08bc..6b6207f 100644 --- a/umad-04-lnurlp-response.md +++ b/umad-04-lnurlp-response.md @@ -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, }, ], @@ -65,3 +57,73 @@ The full structure of the LNURLP response is: The signature here is over `sha256_hash( (eg. "$bob@vasp2.com") + 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. diff --git a/umad-05-payreq-request.md b/umad-05-payreq-request.md index b265e5d..b216afb 100644 --- a/umad-05-payreq-request.md +++ b/umad-05-payreq-request.md @@ -22,7 +22,7 @@ The body of the request is a JSON object with the following fields: // See LUD-18 for details. }, - // 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.