From 3b9dc1312fa8f147d035becb60a3580734bc6ab0 Mon Sep 17 00:00:00 2001 From: Ethan Rose Date: Thu, 16 Mar 2023 15:11:46 +0800 Subject: [PATCH 1/7] LUD-21: Guarantee payment amount in a localized currency using `payRequest`. --- 21.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 ++ dependencies.dot | 8 ++++--- 3 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 21.md diff --git a/21.md b/21.md new file mode 100644 index 0000000..964a548 --- /dev/null +++ b/21.md @@ -0,0 +1,60 @@ +LUD-21: Guarantee payment amount in a localized currency using `payRequest`. +================================================ + +`author: ethanrose` + +--- + +The idea here is that the recipient needs to receive an exact amount of fiat currency. Typically this is for a point-of-sale use-case where a lightning service is acting as a bitcoin-to-fiat payment processor. Currently, a sender would have to use their own calculator to determine how many sats to pay, and the recipient inevitably would receive the wrong amount. This is a massive hinderance to merchant adoption of lightning. + +## 1. `currency` record in payRequest details + +If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a different currency, it MUST alter its JSON response in the payRequest details response to include a `currency` field, as follows: + +```diff + { + "callback": String, + "maxSendable": number, + "minSendable": number, + "metadata": string, ++ "currency": { ++ "options": ["SAT", "PHP"], ++ "default": "PHP", ++ "rateEstimates": { "PHP": 1400000.45, "SAT": 100000000 }, ++ "sendable": { ++ "min": { "PHP": 1, "SAT": 1 }, ++ "max": { "PHP": 50000, "SAT": 1000000 } ++ } ++ }, + "tag": "payRequest", + } +``` + +## 2. User interface for specifying currency + +If there is a `currency` record in the initial response, `WALLET` displays a modified interface: + +- If there is more than one currency in the `currency.options`, `WALLET` should give user a dropdown to change currencies. +- The selected currency option should default to `currency.default`. +- `WALLET` should display the currently selected currency to the user. +- The wallet should do a preliminary validation that the user has enough funds based on `currency.rateEstimates`. + - It is advisable to add 3% padding to the min/max available balance, as exchange rate fluctuations may cause the actual payment request to be higher or lower than expected. +- The sender may optionally display an estimated cost in the user's local currency by using `currency.rateEstimates` + +## 3. Including `currency` in callback parameters + +The wallet must add a query parameter to LNURL-PAY callback with value set to a JSON object: + +```diff +- amount= ++ amount=¤cy=PHP +``` + +## 4. User interface for reviewing & confirming the exchange rate + +`SERVICE` responds with a payment request (`pr`). Payment of this `pr` must guarantee that the recipient will receive the defined amount of currency. Typically, the `SERVICE` will generate these `pr`s with a quick expiry time (30-120 seconds) since they are locking an exchange rate. +- `WALLET` must display a confirmation screen where the user can review the amount that will be deducted from their local wallet (i.e. satoshi) and the amount that the external recipient will receive (i.e. philippine pesos). +- If the `pr` expires, wallet should either inform the user that the exchange rate has expired +- The `WALLET` may opt to automatically refresh the exchange by calling the callback again before the previous `pr` expires. + +If the user approves, they may tap a button to "confirm" acceptance of the exchange rate. diff --git a/README.md b/README.md index bd6fd25..e33d3ec 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ These are all the individual documents describing each small piece of protocol t | [18][18] | Payer identity in `payRequest` protocol. | [Blixt][blixt], [cliché][cliche], [ZBD Discord][zbd], [ZBD Telegram][zbd] | | [19][19] | Pay link discoverable from withdraw link. | [Blixt][blixt], [CoinCorner][coincorner], [SimpleBitcoinWallet][sbw] | | [20][20] | Long payment description for pay protocol. | [Alby][alby], [Blixt][blixt], [Clams][clams], [cliché][cliche], [Phoenix][phoenix] | +| [21][21] | Pay with localized currency amounts. | [Pouch.ph][pouchph] [alby]: https://github.com/getAlby/lightning-browser-extension [bos]: https://github.com/alexbosworth/balanceofsatoshis @@ -210,6 +211,7 @@ Tools for developers [18]: 18.md [19]: 19.md [20]: 20.md +[21]: 21.md Dependency Tree --------------- diff --git a/dependencies.dot b/dependencies.dot index 867d762..5b10ff3 100644 --- a/dependencies.dot +++ b/dependencies.dot @@ -19,17 +19,19 @@ digraph { 18[label="18 payer identity"] 19[label="19 mutual discoverability"] 20[label="20 long description"] + 21[label="21 pay in local currency"] { 01 17 } -> { 02 03 04 06 07 } // base protocols depend on URL format 04 -> { 05 13 } // lnurl-auth seed generation methods 03 -> 08 // fast withdraw 03 -> 14 -> 15 // balanceCheck/balanceNotify - 06 -> 11 // disposable lnurl-pay - 06 -> 20 // long description 06 -> 09 -> 10 // lnurl-pay successAction + 06 -> 11 // disposable lnurl-pay 06 -> 12 // lnurl-pay comments + 06 -> 16 // paying to user@domain.com 06 -> 18 // lnurl-pay payer ids + 06 -> 20 // long description + 06 -> 21 // guarantee payment amount in localized currency { 04 16 } -> 18 [style="dotted"] // loose relationship of payer id with lnurl-auth and lightning address - 06 -> 16 // paying to user@domain.com { 06 14 } -> 19 // mutually discoverable pay and withdraw links } From 285a85d3da3ad39609f8af6cc1afeb2f1ea54ab6 Mon Sep 17 00:00:00 2001 From: Ethan Rose Date: Mon, 20 Mar 2023 10:55:22 +0800 Subject: [PATCH 2/7] Add instructions re: currency.currencyParamSupported --- 21.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/21.md b/21.md index 964a548..ee9ce13 100644 --- a/21.md +++ b/21.md @@ -24,7 +24,8 @@ If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a differe + "sendable": { + "min": { "PHP": 1, "SAT": 1 }, + "max": { "PHP": 50000, "SAT": 1000000 } -+ } ++ }, ++ "currencyParamSupported": true + }, "tag": "payRequest", } @@ -41,15 +42,20 @@ If there is a `currency` record in the initial response, `WALLET` displays a mod - It is advisable to add 3% padding to the min/max available balance, as exchange rate fluctuations may cause the actual payment request to be higher or lower than expected. - The sender may optionally display an estimated cost in the user's local currency by using `currency.rateEstimates` + ## 3. Including `currency` in callback parameters -The wallet must add a query parameter to LNURL-PAY callback with value set to a JSON object: +Some services need to lock-in an exact exchange rate in local currency, while other services prefer using the unmodified LNURL-Pay flow. + +If SERVICE includes `currency.currencyParamSupported: true`, wallet must add a `currency` query parameter to the callback, and specify the `amount` in the currency: ```diff - amount= + amount=¤cy=PHP ``` +However, if `currency.currencyParamSupported` is false or undefined, the wallet must use millisats (standard LNURL-Pay callback!) + ## 4. User interface for reviewing & confirming the exchange rate `SERVICE` responds with a payment request (`pr`). Payment of this `pr` must guarantee that the recipient will receive the defined amount of currency. Typically, the `SERVICE` will generate these `pr`s with a quick expiry time (30-120 seconds) since they are locking an exchange rate. From d04066ebaec207875d52bc779e7e5a40a77d153e Mon Sep 17 00:00:00 2001 From: Ethan Rose Date: Tue, 21 Mar 2023 09:47:23 +0800 Subject: [PATCH 3/7] simplify the spec --- 21.md | 43 ++++++++++++++----------------------------- README.md | 2 +- dependencies.dot | 4 ++-- 3 files changed, 17 insertions(+), 32 deletions(-) diff --git a/21.md b/21.md index ee9ce13..e899113 100644 --- a/21.md +++ b/21.md @@ -1,15 +1,17 @@ -LUD-21: Guarantee payment amount in a localized currency using `payRequest`. +LUD-21: Pay in a different currency. ================================================ `author: ethanrose` --- -The idea here is that the recipient needs to receive an exact amount of fiat currency. Typically this is for a point-of-sale use-case where a lightning service is acting as a bitcoin-to-fiat payment processor. Currently, a sender would have to use their own calculator to determine how many sats to pay, and the recipient inevitably would receive the wrong amount. This is a massive hinderance to merchant adoption of lightning. +The idea here is to enable a merchant to receive an exact payment amount, in whatever currency their goods are priced in (i.e. their own fiat currency). A sender should be able to input the amount in the currency that they are invoiced in by the seller as well. + +Typically this is for a point-of-sale use-case where a lightning service is acting as a bitcoin-to-fiat payment processor. Currently, a sender would have to use their own calculator to determine how many sats to pay, and the recipient inevitably would receive the close-but-wrong amount. This bad experience is a hinderance to adoption of lightning as a cross-border payment system. ## 1. `currency` record in payRequest details -If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a different currency, it MUST alter its JSON response in the payRequest details response to include a `currency` field, as follows: +If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a different currency, it MUST alter its JSON response in the payRequest details response to include a `currency` object, as follows: ```diff { @@ -18,14 +20,11 @@ If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a differe "minSendable": number, "metadata": string, + "currency": { -+ "options": ["SAT", "PHP"], -+ "default": "PHP", -+ "rateEstimates": { "PHP": 1400000.45, "SAT": 100000000 }, -+ "sendable": { -+ "min": { "PHP": 1, "SAT": 1 }, -+ "max": { "PHP": 50000, "SAT": 1000000 } -+ }, -+ "currencyParamSupported": true ++ "code": "PHP", ++ "name": "Philippine Pesos", ++ "symbol": "₱", ++ "minSendable": 1, ++ "maxSendable": 50000 + }, "tag": "payRequest", } @@ -34,33 +33,19 @@ If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a differe ## 2. User interface for specifying currency If there is a `currency` record in the initial response, `WALLET` displays a modified interface: - -- If there is more than one currency in the `currency.options`, `WALLET` should give user a dropdown to change currencies. -- The selected currency option should default to `currency.default`. -- `WALLET` should display the currently selected currency to the user. -- The wallet should do a preliminary validation that the user has enough funds based on `currency.rateEstimates`. - - It is advisable to add 3% padding to the min/max available balance, as exchange rate fluctuations may cause the actual payment request to be higher or lower than expected. -- The sender may optionally display an estimated cost in the user's local currency by using `currency.rateEstimates` - +- The wallet should display the `currency.code` and/or `currency.name` instead of its default currency. ## 3. Including `currency` in callback parameters -Some services need to lock-in an exact exchange rate in local currency, while other services prefer using the unmodified LNURL-Pay flow. - -If SERVICE includes `currency.currencyParamSupported: true`, wallet must add a `currency` query parameter to the callback, and specify the `amount` in the currency: +In the next step of the LNURL-Pay flow, `WALLET` must include a `currency` query parameter in the callback along with the `amount`: ```diff - amount= + amount=¤cy=PHP ``` -However, if `currency.currencyParamSupported` is false or undefined, the wallet must use millisats (standard LNURL-Pay callback!) +- `SERVICE` must respond with a BOLT11 payment request (`pr`) with a short expiry time (i.e. 30 seconds) corresponding to the length of time the service is willing to guarantee the exchange rate. ## 4. User interface for reviewing & confirming the exchange rate -`SERVICE` responds with a payment request (`pr`). Payment of this `pr` must guarantee that the recipient will receive the defined amount of currency. Typically, the `SERVICE` will generate these `pr`s with a quick expiry time (30-120 seconds) since they are locking an exchange rate. -- `WALLET` must display a confirmation screen where the user can review the amount that will be deducted from their local wallet (i.e. satoshi) and the amount that the external recipient will receive (i.e. philippine pesos). -- If the `pr` expires, wallet should either inform the user that the exchange rate has expired -- The `WALLET` may opt to automatically refresh the exchange by calling the callback again before the previous `pr` expires. - -If the user approves, they may tap a button to "confirm" acceptance of the exchange rate. +- `WALLET` must display a confirmation screen where the user can review and approve the amount that will be deducted from their local wallet currency. diff --git a/README.md b/README.md index e33d3ec..66bd287 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ These are all the individual documents describing each small piece of protocol t | [18][18] | Payer identity in `payRequest` protocol. | [Blixt][blixt], [cliché][cliche], [ZBD Discord][zbd], [ZBD Telegram][zbd] | | [19][19] | Pay link discoverable from withdraw link. | [Blixt][blixt], [CoinCorner][coincorner], [SimpleBitcoinWallet][sbw] | | [20][20] | Long payment description for pay protocol. | [Alby][alby], [Blixt][blixt], [Clams][clams], [cliché][cliche], [Phoenix][phoenix] | -| [21][21] | Pay with localized currency amounts. | [Pouch.ph][pouchph] +| [21][21] | Pay in a different currency. | [Pouch.ph][pouchph] [alby]: https://github.com/getAlby/lightning-browser-extension [bos]: https://github.com/alexbosworth/balanceofsatoshis diff --git a/dependencies.dot b/dependencies.dot index 5b10ff3..bdfa635 100644 --- a/dependencies.dot +++ b/dependencies.dot @@ -19,7 +19,7 @@ digraph { 18[label="18 payer identity"] 19[label="19 mutual discoverability"] 20[label="20 long description"] - 21[label="21 pay in local currency"] + 21[label="21 pay in a different currency"] { 01 17 } -> { 02 03 04 06 07 } // base protocols depend on URL format 04 -> { 05 13 } // lnurl-auth seed generation methods @@ -31,7 +31,7 @@ digraph { 06 -> 16 // paying to user@domain.com 06 -> 18 // lnurl-pay payer ids 06 -> 20 // long description - 06 -> 21 // guarantee payment amount in localized currency + 06 -> 21 // pay in a different currency { 04 16 } -> 18 [style="dotted"] // loose relationship of payer id with lnurl-auth and lightning address { 06 14 } -> 19 // mutually discoverable pay and withdraw links } From 6ccff9005c65235a7874a8b5e08b466f1aff6ecb Mon Sep 17 00:00:00 2001 From: Ethan Rose Date: Thu, 23 Mar 2023 15:46:43 +0800 Subject: [PATCH 4/7] Add a warning about how service-provided exchange rates open a new method for dishonest services to trick senders. --- 21.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/21.md b/21.md index e899113..efcc4dc 100644 --- a/21.md +++ b/21.md @@ -48,4 +48,9 @@ In the next step of the LNURL-Pay flow, `WALLET` must include a `currency` query ## 4. User interface for reviewing & confirming the exchange rate -- `WALLET` must display a confirmation screen where the user can review and approve the amount that will be deducted from their local wallet currency. +- `WALLET` must display a confirmation screen where the user can review/verify and "approve" the amount that will be deducted from their local wallet currency. + + +> IMPORTANT: This LNURL specification opens up new vectors for services to perpetrate scams -- services may trick senders into accepting a bad exchange rate if the sender quickly "accepts" the rate (that is, if sender chooses to "trust" instead of taking their opportunity to "verify" the rate displayed on the confirmation screen). It is STRONGLY RECOMMENDED for wallets to add additional protection against services attempting to use dishonest exchange rates: +> - (Low Effort) A wallet may offer a generic warning along the lines of `Caution: This exchange rate may differ from market rate!` +> - (Medium Effort) A wallet may wish to audit the exchange rate against market rate based on a 3rd party API, and warn the user accordingly. From 2e044bba1523545d3867e2bd130a3e917c80df8c Mon Sep 17 00:00:00 2001 From: Ethan Rose Date: Fri, 31 Mar 2023 10:50:22 +0800 Subject: [PATCH 5/7] Update title "local unit of account". Add back rateEstimate concept, per request of Machankura --- 21.md | 9 +++++---- README.md | 2 +- dependencies.dot | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/21.md b/21.md index efcc4dc..e869009 100644 --- a/21.md +++ b/21.md @@ -1,11 +1,11 @@ -LUD-21: Pay in a different currency. +LUD-21: Pay in local unit of account. ================================================ `author: ethanrose` --- -The idea here is to enable a merchant to receive an exact payment amount, in whatever currency their goods are priced in (i.e. their own fiat currency). A sender should be able to input the amount in the currency that they are invoiced in by the seller as well. +The idea here is to enable a merchant to receive an exact payment amount, in whatever currency their goods are priced in (i.e. their own fiat currency). A sender should be able to input the amount in the recipient's own unit of account. Typically this is for a point-of-sale use-case where a lightning service is acting as a bitcoin-to-fiat payment processor. Currently, a sender would have to use their own calculator to determine how many sats to pay, and the recipient inevitably would receive the close-but-wrong amount. This bad experience is a hinderance to adoption of lightning as a cross-border payment system. @@ -24,7 +24,8 @@ If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a differe + "name": "Philippine Pesos", + "symbol": "₱", + "minSendable": 1, -+ "maxSendable": 50000 ++ "maxSendable": 50000, ++ "rateEstimate": 1500000 // Approx. rate for 1 BTC + }, "tag": "payRequest", } @@ -53,4 +54,4 @@ In the next step of the LNURL-Pay flow, `WALLET` must include a `currency` query > IMPORTANT: This LNURL specification opens up new vectors for services to perpetrate scams -- services may trick senders into accepting a bad exchange rate if the sender quickly "accepts" the rate (that is, if sender chooses to "trust" instead of taking their opportunity to "verify" the rate displayed on the confirmation screen). It is STRONGLY RECOMMENDED for wallets to add additional protection against services attempting to use dishonest exchange rates: > - (Low Effort) A wallet may offer a generic warning along the lines of `Caution: This exchange rate may differ from market rate!` -> - (Medium Effort) A wallet may wish to audit the exchange rate against market rate based on a 3rd party API, and warn the user accordingly. +> - (Medium Effort) A wallet may wish to audit the exchange rate against market rate based on a 3rd party API, (i.e. CoinGecko) and warn the user accordingly. diff --git a/README.md b/README.md index 66bd287..c5d6888 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ These are all the individual documents describing each small piece of protocol t | [18][18] | Payer identity in `payRequest` protocol. | [Blixt][blixt], [cliché][cliche], [ZBD Discord][zbd], [ZBD Telegram][zbd] | | [19][19] | Pay link discoverable from withdraw link. | [Blixt][blixt], [CoinCorner][coincorner], [SimpleBitcoinWallet][sbw] | | [20][20] | Long payment description for pay protocol. | [Alby][alby], [Blixt][blixt], [Clams][clams], [cliché][cliche], [Phoenix][phoenix] | -| [21][21] | Pay in a different currency. | [Pouch.ph][pouchph] +| [21][21] | Pay in local unit of account. | [Pouch.ph][pouchph] [alby]: https://github.com/getAlby/lightning-browser-extension [bos]: https://github.com/alexbosworth/balanceofsatoshis diff --git a/dependencies.dot b/dependencies.dot index bdfa635..2c4a60f 100644 --- a/dependencies.dot +++ b/dependencies.dot @@ -19,7 +19,7 @@ digraph { 18[label="18 payer identity"] 19[label="19 mutual discoverability"] 20[label="20 long description"] - 21[label="21 pay in a different currency"] + 21[label="21 pay in local unit of account"] { 01 17 } -> { 02 03 04 06 07 } // base protocols depend on URL format 04 -> { 05 13 } // lnurl-auth seed generation methods @@ -31,7 +31,7 @@ digraph { 06 -> 16 // paying to user@domain.com 06 -> 18 // lnurl-pay payer ids 06 -> 20 // long description - 06 -> 21 // pay in a different currency + 06 -> 21 // pay in local unit of account { 04 16 } -> 18 [style="dotted"] // loose relationship of payer id with lnurl-auth and lightning address { 06 14 } -> 19 // mutually discoverable pay and withdraw links } From 7302d15efe38beb95987407d5ca5aa2cca5f1036 Mon Sep 17 00:00:00 2001 From: Ethan Rose Date: Sat, 1 Apr 2023 11:31:42 +0800 Subject: [PATCH 6/7] update rateEstimate to multiplier --- 21.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/21.md b/21.md index e869009..9e43c4e 100644 --- a/21.md +++ b/21.md @@ -11,7 +11,7 @@ Typically this is for a point-of-sale use-case where a lightning service is acti ## 1. `currency` record in payRequest details -If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a different currency, it MUST alter its JSON response in the payRequest details response to include a `currency` object, as follows: +If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a different unit of account, it MUST alter its JSON response in the payRequest details response to include a `currency` object, as follows: ```diff { @@ -25,16 +25,23 @@ If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a differe + "symbol": "₱", + "minSendable": 1, + "maxSendable": 50000, -+ "rateEstimate": 1500000 // Approx. rate for 1 BTC ++ "multiplier": 64501 // estimated millisats per "unit" + }, "tag": "payRequest", } ``` +NOTE: `SERVICE` must include a `multiplier` property. This is an estimate which helps the `WALLET` do frontend validation & set expectations for users. A simple helper for the `SERVICE` to calculate millisats `multiplier` from common BTC rates is: + +``` +10^11 / btcRate +``` + ## 2. User interface for specifying currency -If there is a `currency` record in the initial response, `WALLET` displays a modified interface: -- The wallet should display the `currency.code` and/or `currency.name` instead of its default currency. +If there is a `currency` record in the initial response, `WALLET` must display a modified interface: +- The wallet must display the `currency.code` and/or `currency.name` instead of its default currency. +- The wallet must enforce `currency.minSendable` and `currency.maxSendable`. ## 3. Including `currency` in callback parameters @@ -45,13 +52,6 @@ In the next step of the LNURL-Pay flow, `WALLET` must include a `currency` query + amount=¤cy=PHP ``` -- `SERVICE` must respond with a BOLT11 payment request (`pr`) with a short expiry time (i.e. 30 seconds) corresponding to the length of time the service is willing to guarantee the exchange rate. - ## 4. User interface for reviewing & confirming the exchange rate -- `WALLET` must display a confirmation screen where the user can review/verify and "approve" the amount that will be deducted from their local wallet currency. - - -> IMPORTANT: This LNURL specification opens up new vectors for services to perpetrate scams -- services may trick senders into accepting a bad exchange rate if the sender quickly "accepts" the rate (that is, if sender chooses to "trust" instead of taking their opportunity to "verify" the rate displayed on the confirmation screen). It is STRONGLY RECOMMENDED for wallets to add additional protection against services attempting to use dishonest exchange rates: -> - (Low Effort) A wallet may offer a generic warning along the lines of `Caution: This exchange rate may differ from market rate!` -> - (Medium Effort) A wallet may wish to audit the exchange rate against market rate based on a 3rd party API, (i.e. CoinGecko) and warn the user accordingly. +- `WALLET` must display a confirmation screen so that the user can review/verify and "approve" or "confirm" the resulting invoice amount. From 8d5af2e71e421141ec418d54c8975905a991eaa6 Mon Sep 17 00:00:00 2001 From: Ethan Rose Date: Sat, 1 Apr 2023 11:40:58 +0800 Subject: [PATCH 7/7] use proper exponent operator in code block --- 21.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/21.md b/21.md index 9e43c4e..2bd4024 100644 --- a/21.md +++ b/21.md @@ -34,7 +34,7 @@ If `SERVICE` wishes for a `WALLET` user to specify a payment amount in a differe NOTE: `SERVICE` must include a `multiplier` property. This is an estimate which helps the `WALLET` do frontend validation & set expectations for users. A simple helper for the `SERVICE` to calculate millisats `multiplier` from common BTC rates is: ``` -10^11 / btcRate +10**11 / btcRate ``` ## 2. User interface for specifying currency