• abdullahkhalids 6 hours ago

    How would this handle Canadian guidelines for dealing with cents in cash, where you round to the nearest 5c [1]?

        Amounts ending in 1 cent and 2 cents are rounded down to the nearest 10 cents;
        Amounts ending in 3 cents and 4 cents are rounded up to the nearest 5 cents;
        Amounts ending in 6 cents and 7 cents are rounded down to the nearest 5 cents;
        Amounts ending in 8 cents and 9 cents are rounded up to the nearest 10 cents;
        Amounts ending in 0 cent and 5 cents remain unchanged.
    
    EDIT: I think if you send 12 cents,

        send [CADCASH/2 12] ( source = @user1 destination = @user2 )
    
    It should result in sending 10 cents.

        "postings": [{"source": "user1",
                      "destination": "user2",
                      "amount": 10,
                      "asset": "CADCASH/2"}]
    
    Can this happen?

    [1] https://www.canada.ca/en/revenue-agency/programs/about-canad...

    • superzamp 5 hours ago

      Well that's definitely a good puzzle. I've tried to model it for a bit, but it indeed looks like we'd need to add something to the language to make it possible at all! Thanks for bringing this up.

      • fallat 5 hours ago

        Same thing with income tax brackets. You need conditional logic.

        • superzamp 4 hours ago

          For this particular case, I would say that tax-brackets sort of logic can be expressed in the destination block with ordered destinations.

          For example, you could have something like this:

              send [USD/2 *] (
                source = @users:1234
                destination = {
                  // first $1000 are taxed at 10%
                  max [USD/2 100000] to {
                    10% to @taxes
                    remaining kept
                  }
                  // Anything above that is, taxed at 20%
                  remaining to {
                    20% to @taxes
                    remaining kept
                  }
                }
              )
          
          (You can test it on the playground, you'll just want to feed the "users:1234" account with an initial balance in the input section)
      • euroderf 4 hours ago

        The rules listed (1,2,6,7 round down; 3,4,8,9 round up). AFAIK these are also the official Eurozone cash rules for countries that choose not to circulate 1 and 2 eurocent coins. (Altho of course, electronic transactions are exact to the penny.) So you might want to cover this use case.

      • bschmidt1 3 minutes ago

        This is mindblowing. It's like the missing piece of blockchain that was needed for dev adoption. I can see it also being used for modern bank/payments apps including those in games and other simulated economies.

        Now let's see a "ContentScript" for posting content to ledgers :D

            send [Image "tacos.jpg", Text "taco 2sday!"] (
              source = @bschmidt1
              destination = @us-west-relay
            )
        • vslira 7 hours ago

          Super interesting and thanks for sharing. If I understood the license page on the repository correctly, the DSL is MIT-licensed since it's not within the enterprise directory, right?

        • OutOfHere 4 hours ago

          Can this or Formance interact with credit card systems, checking accounts, and layer 2 crypto wallets? If not, how is the money even going to come in or out?

          • robk 7 hours ago

            This seems cool but what's the intention with the USD/2 notation? Is that for fractional sub-cent precision in rounding situations?

            • superzamp 7 hours ago

              It's indeed relative to cents in a sense, the idea is to force you to declare the precision of the monetary amount you're expressing.

              You can see various interpretation of what "USD" means in the wild, as some APIs will happily parse USD 100 as $1.00 while some others might parse USD 100 as $100.00.

              So we recommend this explicit [ASSET/SCALE AMOUNT] notation, where SCALE describes the negative power of ten to multiply the AMOUNT with to obtain the decimal value in the given ASSET.

              It makes subsequent interaction with external systems much easier. You can read a bit more about it here [1].

              [1] https://docs.formance.com/stack/unambiguous-monetary-notatio...

              • tway_GdBRwW 6 hours ago

                Used to work at a payments company. Yes, you need to be *very* explicit in how you model currency amounts and precision. See also earlier post about Canadian rounding rules. Some of the "logic" is regulatory/compliance driven.

                ref child post about stocks trading for 0.0001. Yes, those are real trades and (probably) fully legal etc, but I'm not sure the Fed recognizes currency amounts less than 1 US cent ($0.01), so the accounting rules and tax rules might not match expectations based on generalized floating point math.

                • euroderf 4 hours ago

                  Doesn't the Fed recognise mills ? They are not extinct.

                • girvo an hour ago

                  Just to add to this, having also implemented a production payment system, we did the same thing. One needs to be very explicit about the scale and how it should be rounded and dealt with, and how to operate on two different scale systems. Quite a fun challenge, though I do not miss the edge cases.

                  Our system was a payment system for childcare management software, interfacing with banks and the government directly.

                  • flockonus 6 hours ago

                    What about units that cost sub-cent? For examples, I've seen private company stocks being $0.0001

                    Not sure why you'd need to make a note in the internal representation, vs. leave adapters to handle conversions.

                    • bbor 6 hours ago

                      Not to speak for them, but I think you’ve understood the point exactly. You need to be able to support arbitrary precision, but that support needs to be intentional to avoid errors. And you have to record that decision somewhere if adapters are to correctly handle your outputs; why not in the unit name?

                      • petesergeant 6 hours ago

                        If I understand their docs correctly, that’s equivalent to [USD/4 1]

                  • henning 2 hours ago

                    Ah, what better input format than JSON, a poorly defined, ambiguous format that freely mixes integers and floating points and lacks supports for bigints and bigdecimals.

                    • jimbokun 5 hours ago

                      Are there converters to/from OFX for Numscript?

                      • bbor 6 hours ago

                        To this noob, this seems like a problem that was pretty convincingly solved by double entry accounting ledgers, but from your post it sounds like this isn’t a replacement-of but rather an addition-to that model. What’s a situation where an imperative approach would be preferable to the traditional declarative approach? My depth of knowledge pretty much starts and ends with the below document, so apologies if this is obvious to experts!

                        https://beancount.github.io/docs/the_double_entry_counting_m...

                        E: the problem being “tracking transactions”. Yes?

                        • superzamp 6 hours ago

                          That's a very good question. So the DSL here operates an agnostic source/dest transaction model, which is akin to the credit/debit model sans the semantic baggage. The goal of this model is indeed to be "tracking transactions" in the abstract sense, having the benefit of not forcing accounting decisions too early on when there is (still yet) none.

                          For example, if you create a transaction moving money from "@stripe:main" to "@acct:123" and "@acct:234", you're merely representing the fact that you want this money to be moved. Wether the movement is clearing off a liability or generating revenue is another concern that you (in our model) want to take care of in a separate layer, that will also likely involve some intense intentionality and iterations from your accounting team.

                          In a sense, it's as close to accounting than it is to warehousing money, moving unitary boxes of it from one location to another.

                          These two models have the same amount of information per entry, so they can actually be converted from one to another, enabling you to also represent some accounting-ish transactions with this DSL, e.g. with a send [USD/2 100] from @ar:invoices:1234 to @sales.

                          • mamidon 3 hours ago

                            I'm living this life right now; except we baked in notions of Assets/Liabilities/Income/Expenses into our ledger logic. Only to realize our customers don't care and just want to do whatever it is they've been doing.

                            • bbor 4 hours ago

                              Fascinating, thanks for taking the time to educate! Makes sense to me — it seems this tool is purpose built for situations where tracking is complex enough to deserve decoupling from annotating or interpreting, to put it in my own kindergarten terms.

                              I don’t have a need for this personally but I’ll definitely be bouncing this around in my head for a while, both technically (JS ALL the things!) and methodologically. Accounting is pretty trivial when you don’t have any income to track!