DCP: 0006 Title: Decentralized Treasury Author: Marco Peereboom <[email protected]> Status: Active Created: 2020-09-18 License: CC0-1.0 License-Code: ISC
This document specifies modifications to the Decred treasury to make it a more decentralized process.
The main changes are:
- Move multisig unsigned transaction output (UTXO) based
treasury address
to a treasury account that can only be debited when Decred stakeholders agree to it. - Credit development subsidy to treasury account every block.
- Add three new opcodes:
OP_TADD
,OP_TSPEND
, andOP_TGEN
. - The aforementioned opcodes are then in turn used to construct three new types of stake transactions:
Treasurybase
transaction - treasury subsidy in every block.Treasury add
transactions - method to credit the treasury account.Treasury spend
transactions - method to debit the treasury account.
Spending from the Decred treasury is a manual process that is executed and governed by humans. The current process requires contractors to each produce a monthly invoice with a reimbursement report, denominated in USD, that is submitted to the project treasury auditors. If the invoice is approved a payout is made to the contractor-provided address from the treasury funds, using an averaged DCR/USD exchange rate over the month the invoice applies to. These payouts are made by Decred Holdings Group LLC ("DHG" for short), a conventional corporate entity which holds the treasury funds. This is undesirable for various reasons, such as
- Sovereignty over treasury spends is not vested in the stakeholders.
- Risk of theft of funds.
- Risk of key project members abandoning the project.
- Risk of coercion being used against key project members.
- Process of treasury spending is insufficiently transparent.
Currently, every block that is mined must include a coinbase
transaction that
generates a UTXO of a specific amount that requires a 2-of-3 multisig to spend.
This is enforced by consensus. During payout time, DHG creates and signs
transactions to all payees. This process is not adequate to support the
features proposed in this DCP.
Essentially, the treasury is converted from a UTXO based model to an account
based model. The account balance is determined by starting with an initial
balance of zero followed by state changes that are recorded on the blockchain.
This process "burns" and "creates" UTXOs as needed. Sending UTXOs to the
treasury burns the coins and adds value to the treasury account and spending
from the treasury creates UTXOs. This process is analogous to the ticket
purchases and redeems. The treasury changes shall be added to the staking
mechanism. The stake tree was selected for these changes because the coin burn
and creation is analogous to the consensus voting mechanism. Additionally, the
treasury votes are added as optional data to OP_SSGEN
so that
voting can happen simultaneously.
This DCP introduces three distinct new processes.
- Subsidy generation for the Treasury is now accomplished by a new
treasurybase
stake transaction type which MUST be the first entry in the stake transaction tree as opposed to thecoinbase
of the regular transaction tree. - Crediting the Treasury from existing UTXOs is handled by a new
treasury add
stake transaction type that burns the UTXO(s) and credits the Treasury account accordingly. This is analogous to purchasing a ticket. - Spending treasury funds now requires stakeholders to vote on the expenditure. The Politeia (or Pi) key operators create a
treasury spend
transaction and sign it. This transaction is then broadcast onto the network where it enters themempool
. Voting wallets are expected to detect this transaction and voteYes
orNo
on the expenditure based on stakeholder preference via the existingvote
stake transactions. Thetreasury spend
transaction is not valid until enoughYes
votes are cast by the stakeholders at which point it is included in a block thereby finalizing the payouts.
The following section details the new transaction types. All new transactions shall be part of the stake tree and all treasury opcodes shall be rejected if used in scripts in the regular tree.
The newly introduced treasurybase
moves the developer subsidy from
the coinbase
transaction to its own transaction in the stake tree. The
treasurybase
transaction shall be the first transaction in the
stake tree. There shall be no more than one treasurybase
transaction per block. The developer subsidy shall credit the treasury account
in full unlike the current implementation which credits a proportion based on
the number of tickets included in the block.
A treasurybase
transaction is identified by the following characteristics:
- The wire message transaction version shall be 3.
- One transaction input that shall *NOT* have a signature script.
- All transaction output scripts shall be version 0.
- There must be two transaction output scripts.
- transaction output 0 script must be
OP_TADD
. - transaction output 1 shall be an
OP_RETURN
followed by a twelve-byte data pushOP_DATA_12
and corresponding data for its script.
- transaction output 0 script must be
- The previous transaction output point shall be null.
Transaction | Script | Description |
---|---|---|
transaction input 0 | No script | Stakebase and value shall be exact development subsidy. |
transaction output 0 | OP_TADD | Value shall be exact development subsidy. |
transaction output 1 |
OP_RETURN OP_DATA_12 {LE encoded height} {random} | Block height shall be little endian encoded. |
Additional consensus enforced characteristics:
Note that some rules have been enforced prior the ones listed but out of an abundance of caution some tests are repeated in places where it makes sense. This is normal and desired.
- First transaction of the stake tree shall be a
treasurybase
. - There shall be only one
treasurybase
transaction in the stake tree. - The previous out point for transaction input 0 shall be null.
- The
treasurybase
transaction fraud proof shall be null. - The length of the signature script of transaction input 0 shall be zero.
- The
treasurybase
transaction shall have more than 1 outputs. - The
treasurybase
transaction output 1 script version shall be 0. - The length of transaction output 1 script shall be 14 bytes and consist of an
OP_RETURN
,OP_DATA_12
followed by 12 bytes. The block height where thistreasurybase
is included shall be little endian encoded in the first four bytes following theOP_DATA_12
opcode.
- The number of
treasurybase
output scripts shall be 2. - The version of transaction output 0 script shall be 0.
- The length of transaction output 0 script shall be 1 and the script shall be
OP_TADD
. - The treasury subsidy shall be calculated based on the height and verified to be correct in the transaction. One notable difference is that the treasury subsidy is NOT divided by the number of votes on the block. This is the only difference from the original
coinbase
subsidy calculation.
coinbase
:
- Coinbase shall no longer carry the treasury subsidy transaction at transaction output 0.
- Coinbase transaction version shall be 3.
- The treasury subsidy value is subtracted from transaction input 0 value. An important and intended consequence of this is that disapproved blocks no longer remove the per-block treasury payout.
A user can send funds to the treasury for various reasons. A few examples are
- Moving old treasury balance to new treasury account.
- Returning funds due to overpayment.
- Donations to the Decred project.
treasury add
transaction is identified by the following characteristics:
- The wire message transaction version shall be 3.
- There shall be at least one transaction input script.
- There shall be one or two transaction output scripts.
- All transaction output scripts shall be version 0.
- transaction output 0 script must be
OP_TADD
. - transaction output 1 is optional if there is no change. If there is change it shall be a default
OP_SSTXCHANGE
script.
Transaction | Script | Description |
---|---|---|
transaction input 0..N | Default UTXO scripts | Normal UTXO scripts as you would find on normal transactions. |
transaction output 0 | OP_TADD | Value shall be what is credited to the treasury. |
transaction output 1 | OP_SSTXCHANGE | Optional if there is no change. |
Additional consensus enforced characteristics:
- A
treasury add
transaction shall not have a zero value for change. - There shall be no more than twenty
treasury add
transactions per block.
Voting on valid treasury spend
transactions is done by piggy-backing on consensus
voting transactions. The treasury votes are optionally appended to the
consensus vote.
A treasury vote is identified by the following characteristics:
- The consensus vote format shall remain identical to the pre decentralized treasury agenda activation save for one additional optional output.
- When
treasury spend
votes are appended the version of the transaction shall be 3. - The optional
treasury spend
vote output shall be the last output of the transaction. - The optional
treasury spend
vote output shall be a valid null script. - The null script shall be an
OP_RETURN
followed by a data push and the first two bytes of the data push shall beTV
(or in hex 0x54,0x56). - The remainder of the data length shall be 0 modulo of 32+1 (
treasury spend
transaction hash + vote) - A
treasury spend
transaction hash shall only occur once. - The vote shall be either
Yes = 0x01
orNo = 0x02
and all other values shall be rejected. This means the entire consensus vote shall fail.
treasury spend
votes that are occurring simultaneously.
Format 1
Transaction | Script | Description |
---|---|---|
transaction output N-1 |
OP_RETURN OP_DATA_XX <code>TV treasury vote...
| Up to two (2) treasury votes can be encoded using this format. |
Format 2
Transaction | Script | Description |
---|---|---|
transaction output N-1 |
OP_RETURN OP_PUSHDATA1 data length treasury vote...
| Up to seven (7) treasury votes can be encoded. |
Treasury vote
Transaction | Script | Description |
---|---|---|
transaction output N-1 |
treasury spend transaction hashbyte vote bits |
Yes vote = 0x01 No vote = 0x02 All other values shall be rejected rendering the overall transaction invalid. |
The treasury spend
transactions are rather complex and some additional definitions need
to be made prior to explaining the format.
Required chain configuration parameters:
- Treasury Vote Interval, or TVI, determines in which blocks a
treasury spend
may occur. A block is considered on a TVI when the block height modulo TVI is equal to zero. - Treasury Vote Interval Multiplier, or TVIM, dictates the total duration (total duration = TVI * TVIM) where votes for or against the expenditure are considered valid.
- Treasury Vote Quorum Multiplier and Divisor, TVQM, and TVQD respectively, are used to calculate the required number of votes to reach quorum.
- Treasury Vote Required Multiplier and Divisor, TVRM and TVRD respectively, are used to calculate the required number of Yes votes.
- Treasury Expenditure Policy, or TEP, determines the overall duration where all treasury expenditures are summed and averaged.
- Treasury Expenditure Window, or TEW, is used to calculate the window that is used to verify that the sum of all
treasury spend
does not exceed ~150% of the average treasury spending. - Treasury Expenditure Bootstrap, or TEB, is used to determine a baseline expenditure in order to bootstrap treasury payouts.
- Politeia Keys, or PiKeys, are a number of well-known secp256k1 public keys that are allowed to sign
treasury spend
transactions.
The life-cycle of a treasury spend
transaction is as follows
- PiKey administrator creates a
treasury spend
transaction with an Expiry in the future. - The
treasury spend
is signed and broadcast to the network. - If the
treasury spend
is nominally valid (Expiry in the future, valid signature, valid public key etc) it is allowed in the mempool. - Once the
treasury spend
hits the mempool wallets will be notified. - Voting wallets with a voting policy will start voting either yes/no or abstain at the
treasury spend
vote window start. - Votes are accumulated every block. It is possible for a vote to be "short-circuited" if the outcome is already determined on a TVI block before the end of the voting interval. If an insurmountable tally of yes votes is reached, the
treasury spend
is added to the TVI block. If an insurmountable tally of no votes is reached, thetreasury spend
is removed from the mempool on the TVI block. - At the end of the
treasury spend
window (which is always on a TVI because start is zero based) votes are tallied and if quorum and yes votes breach their respective thresholds thetreasury spend
transaction is added to the block. - If the
treasury spend
transaction does not make it into a block on the final TVI in the window the Expiry will force it from the mempool on the next block.
treasury spend
transaction voting window and validity is completely calculated from
the Expiry field. The Expiry shall always be any TVI+2. This odd number is
emergent from the handling of Expiry in the mempool. A transaction is expired
from the Mempool one block prior to the actual Expiry. Thus in order for the
Tspend transaction to not get evicted from the mempool on the last possible TVI
the Expiry must be set to +2.
The start of a treasury spend
transaction voting window is calculated as follows: Expiry -
(TVI*TVIM) - 2.
The end of a treasury spend
transaction voting window is calculated as follows: Expiry
- 2.
A treasury spend
transaction is considered "inside the window" when the block height >=
start and block height <= end. The end parameter is inclusive for allowing a
treasury spend
in a block however it is exclusive for allowing votes on the treasury spend
that
may end up being allowed on the block.
A treasury spend
transaction is identified by the following characteristics:
- The wire message transaction version shall be 3.
- There shall be one input script.
- There shall be at least two output scripts.
- All output scripts shall be version 0.
- transaction input 0 signature script shall be exactly 100 bytes in length. The script format is
OP_DATA_64
(signature),OP_DATA_33
(Pi public key) followed by anOP_TSPEND
.- The Pi public key that is included in transaction input 0 shall be of the strict compressed public key encoding type.
- transaction output 0 script shall be an
OP_RETURN
OP_DATA_32
. - transaction output 1..N scripts shall be an
OP_TGEN
followed by a P2PKH or a P2SH script.
Transaction | Script | Description |
---|---|---|
transaction input 0 |
OP_DATA_64 signature OP_DATA_33 Pi public key OP_TSPEND | The value shall be sum(expenditures) + mining fee. |
transaction output 0 |
OP_RETURN OP_DATA_32 | Bytes that make the entire transaction unique. First 8 bytes are the little endian encoded value from transaction input 0. The following 24 bytes are random. |
transaction output 1..N |
OP_TGEN P2PKH or P2SH script | These are the individual payouts from the treasury account. |
Additional consensus enforced characteristics:
- The previous out point for transaction input 0 shall be null.
- The
treasury spend
transaction fraud proof shall be null. - The length of the signature script in transaction input 0 shall be 100 bytes ([OP_DATA_64] [signature] [OP_DATA_33] [PiKey] [OP_TSPEND] = 1 + 64 + 1 + 33 + 1 = 100)
- A
treasury spend
transaction shall not be allowed in a block that is not a TVI. - A
treasury spend
transaction shall not be allowed in a block if the start of the voting window is prior to stake validation height. - A
treasury spend
transaction shall not be allowed in a block if the Expiry is outside of thetreasury spend
validity window. - The value of input 0 of a
treasury spend
transaction shall be int64 little endian encoded in the output 0 script in bytes 2 through 10. The value of both shall be identical. - A
treasury spend
transaction shall not be allowed in a block if it has been mined in a prior block (this is to enable support for short-circuiting a vote) that is in the chain of ancestors. - A
treasury spend
transaction shall not be allowed in a block if it does not reach quorum which is calculated as follows:MaxPossibleTSpendVotes = TicketsPerBlock * TVI *TVIM
MinRequiredVotes = MaxPossibleTSpendVotes * TVQM / TVQD
sum(yes votes) + sum (no votes) >= MinRequiredVotes
- A
treasury spend
transaction shall not be allowed in a block if it does not reach enough yes votes which is calculated as follows: (sum(votes cast) + sum(possible remaining votes)) * TVRM / TVRD - A
treasury spend
transaction shall not deplete the entire treasury. The treasury balance shall not become negative. - The sum of all
treasury spend
transactions within the most recent TEP shall not exceed 150% of avg(sum(treasury spends
), TEW). - A
treasury spend
transaction shall not be allowed in a block if the secp256k1 public key is not well-known (encoded in chain parameters). - A
treasury spend
transaction shall not be allowed in a block if the Schnorr signature of the transaction does not match the provided well-known public key. Thetreasury spend
transaction hash shall be calculated via theSigHashAll
method.
All treasury funds in or out are subject to coinbase
maturity rules and thus
the current treasury account balance is determined by adding the sum of all
additions and subtractions from the treasury account as of coinbase
maturity
blocks ago.
The treasury account balance shall remain 0 until the treasury agenda is voted
in and the block height reaches activation height + coinbase
maturity. Only at
that point are any additions and subtractions possible.
In order to allow treasury spend
transactions into the mempool some modifications have to
be made.
- A
treasurybase
transaction shall not be allowed in the mempool. - There shall not be more than seven (7) concurrent
treasury spend
transactions in the mempool. - A
treasury spend
transaction shall not be allowed in the mempool prior to stake validation height. - A
treasury spend
transaction shall not be allowed in the mempool if the Expiry is farther than 2*TVI*TVIM block height away. - A
treasury spend
transaction shall not be allowed in the mempool if the Expiry is not exactly on a TVI+2. - A
treasury spend
transaction shall not be allowed in the mempool if the PiKey in input 0 is not well known. - A
treasury spend
transaction shall not be allowed in the mempool if the signature in input 0 was not signed with the PiKey in input 0. - A
treasury spend
transaction shall not be allowed in the mempool if it was mined in an ancestor block.
It is possible to modify V2 instead of introducing V3 because nothing changes from the viewpoint of the wallet and treasury opcodes are disallowed prior to agenda activation.
- All
treasury spend
transaction output scripts that are tagged withOP_TGEN
shall be added to the filter. - All valid
treasury add
regular transaction inputs shall be added to the filter. - All valid
treasury add
stake transaction inputs shall be added to the filter. treasury add
stake change shall be added to the filter.
The following blockchain parameters were added:
- Politeia key #1: 03f6e7041f1cf51ee10e0a01cd2b0385ce3cd9debaabb2296f7e9dee9329da946c
- Politeia key #2: 0319a37405cb4d1691971847d7719cfce70857c0f6e97d7c9174a3998cf0ab86dd
- Treasury Vote Interval, or TVI: 288 blocks (~1 day)
- Treasury Vote Interval Multiplier, or TVIM: 12 (~7.2 days for short circuit approval; up to 42% of the target-ticket-pool tickets can participate in the vote (if it doesn't short-circuit)
- Treasury Expenditure Window, or TEW: 2 (sum of
treasury spends
within any ~24 day window cannot exceed policy check) - Treasury Expenditure Policy, or TEP: 6 (policy check is average of prior ~4.8 months + a 50% increase allowance)
- Treasury Expenditure Bootstrap, or TEB: 16000 * 1e8 (16000 DCR/TEW as expense bootstrap)
- Treasury Vote Quorum Multiplier, or TVQM: 1 (20% quorum required)
- Treasury Vote Quorum Divisor, or TVQD: 5
- Treasury Vote Required Multiplier, or TVRM: 3 (60% yes votes required)
- Treasury Vote Required Divisor, or TVRD: 5
This proposal will be deployed to mainnet using the standard Decred on-chain voting infrastructure as follows:
Name | Setting | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Deployment Version | 8 | ||||||||||||
Agenda ID | treasury | ||||||||||||
Agenda Description | Enable decentralized Treasury opcodes as defined in DCP0006 | ||||||||||||
Start Time | 1596240000 (Aug 1st, 2020 00:00:00 +0000 UTC) | ||||||||||||
Expire Time | 1627776000 (Aug 1st, 2021 00:00:00 +0000 UTC) | ||||||||||||
Mask | 0x06 (Bits 1 and 2) | ||||||||||||
Choices |
|
This proposal was approved by the stakeholder voting process and is now active.
Implementations MAY optimize their enforcement activation logic to apply the new
rules specified by this proposal to the Active
block and all of its
descendants as opposed to tallying historical votes.
Status | Block Hash | Block Height |
---|---|---|
Voting Started | 000000000000000006005a7e67eafc7fdc65909d10498bed4093d926d7b5318e | 536320 |
Locked In | 000000000000000012449cc1cc38a6e41294ed9525f7e64ab39f0de8801c8d38 | 544384 |
Active | 00000000000000001c6fc262b2673d94827f87daa329b0bdeb7866562ef919cf | 552448 |
This is a hard-forking change to the Decred consensus. This means that once the agenda is voted in and becomes locked in, anybody running code that fully validates blocks must upgrade before the activation time or they will risk rejecting a chain containing the various treasury transactions and accompanying consensus changes that are valid under the new rules but invalid under the old rules.
Other software that performs full validation will need to modify their consensus enforcement rules accordingly.
Wallets, block explorers and other software that interpret blockchain data must observe the new format and rules.
A reference implementation of the decentralized treasury is implemented by pull request #2170.
A reference implementation of enforcing the new semantics in accordance with the results of the agenda vote is implemented by pull request #2170.
A reference implementation of the required agenda definition is implemented by pull request #2170.
Thanks to Dave Collins (@davecgh) and Matheus Degiovani (@matheusd) for helpful discussions regarding many of the design details.
Thanks to the following individuals who provided valuable feedback during the review process of this proposal (alphabetical order):
- Dave Collins (@davecgh)
- Donald Adu-Poku (@dnldd)
- Jake Yocom-Piatt
- Jamie Holdstock (@jholdstock)
- Joe Gruffins (@JoeGruffins)
- Josh Rickmar (@jrick)
- Matheus Degiovani (@matheusd)
This document is licensed under the CC0-1.0: Creative Commons CC0 1.0 Universal license.
The code is licensed under the ISC License.