Native Group Tokenization

@andrewstone if you’re willing to dig it up, I’d love to see what I missed. I want to prepare some kind of compendium about group tokens… here’s a start

Timeline

2017-10-16 Intro

https://medium.com/@g.andrew.stone/bitcoin-scripting-applications-representative-tokens-ece42de81285

2017-11-19 BUIP

https://github.com/BitcoinUnlimited/BUIP/blob/master/077.md

2017-11-22 Chris Pacia’s explanation

https://web.archive.org/web/20191106134854if_/https://www.yours.org/content/colored-coins-in-bitcoin-cash-b26804e05964/

2018-05-21 Group Tokenization document

https://docs.google.com/document/d/1X-yrqBJNj6oGPku49krZqTMGNNEWnUJBRFjX7fJXvTs/edit

2021-01-27 Jonathan Toomim comments

https://youtu.be/GbS7Q4pb-yg?t=3017

2021-02-03 Jason’s thread

https://bitcoincashresearch.org/t/native-group-tokenization/278

2021-02-12 BU Poll

https://twitter.com/BitcoinUnlimit/status/1360297716757245956

2021-02-13 George and Andrew Interview

https://www.reddit.com/r/btc/comments/liflma/bitcoin_cash_needs_a_big_tech_project_to_show_it/

2021-02-13 We want first class tokens on BCH! Part 1/N, motivation

https://www.reddit.com/r/btc/comments/liz5xf/we_want_first_class_tokens_on_bch/

2021-02-15 We want first class tokens on BCH! Part 2/N, scalability, stakeholders

https://www.reddit.com/r/btc/comments/lkb7ez/we_want_first_class_tokens_on_bch_part_2n_and_we/

Looks like I missed quite a bit of discussion over Valentine’s Day weekend! Going to try to compress responses into one post:

Group Tokenization Needs a Spec

@tom and others have been extremely generous with their time, deeply reviewing this topic and several other proposals in this forum.

I don’t think this is about process: Group Tokenization simply does not have a specification. It has a 43 page, mostly-prose, Google Doc with no public edit history and very little provided rationale about specific technical decisions. (Edit: In fact, I think it was edited as I wrote this comment? it is now 44 pages.)

Huge segments of the Group Tokenization proposal don’t seem to be formally specified at all: “group authority UTXOs”, authority “capabilities”, “subgroup” delegation, the new group transaction format, “script templates”, and “script template encumbered groups” – all of these are described in prose, but the reader is left to guess about important details. In my review, I tried to assume the best in each case, but I can see why others find that frustrating.

After this discussion, I was reasonably convinced that “native” tokens could be implemented without negatively impacting scaling. I’m not yet sure whether the latest Group Tokenization proposal does so successfully, but we’ll see once a draft specification exists. (I think earlier versions of the proposal did impact scaling, but I can’t verify without a history of spec changes.) Regardless, a complete specification would be the best way to put all these fears to rest.

@andrewstone: would you consider developing an “implementation-ready” specification like PMv3? We need some concise, details-only document of the precise changes and any relevant test vectors. It’s valuable to include rationale, but please provide it in a truncatable “Rationale” section at the end. I think it’s also very important that the specification be source-controlled in a Git repo.

Unanswered Concerns

We still don’t have answers for some of the concerns I mentioned at the beginning of this thread:

So, @andrewstone:

  1. How are you confident that the current Group Tokenization proposal is “complete” and doesn’t need to first be tested in a “userland” system like CashTokens? Or do you expect future upgrades can correct any deficiencies we discover after this Group Tokenization proposal is rolled out?
  2. Can you provide any full example of “group tokens” interacting with covenants?

On (2), I posed a small challenge a couple of weeks ago:

I’m asking this again because in reading your recent comparison of Group Tokens and CashTokens on Reddit, you still seem to think “CashTokens” is an alternative to Group Tokens. I want to suggest: the most interesting use cases allowed by parent transaction introspection (“CashTokens”) are not possible to achieve with Group Tokens. Group Tokens need parent transaction introspection too. I think if you try to implement this covenant (as might be used by a side-chained prediction market) you will find that you need a solution like hashed witnesses.


Unless someone can demonstrate how Group Tokens might avoid the need for hashed witnesses, my current preference is that we first implement a smaller change like PMv3 in May 2022. This would give end-user-developers complete flexibility in implementing creative new token designs at no risk to the network. (And PMv3/hashed witnesses are important for use cases other than tokens, so they will remain valuable regardless of whatever “token solution” ultimately sees the most adoption.)

After some miner-validated token standards emerge on the market, we could eventually choose one like this Group Tokenization proposal to “bless” as the standard (e.g. in May 2023). With good real-world examples, we’d be able to more effectively evaluate features and tradeoffs. It seems premature to optimize specific token use cases – using new, permanent consensus changes and data structures – before we can quantify the value of those optimizations.

3 Likes

That “spec” doc is more than a spec. It is a roadmap with multiple options considered and full of use examples etc.

The step 1 of the roadmap is simple, it involves a new opcode OP_GROUP with simple verification requirements. Yes, it writes that an older spec required to look around but current one does not, so I think it scales well and avoids problems toomim was talking about.

Actual manipulation of the tokens is achieved by cleverly using the spec above, it’s not part of the consensus touching spec, but it will be a part of userland spec, an user manual. How to do X? How to mint, how to melt, how to change authority, etc… that all happens in userland. OP_GROUP simply enables such solutions.

The most basic implementation is so simple it’s beautiful and I think that’s confusing everyone, because we don’t know what we’re discussing, step 1 or something down the line which may or may not come after step 1. That’s where a spec for only the step 1 will come in handy, which I volunteer to write when I gather enough knowledge.

From previous correspondence and reading how group tokens are supposed to work, you just attach a special message to each output it’s so simple it’s beautiful… because it uses bch for double-spend checks because every group tx is also a bch tx, then when it’s time to check the tx balance you piggy back on those reads writes and deletes you have to do anyway for bch. Once you’ve read a group utxo you add the group amount to some cache ie running sum(s), once you’ve deleted it, you subtract from the sum, and at the end you check the balance of both bch and whatever group tokens you encountered and give a yes or no for the tx. It’s as simple as that. There’s no extra loops or looking at other TXOs. All the magic happens inside existing loops we use to check bch balance. I’d be happy if Andrew could confirm my understanding.

Now, if you want to be a group token block explorer, only then you have to index the tokens, but that can be done separately, that’s userspace, not node/mining job. Can’t have tokens and not have them. Question is - who does what part of the job to have them? With SLP it’s all userland. With group tokens, miners will do a tiny but important part: basic accounting equation.

1 Like

Is BCH going to compete with Bitcoin, Ethereum, neither, or both? Personally I think the answer is “Bitcoin – by doing everything it does, and p2p cash as well”. Other projects are already competing with Ethereum, and one of them might succeed.

1 Like

BCH already competes with BTC for the original use case which is P2P Cash. BTC can’t even compete there anymore so it’s no competition. The narrative around BTC changed to “store of value” “anything hedge” “new asset class” “digital gold” etc. That narrative is too strong, and big tech and big finance is getting in, so I think that’s the way it will be. Any competition with BTC is competing with the narrative, not the technology. We can’t compete with that narrative, and we shouldn’t. BCH should become a store of value organically, as a side-effect after it’s been used as cash because it works well.

We see many other cryptos saying they enable instant cheap transactions that could be seen as competition, but where are their transactions? BCH seems to have an advantage there because it has boots on the ground, it has volunteers working hard every day to bring it out there and it’s taking root. Of all the cryptos that can do cash because their tech enables it, BCH is the only one that’s actually doing it because it’s bringing in users. I love to look at this map and see places where BCH acceptance is concentrated: https://map.bitcoin.com/ We need concentration, because that way we reduce churn. We need to continue to build the narrative about cash, so when someone thinks crypto/digital cash they think Bitcoin Cash!

Ok, the above is more for Reddit, what does it have to do with Group Tokens? It has everything to do with it. Because GTs are a way to expand the scope of “cash”. GTs are 1st class tokens meaning they enjoy the same efficiencies that BCH has. Miner enforcement, SPV wallets, 0-conf, etc. Cash is not just 1 currency. Having 1st class tokens would enable multiple currencies on BCH blockchain, and they’d all be carried around by small amounts of BCH and paying fees in BCH. GTs are NOT smart contracts. But future smart contracts could be using them alongside BCH.

1 Like

Here’s an interesting argument about UTXO. Fact is that every NGT UTXO is also a BCH UTXO. At the beginning I saw this as an interesting side-effect, and now I see it as an important feature because it will provide economic incentive to consolidate NGT UTXOs if the token value disappears. If the NGTs have value, there’s even more value to consolidate, you’re consolidating both NGT and BCH amounts in the same TX. Say you have 10 NGT UTXOs, you can consolidate them all into 1 NGT UTXO and you can choose what to do with the excess BCH you freed - either keep it colored or send elsewhere as 1 more pure BCH UTXO. Like this you claim “free” BCH for consolidating NGT UTXOs! If you want to split a NGT UTXO, you have to lock up more BCH.

Hey all! We now have a high level doc outlining the requirements for enabling group token semantics. It’s one and half A4 page, should be easy to read and enough to enable us to assess impact on scaling etc, ie start the talk at high level, and as everyone’s understanding catches up can work our way down to design choices and implementation details, in a way we will together reinvent group tokens.

I’m gonna embed the doc here below, and later edit as required. Meanwhile, Andrew is working on a full spec which you can find here. He already had some comments on the doc below, but the essence is good already. I need to read up more to implement those comments for this doc and it can be part of this reinvention process.

Native Group Tokens High Level Requirements Overview

Script Requirements

OP_GROUP enables storage of data in a place preceding normal script. That’s all
that Script has to check. That data is given meaning in the consensus checking
part. This data could be stored in a new transaction field all the same.

Grouped transaction output scripts MUST follow the following format (<>
brackets indicate data pushes):

<Group ID> <quantity> OP_GROUP [normal script constraints],

Consensus Requirements

When verifying an individual transaction, perform the below in addition to
normal processing.

For every input seen:

  • If they have the OP_GROUP opcode then:
    • Check whether fields are of valid size. Fail the transaction if not.
    • If it’s a group token then add group balances to running sums.
    • If it’s a group authority then OR group authorities to running
      flags.
  • Else do nothing.

For every output seen:

  • If they have the OP_GROUP opcode then:
    • Check whether fields are of valid size. Fail the transaction if not.
    • If it’s a group token then add group balances to running sums.
    • If it’s a group authority then OR group authorities to running
      flags.
  • Else do nothing.

Finally, check the validity of the transaction as a whole:

  • If an authority appears from nothing AND group genesis requirement is NOT met
    then fail the transaction.
  • Else check whether authority “balances” out i.e. only lower or equal authority
    can be found in the outputs flag. Fail the transaction if not met.
  • Check token balance taking into consideration authority found in the input and
    fail the transaction if criteria not met.
    • No authority: input group token balance == output group token balance
    • Mint authority: input group token balance <= output group token balance
    • Melt authority: input group token balance >= output group token balance

That’s it. Whatever Native Group Token semantic details will designed, they will
be implemented in one of these 3 places above. This high-level description
should be sufficient to evaluate impact on scaling.

User Requirements

Users can decide whether to support the Native Group Token semantics or not. If
it will not be supported, then NGT UTXOs will be unspendable by the user.

Non-supporting wallets should at least check for the presence of OP_GROUP and
deal with them in a way that makes sense otherwise regular transactions created
by the wallet could fail by accidentally including an OP_GROUP UTXO as input.

Assuming majority of wallets already match the UTXO script against known patterns, this
shouldn’t be an issue, as those will just ignore those UTXOs.

It is recommended that non-supporting wallets at least show them as non-spendable BCH
balance because showing 0 would hide the fact that there’s still something in there.

User Manual

Should the user choose to support NGTs then he should support, as a minimum:

  • Preservation of authority UTXOs i.e. if you use one as input, you must create
    one as change output.
  • Tracking wallet NGT balances which is as simple as summing UTXOs that belong to the wallet
  • Building ordinary NGT transactions, which are transactions containing OP_GROUP and respecting the consensus rules shown above
  • Melting NGT UTXOs

While advanced features won’t be supported this way, at least the end user will
be protected from accidentally giving up authority or unknowingly passing it
on to other parties. If he doesn’t want the tokens, end user can burn the tokens
and claim the locked BCH.

Copyright

This document is placed in the public domain.
Attribution neither required nor desired.

Credits

Andrew Stone

2 Likes

Thanks for this succinct and clear overview.

One thing that is unclear to me however is how authorities work - it seems these are tied to UTXOs, but it is unclear how one can see whether UTXOs have mint/melt permissions.

I don’t think melt authority should be a thing. Anyone should be able to melt and access their own BCH: token issuers should not be able to hold the underlying BCH from other people hostage. Bitcoin Cash also allows people to burn their own BCH, so it would be strange if you wouldn’t be allowed to burn your own tokens.

3 Likes

Yes, there are 2 kinds of group utxos authority and token. Authority reuses the amount field to store authority bits. If a particular authority bit exists in any of the input utxos then creation of other authority utxos in the outputs may be allowed, and circumventing the sum_in=sum_out may be allowed. This also means that if you don’t want to give up authority, you need to always create a “change” utxo to preserve it. I think this was not the 1st idea but he worked his way to this, and I love it for it’s elegance.

I don’t think melt authority should be a thing.

My view is that it should be a thing but anyone should be allowed to create melt authority from “nothing”. If you just allowed it by directly allowing sum token outs to be <ins, then people could accidentally burn their tokens. With BCH you have to go out of your way to burn. That should continue to be the case with tokens. Example:

TX     Inputs                           Outputs
----------------------------------------------------------------------------------
 1     0.01 BCH UTXO                    NGT melt authority UTXO (0.01 BCH wrapped)
----------------------------------------------------------------------------------
 2     NGT melt (0.01 BCH)              0.02 BCH UTXO
       100 NGT tokens token (0.01 BCH)
----------------------------------------------------------------------------------

Anyway I’m asking Andrew about that to clarify. He thought of a “fencing” feature which would enable people to hold it hostage as a feature, I think. Like, you make group tokens but they carry significant amount of BCH, so you could color a bunch of BCH which only folks with authority could take out, or you could only move BCH inside the fence. I’ll repeat the question here and add the answer when I get it:

Maybe we should reconsider and let people melt and give up the fencing feature so BCH can’t get stuck with worthless tokens. I imagine you already thought about it, but would be good to share the rationale.

Andrew:

That min bch feature is called the “dust limit”, BTW. WRT melting, there are future smart contract reasons to require a melt constraint script to be met. They are basically along the lines of “if have X you can melt it to get Y”. The group creator can give melt permissions to everyone by creating a melt authority that has no constraints… they then just toss a bunch of these onto the blockchain and anyone can use one. Also, note that the bch in the utxo isn’t constrained by the group (unless a flag is set). So you could extract all the bch down to the dust limit without melting. One reason for this is fees. Group UTXOs can be “charged up” with enough BCH to pay a few transfers worth of fees (if desired). Doing this keeps tx smaller because you don’t have to pull in a bch-only UTXO and pay yourself change just to pay fees, so long as you can use some from the token UTXO.

Me:

I’m talking about extracting the dust, too. Imagine you have 1000 token UTXOs and the token becomes worthless. If you could give yourself melt authority regardless of the token creator wishes, you could melt them all into 1 normal BCH UTXO. On a second thought, w/o melt authority you simply consolidate them down to 1 token UTXO and 1 BCH UTXO which would extract 999 dust amounts. If fence flag was enabled, you could consolidate them to 1 token UTXO but couldn’t recover the BCH in which case there’s no incentive to do it if token is abandoned and the UTXO is left with 1000 zombie UTXOs.

Andrew:

Sounds about right.

WRT being unable to extract the “fenced” BCH – today you can send BCH to unspendable addresses where it will be stuck forever… there’s no real difference.

Me:

Difference is in incentives I guess. There’s no utility in burning BCH to unspendable addresses. There is utility in creating lots of tokens for your project so that’s ok, we want utility. And if the project fails and tokens become worthless that means all those UTXOs become zombies without any incentive to consolidate, that could be a problem because we lose the ability to clean up. Removing BCH from the circulating supply could be seen as “paying” for their tombstone in the UTXO set. 1m zombies would remove 5.46 BCH from the supply.

If you want to prevent accidental burning by wallets unaware of OP_GROUP then I suggest to simply require a new transaction version (i.e. make any use of OP_GROUP invalid in the existing transaction versions 1 and 2). Actually, on second thought, accidental burning is impossible anyway, because wallets that don’t understand OP_GROUP will not recognise the public key script and hence will not believe the coins are part of the wallet. (Unlike SLP, where the tokens look like normal wallet coins.)

Then you get a much simpler system: no more dealing with melt authorities, and the only remaining authority is mint authority which can be encoded simply as zero/null quantity.

2 Likes

Andrew told me the same just now:

Actually nonsupporting wallets won’t even recognize a group UTXO as one of “theirs” (because this happens by matching the UTXO script against known patterns) so no explicit checking is needed.

So I will update that in the doc above. I imagine a wallet could still mess it up by awkward implementation but from Andrews answer I figure that wasn’t the main motivation for requiring melt authority anyway. Check out my updated post above.

the only remaining authority

He imagined a few more authorities, like authority to give sub-authorities which would enable a lot of interesting functionality. I’m thinking about producing something like a feature tree: this authority enables this functionality down the line, and then we see what we discuss what want and what are the trade-offs.

Is BATON authority the same as CCHILD referred to in ALL_PERM_BITS definition?

Should be, looks like an error maybe he was changing the names of things and forgot that one. I’m not sure whether he considers the doc as in progress or complete. I did say he’s “working on a full spec” :slight_smile:

Yes. I am currently updating the specifications in some ways. One way is to move to the more modern terminology. SLP borrowed the Group system and renamed it “batons”, I name it “authorities”. Its funny because those two names get to the 2 essential properties of the system. I like their name “baton” and it’s widely known. So I am moving the specs to use the term “Authority Baton”, and “baton” in particular when that action (passing the authority from input to output UTXO) happens. So the CCHILD bit becomes the BATON bit.

Please understand that the Group Tokenization document likely lays out the content of a few hard forks. In particular there’s a natural separation between basic tokens and enhancing BCH script to handle robust smart contracts.

Unless the community really wants to make all the changes at once, I’ll be proposing first just the Group changes (so none of the OP_TEMPLATE, OP_PUSH_TX_STATE, or OP_EXEC changes). But if you read and understand those sections, you can get a good understanding of where we need to go to have robust smart contracts, irrespective of whether Group is deployed.

3 Likes

So to clarify the melt rationale, it is not the same as burning. From talking with Andrew it was never about error prevention, it was just that I saw it could be used like that among other things. You don’t need any authority to burn. You can send both the token+bch from an UTXO to 1bitcoineater and burn them forever together. Or use OP_RETURN to burn them.

Melting is another animal, it burns only the token and frees the BCH. But since BCH is free to cross group borders, you can free your BCH without melting by combining multiple token UTXOs into a single token UTXO and recover the excess BCH. Like, if you had 1000 token UTXOs, you consolidate them into 1 token UTXO locked with only the 546 sats and you extract 999x546 sats into the pure BCH UTXO with this operation. This also means that you can charge token UTXOs with more than the minimum, so they can pay for the fee themselves without having to include a pure BCH input alongside.

Fencing locks the border but also disables token amounts. This creates colored BCH, where only authorities can add or remove coloring.

So, these authorities enable a lot of versatility in how we can use group tokens. There’s more about that in the functional description doc.

2 Likes

You are right. Burning is sending a coin or token to an output that is either provably or convinceably something that can never be spent. But that UTXO lives onchain forever, and actually it may take a human’s input to decide whether the token is burnt (a machine likely won’t understand that 1tokeneater… is a probable burn, unless its been specifically coded for that address).

Melting removes the UTXO. So its easy for machines to identify and reduces UTXO database size.

4 Likes

I have extracted the proposed consensus rules into a pretty succinct document here:

5 Likes

@andrewstone: would you consider developing an “implementation-ready” specification like PMv3 ?

Yes, I have extracted a specification out of the documentation and implementation, here: Group Tokenization Consensus Specification. You are essentially correct that the purpose of the Group Tokenization document is to explain the architecture and power of the approach while leaving a concrete specification until the point where there was interest in doing it.

Group Tokenization Script Templates and Contract Encumbered Groups seem aimed here, but those solutions seem like a much more complex way to accomplish similar goals as CashToken’s parent transaction validation. (@andrewstone would you disagree?)

Yes I disagree. As a general rule of thumb, any time a script would enforce token balance or a covenant you could just remove that logic and let Group tokens do it for you. This is more than just a “nice-to-have”. Without loops a BCH script will never be able to analyze and enforce covenants over any set of outputs arbitrarily. So there will always be awkward rules about where certain outputs need to go, and limitations in things like splitting utxos for the same reason. For example AFAICT, you can’t operation on 2 cashTokens in 1 transaction because the cashToken output MUST be output 0. This is a major limitation since it prevents atomic token swaps, and its very basic.

Contract Encumbered Groups is a simple comparison of a prevout script with the current output script. Fancy name, simple thing.

Script Templates is trying to solve a general problem with covenants that perhaps you haven’t come across yet. The problem is that (with covenants) there are now 3 antagonistic entities and only two places to put data. By antagonistic I mean “will take advantage of mistakes in each other’s code”. Today we have 2, the constrainer and the satisfier. It should be obvious that P2SH for example uses a cryptographic hash to identify the redeem script because if the “satisfier” could cheat and provide a different, easily satisfied constraint script, it would do so.

With covenants, the situation becomes more complex – the constrainer (holder of covenanted BCH or tokens) might gain advantage if they can break the covenant, the satisfier (spender) might gain advantage if they can break the constrainer OR the covenant.

And we basically have 2 entities that want to put constraints on spending, but only one place to do so (the output or redeem script).

Today, you can avoid this problem in a few ways: First, if your covenants are “anyone-can-spend”, there may be no concept of a holder and therefore no additional constraints. This might happen if your covenant implemented a defi service available to anyone, such as a CPMM (like uniswap), or the cashTokens state “baton” I think would apply.

Second, you could increase the complexity of your covenant enforcement to leave “gaps” for the holder to fill in (with their pubkeyhash, for example). I think this would be painful to implement even with an OP_PUSH_TX_DATA tx introspection opcode, and it becomes even more painful if the UTXO-efficient P2SH style output is used. But to get to real versatility, and provide an analogue to ETH’s inter-contract calling, the holder needs to add programmatic constraints, not just data constraints. This adds yet another level of complexity and area for security flaws for 2 reasons: 1. the gaps are variable sized. 2. The “holder” code can modify any part of the stack.

Script Templates solves this problem in a general fashion.

However, it makes sense to evaluate these different technologies in parts… so Script Templates is not part of what I’m proposing for Group Tokenization.

We do need to enhance the scripting language to enable smart contracts. And yes, once it is enhanced (to turing or near-turing levels) we could go the ethereum route and implement tokens (or any other computable function) on top of it. But as I’ve said in other venues, that turns BCH into a poor copy of ETH. And given ETH’s head start both in technology and adoption we will never catch up by copying. The more efficient approach is to make tokens native, and suddenly our blockchain fundamentally works faster and more efficiently than ETH plain token operations, and the token part of smart contract operations… that will be interesting to many people.

2 Likes

Hi all, I went ahead and produced something, how’s this for a first draft CHIP? Why not collaborate on moving this forward, this chip needs to be more serious than my previous posts and I’d appreciate if you could check my tone or any other points through the doc :slightly_smiling_face: I’m most proud of the “technical description” section I think it’s very concise and describes it well

I first put Andrew’s name as author without asking for permission even though he didn’t see it yet. I meant no disrespect, I meant quite the opposite. I removed it since then, and I’ll be happy to put back if he wants. I don’t own this, I just wanted to write stuff that’s missing. This was a bad call, and I feel embarrassed, sorry about that. I consider myself a self-appointed ghostwriter in this case, and I want to give proper credits. At the end, I believe it will be Andrew who will “officially” post this CHIP, so thought why not put the name anyway, I don’t want to be seen as stealing this. He may or may not want to use stuff that’s been written in this draft.

1 Like

It’s here: BUwiki/groupbchspec.md at master · bitcoin-unlimited/BUwiki · GitHub

As for the CHIP, I merged a pull request from Andrew just now, and he helped clear up the mess I made with the author field, while also correcting my typos, adding clarifications and Industry Acceptance section detailing other blockchains doing similar token approaches.

BTW, it was the native introspection CHIP that prompted me to write the group CHIP. Imagine if we deliver it at the same time and it supports introspecting the OP_GROUP field among other things, and then HashedWitness contracts could work with tokens too. With increased collaboration between teams working on various solutions, we can achieve synergistic effect, constructive resonance, and then deliver something more powerful than any single team could alone, that’s why I feel like I’m racing with time even though no deadlines exist. I think I can finally chill, a little :slight_smile: Thanks for bearing with me so far!