NDAO-0000 burn unused treasury funds

Thank you for your clear words. We don’t want to create a disincentive for future proposals that request on DAO funding.

Since DAO users are the ones who vote on proposals using their DAO holdings, this would create a conflict of interest. We must view the DAO inflation-offset as a fixed mechanism, just like Bitcoin’s 21 million.

So the anti-inflationary compensation for Nervos-DAO users will increase once the secondary issuance got activated? That’s how I originally understood the mechanism—that DAO depositors remain protected against dilution even when the secondary issuance will get fully distributed.

The compensation would therefore vary depending on whether the distribution is used to finance a project or not. Will we see fluctuating DAO compensation percentages depending on whether the distribution is being claimed at the current time or whether burning is active?

To this end, an additional visualization could be introduced in Explorer, showing the actual percentage of inflation compensation at any given time and the percentage over the course of the year.

1 Like

Under your mental model, today Nervos DAO depositors receive a larger percentage of total issuance than the tokenomic design stipulates.

Have you checked out the section of the positioning paper I linked earlier?

1 Like

Thanks, I think it’s finally starting to click for me, too. The percentage won’t change.

4.5 Economic Model

CKByte owners can deposit their tokens into the NervosDAO and receive a portion of secondary issuance that exactly offsets inflationary effects from secondary issuance.

4.6 Treasury

Funding of protocol development is strictly derived from the opportunity cost to short-term token holders.

4.7 Governance

  • Issuance schedule is completely fixed, thus shall never change.

:backhand_index_pointing_right: This:

4.6 Treasury

The portion of secondary issuance that doesn’t go to 1) miners or 2) long-term holders with tokens locked in the NervosDAO, will go toward a treasury fund. […] of the secondary issuance, and 10% of the secondary issuance will go to the treasury.

Thanks—I had gotten that wrong! :handshake: If I wanted to explain my confusion to myself, I would probably say: The DAO’s anti-inflationary compensation mechanism has no way of knowing whether the distributions for the treasury are burned or not.

4 Likes

I highly support this position. These type of decisions are exactly why i choose CKB and will continue to. Thanks for the detailed response :folded_hands:

2 Likes

We split the treasury system into two components: a creating component and a voting component.

The voting component is already available at: GitHub - XuJiandong/ckb-vote-poc · GitHub

We have now proposed a creating component for it.

All comments are welcome. @phroi

3 Likes

Hey @xjd, congratulations on all the hard work to are putting towards this crucial change in the ecosystem!! :flexed_biceps:

I would love if we could find a method where those funds are not minted at all instead of sending them to a zero lock. Then again, I cannot see a simple way of achieving it.

You found a good method of burning unused treasury with local information, that said this design has a weakness:

Change cells lose the original header deps for a fresh one.

Freshness attack

This can be abused by freshness attack: a reward recipient can use as input all treasury cells and mint as change a new treasury cell with fresh header deps.

This attack makes treasury funds un-burnable.

A solution could be for treasury lock to require Treasury change to be smaller than any of the single input treasury cells, so attacker is not consuming cells that he is not using.

At this point a small change cell with fresh header is not a problem anymore, right?

Freshness attack v2

Change cell is still a problem, enter freshness attack v2: a reward recipient can use as input a single treasury cell and mint as change a new treasury cell with fresh header deps.

Difference here is that Attacker just requests as reward as little CKB as possible for all treasury cells.

This attack makes Treasury funds un-burnable.

Possible Solution

Ideally to avoid freshness attack, treasury lock should additionally validate the following on Treasury change cells:

  1. Exists at most one Treasury change cell for a Reward Tx
  2. Treasury change cell is smaller than any of the input Treasury Cells
  3. Treasury change cell stores in cell data the header hash of the most recent input Treasury Cell

3 also have the additional consequence that burn now has to differentiate between normal Treasury cells and change Treasury cells to load the appropriate header.

Extra Perspectives

Depending on how you refine validation, I can refine attacks.

For example, if you decide to simplify into no change cells, then attack becomes burn all treasury with a variation of Freshness attack v2.

If instead treasury reward is a all or nothing (no partial reward withdrawals), then you have a fairness issue: new grantor with smaller claimable reward can jump in front of bigger grantor who is waiting for his full reward to be minted on-chain. This means that a stream of small grantor can effectively prevent a big grantor from withdrawing his reward.

Keep up the Great Work @xjd :flexed_biceps:
Phroi

PS: I don’t mind keeping this conversation going over here, but if you feel more comfortable on Github, feel free to create a proper Github Repo and we can discuss over there.

PPS: the following phrase is incorrect cause Output Locks do not trigger validation by themselves (I wish they would):

Treasury cells can only be created by consensus, similar to a cell base

1 Like

Could you explain more about these two items? header_dep is not mentioned in the RFC or design at all. All information is stored in script args as <8-byte block number>.

1 Like

Hey @xjd, sorry for the misunderstanding, looking at specs without code is pretty fluffy :laughing:

For example, from: https://app.notion.com/p/Treasury-Creating-Component-3736ed138b7a80859776e320a2d27065

Variable-length fields in the cell, such as args, cell data, and witness, should be left empty. This prevents capacity attacks, where an attacker fills these fields with garbage data.

Conversely, I re-checked the spec file and indeed it specifies 8 bytes.

BTW these are only current rules on change cells:

When a treasury cell is consumed, like any normal transaction, change outputs are required. For example, if there are 2 treasury cells containing 10,000 CKB in total but the proposal only requests 8,000 CKB, the remaining 2,000 CKB must be returned to a treasury cell. Without a change output, the remainder would be consumed as a transaction fee, which is not the intended behavior.

The change cell’s lock script and type script must be identical to those of the first treasury cell.

Another consideration is who pays the transaction fee. A simple strategy is that whoever claims the CKB also pays the fee, so the change amount can be calculated straightforwardly.

So Freshness Attack v1 still stands:

  1. Consume all
  2. Change cell equal to input most recent Treasury Cell
  3. Wait for new treasury cells
  4. Back to 1.

Feel free to update the spec, code and examples… and I’ll happily revew again,
Phroi

2 Likes