The amount option is leaving a slightly bitter taste in my mouth.
• It allows commas, which will just be stripped on execution. This feels like it’s just inviting errors unnecessarily, especially given that some parts of the world use comma (,) as their decimal separator and full stop (.) for grouping, rather than the other way round. I see no compelling reason for allowing grouping at all.
• “The 'unit' value MUST be smaller than 2^53. If present, the 'fraction' MUST consist of no more than 8 decimal digits.” Both of these feel a mite surprising, and the combination of them far more surprising. The 2⁵³ limit is doubtless to allow it to be safely stored in a 64-bit floating point number, specifically for JavaScript’s sake; but (dealing with this part first) do you know how small 2⁵³ is? 9 quadrillion. That’s honestly not that large. I’ve handled a 100 trillion dollar note, and that’s hardly the highest any currency has ever gone. (Admittedly, the sorts of currencies where this is happening probably have limited use for a payto: URI scheme at the time.) But anyway, skipping onto the second part, a fraction of up to eight digits. Skipping over the apparent arbitrariness of the number (which happens to match Bitcoin’s division), if you’ve made concession to treat the unit as a Number, what about the fraction? If you wanted to retain eight decimal places of significance, you’d be limiting your unit to 2⁵³ ÷ 10⁸, about 90 million, which is obviously too low, so you clearly can’t be meant to be representing the whole thing as a Number, so why that restriction on the unit? So yeah, both of these limits simply feel weird to me.
But other than these quibbles, I say: finally! I’m really glad about this and hope it gets adopted by banking apps and the likes quickly, and added to the HTML spec’s safelisted schemes (https://html.spec.whatwg.org/#safelisted-scheme) so that banks’ web apps can also navigator.registerProtocolHandler("payto", "https://bank.example/payto-handler/%s") soon. And also that Australian banks either register some way of addressing their accounts as a payto payment target type, or adopt IBAN.
Omitting a comma turns an amount with Euro Cents to 100 times the amount here in Germany. I can both see this comma/dot problem be missed in development and can also imagine such a payment go through, as a few digit amount times one hundred still gives an amount that people can have in their bank accounts. Users clicking through confirmation dialogs and dismissing wrong information as 'computer problems' is not an unheard-of problem either.
This is really inviting trouble - without good reason? - as a payment 'API' having to deal with how a number was displayed to a user seems out of scope for it.
Seriously, not to get too down on the author, but whoever wrote this was way out of touch with what a decent standard should look and act like. So many blatant flaws like this.
This reminds me of a bug I happened to come across with a cheap offshore company I had to deal with a while back (well, a very expensive consulting company that used a very cheap offshore company for development). We were dealing solely with Pound Sterling (100 pence make a pound). As part of the API requirements, they were asked to solely deal with pence in integers. They ignored the requirements and used pounds in floats.
This caused rounding errors here and there. We spotted the problem as soon as we heard about the rounding errors, and asked them to correct it. Later on, our customer asked us why the items that cost £1.85 were being charged correctly, but the items that cost £1.90 were being charged at 19p.
Turns out that rather than doing anything sensible, they took the float, converted it to a string, stripped out the period, then converted the string to an integer. So £1.85 became "1.85", then "185", then 185p, but £1.90 became "1.9", then "19", then 19p.
They managed to put this into production before we had a chance to see it. Yes, it was a dysfunctional project. But there’s lots of them out there. If you leave a footgun like this lying around, there’s no end of companies that will not only shoot themselves in the foot but happily reload while you are scrambling to stop them.
I've worked on an enterprise application serving hundreds of millions of users and this exact error went out the door.
So no, practically speaking, this absolutely does not get caught right away. And if the specification is this sloppy, it should be thrown out and redone.
The specification is not sloppy, it specifies precisely the wire format, and does expressly cover this problem of how the values MUST be interpreted. The specification does not cover how the application should render the amount when showing it to the user, so when applications show the amount to the user they can of course still render it in a culturally appropriate way.
Woah, this is beyond just "bitter taste." If these values are potentially stored in JS Numbers, this scheme is completely dead on arrival. It is not acceptable for currency to be stored in a floating-point data type, full stop. This proposal needs to at a minimum define a datatype for how these values should be stored, not just leave it up to implementations to throw it at `var currency = x;`
This RFC is woefully underspecified, and the fact that there's an amount of its already-small specification devoted to "7.5. Bitcoin Address" makes me question their priorities and destroys a lot of confidence in the proposal.
I think you’re exaggerating the severity of the issues. “Such-and-such an integer must be less than 2⁵³” is normally a reasonable constraint to make life easier for people across all environments, and to make some such constraint is typically a good thing, rather than leaving it unspecified. I just think that the limit is on the low side here and probably unjustified due to what else is going on—and that perhaps this should be one of the rare cases where you deliberately don’t specify any limit (to the magnitude of unit or the length of fraction), and leave it to the client to decide what makes sense.
On the Bitcoin part: that’s just putting an entry in the registry, a perfectly reasonable and normal thing to do in such a specification. They’ve included entries for four of the main traditional banking systems, and two of the main new-generation systems that people are sure to want to combine this with.
If you deal with money, you do have to store the fraction separately anyway and clearly should not use floating point. But that's beyond the point. The upper bound is there to ensure that you do not have to use BigNum in languages like JavaScript, not to tempt you to simply represent the amount in a double.
> The upper bound is there to ensure that you do not have to use BigNum in languages like JavaScript,
I think that is a far too generous read of the document. I think it's because they wanted you to be able to use a JS Number to store the value, which is the Wrong Thing To Do. In fact, using two BigInts to separately represent the fractional and whole pieces of the currency would be far better.
This is the kind of ambiguity that I refer to when I say this is underspecified.
Eh, it’s not underspecified. It’s just… strangely specified, in a way that people will ignore and misparse. But then, if it had been specified in any other way people would have ignored and misparsed it too.
People going to put money in floats unless you make it impossible. Then they send it via json and round and probably over or under flow and all sorts of amusing bugs result.
If JavaScript numbers work up to 2^52 that could precisely represent $45 trillion in cents.
IMHO if they had a choice between dropping Javascript support in preference of languages with BigInt support, or dropping support for payments larger than $45 trillion, they probably made the right decision.
I know. That was meant as a joke somehow. But nevertheless, you can email the authors and tell them about your concerns. I think there's a process of improving RFCs via errata.
It's an informational RFC which is already published. So there's no review process anymore, it's done already. And as it's informational, it's not a "real" standard (no going through implementations etc)
If you don’t need to work with the value, store it in a string. If you do, use a proper decimal type. (Your question may then apply to the internals of the decimal type, but the point is that that should be transparent to the developer accessing the decimal value.)
Meh, from what I've seen so far, it's just so people see, e.g. 2.55 $/gal with the tiny nine in the corner, stop by and get charged 2.559 $/gal (essentially squeezing that last cent out of customers.)
I'd be interested to hear if anyone else has seen any digit other than nine in the tenth-of-a-cent column though.
I believe it's because gas prices are quoted with tax (which is unusual in the US), and there is a federal tax ending in 9 tenths of a cent. Probably lobbied by the small 9 marquee digit manufacturers of america.
Australian fuel prices are listed in cents to one decimal place. >80% of the time the last digit is a nine, the rest of the time it’s most commonly a 5. I’ve seen other odd digits rarely, with even numbers just about unheard of. But what you actually pay will be rounded to the cent, or to the nearest 5¢ if you pay in cash.
• It allows commas, which will just be stripped on execution. This feels like it’s just inviting errors unnecessarily, especially given that some parts of the world use comma (,) as their decimal separator and full stop (.) for grouping, rather than the other way round. I see no compelling reason for allowing grouping at all.
• “The 'unit' value MUST be smaller than 2^53. If present, the 'fraction' MUST consist of no more than 8 decimal digits.” Both of these feel a mite surprising, and the combination of them far more surprising. The 2⁵³ limit is doubtless to allow it to be safely stored in a 64-bit floating point number, specifically for JavaScript’s sake; but (dealing with this part first) do you know how small 2⁵³ is? 9 quadrillion. That’s honestly not that large. I’ve handled a 100 trillion dollar note, and that’s hardly the highest any currency has ever gone. (Admittedly, the sorts of currencies where this is happening probably have limited use for a payto: URI scheme at the time.) But anyway, skipping onto the second part, a fraction of up to eight digits. Skipping over the apparent arbitrariness of the number (which happens to match Bitcoin’s division), if you’ve made concession to treat the unit as a Number, what about the fraction? If you wanted to retain eight decimal places of significance, you’d be limiting your unit to 2⁵³ ÷ 10⁸, about 90 million, which is obviously too low, so you clearly can’t be meant to be representing the whole thing as a Number, so why that restriction on the unit? So yeah, both of these limits simply feel weird to me.
But other than these quibbles, I say: finally! I’m really glad about this and hope it gets adopted by banking apps and the likes quickly, and added to the HTML spec’s safelisted schemes (https://html.spec.whatwg.org/#safelisted-scheme) so that banks’ web apps can also navigator.registerProtocolHandler("payto", "https://bank.example/payto-handler/%s") soon. And also that Australian banks either register some way of addressing their accounts as a payto payment target type, or adopt IBAN.