<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>verbs</title>
        <link>https://paragraph.com/@verbsteam</link>
        <description>we build smart contracts for Nouns.
we're on twitter @davidbrai and @eladmallel.</description>
        <lastBuildDate>Wed, 21 Oct 2026 18:30:18 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>verbs</title>
            <url>https://storage.googleapis.com/papyrus_images/b68176a23b8c2572cf42308874277668be6afe242da1d73b868c1ea182b1f841.png</url>
            <link>https://paragraph.com/@verbsteam</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Updated spec for stream based minority protection]]></title>
            <link>https://paragraph.com/@verbsteam/updated-spec-for-stream-based-minority-protection</link>
            <guid>x35FqtEnZLVH7Zwtvs5B</guid>
            <pubDate>Wed, 02 Oct 2024 09:16:44 GMT</pubDate>
            <description><![CDATA[Edit 2024-10-14: DAO can allow additional contracts to create streams. This is in order to allow selling of treasury nouns outside the auction. In this post we describe an updated spec to the stream based minority protection we introduced in the previous post.High Level DesignNouns DAO auctions an NFT every day. Part of the auction proceeds are sent immediately to the DAO treasury and the rest are streamed over time. For the purpose of this document, we will refer to the escrow contract as St...]]></description>
            <content:encoded><![CDATA[<p><em>Edit 2024-10-14: DAO can allow additional contracts to create streams. This is in order to allow selling of treasury nouns outside the auction.</em></p><p>In this post we describe an updated spec to the stream based minority protection we introduced in the previous <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/jFi5T0aehwZws7Q6jdRn8xZmORu25TiyWz4G5LAHuaU">post</a>.</p><h2 id="h-high-level-design" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">High Level Design</h2><p>Nouns DAO auctions an NFT every day. Part of the auction proceeds are sent immediately to the DAO treasury and the rest are streamed over time. For the purpose of this document, we will refer to the escrow contract as StreamEscrow.</p><p>For more context please see <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://foundation.nouns.wtf/2024/09/06/duna/">this Nouns Foundation post</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/jFi5T0aehwZws7Q6jdRn8xZmORu25TiyWz4G5LAHuaU">our initial post about this design</a>.</p><h3 id="h-step-by-step-example" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step by step example</h3><ul><li><p>Alice wins the daily auction for 10 ETH.</p></li><li><p>Upon auction settlement:</p><ul><li><p>An initial amount of 2 ETH (20%) is paid immediately to the DAO.</p></li><li><p>The remaining 8 ETH are streamed from Alice to the DAO over 1500 days.</p></li><li><p>All newly vested amounts from all streams are sent to the DAO at each auction settlement.</p></li></ul></li><li><p>The stream is managed by a non-upgradeable contract, not in control of the DAO (or anyone else).</p></li><li><p>Alice cancels her stream after 375 days (25% of the stream length), by returning her Noun and withdrawing her unstreamed funds, which come out to 6 ETH.</p></li></ul><h3 id="h-stream-management" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Stream management</h3><p>All streams are managed via a single StreamEscrow contract. All the streams’ funds are deposited into this single contract. It maintains internal accounting in order to know how many funds belong to which stream, and how much has already been streamed to the DAO.</p><p>The reason for a single contract as opposed to a contract per stream, is because it is significantly more gas efficient.</p><p>In the example above, once the stream is created, 8 ETH are transferred to StreamEscrow. The Auction House contract notifies StreamEscrow every time an auction is settled and another chunk of the funds are streamed to the DAO.</p><h3 id="h-creating-a-stream" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Creating a stream</h3><p>To create a stream for a Noun, the account creating the stream must meet two conditions at the same time:</p><ol><li><p>Be on the StreamEscrow contract allowed accounts list, and</p></li><li><p>Be the owner of the Noun in question, or approved to transfer the Noun in question by its owner.</p></li></ol><p>The primary use case is the Auction House contract creating streams upon auction settlement. The Auction House will be allowed by the DAO starting at the proposal that upgrades Auction House to the new streams-supporting version. Auction House is also the owner of each new Noun just before its sent to the auction winner, so it will meet these two conditions consistently.</p><p>Additional use cases might include selling treasury-owned Nouns outside the auction mechanism. In such cases we might create a helper contract that will be allowed, and the DAO will approve such a helper contract to transfer some or all of its Nouns.</p><p>The right to cancel the stream is attached to the Noun NFT, i.e. if Alice transfers her Noun to Bob, then only Bob is allowed to cancel the stream and withdraw the unstreamed funds.</p><h3 id="h-canceling-a-stream" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Canceling a stream</h3><p>In order to cancel her stream, Alice calls a function on StreamEscrow which:</p><ul><li><p>Transfers her Noun into the Nouns DAO treasury.</p></li><li><p>Cancels her stream so that it doesn’t stream any more funds to the DAO.</p></li><li><p>Sends unstreamed funds back to Alice.</p></li></ul><h3 id="h-dao-receiving-streamed-funds" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">DAO receiving streamed funds</h3><p>At each tick of the StreamEscrow clock (every 24 hours or longer), all streams are advanced one step forward, and the newly vested amount is sent to the DAO immediately, as part of the same clock-forwarding transaction.</p><p>Upon every transfer of ETH to the DAO an event is emitted with the ETH amount; this is the primary means of tracking streams revenues.</p><p>The DAO can pass a proposal to change the address to which ETH should be sent; this flexibility can be used in future for example to run revenues through a tax withholding helper contract, or if the DAO chooses to move to a new treasury / executor contract.</p><h3 id="h-fast-forwarding-streams" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Fast-forwarding streams</h3><p>Any Noun owner whose Noun has an active stream can choose to fast-forward their stream by some amount of ticks, all the way up to sending the full value of their stream to the DAO immediately. This is helpful when a Noun owner wants to accelerate their funding of Nouns DAO. The primary downside of fast-forwarding is the reduction in minority protection.</p><h3 id="h-past-nouns" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Past Nouns</h3><p>Nouns that were auctioned before this change was introduced don’t have any stream attached to them.</p><h3 id="h-nounder-nouns" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Nounder Nouns</h3><p>Nounder Nouns will not have any refund available, since none of them are paid for and therefore will not have an escrowed stream.</p><h3 id="h-currency" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Currency</h3><p>Auctions and streams are all conducted in ETH.</p><h3 id="h-summary-of-configuration-parameters" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Summary of configuration parameters</h3><h4 id="h-auction-house-parameters" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Auction House parameters</h4><ul><li><p>Upgradeable and under DUNA control: Yes.</p></li><li><p>Initial payment percentage</p><ul><li><p>Value: 20%.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li></ul></li><li><p>Stream duration:</p><ul><li><p>Value: 1500 ticks.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li><li><p>Only affects new streams. Existing streams cannot be modified.</p></li></ul></li><li><p>StreamEscrow contract address</p><ul><li><p>Can it be modified: Yes, via a DAO proposal to upgrade the Auction House code.</p></li></ul></li></ul><h4 id="h-streamescrow-parameters" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">StreamEscrow parameters</h4><ul><li><p>Upgradeable and under DUNA control: No.</p></li><li><p>DAO executor address, i.e. who’s the admin of this contract.</p><ul><li><p>Value: current treasury.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li></ul></li><li><p>ETH recipient address, i.e. where vested funds are sent.</p><ul><li><p>Value: current treasury.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li></ul></li><li><p>Nouns recipient address, i.e. where Nouns are sent when streams are canceled.</p><ul><li><p>Value: current treasury.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li></ul></li><li><p>The list of accounts allowed to create streams</p><ul><li><p>Value: starts with just Auction House.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li></ul></li></ul><h2 id="h-detailed-design" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Detailed design</h2><p>Introducing refunds via escrowed streams requires the following:</p><ol><li><p>Changing Auction House.</p></li><li><p>Deploying the new StreamEscrow contract.</p></li><li><p>Disabling the Fork.</p></li></ol><p>The gist of the change is that auction proceeds are split, such that some are sent to the DAO, most remaining funds are streamed to the DAO over time. The StreamEscrow clock can be advanced every 24 hours or longer. For convenience, we are “piggybacking” on the Auction House daily settlement transaction, as Nouns’ reliable daily transaction, thus avoiding the need to otherwise automate these stream clock forwarding transactions.</p><p>The code can be found <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/pull/866">here</a>.</p><h3 id="h-why-use-auction-house-as-the-clock" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Why use Auction House as the clock?</h3><p>The primary consideration is that when streams vest, the recipient (DAO) should recognize revenue, and tying vesting to the auction achieves two positive things for the DAO:</p><ol><li><p>Legibility: instead of implicit revenue that’s hard to track, it occurs as part of a transaction, where we can emit events and index them and make them easily trackable.</p></li><li><p>External call piggyback: to have this legibility, someone needs to initiate a transaction; instead of funding bots or humans to do this for us, we can use Nouns’ existing recurring transaction.</p></li></ol><p>The “implicit” alternative seems bad to us. Without explicit transactions, say just vesting every 24 hours or every block, accounting becomes more challenging. We would have to build new tooling that would check the state of streams at specific blocks and store that information in a dedicated database in order to keep track.</p><h3 id="h-auction-house-changes" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Auction House Changes</h3><p>The Auction House change is straightforward: upon auction settlement, instead of sending 100% of the winning bid directly to the DAO’s treasury, the new code will:</p><ul><li><p>Send 20% directly to the treasury.</p></li><li><p>Send 80% to StreamEscrow and register a new stream, with an end time articulated in the number of ticks from today.</p></li><li><p>Notify StreamEscrow that an auction has settled in order to advance all streams by one “tick” (i.e. one auction).</p></li></ul><h3 id="h-streamescrow-details" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">StreamEscrow Details</h3><p>StreamEscrow (SE) performs its accounting using a few key variables:</p><ul><li><p><code>minimumTickDuration</code>: the minimum amount of time that needs to pass between ticks; we intend to set it to 24 hours. This variable is immutable.</p></li><li><p><code>ethStreamPerTick</code>: the amount of ETH streamed to the DAO at each “tick” (i.e. every 24 or longer, when <code>forwardAll</code> is called; default is at auction settlement).</p></li><li><p><code>currentTick</code>: how many ticks have occurred since this contract started handling streams.</p></li><li><p><code>lastForwardTimestamp</code>: the last time a tick occurred; used to enforce the minimum tick duration.</p></li><li><p><code>ethStreamEndingAtTick</code>: a mapping from a tick to the rate of ETH vesting that should stop vesting once we reach that tick.</p></li><li><p><code>streams</code>: a mapping from noun ID to its stream information, including:</p><ul><li><p><code>ethPerTick</code>: the amount of ETH to stream at each tick for this specific stream.</p></li><li><p><code>lastTick</code>: the tick at which this stream will end.</p></li><li><p><code>canceled</code>: whether the Noun owner canceled the stream or not.</p></li></ul></li><li><p><code>allowedToCreateStream</code>: a mapping from an address to whether or not it’s allowed to create streams.</p></li></ul><h4 id="h-functions-used-by-auction-house" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Functions used by Auction House</h4><pre data-type="codeBlock" text="forwardAllAndCreateStream(uint256 nounId, uint16 streamLengthInTicks)
"><code><span class="hljs-built_in">forwardAllAndCreateStream</span>(uint256 nounId, uint16 streamLengthInTicks)
</code></pre><ol><li><p>Requires the following (reverts if not true):</p><ol><li><p><code>msg.sender</code> must be an approved caller, i.e. its value in <code>allowedToCreateStream</code> is <code>true</code>.</p></li><li><p><code>msg.sender</code> must be the owner of the input Noun, or approved by its owner.</p></li></ol></li><li><p>Calls <code>forwardAll()</code> to advance all active streams by one tick to the DAO (more info below).</p></li><li><p>Calculates when this nounId’s stream should end, i.e. at what tick value, using the input of stream length it gets from Auction House.</p></li><li><p>Calculates the new stream’s <code>ethPerTick</code> value by dividing the stream amount (received as ETH sent in this function call) by the stream length input.</p></li><li><p>Adds the new stream’s <code>ethPerTick</code> to the overall <code>ethStreamPerTick</code> rate of streaming per tick for all streams.</p></li><li><p>Adds this new stream to the <code>streams</code> contract-level mapping.</p></li></ol><pre data-type="codeBlock" text="forwardAll()
"><code><span class="hljs-built_in">forwardAll</span>()
</code></pre><ol><li><p>Gracefully requires the following (stops execution without reverting if true, to not halt auction house execution):</p><ol><li><p>At least <code>minimumTickDuration</code> (24 hours) have elapsed since the last time all streams were forwarded.</p></li></ol></li><li><p>Increments <code>currentTick</code> by one.</p></li><li><p>Transfers ETH to the DAO at the amount of <code>ethStreamPerTick.</code></p></li><li><p>Emits the event <code>ETHStreamedToDAO</code> with the amount of ETH streamed at this tick.</p></li><li><p>Handles finished streams (streams whose <code>lastTick</code> value equals the current tick value): 3. For each such stream, decrements <code>ethStreamPerTick</code> by the stream’s <code>ethPerTick</code>.</p></li></ol><h4 id="h-functions-used-by-dao-side-contracts" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Functions used by DAO side contracts</h4><pre data-type="codeBlock" text="createStream(uint256 nounId, uint16 streamLengthInTicks)
"><code><span class="hljs-built_in">createStream</span>(uint256 nounId, uint16 streamLengthInTicks)
</code></pre><ol><li><p>Requires the following (reverts if not true):</p><ol><li><p><code>msg.sender</code> must be enabled via <code>setAllowedToCreateStream.</code></p></li><li><p><code>msg.sender</code> must own the given Noun, or be approved by its owner.</p></li><li><p>There is no active stream for <code>nounId.</code></p></li></ol></li><li><p>Creates a new stream, without forwarding existing streams.</p></li></ol><h4 id="h-functions-used-by-noun-owners" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Functions used by Noun owners</h4><pre data-type="codeBlock" text="cancelStream(uint256 nounId)
"><code><span class="hljs-built_in">cancelStream</span>(uint256 nounId)
</code></pre><ol><li><p>Requires the following (reverts if not true):</p><ol><li><p><code>msg.sender</code> is the owner of nounId.</p></li><li><p>The nounId stream hasn’t been canceled already.</p></li><li><p>The nounId stream hasn’t ended yet.</p></li></ol></li><li><p>Sends Noun with <code>nounId</code> from the owner to the DAO treasury.</p></li><li><p>Decrements <code>ethStreamPerTick</code> by the stream’s <code>ethPerTick</code>.</p></li><li><p>Calculates and sends <code>msg.sender</code> the refund amount (<code>ethPerTick</code> times ticks left until the stream ends).</p></li><li><p>Emits the event <code>StreamCanceled</code> with the amount of ETH sent back to the Noun owner.</p></li></ol><h4 id="h-functions-used-by-the-dao-via-proposals" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Functions used by the DAO (via proposals)</h4><pre data-type="codeBlock" text="setDAOExecutorAddress(address treasury)
"><code><span class="hljs-built_in">setDAOExecutorAddress</span>(address treasury)
</code></pre><ol><li><p>Requires the following (reverts if not true):</p><ol><li><p><code>msg.sender</code> is the DAO executor (treasury).</p></li></ol></li><li><p>Sets the executor address to the new value.</p></li></ol><pre data-type="codeBlock" text="setAllowedToCreateStream(address contract, bool allow)
"><code>setAllowedToCreateStream(<span class="hljs-keyword">address</span> <span class="hljs-class"><span class="hljs-keyword">contract</span>, <span class="hljs-title"><span class="hljs-keyword">bool</span></span> <span class="hljs-title">allow</span>)
</span></code></pre><ol><li><p>Requires <code>msg.sender</code> to be the DAO executor address.</p></li><li><p>Enables/disables the contract to call <code>createStream</code></p></li></ol><pre data-type="codeBlock" text="setETHRecipient(address newAddress)
"><code><span class="hljs-built_in">setETHRecipient</span>(address newAddress)
</code></pre><ol><li><p>Requires <code>msg.sender</code> to be the DAO executor address.</p></li><li><p>Sets <code>ethRecipient</code> to the new address; future vested ETH gets sent to this new address.</p></li></ol><pre data-type="codeBlock" text="setNounsRecipient(address newAddress)
"><code><span class="hljs-built_in">setNounsRecipient</span>(address newAddress)
</code></pre><ol><li><p>Requires <code>msg.sender</code> to be the DAO executor address.</p></li><li><p>Sets <code>nounsRecipient</code> to the new address; future Nouns from canceled streams get sent to this new address.</p></li></ol><h3 id="h-disabling-the-fork" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Disabling the Fork</h3><p>To disable the Fork, the DAO will need to pass a proposal calling the DAO logic function <code>_setForkThresholdBPS</code> with a new value of 10,000, such that it becomes impossible to fork.</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[From Forks to Streams]]></title>
            <link>https://paragraph.com/@verbsteam/from-forks-to-streams</link>
            <guid>bweNSbOBEsc2UbD9fdOs</guid>
            <pubDate>Fri, 06 Sep 2024 13:25:00 GMT</pubDate>
            <description><![CDATA[Nouns DAO is considering incorporating as a Wyoming Decentralized Autonomous Unincorporated Non-profit Association (a “DUNA”). For more information regarding the considerations around that process, please read the Noun Foundation’s blog post. Because of restrictions on the circumstances pursuant to which a DUNA may make distributions to its members, a key change in this transition will be redesigning the minority protection from forks to cancellable streams. This post contains an initial draf...]]></description>
            <content:encoded><![CDATA[<p>Nouns DAO is considering incorporating as a Wyoming Decentralized Autonomous Unincorporated Non-profit Association (a “<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://a16zcrypto.com/posts/article/duna-for-daos/">DUNA</a>”). For more information regarding the considerations around that process, please read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://foundation.nouns.wtf/2024/09/06/duna/">the Noun Foundation’s blog post</a>.</p><p>Because of restrictions on the circumstances pursuant to which a DUNA may make distributions to its members, a key change in this transition will be redesigning the minority protection from forks to cancellable streams. This post contains an initial draft of the streams specification - the design is not yet finalized. To that end, we are sharing this information with the intention of soliciting feedback from the community. We’d love your help finding issues and improving the plan wherever possible.</p><p>In tandem with soliciting feedback from the community, we are also working closely with the Nouns Foundation’s advisors to determine how to best achieve full legal compliance for all Nouners, delegates, DUNA administrators, and community members, without sacrificing any of the core principles of the DAO.</p><h2 id="h-a-potential-design-escrowed-streams" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">A Potential Design: Escrowed Streams</h2><p>We are contemplating changing how auction winners pay for their Noun: instead of paying the full amount to the DAO right away, a small part would be paid to the DAO upon settlement, with most of the funds instead being deposited into a non-custodial and non-upgradeable escrow contract that then autonomously streams auction funds to the DAO over a period of 4 years.</p><p>If a Nouner wishes to exit the DAO, they can send their Noun back to the DAO, which will automatically cancel the stream, and they would then receive any unstreamed funds back from the escrow contract.</p><p>The stream cancellation right is transferable and tied to the Noun NFT.</p><h2 id="h-a-concrete-example" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">A Concrete Example</h2><ul><li><p>Alice wins the auction for 10 ETH.</p></li><li><p>Upon auction settlement:</p><ul><li><p>An initial amount of 2 ETH is paid immediately to the DAO.</p></li><li><p>The remaining 8 ETH are deposited into the escrow contract and streamed to the DAO over 4 years.</p></li></ul></li><li><p>The stream is autonomously managed by a non-upgradeable contract which is not under the control of the DAO (or anyone else).</p></li><li><p>Alice cancels her stream after one year by returning her Noun, which allows her to withdraw her unstreamed funds from the escrow contract (which comes out to 6 ETH).</p></li><li><p>The DAO can withdraw the already streamed funds from the escrow contract (which comes out to 2 ETH, minus whatever the DAO has already withdrawn).</p></li></ul><h2 id="h-no-streams-for-past-nouns" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">No Streams for Past Nouns</h2><p>Unfortunately Nouns which pre-date this change will not have a stream attached. This is due to requirements related to the restructuring of the DAO.</p><h2 id="h-nounder-nouns" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Nounder Nouns</h2><p>Nounder Nouns will not have any stream, since none of them are paid for.</p><h2 id="h-summary-of-configuration-parameters" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Summary of configuration parameters</h2><h3 id="h-auction-house-parameters" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Auction House parameters</h3><ul><li><p>Upgradeable and under DUNA control: Yes.</p></li><li><p>Initial payment percentage</p><ul><li><p>Value: 20%.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li></ul></li></ul><h3 id="h-escrow-parameters" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Escrow parameters</h3><ul><li><p>Upgradeable and under DUNA control: No.</p></li><li><p>Stream duration:</p><ul><li><p>Value: 4 years.</p></li><li><p>Can it be modified: No.</p></li></ul></li><li><p>DAO treasury address</p><ul><li><p>Value: current treasury.</p></li><li><p>Can it be modified: Yes, via DAO proposal.</p></li></ul></li></ul><h2 id="h-summary" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Summary</h2><p>We understand that the streams specification represents a large change to how the DAO has historically operated; however, we think that the change, as part of the DUNA migration, is necessary to enable the continued viability of the DAO. As noted above, these plans are not finalized. We are looking forward to continued discussion with the community and welcome any feedback.</p><p>Thanks,</p><p>verbs ⌐◨-◨</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[A Nouns token delegation vulnerability]]></title>
            <link>https://paragraph.com/@verbsteam/a-nouns-token-delegation-vulnerability</link>
            <guid>gpNNldp11QXaC9vZ07c7</guid>
            <pubDate>Mon, 29 Jul 2024 13:54:08 GMT</pubDate>
            <description><![CDATA[A Nouns token delegation vulnerabilityWe were recently approached by 0xkasper from hexens, a white hat security team, who found a new attack vector based on a vulnerability we were aware of in the Nouns token contract. Nouns tech grants pod has initiated a bounty payment of 30K USDC to the team.TLDRWho’s at risk? Noun owners delegating to EOA accounts (not smart contract accounts).What’s the damage? Noun NFTs can become non-transferrable with no voting power.How likely is it to happen? The pr...]]></description>
            <content:encoded><![CDATA[<h1 id="h-a-nouns-token-delegation-vulnerability" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">A Nouns token delegation vulnerability</h1><p>We were recently approached by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://x.com/0xkasper">0xkasper</a> from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hexens.io/">hexens</a>, a white hat security team, who found a new attack vector based on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discourse.nouns.wtf/t/nouns-dao-v2-audit-summary/2525">a vulnerability we were aware of</a> in the Nouns token contract. Nouns tech grants pod has initiated a bounty payment of 30K USDC to the team.</p><h2 id="h-tldr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">TLDR</h2><ul><li><p>Who’s at risk? Noun owners delegating to EOA accounts (not smart contract accounts).</p></li><li><p>What’s the damage? Noun NFTs can become non-transferrable with no voting power.</p></li><li><p>How likely is it to happen? The probability is low if you trust your delegates and their wallet security setup; otherwise please consider changing your delegation immediately.</p></li></ul><h2 id="h-an-example-scenario" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">An example scenario</h2><p>Alice owns Noun 1, and Bob owns Noun 2.Alice delegates to Bob (Alice votes: 0; Bob votes: 2).</p><p>The problem begins when Bob, whether intentionally or not, uses a faulty delegation function.</p><p>Bob uses the <code>delegateBySig</code> function in the Nouns token contract to delegate to address zero (0x0000…). By doing so, one voting power unit was burned and can never be recovered (Alice votes: 0; Bob votes: 1). This is because most of the code does not expect delegation to address zero to be possible, but <code>delegateBySig</code> allows such a delegation to pass into the voting power change code.</p><p>Continuing the story:</p><p>Bob transfers Noun 2 to a new wallet, let’s name it Bobby (Alice votes: 0; Bob votes: 0; Bobby votes: 1).</p><p>Now Alice&apos;s Noun 1 is a zombie:</p><ul><li><p>its voting power is gone forever.</p></li><li><p>It can never be transferred out of Alice&apos;s wallet (a transfer attempt will always revert).</p></li></ul><p>The reason why transfer attempts will revert is because upon each transfer the Nouns contract reduces the sender’s voting power by one, and since Bob is already at zero, that is an invalid operation (an underflow error).</p><p>The conditions under which this can happen:</p><ul><li><p>You delegate to an EOA account (only EOA accounts can use <code>delegateBySig</code> because it requires a signature with a private key).</p></li><li><p>That EOA account has at least one Noun that it owns.</p></li></ul><p>For more technical information see the last section of this post.</p><h2 id="h-important-takeaways" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Important takeaways</h2><p>The obvious case to worry about is delegating to people you do not trust, who might want to grief you. However, even if you trust your delegate’s intention, they might be subjected to a phishing attack or some other hack, and their attacker might perform these actions to grief you.</p><p>Unfortunately, the NounsToken contract is not upgradeable, so we cannot fix the bug directly, instead we must work around it. The fact that smart contract delegate accounts cannot participate in this attack is very useful.</p><p>For now, the safest bet is to delegate to smart contract accounts only. Ask your delegates to create a Gnosis Safe account and delegate to them there. Until then if you are not sure what to do, delegate back to your Noun owner account.</p><p>For the long term, there are a few design options we’re exploring for how to mitigate this attack vector with a less cumbersome user experience. We will share more information in an upcoming post.</p><p>That’s all for the high level summary. You can find additional technical information below.</p><p>Thanks,verbs ⌐◨-◨</p><h2 id="h-technical-details" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Technical details</h2><p>For those of you who made it this far and care to know exactly how this attack works, here’s a deeper dive.</p><p>The main function to understand is <code>_moveDelegates</code> which is called every time a noun is transferred or when a noun owner account delegates to any other account. See the function code below.</p><p>Let’s follow the story above from a more technical point of view.</p><p>When a noun is bought on auction, it is first minted to the auction house. Minting looks like a transfer from address zero to the recipient. If you follow the code you’ll notice that there’s a special condition regarding address zero that skips the voting power update code for any source or recipient that is address zero. So when a noun is minted, a new voting power unit is created and added to the auction house’s voting power balance (this happens in the <code>_writeCheckpoint</code> function).</p><p>When Alice and Bob bought their respective nouns, the <code>_moveDelegates</code> function ran again, this time deducting one vote from the auction house, and incrementing the buyer’s voting power by one vote.</p><p>When Alice delegated to Bob, this function ran again, this time writing a checkpoint for Alice saying she has zero votes, while giving Bob one more vote, for a total of two (srcRep would be Alice, dstRep would be Bob, and amount would be one, equal to the voting power Alice owns).</p><p>When Bob used <code>delegateBySig</code> and provided the zero address as the delegate, <code>srcRep</code> was Bob, and <code>dstRep</code> was <code>address(0)</code>. Notice how the first part of <code>_moveDelegates</code> that updates <code>srcRep</code> votes executed, while the second part that updates <code>dstRep</code> votes did not execute because <code>dstRep</code> was <code>address(0)</code> – this is the key moment in the attack vector. The result of this transaction is that a vote was deducted, never to be added again. The total number of votes represented in all the latest checkpoints combined are now one short of the Nouns NFT total supply.</p><p>At this moment in time it’s not obvious that Alice should suffer from the situation. In theory, if Bob does nothing else, Alice can still pull her delegation from Bob and her noun wouldn’t become a zombie; in that case it would be Bob’s noun that becomes a zombie.</p><p>The crux of the griefing is when Bob immediately after delegating to address zero, also transfers his noun to a different wallet; in this action <code>_moveDelegates</code> runs again, decreasing Bob’s vote count from one to zero, and increasing Bob’s new wallet’s votes to one. This is another side of the bug; in valid delegation scenarios when Bob delegates to Charlie and Bob transfers a noun they own, a vote is deducted from Charlie’s votes, since that is in fact where Bob’s noun’s vote resides. In our address zero buggy scenario, due to how the view function <code>delegates</code> is implemented, address zero is a magic value that assumes an account is its own delegate, so from the code’s point of view Bob is his own delegate, not address zero, and so Bob’s vote count is decreased.</p><p>Remember, Alice is still delegating to Bob, while Bob has zero votes. If she tries to undelegate from Bob, <code>_moveDelegates</code> is called where <code>srcRep</code> is Bob and <code>dstRep</code> is Alice, and the line that calculates <code>srcRepNew</code> will revert with the underflow error you can see in the code, because it would be attempt to run the calculation <code>0 - 1</code> on an unsigned integer.</p><p>The same problem arises if Alice tries to transfer her noun to a different account. The function <code>_beforeTokenTransfer</code> is executed, and in it again <code>_moveDelegates</code> is called, moving votes from Alice’s delegate, Bob, to the recipient’s delegate, which by default is the recipient account itself. And so again the code is run with Bob as <code>srcRep</code>, and we hit the underflow error.</p><p>At this moment again, it’s not entirely the case that Alice’s noun has to get stuck in her wallet with no voting power. If for whatever reason Bob buys another noun, or any other noun owner delegates votes to Bob, Bob’s votes go above zero again, and Alice then has the opportunity to undelegate or transfer her noun elsewhere. The problem of the zombie noun would then transfer to whichever noun remains owned by or delegated to Bob.</p><h3 id="h-nouns-token-relevant-code-snippets" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Nouns Token relevant code snippets</h3><pre data-type="codeBlock" text="function _moveDelegates(
    address srcRep,
    address dstRep,
    uint96 amount
) internal {
    if (srcRep != dstRep &amp;&amp; amount &gt; 0) {
        if (srcRep != address(0)) {
            uint32 srcRepNum = numCheckpoints[srcRep];
            uint96 srcRepOld = srcRepNum &gt; 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
            uint96 srcRepNew = sub96(srcRepOld, amount, &apos;ERC721Checkpointable::_moveDelegates: amount underflows&apos;);
            _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
        }

        if (dstRep != address(0)) {
            uint32 dstRepNum = numCheckpoints[dstRep];
            uint96 dstRepOld = dstRepNum &gt; 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
            uint96 dstRepNew = add96(dstRepOld, amount, &apos;ERC721Checkpointable::_moveDelegates: amount overflows&apos;);
            _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
        }
    }
}

function _writeCheckpoint(
    address delegatee,
    uint32 nCheckpoints,
    uint96 oldVotes,
    uint96 newVotes
) internal {
    uint32 blockNumber = safe32(
        block.number,
        &apos;ERC721Checkpointable::_writeCheckpoint: block number exceeds 32 bits&apos;
    );

    if (nCheckpoints &gt; 0 &amp;&amp; checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
        checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
    } else {
        checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
        numCheckpoints[delegatee] = nCheckpoints + 1;
    }

    emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
}

function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId
) internal override {
    super._beforeTokenTransfer(from, to, tokenId);

    /// @notice Differs from `_transferTokens()` to use `delegates` override method to simulate auto-delegation
    _moveDelegates(delegates(from), delegates(to), 1);
}

function delegates(address delegator) public view returns (address) {
    address current = _delegates[delegator];
    return current == address(0) ? delegator : current;
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_moveDelegates</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> srcRep,
    <span class="hljs-keyword">address</span> dstRep,
    <span class="hljs-keyword">uint96</span> amount
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
    <span class="hljs-keyword">if</span> (srcRep <span class="hljs-operator">!</span><span class="hljs-operator">=</span> dstRep <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> amount <span class="hljs-operator">></span> <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">if</span> (srcRep <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-keyword">uint32</span> srcRepNum <span class="hljs-operator">=</span> numCheckpoints[srcRep];
            <span class="hljs-keyword">uint96</span> srcRepOld <span class="hljs-operator">=</span> srcRepNum <span class="hljs-operator">></span> <span class="hljs-number">0</span> ? checkpoints[srcRep][srcRepNum <span class="hljs-operator">-</span> <span class="hljs-number">1</span>].votes : <span class="hljs-number">0</span>;
            <span class="hljs-keyword">uint96</span> srcRepNew <span class="hljs-operator">=</span> sub96(srcRepOld, amount, <span class="hljs-string">'ERC721Checkpointable::_moveDelegates: amount underflows'</span>);
            _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
        }

        <span class="hljs-keyword">if</span> (dstRep <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)) {
            <span class="hljs-keyword">uint32</span> dstRepNum <span class="hljs-operator">=</span> numCheckpoints[dstRep];
            <span class="hljs-keyword">uint96</span> dstRepOld <span class="hljs-operator">=</span> dstRepNum <span class="hljs-operator">></span> <span class="hljs-number">0</span> ? checkpoints[dstRep][dstRepNum <span class="hljs-operator">-</span> <span class="hljs-number">1</span>].votes : <span class="hljs-number">0</span>;
            <span class="hljs-keyword">uint96</span> dstRepNew <span class="hljs-operator">=</span> add96(dstRepOld, amount, <span class="hljs-string">'ERC721Checkpointable::_moveDelegates: amount overflows'</span>);
            _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_writeCheckpoint</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> delegatee,
    <span class="hljs-keyword">uint32</span> nCheckpoints,
    <span class="hljs-keyword">uint96</span> oldVotes,
    <span class="hljs-keyword">uint96</span> newVotes
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> </span>{
    <span class="hljs-keyword">uint32</span> blockNumber <span class="hljs-operator">=</span> safe32(
        <span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span>,
        <span class="hljs-string">'ERC721Checkpointable::_writeCheckpoint: block number exceeds 32 bits'</span>
    );

    <span class="hljs-keyword">if</span> (nCheckpoints <span class="hljs-operator">></span> <span class="hljs-number">0</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> checkpoints[delegatee][nCheckpoints <span class="hljs-operator">-</span> <span class="hljs-number">1</span>].fromBlock <span class="hljs-operator">=</span><span class="hljs-operator">=</span> blockNumber) {
        checkpoints[delegatee][nCheckpoints <span class="hljs-operator">-</span> <span class="hljs-number">1</span>].votes <span class="hljs-operator">=</span> newVotes;
    } <span class="hljs-keyword">else</span> {
        checkpoints[delegatee][nCheckpoints] <span class="hljs-operator">=</span> Checkpoint(blockNumber, newVotes);
        numCheckpoints[delegatee] <span class="hljs-operator">=</span> nCheckpoints <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;
    }

    <span class="hljs-keyword">emit</span> DelegateVotesChanged(delegatee, oldVotes, newVotes);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_beforeTokenTransfer</span>(<span class="hljs-params">
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
    <span class="hljs-keyword">address</span> to,
    <span class="hljs-keyword">uint256</span> tokenId
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{
    <span class="hljs-built_in">super</span>._beforeTokenTransfer(<span class="hljs-keyword">from</span>, to, tokenId);

    <span class="hljs-comment">/// @notice Differs from `_transferTokens()` to use `delegates` override method to simulate auto-delegation</span>
    _moveDelegates(delegates(<span class="hljs-keyword">from</span>), delegates(to), <span class="hljs-number">1</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delegates</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> delegator</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span></span>) </span>{
    <span class="hljs-keyword">address</span> current <span class="hljs-operator">=</span> _delegates[delegator];
    <span class="hljs-keyword">return</span> current <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>) ? delegator : current;
}
</code></pre>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Nouns Governor: a significant design challenge]]></title>
            <link>https://paragraph.com/@verbsteam/nouns-governor-a-significant-design-challenge</link>
            <guid>nYPVF027XZTjnUKYdf9r</guid>
            <pubDate>Mon, 10 Jun 2024 15:42:43 GMT</pubDate>
            <description><![CDATA[Intro & TLDRSince our last update on Nouns Governor we’ve been working on speccing and implementing the design described as “Approach 1: Delegation NFTs”. While working on the proposed design for $nouns and soliciting feedback from Nouners (thanks 9999!) we discovered a flaw in the Nouns Gov design we were working towards. The flaw enables an attacker to use the voting power of swappable Nouns sitting idle in a contract. We describe it in detail below. All the solutions we could come up with ...]]></description>
            <content:encoded><![CDATA[<h2 id="h-intro-and-tldr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Intro &amp; TLDR</h2><p>Since our last <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/wovYOvDZym79vxBnr01WYH3pjy_r7GNSQQ1Pa9-QM3U">update</a> on Nouns Governor we’ve been working on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/verbsteam/specs/blob/main/nouns-gov-interface.md">speccing</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/compare/master...verbsteam:nouns-monorepo:verbs-nouns-gov-poc-flashloan-protection">implementing</a> the design described as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/wovYOvDZym79vxBnr01WYH3pjy_r7GNSQQ1Pa9-QM3U#heading-approach-1-delegation-nfts">“Approach 1: Delegation NFTs”</a>. While working on the proposed design for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.nouns.camp/proposals/536">$nouns</a> and soliciting feedback from Nouners (thanks 9999!) we discovered a flaw in the Nouns Gov design we were working towards.</p><p>The flaw enables an attacker to use the voting power of swappable Nouns sitting idle in a contract. We describe it in detail below.</p><p>All the solutions we could come up with to mitigate this attack require the Nouner to deposit their Noun(s) in a new contract, which is a requirement we were hoping to avoid.</p><p>If we choose to accept this requirement, then we think there’s a simpler design which enables granular delegation, without switching to an NFT based voting approach. We will describe it in a followup post.</p><h2 id="h-removing-checkpoints" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Removing checkpoints</h2><p>When switching to NFT based voting we decided to not use the voting power checkpointing system used today. Voting by NFT eliminates the ability to double vote with the same token because we record each time an NFT is used to vote.</p><p>Unfortunately, removing the checkpoints also opens up a new attack vector.</p><h2 id="h-the-attack" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The attack</h2><p>Setting up the stage:</p><ul><li><p>A contract (pool) holds 20 Nouns and enables permissionless swapping.</p></li><li><p>This could be the case with the proposed $nouns contract for example.</p></li><li><p>A Nouns proposal is up for voting.</p></li></ul><p>Attack steps:</p><ol><li><p>The attacker has one Noun; they vote with their Noun.</p></li><li><p>They swap their Noun with a Noun from the pool; they use the pool Noun to vote as well.</p></li><li><p>Repeat for all the Nouns available for swapping in the pool.</p></li></ol><p>This enables the attacker to use the voting power of the Nouns in the pool as their own. This attack is not possible today because the Nouns contract keeps checkpoints of the voting power of each account at each block. Unless the attacker buys more Nouns, their swapping with the pool can only give them a single vote, because they can only hold a single Noun per block.<br>Unfortunately, the Nouns contract does not keep track of which account controlled which Noun in its checkpointing system, and the contract is not upgradeable, so the most straightforward solution - having said tracking native to Nouns token - is not possible. We detail below the alternatives we’ve come up with so far.</p><h2 id="h-possible-mitigations" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Possible mitigations</h2><h3 id="h-checkpointing-ndt-ownership" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Checkpointing NDT ownership</h3><p>One of the ideas we were exploring as a mitigation to this attack was to have checkpoints for Noun Delegation Tokens (NDTs). NDTs are one-to-one NFTs which a Nouner can mint to delegate their voting power of that Noun to someone else. Any time an NDT changes ownership, we would record the block. This would allows us to answer the following question in the contract: was this user the owner of this NDT when this proposal’s voting started?</p><p>Unfortunately this does not solve the problem. One could perform a similar sequence to the one above, just before a proposal’s voting starts:</p><ol><li><p>Swap their Noun with a Noun from the pool.</p></li><li><p>Mint themselves an NDT.</p></li><li><p>Repeat for all the Nouns in the pool.</p></li></ol><p>This ensures that they will be the owner of all the NDTs at the proposal’s snapshot block. The only scenario in which this wouldn’t be the case is if another attacker backruns them and does the same thing. In any case, the problem remains.</p><p>The root of the problem is that we can’t hook into Nouns transfers. And since the Nouns token contract is not upgradeable, we can’t add those hooks either.</p><h3 id="h-storage-proofs" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Storage proofs</h3><p>We could use storage proofs to prove that a Noun was owned by a specific account at a specific block; <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.federation.wtf/">federation.wtf</a> does something similar. Besides the additional complexity of requiring users to generate these proofs, it would probably also require relying on a third party to have access to historic block hashes. This level of complexity is not a good fit for the core governance contracts.</p><h3 id="h-depositing-nouns-in-custody" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Depositing Nouns in custody</h3><p>We could keep track of Nouns transfers if we require users to deposit their Nouns into a custody contract. This would allow us to keep ownership info checkpoints at the Noun level, and not just the NDT. For example, we could create a “WrappedNoun” contract (similar to wrapped punks). In this WrappedNoun contract, we could keep track of the owner per block.</p><p>The main drawback here is that Nouners would have to deposit their Nouns into a new contract, which is something we were hoping to avoid.</p><p>In the solution space of depositing Nouns in custody there’s another possible solution we’re currently exploring. We could have a delegator contract which keeps each of your Nouns in a separate custody wallet. This would allow you to delegate each Noun to a different address. One advantage of this solution is that it doesn’t require any changes in the current governor contracts. We’ll publish another post describing this solution in detail soon.</p><h2 id="h-next-steps" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Next steps</h2><p>We aren’t happy with any of the solutions we came up with so far. We think this issue is risky enough to be a showstopper for the Nouns Governor design. We will soon publish a design for granular delegation that works with the current governor contract. If you think differently, or if you have other solutions in mind, we’d love to hear from you.</p><p>We will start a conversation about this in the new <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://warpcast.com/~/channel/nouns-protocol">nouns-protocol</a> channel on farcaster. We are experimenting with using rounds.wtf to incentivize and reward good ideas &amp; feedback.</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[How to participate in Nouns Client Incentives?]]></title>
            <link>https://paragraph.com/@verbsteam/how-to-participate-in-nouns-client-incentives</link>
            <guid>wv87CgtpT1qGLenJO8Dl</guid>
            <pubDate>Wed, 08 May 2024 09:04:00 GMT</pubDate>
            <description><![CDATA[What are Client Incentives?Client Incentives is a new mechanism for Nouns to pay clients (frontends) for interactions they facilitate between users and the Nouns protocol. For more details please read our blog post about it. As of today, the rewards have no been activated yet. They will be once another DAO proposal goes through to configure and enable them.I have a frontend for Nouns, how do I join?1. Register a clientIdCall the registerClient function of the Rewards contract. This function e...]]></description>
            <content:encoded><![CDATA[<h2 id="h-what-are-client-incentives" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What are Client Incentives?</h2><p>Client Incentives is a new mechanism for Nouns to pay clients (frontends) for interactions they facilitate between users and the Nouns protocol.</p><p>For more details please read our <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/28ONBDu7kti7cYBFBnEKgktxzuelvhuxu_jtGw9YrdU">blog post</a> about it.</p><p>As of today, the rewards have no been activated yet. They will be once another DAO proposal goes through to configure and enable them.</p><h2 id="h-i-have-a-frontend-for-nouns-how-do-i-join" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">I have a frontend for Nouns, how do I join?</h2><h3 id="h-1-register-a-clientid" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. Register a clientId</h3><p>Call the <code>registerClient</code> function of the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x883860178f95d0c82413edc1d6de530cb4771d55">Rewards contract</a>.</p><p>This function expects these parameters:</p><ul><li><p><code>name</code>: what is the name of your client? e.g. camp</p></li><li><p><code>descriptor</code>: a short description of your client, ideally a URL</p></li></ul><p>After calling this function, a new Nouns Client Token <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://testnets.opensea.io/assets/sepolia/0x7cc7bf1479a5e41b61b26b99792d2f685bf3ca32/1">NFT</a> will be minted to you. The ID of that NFT is your clientId. You will need to send your clientId in order to get attribution and get rewards.</p><p>Currently you can use it in the following functions:</p><ul><li><p>NounsAuctionHouse: <code>createBid(nounId, clientId)</code></p></li><li><p>NounsDAO:</p><ul><li><p><code>castRefundableVote(proposalId, support, clientId)</code></p></li><li><p><code>castRefundableVoteWithReason(proposalId, support, reason, clientId)</code></p></li><li><p><code>propose(targets, values, signatures, calldatas, description, clientId)</code></p></li><li><p><code>proposeBySigs(proposerSignatures, targets, values, signatures, calldatas, description, clientId)</code></p></li></ul></li></ul><p>The NFT also gives you permission to:</p><ul><li><p>Call <code>updateClientMetadata</code> to update the name &amp; description of your client.</p></li><li><p>Call <code>withdrawClientBalance</code> to withdraw your rewards.</p></li></ul><h3 id="h-2-collect-rewards" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. Collect rewards</h3><p>If your clientId was used in any of the functions mentioned above, then you may be eligible for rewards.</p><p>In order to reduce gas costs on the DAO functions, rewards are only updated when someone calls the following functions on the Rewards contract:</p><ul><li><p><code>updateRewardsForAuctions</code></p></li><li><p><code>updateRewardsForProposalWritingAndVoting</code></p></li></ul><p>Gas is refunded for these calls as long as the contract is holding enough WETH.</p><p>You can check your balance to see if you have any rewards to withdraw by calling <code>clientBalance</code> with your clientId.</p><h3 id="h-3-enable-withdrawals-on-your-clientid" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. Enable withdrawals on your clientId</h3><p>To withdraw your rewards, your clientId needs to be approved for withdrawals. We added this step to reduce the risk of bad actors trying to abuse the system.</p><p>Clients can be approved only via DAO proposals. To get your clientId approved, create a proposal in which the DAO invokes the Rewards contract with the following function:</p><ul><li><p><code>setClientApproval(clientId, true)</code></p></li></ul><h3 id="h-4-withdraw-rewards" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4. Withdraw rewards</h3><p>Once your clientId has been approved for withdrawals, call the <code>withdrawClientBalance(clientId, to, amount)</code> function to withdraw your rewards.</p><p>If you have any questions, feel free to reach out to us on farcaster: @el4d &amp; @davidbr</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Client Incentives V1 scope]]></title>
            <link>https://paragraph.com/@verbsteam/client-incentives-v1-scope</link>
            <guid>wkH6sWjIPV34M81uWgTz</guid>
            <pubDate>Wed, 31 Jan 2024 11:18:06 GMT</pubDate>
            <description><![CDATA[Background & contextClient Incentives is a new mechanism for Nouns to pay clients (frontends) for interactions they facilitate between users and the Nouns protocol. In our previous post we described the goals and direction we’re exploring with client incentives. If you haven’t read it, please do. In this post, we’ll describe the scope for the first version we plan to release. A short recap of the goals of client incentives:Incentivize the existence of multiple frontends for the nouns protocol...]]></description>
            <content:encoded><![CDATA[<h2 id="h-background-and-context" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Background &amp; context</h2><p>Client Incentives is a new mechanism for Nouns to pay clients (frontends) for interactions they facilitate between users and the Nouns protocol. In our previous <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/vyhDmS56XvnIBFUQ65n_KgmYzkD88-UHxUitxRGw08o">post</a> we described the goals and direction we’re exploring with client incentives. If you haven’t read it, please do. In this post, we’ll describe the scope for the first version we plan to release.</p><p>A short recap of the goals of client incentives:</p><ul><li><p>Incentivize the existence of multiple frontends for the nouns protocol</p></li><li><p>Create a clear compensation structure for building and maintaining a frontend</p></li><li><p>Allow sunsetting nouns.wtf’s protocol interactions without disruption</p></li></ul><p>The Client Incentives mechanism measures a client’s contribution only based on generated calls to the Nouns smart contracts. We don’t think it’s a complete way to measure contribution, but good enough for some automatic compensation. We think Nouns should keep funding/retro-funding clients for other contributions and innovations as they happen.</p><h2 id="h-interactions-rewarded-in-v1" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Interactions rewarded in V1</h2><p>In V1 the following interactions will be rewarded:</p><ol><li><p>Creating proposals</p></li><li><p>Voting on proposals</p></li><li><p>Bidding on auctions</p></li></ol><p>We chose not to include the following interactions in V1:</p><ul><li><p>Forking: since it’s a pretty rare event, compensating based on usage is probably not the right way to guarantee support. We suggest that for the time being, the foundation maintains forking support on nouns.wtf and the DAO allocates budget for maintenance as needed.</p></li><li><p>Delegation: it’s less obvious how to prevent gaming with delegation so we decided to postpone it for now.</p></li><li><p>Settling auctions: there are currently other incentives for settling auctions, mostly for picking specific traits for the next minted noun (e.g. FOMO, nounscout.wtf).</p></li><li><p>Updating proposals: we expect clients that build tools for creating proposals will also be expected to support updating proposals.</p></li><li><p>Proposal candidates: candidates are rewarded once they become proposals via `proposeBySigs`. We think that may be sufficient for V1.</p></li></ul><h2 id="h-reward-structure" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Reward structure</h2><p>At first we wanted to use a pay-per-use reward structure. Meaning, for every time a smart contract was called via a client, the client would get rewarded. The main benefit of this approach was simplicity, both conceptually, and technically.</p><p>Thanks to feedback we received on our previous post, we decided to change the rewards to all be defined as a percentage of auction revenues; this has two benefits:</p><ul><li><p>Incentive alignment between clients and the DAO for auction revenue to increase</p></li><li><p>Easier to budget a % of income than pay-per-use which is less predictable</p></li></ul><p>For auctions, the client which facilitated the winning bid will be entitled to a percentage of that auction’s bid.</p><p>For creating &amp; voting on proposals the process is slightly more involved; Proposals are rewarded periodically. A percentage of all auction revenue in that period is used as the reward pool which is split between clients based on usage of proposal creation and voting. Proposals are only eligible for rewards if a minimum % of voting supply voted For the proposal. This is meant as an anti-spam measure.</p><p>The DAO has the following main parameters to configure:</p><ol><li><p><em>percentRewardAuctions</em>: % of auction revenue rewarding auction bidding</p></li><li><p><em>percentRewardProposals</em>: % of auction revenue for rewarding writing proposals</p></li><li><p><em>percentRewardProposalVotes</em>: % of auction revenue for rewarding votes</p></li></ol><p>For more detailed description, please review <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/verbsteam/specs/blob/main/client-incentives-spec.md">the spec</a>.</p><h2 id="h-who-can-participate" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Who can participate?</h2><p>We want to start permissionless, meaning that anyone can register themselves as a client. We hope this will lower the friction for building a client and being rewarded. Any developer can build a client, register themselves, and immediately start getting paid if they get usage, without the need to put a proposal for funding.</p><p>If we see there’s abuse of the system, e.g. trying to get rewards for yourself or using rewards to pay users to use a specific client, we will change the system to either be permissioned or have some ability to punish misbehaving clients.</p><h2 id="h-l1-vs-l2" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">L1 vs L2</h2><p>We’ve considered implementing this contract on an L2 to reduce gas costs. Specifically we’ve explored Axiom’s ZK Coprocessor as a way to read mainnet storage state from an L2. While Axiom’s platform is very powerful, at the moment it seems to not yet be a good fit for our needs. Specifically, the limitation on the number of datapoints that can be verified in a single call forces the solution to be more complex than we’d like. There’s a lot more technical details here to explain which we’ll consider expanding on in a separate post if there’s demand for it. The main reasons we chose to stick to mainnet for this version are:</p><ul><li><p>The L2 solution is significantly more complex resulting in longer shipping time as well as technical dependencies.</p></li><li><p>Axiom’s V2 is not live yet on mainnet and L2s.</p></li><li><p>The associated costs with using Axiom were not trivial to calculate given the complexity of the required solution.</p></li></ul><p>We’re hoping that by the time we’re working on the next version of client incentives it will be on an L2, but for now we’re staying on mainnet.</p><h2 id="h-next-steps" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Next steps</h2><p>If you have any questions, please check the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/verbsteam/specs/blob/main/client-incentives-spec.md">spec</a> for more details. If you still have questions, feedback or suggestions, please reach out!</p><p>In the meantime, we’re developing the contracts based on the spec mentioned above. Besides the side contract used for rewards, we will need to upgrade core contracts:</p><ul><li><p>AuctionHouse: will be upgraded to record historic prices as well as the winning bid clientId.</p></li><li><p>DAOLogic: will be upgraded to record the clientId used for proposals &amp; votes.</p></li></ul><p>We will do an audit for these changes and propose the upgrade to the DAO.</p><p>Once deployed, the DAO will need to fund the side contract, and decide on what percentage of the auction’s revenue to dedicate to each of the rewards.</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Nouns Fork: Exploring the Griefing Attack]]></title>
            <link>https://paragraph.com/@verbsteam/nouns-fork-exploring-the-griefing-attack</link>
            <guid>hkDLDH1rWgwDhDwtSGZo</guid>
            <pubDate>Wed, 27 Dec 2023 23:19:11 GMT</pubDate>
            <description><![CDATA[Nouns Fork is a minority protection mechanism that allows Nouners to exit Nouns DAO (aka OG DAO), into a fresh copy of Nouns DAO, reusing their token IDs and art, and the Nouns governance system, and taking with them their fair share of OG DAO’s treasury into the fork DAO treasury. Nouners need to band together to meet the fork threshold to be able to fork. We launched V1 of Nouns Fork with a known griefing vector, which we’d like to better explore and explain, and ultimately decide if there’...]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/iN0FKOn_oYVBzlJkwPwK2mhzaeL8K2-W80u82F7fHj8">Nouns Fork</a> is a minority protection mechanism that allows Nouners to exit Nouns DAO (aka OG DAO), into a fresh copy of Nouns DAO, reusing their token IDs and art, and the Nouns governance system, and taking with them their fair share of OG DAO’s treasury into the fork DAO treasury. Nouners need to band together to meet the fork threshold to be able to fork. We launched V1 of Nouns Fork with a known griefing vector, which we’d like to better explore and explain, and ultimately decide if there’s a worthwhile solution we should build.</p><p>While <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/W4gaOrp6NC6jopc6vGsGuhz3o4ej0G_0TFhBlcLed94">arbitrage</a> remains the top concerns many Nouners have with regards to the Fork, we won’t be covering that here. On the arbitrage problem, we are happy to explore further if we get a strong signal from the DAO, similar to how we made Fork V1 our most urgent priority <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://snapshot.org/#/nouns.eth/proposal/0x7f4db41648494a7406d58a2a621280fb3568aaa87c5f26aadd36b1f657a0e7a9">after receiving a strong signal on a Snapshot vote</a>.</p><p>In this post we will stay focused on the known griefing attack Fork V1 has, and potential mitigations we’re considering.</p><h2 id="h-the-griefing-attack" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The griefing attack</h2><p>An attacker with a voting majority can force an honest minority to fork and then disband their fork DAO by forcing them to ragequit.</p><p>Let’s walk through it step by step:</p><ol><li><p>The attacker buys a majority share of votes (by owning Nouns or bribing others).</p></li><li><p>The attacker then either puts up a malicious proposal, or holds the DAO hostage by shooting down all proposals.</p></li><li><p>The minority, e.g. all other Nouners, initiate a fork.</p></li><li><p>The attacker joins their fork and has majority votes in the fork DAO as well.</p></li><li><p>The attacker puts up a malicious proposal in the fork DAO.</p></li><li><p>The minority has no choice but to ragequit.</p></li></ol><p>The griefing attack stems from the fact that any Noun can join any fork, so if there’s a malicious majority, they can force the minority into forking and then simply join their fork DAO. The mitigation we currently have is allowing fork DAO Nouners to ragequit at any time without needing to band together, so people get away with their fair share and leave the malicious Nouner with little-to-no profit.</p><p>This griefing is problematic despite having ragequit because one of Fork’s aspirations is to keep forkers together as DAO members; while the honest minority can choose to regroup into a new DAO after they ragequit, it might still be a significant hit to the project’s momentum.</p><p>You might wonder: why would anyone perform this attack? We think the most likely motivation is to hurt or ruin Nouns.</p><h2 id="h-potential-solutions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Potential solutions</h2><p>We have a couple of ideas, both are variations of the same principle: somehow limiting which Nouns can or cannot join a fork. The first idea is based on forking on a specific proposal, and blacklisting Nouns that voted and got what they wanted (e.g. voted For and the proposal succeeded). The second idea is allowing Nouners who initiate a fork to set a blacklist (or whitelist) of which Nouns can join. Let’s explore how each idea might work in more detail.</p><h3 id="h-automatic-vote-based-blacklisting" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Automatic vote-based blacklisting</h3><p>A fork is created on a specific proposal, as part of the proposal’s timeline. Once a proposal reaches the Successful / Defeated / Vetoed state, an Escrow Period starts giving Nouners time to escrow to meet fork threshold, and if threshold is met the fork is executed and others can join, same as today. The key difference is: if the proposal is Successful, Nouns that voted For cannot fork, and if the proposal is Defeated, Nouns that voted Against cannot fork. Vote-based conditions will only be possible with the upcoming <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/tQ64cUYlf9hwdDvY8HLs3uw2vs_XwJelp8cY9leMO6c">Noun Governor</a>’s NFT-based voting.</p><p>For example say a majority group passes a proposal to take all treasury funds, other Nouns can fork off knowing that at least the Nouns that voted for the proposal can’t fork with them; the attacker might have extra Nouns that didn’t vote to fork with, but likely not a significant amount to pose an immediate threat.</p><h4 id="h-new-problems-and-possible-solutions" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">New problems and possible solutions</h4><p>One problem can arise when a Nouner’s delegate votes in favor of an attack or a proposal the Nouner deeply opposes (intentionally or accidentally); this would result in the Nouner not being able to fork, while they ought to be included. This problem can be mitigated by expecting Nouners to keep track of all proposals and change their delegation before voting on a malicious proposal begins. Another possible mitigation is adding a “delegate override” ability for Nouners to override their delegates’ votes.</p><p>As we’ve seen onchain this year, forks can often happen due to political polarization. In such times Nouners want to make sure they fork or stay with others they feel aligned with. In this design Nouners can be left behind when they vote differently from others they feel allied with, and if their Nouner friends choose to fork on a proposal where they voted differently, the Nouner in question is unable to join. We imagine this leading to voting anxiety and more “copy-paste” voting rather than voting as Nouners truly think. The easiest mitigation in our view is to keep Fork V1’s existing forking mechanism, such that a group of Nouners can fork together without these exclusion risks.</p><h3 id="h-manual-blacklisting" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Manual blacklisting</h3><p>We can avoid these automatic blacklisting problems in one fell swoop, by taking a different approach: manual blacklisting (or whitelisting).</p><p>In the manual design, any Nouner can initiate a fork and set a blacklist of Noun IDs, thereby preventing the attacker from joining their fork.</p><h4 id="h-new-problems-and-possible-solutions" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">New problems and possible solutions</h4><p>Using this design with a high fork threshold seems problematic. One problem is that if a real threat arises and such a selective fork is used, some honest Nouners might get left behind for unfortunate reasons, either by the fork initiator making a mistake, or leaving them out on purpose. This problem exists in the automatic design as well, but to a much lesser degree since the fork initiator has no control over the blacklist.</p><p>Lowering fork threshold has its risks as well, as discussed during the initial Fork design period. We’d like to restart some of those discussions and see if a very low threshold is viable.</p><p>If the DAO decides to use a low threshold, this design can lead to many forks one after the other. Therefore, if we were to disable proposal execution during each fork’s forking period, the DAO might be unable to execute proposals for a long time; this could be exploited as a way of griefing the DAO.</p><p>To mitigate this concern we think these kinds of forks should not block proposal execution; instead, the fork initiator needs to manually set the forking period expiration timestamp, and if they are trying to exit prior to a specific proposal’s execution they would need to make sure that timestamp precedes when said proposal can be executed.</p><p>Worth noting that in the future an attacker might have ways to swap out their Nouns, either with treasury Nouns or some other liquidity pool, and they might use a swap to circumvent a fork blacklist. The minority can mitigate this risk by blacklisting all treasury (or liquidity pool) Nouns.</p><h2 id="h-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h2><p>The manual approach combined with a lower fork threshold seems better than the automatic approach; the rules for when one can fork and which forks one can join are easier to grok. Specifically Nouners are less likely to be left behind in the OG DAO for unfortunate reasons.</p><p>Whether we can use a much lower fork threshold requires further inquiry with the DAO and the foundation.</p><p>As always, we are asking for your thoughts and feedback; should we solve this griefing problem? or just leave it open? Are there any Fork design changes you think we should explore further?</p><p>Special thanks to wag, for coming back to Nouns with gusto, and engaging with us on these challenging design questions and adding ideas like the manual fork admin direction.</p><p>Thanks everyone and looking forward to your feedback,<br>verbs team ⌐◨-◨</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[How a medium severity issue can become critical: our recent Nouns DAO audit]]></title>
            <link>https://paragraph.com/@verbsteam/how-a-medium-severity-issue-can-become-critical-our-recent-nouns-dao-audit</link>
            <guid>rJIW6LgHTOP50gz8Sye7</guid>
            <pubDate>Tue, 28 Nov 2023 10:52:27 GMT</pubDate>
            <description><![CDATA[In July 2023 we did two audits for a big Nouns DAO upgrade, first with Spearbit and then with code4rena. During the Spearbit audit, one of the fixes we made, for a medium severity issue, introduced a new critical issue; the critical issue was not caught in the first audit’s mitigation review, but was luckily caught in the second audit. We messed up but got lucky, and we worry this might happen in other projects. We wanted to share a short retrospective and some mitigation ideas, hoping to hel...]]></description>
            <content:encoded><![CDATA[<p>In July 2023 we did two audits for a big Nouns DAO upgrade, first with Spearbit and then with code4rena. During the Spearbit audit, one of the fixes we made, for a medium severity issue, introduced a new critical issue; the critical issue was not caught in the first audit’s mitigation review, but was luckily caught in the second audit.</p><p>We messed up but got lucky, and we worry this might happen in other projects. We wanted to share a short retrospective and some mitigation ideas, hoping to help others avoid such mistakes in future.</p><h2 id="h-the-issue-in-detail" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The issue in detail</h2><p>If you’re not interested in the technical details of the issues, feel free to skip this section.</p><p>A bit of context to help understand the issue:</p><ul><li><p>A key change in this project added a minority protection mechanism to Nouns DAO, which lets a minority group fork off to a new instance of Nouns DAO; let’s call those fork DAOs.</p></li><li><p>Forks DAOs come with a classic ragequit mechanism, allowing a token holder to quit by giving up their token(s), and receiving their fair share of the fork DAO’s treasury.</p></li><li><p>One’s fair share of the treasury can include ETH as well as ERC20 tokens. The ERC20 tokens sent upon quit are set in a whitelist configured by the DAO.</p></li></ul><p>Now we can talk about the original medium issue Spearbit found (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/blob/d417586ae46f8d32801a3028c2c3496b119fc032/packages/nouns-contracts/audits/dao%20v3%20-%20spearbit%20audit%20report.pdf">issue 5.2.16</a>). The gist is:</p><ul><li><p>If there is a malicious majority of token holders in the fork DAO.</p></li><li><p>Then they can pass a proposal to change the whitelist of ERC20s, to include faulty addresses, such that the quit function always reverts.</p></li><li><p>Thereby disabling the quit function for all other fork DAO members.</p></li></ul><p>We followed the auditors’ recommendation and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/pull/732">submitted a change</a> that allows token holders to specify a subset of ERC20s to receive when they quit. The change was approved during the mitigation review process.</p><p>The critical issue we accidentally introduced, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://code4rena.com/reports/2023-07-nounsdao#h-01-user-can-steal-tokens-by-using-duplicated-erc20-tokens-as-parameter-in-nounsdaologicv1forkquit">and was caught by code4rena (issue H-01)</a>, allows fork DAO members who quit to steal tokens by submitting duplicate ERC20 contract addresses to the modified quit function.</p><h2 id="h-how-did-this-happen" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How did this happen?</h2><h3 id="h-the-flaws-in-our-approach" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">The flaws in our approach</h3><p>We felt under significant pressure to ship fast; many DAO members were impatient to have this version live. Since our north star is serving the needs of the DAO, we took that pressure to heart, perhaps more than we should have. We were rushing this version forward way more than we would have without that pressure.</p><p>This rushing sentiment played a key role in other aspects mentioned below.</p><h3 id="h-mitigation-review" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Mitigation review</h3><p>Spearbit’s audit process included a two-week fix period during which the audit team is available for up to two business days, to review fixes we submitted for issues they found. It was during this period that we introduced the critical issue that was missed.</p><p>In hindsight, we relied too heavily on the mitigation review. We advise protocol teams to carefully consider every fix, and to not regard time-limited mitigation reviews with the same trust as the primary audit period.</p><p>We would like to invite Spearbit to share their learnings with us and the broader community; what could have been done differently?</p><h3 id="h-signal-to-noise-in-issues-found" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Signal to noise in issues found</h3><p>One of our assumptions going into an audit with a reputable org like Spearbit is that we won’t need to review &amp; respond to many minor issues. However, this wasn’t the case.</p><p>A lot of our time was spent discussing why we think certain issues are not interesting to us.</p><p>Specifically, there were multiple occasions where medium-severity issues assumed that a DAO could pass visibly malicious proposals. Quoting from the report:</p><blockquote><p>While the governance process gives an opportunity to detect and block such malicious proposals, the assumption is that a malicious majority can force through any proposal, even a visibly malicious one. Also, it is not certain that all governance proposals undergo thorough scrutiny of security properties and their impacts. Token holders need to actively monitor all proposals for malicious updates to create, execute, and join a fork before such a proposal takes effect.</p></blockquote><p>While we agree with the general statement, this is an issue with DAOs at large, and the forking feature introduced is actually a way to help mitigate this risk.</p><p>These kinds of issues are labeled as medium-severity due to Spearbit’s risk classification matrix:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fb16d3fa6fc7ef6f7d7c1af73100d4e4e70b6c275cef26b106fef5128fe93686.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Low likelihood x High impact = Medium severity.</p><p>Because the lowest likelihood level is low, any high-impact issue, no matter how unlikely, is classified at Medium severity.</p><p>We recommend adding another level of likelihood below “low” such that: very low likelihood x High impact = Low severity.</p><p>Another reason we chose to fix certain issues was so they wouldn’t get flagged during the subsequent code4rena audit. In hindsight, it would’ve been better to leave them as is and mark them as “known issues” for the second audit.</p><h3 id="h-fixing-medium-severity-issues-might-not-be-worth-the-risk" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Fixing medium severity issues might not be worth the risk</h3><p>Making changes to critical areas of the protocol at such a late stage of the development cycle, especially while trying to meet deadlines, might not be worth the risk.</p><p>Fixes introduced at this stage will probably not get the same level of testing and attention they require. Knowing that, it may be better to leave some fixes for a future version.</p><p>For this reason, we decided to leave some of the issues found in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://code4rena.com/reports/2023-07-nounsdao">code4rena audit</a> unfixed for now.</p><h2 id="h-what-can-we-do-to-improve" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What can we do to improve?</h2><p>Protocol teams, do your best to allocate ample time for audits, and help your devs feel safe to optimize for quality and less for deadlines. Mistakes during this period can be very costly. And don’t feel like you have to fix every issue; if it’s not a must, err on the side of letting it go for now.</p><p>The labeling of issues by severity is useful for understanding which issues should be fixed, but it does not provide the whole picture. When deciding whether an issue should be fixed, the complexity of the potential fix is an important consideration. For example, a medium-severity  issue, with a trivial fix, should probably be fixed. On the other hand, if a non-trivial fix is recommended, more careful assessment is required on whether the fix is worthwhile, and what kind of review or follow-up audit should be done.</p><p>We think that auditors could provide more guidance on which issues they recommend fixing. For example:</p><p><strong><em>Issue</em></strong><em>: Some issue with proposal creations<br></em><strong><em>Severity</em></strong><em>: Medium<br></em><strong><em>Potential Fix</em></strong><em>: Change the rules for how a proposal can be created<br></em><strong><em>Recommendation</em></strong><em>: Don’t fix in this version due to high complexity. Consider fixing in future protocol versions with additional audits.</em></p><p>Perhaps auditing teams can check in with their clients during the audit and ask if they are happy with the signal-to-noise ratio. If the clients are experiencing fatigue, it seems very important to pause and discuss how to improve; the mid-audit client experience seems underrated.</p><p>Specifically for DAO audits, audits can be much better if there’s early alignment on how to treat all issues that start with a malicious majority assumption; we suspect most protocol teams will prefer to spend very little time on those issues.</p><p>Above all, let’s have more public conversations about the auditing experience from both sides and continue iterating on making it awesome.</p><p>Thanks for reading,</p><p>verbs ⌐◨-◨</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[The Nouns Arb Game]]></title>
            <link>https://paragraph.com/@verbsteam/the-nouns-arb-game</link>
            <guid>LoDJa0hyEcuLPFhQztum</guid>
            <pubDate>Tue, 07 Nov 2023 17:23:33 GMT</pubDate>
            <description><![CDATA[For most of 2023 Nouns DAO auctions have been won by ‘arbitrageurs’ whose primary goal is to extract profits from the DAO’s treasury by redeeming their Nouns to the DAO at a higher price than they paid at auction. This arbitrage is the result of the project’s history, having been launched in the previous bull cycle when treasury grew much faster than the DAO could spend it, followed by the bear market we’re in right now, with auctions settling at much lower prices. This activity is problemati...]]></description>
            <content:encoded><![CDATA[<p>For most of 2023 Nouns DAO auctions have been won by ‘arbitrageurs’ whose primary goal is to extract profits from the DAO’s treasury by redeeming their Nouns to the DAO at a higher price than they paid at auction. This arbitrage is the result of the project’s history, having been launched in the previous bull cycle when treasury grew much faster than the DAO could spend it, followed by the bear market we’re in right now, with auctions settling at much lower prices.</p><p>This activity is problematic for Nouns because it blocks long-term-aligned participants from acquiring Nouns and contributing their energy, capital, and perspective to the project. Additionally, this process ‘leaks’ a portion of the DAO treasury to arbitrageurs at the expense of future proposers.</p><p>In this post we’d like to show how specific DAO parameter changes and activities can affect arbitrage in Nouns DAO auctions and help us get back to a place where we can attract one new long term member every day.</p><h2 id="h-first-some-quick-definitions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">First, some quick definitions:</h2><h3 id="h-fork-threshold" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Fork Threshold</h3><p>The % of the circulating (not including DAO-owned Nouns) Noun supply that’s required to exit to a new instance of Nouns DAO.</p><h3 id="h-book-value" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Book Value</h3><p>The amount of ETH (and other assets) that a Noun NFT would bring with it upon forking to its own instance of Nouns DAO.</p><h3 id="h-arbitrageur-arber" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Arbitrageur (arber)</h3><p>While not arbitrage in the purest sense of the word, Nouns DAO arbitrageurs are attempting to buy Noun NFTs in the daily auctions and exit them to their own instance of Nouns DAO with their pro-rata share of the treasury. Once in control of their own instance of Nouns DAO, they will withdraw the treasury ETH, hopefully earning more than they bid in the primary DAO auctions.</p><h3 id="h-natural-demand" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Natural Demand</h3><p>The prices long-term Nouners are willing to bid to win Nouns auctions. At the time of this writing natural demand almost always loses auctions to arbers.</p><h2 id="h-how-an-arber-might-think" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How an Arber Might Think</h2><p>Arbers bid to make a profit. To do so, they attempt to predict the eBV (expected book value) at the time the next fork event will occur and win Nouns auctions below their eBV, leaving them with a profit margin.</p><p>To decide if and how much to bid, arbers ask themselves (1) when will the next fork happen, and (2) what will BV be at fork time (eBV).</p><p>When the next fork happens is affected by variables like: the fork threshold and adjusted total supply, which together tell us how many nouns must escrow to initiate a fork; and how many nouns are already held by arbers who intend to fork.</p><p>What will BV be at fork time is affected by variables like: auction revenues; predicted spend rate; and predicted DAO-owned nouns distribution.</p><p>We have <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.google.com/spreadsheets/d/1mky9mWhUvd7L55z3hzU0Axg1XBxfngefG3X9Trof1NY/edit#gid=87840035">a simplified spreadsheet model</a> you can clone and play with, to better develop your arb intuitions.</p><p>With this understanding of how an arber might think, we can switch to the Nouner perspective, explore how Nouners can affect the arb game, and what Nouners might want to do to best serve the project.</p><h2 id="h-how-nouners-can-change-the-arb-game" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How Nouners Can Change the Arb Game</h2><p>The main problem we’re hoping to solve: not enough auctions are won by long-term players.</p><p>As long as eBV is greater than natural demand, arbers will continue to dominate auctions. We expect eBV to reach natural demand one way or another, and then we expect to see a growing portion of auctions won by long-termers.</p><p>Yes, eBV (and BV) is trending in the direction we think solves the problem. However, we think it’s too slow and too much value is leaking to arbers until we get there.</p><p>Nouners can change the arb game for the better. Let’s look at a few key variables and how they affect the arb. After that we discuss possible directions and their potential implications.</p><h3 id="h-spend-the-treasury" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Spend the treasury</h3><p>As long as Nouns DAO controls funds that sum up to BV being greater than natural demand, we expect arbers to continue their efforts to extract ETH from the treasury, either through forking or through malicious proposals.</p><p>Various poison pills like buying a Punk or sending funds to a timelock smart contract can certainly hurt the arb via forking; however we advise against such tactics as they grow the incentive to mount a majority attack.</p><p>The only way out is through. Spending on proposals is the safest most effective anti-arb strategy. Worth noting Nouners have been successful at decreasing BV through proposal spending ever since the last bull market ended.</p><p>Arbers are tracking the DAO’s spend rate. If they believe Nouners intend to accelerate spending, we expect lower auction bids due to a lower eBV.</p><h3 id="h-distribute-nouns" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Distribute Nouns</h3><p>BV is the treasury value divided by the number of nouns in circulation, i.e. not owned by the DAO. Therefore distributing DAO-owned Nouns to any recipient other than the DAO dilutes BV. If arbers see more nouns distributed, they will predict a lower eBV and therefore bid lower.</p><p>At the time of this writing, adjusted (circulating) supply is 370, while the DAO owns 532 Nouns (303 treasury + 229 escrow). If the DAO were to distribute all its Nouns today, BV would immediately shrink by a factor of ~2.4x.</p><p>However, we don’t think this is a meaningful lever to impact the arb because realistic distribution rates seem to have a negligible effect. For reference, since fork 0 ended on September 15th, 12 nouns were distributed (including 3 to the PropHouse round) in 53 days, making the rate 0.226 nouns per day.</p><h3 id="h-change-fork-threshold" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Change fork threshold</h3><p>In the context of the arb game, it’s most useful to translate fork threshold into the number of auctions or days until the next fork becomes possible or likely.</p><p>We think this is the most interesting parameter to discuss, since it’s a simple configuration change that can have dramatic effects. To further develop intuitions on Fork Threshold, let’s discuss what might happen with a high vs zero threshold.</p><p><strong>What might happen if Fork Threshold is much higher?</strong></p><p>A longer time to fork makes eBV harder to predict, so arbers will bid lower to account for the added risk. Nouners can use higher threshold values to push arber bids down as a way of getting closer to natural demand.</p><p>A greater threshold leads to arbers holding a larger number of votes they will likely use to vote against most spending proposals, as we’ve seen before fork 0, in an attempt to preserve BV. It’s not all bad as it gives good reason for dormant voters to engage or delegate.</p><p>If Fork Threshold is raised and we continue to see arbers accumulating nouns, it might need to be raised again until we’re convinced eBV has met natural demand.</p><p>After a few months BV should catch up with eBV and natural demand, making it safe to lower Fork Threshold again to provide better minority protection.</p><p><strong>And what if Fork Threshold is much lower?</strong></p><p>A very low threshold provides arbers with high predictability and little time delay, making it rational for arbers to compete with each other up to a small profit margin. In other words, you should expect auctions to settle just short of BV at auction time.</p><p>A positive aspect is that per auction the treasury value leak becomes minimal, meaning Nouners can feel a lesser sense of urgency to spend BV down (some urgency should remain in order to meet natural demand).</p><p>The main downside is arbers are likely to continue dominating the auctions a while longer, until other factors like spending on proposals push BV down to where natural demand is able to compete with arbers.</p><p>Another concern is DAO potentially spending significant amounts of time in forking periods, unable to execute proposals. We may need to consider introducing a short cool down period between forks to ensure the DAO has time to execute proposals.</p><h3 id="h-example-model-tinkering" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Example model tinkering</h3><p>Let’s look at four configurations with different Fork Threshold and daily spending values.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/54a9c96a85120ff5ef044293613815204fbbad0e10e4a92231b29dba4273128c.png" alt="10% Fork Threshold, 30 ETH daily spend" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">10% Fork Threshold, 30 ETH daily spend</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/211bf0f3c3f37d8cc1f57d2a42ca5be32a3fc56c2fd9cc890caecc5287809b1f.png" alt="10% Fork Threshold, 90 ETH daily spend" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">10% Fork Threshold, 90 ETH daily spend</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/396f72e57f6f157302ad87e1fbee705829296e0b53c13020961f83232c2b5a25.png" alt="30% Fork Threshold, 30 ETH daily spend" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">30% Fork Threshold, 30 ETH daily spend</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fbe6fb5f94874e22e07acf1acb23b547cc0eebd8bcc808be7b069b1f517c7c75.png" alt="30% Fork Threshold, 90 ETH daily spend" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">30% Fork Threshold, 90 ETH daily spend</figcaption></figure><p>Notice the big difference in time to fork between Fork Threshold at 10% vs 30%; this results in the big eBV difference we see between spending 30 ETH vs 90 ETH daily.</p><p>Let’s run a similar comparison, varying Fork Threshold and daily nouns distribution values.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1c2c0316611e8902064bf4ad23274970609808f43ffe06556db04052390fc3b7.png" alt="10% Fork Threshold, 0.3 nouns distribution per day" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">10% Fork Threshold, 0.3 nouns distribution per day</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a8b3fa0a292e699655065cc0de64902bc5b56818782bba5b9bc723d27d469147.png" alt="10% Fork Threshold, 1 nouns distribution per day" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">10% Fork Threshold, 1 nouns distribution per day</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d45d700eb95921a138f4281dbc1b64a86e14f2a51231a98d50ac0294702bb5e3.png" alt="30% Fork Threshold, 0.3 nouns distribution per day" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">30% Fork Threshold, 0.3 nouns distribution per day</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fbb4daeefbe24b7dc34dcf6c284fca3f98d55da5de7ded81552366cc1a4bdb18.png" alt="30% Fork Threshold, 1 nouns distribution per day" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">30% Fork Threshold, 1 nouns distribution per day</figcaption></figure><p>Nouns distribution makes little difference to eBV at 10% Fork Threshold, while at 30% threshold it’s a bit more interesting. Still we maintain this lever isn’t cost-effective as a means of lowering eBV; it’s still an interesting activity for other reasons like growing Nouns’ network value.</p><h3 id="h-a-visual-model" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">A visual model</h3><p>At some point we dreamed this post would be an exciting interactive page like the famous NYTimes infographic articles. Instead we have <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.google.com/spreadsheets/d/1mky9mWhUvd7L55z3hzU0Axg1XBxfngefG3X9Trof1NY/edit#gid=87840035">the simplified sheet above</a>, as well as a more visual and interactive model below. We might post improved models if this version isn’t useful enough.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.desmos.com/calculator/jcdoesxbyj">In this visual model</a> we chose Fork Threshold for the X axis, as it seems like the most interesting parameter for Nouners. The Y axis is eBV, the variable Nouners probably want to push down to let natural demand win Nouns auctions.</p><p>The model lets you change the values of all other parameters and see their direct impact on the relationship between Fork Threshold and eBV. For example, try increasing spend rate and see how eBV declines much faster, or increase the number of Nouns already intending to fork, and see how eBV increases.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ec377c1f213fd3b26ab70edac29061a760813b5d2267761e48a287032a8a2d21.png" alt="Desmos visual model screenshot, please click through and play https://www.desmos.com/calculator/jcdoesxbyj " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Desmos visual model screenshot, please click through and play https://www.desmos.com/calculator/jcdoesxbyj</figcaption></figure><h2 id="h-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h2><p>Right now 90%+ of auctions are won by arbitrageurs. As long as the ability to fork is a feature of the DAO, we would not expect arbitrage activity to ever reach zero.</p><p>So what can Nouners do?</p><ul><li><p>Iterate on <strong>high fork threshold</strong> values until eBV meets natural demand; run frequent reassessments until successful or a new approach is discovered.</p></li><li><p><strong>Lower fork threshold to zero</strong> (w/ upgrade) and let arbers compete on smaller margins, taking longer to spend BV down and accepting the reality of almost zero new long-term players joining via auctions.</p></li><li><p><strong>Change nothing</strong>. The current spend rate might be sufficient; a daily/monthly spending Dune dashboard is a critical missing tool to continue the conversation.</p></li><li><p><strong>Disable the fork</strong>, but we won’t elaborate on this option.</p></li></ul><p>We believe that a good near-term milestone is seeing 50%+ of auctions won by long-term Nouners. The best way we have thought of so far is the <strong>high fork threshold coupled with fast-enough spending and ongoing analysis</strong>.</p><p>Please let us know if this breakdown was helpful, if any additional questions arise, and how might we make it better.</p><p>Thanks!<br>the verbs ⌐◨-◨</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Nouns Protocol Rewards]]></title>
            <link>https://paragraph.com/@verbsteam/nouns-protocol-rewards</link>
            <guid>VsD0gHZcKeRV6Q5eNoh3</guid>
            <pubDate>Thu, 28 Sep 2023 07:56:03 GMT</pubDate>
            <description><![CDATA[MotivationLike any other protocol, Nouns DAO relies on clients (webapps / mobile) to interact with its smart contracts. There are many reasons for the DAO to benefit from having multiple clients available, to name a few:Redundancy of clients reduces risk of technical issues limiting accessThe ability to sunset or stop developing nouns.wtf which is currently being maintained by NoundersGives space for new clients to emerge, including specialized clients like a proposal builderCurrently nouns.w...]]></description>
            <content:encoded><![CDATA[<h1 id="h-motivation" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Motivation</h1><p>Like any other protocol, Nouns DAO relies on clients (webapps / mobile) to interact with its smart contracts. There are many reasons for the DAO to benefit from having multiple clients available, to name a few:</p><ul><li><p>Redundancy of clients reduces risk of technical issues limiting access</p></li><li><p>The ability to sunset or stop developing nouns.wtf which is currently being maintained by Nounders</p></li><li><p>Gives space for new clients to emerge, including specialized clients like a proposal builder</p></li></ul><p>Currently nouns.wtf is in an awkward place where it’s still probably the most popular client, but at the same time it’s not being actively maintained. It’s also not entirely clear how decisions are made on what can be added to the site.</p><p>We want to propose a model where clients get paid by the DAO based on usage. By usage we mean interactions with the smart contracts such as bidding on auctions, creating proposals, and voting. This is similar to the way <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="">Liquity</a> incentivizes frontends with “kickbacks”.</p><p>We hope this will create the following incentives:</p><ol><li><p>Incentivize clients to provide great UX (and do some minimum marketing) to drive more usage to their apps.</p></li><li><p>Incentivizes clients to solve for all the interactions the DAO pays for (and we can pay more for interactions with insufficient coverage).</p></li><li><p>Incentivizes clients to keep up with DAO upgrades, so they remain functional and continue to be used.</p></li></ol><p>The simplest way this can work is by adding a <code>client</code> parameter to the function calls, e.g.:</p><p><code>castVote(proposalId, support, reason, client)</code> where <code>client</code> is the wallet address of the client that facilitated this transaction.</p><h1 id="h-diving-deeper" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Diving deeper</h1><p>Let’s discuss the key interactions we think are worth paying for, how they could be paid, and how to make sure they can’t be gamed.</p><h3 id="h-bidding-on-auctions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Bidding on auctions</h3><h4 id="h-how-to-mitigate-gaming" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">How to mitigate gaming?</h4><p>We don’t want to pay for every <code>createBid</code> call because that can be easily gamed by making many low value bids. One way to get around it is to only pay for the interaction of the <em>winning bid</em>.</p><h4 id="h-options-for-calculating-payouts" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Options for calculating payouts</h4><ul><li><p>Fixed percentage of the auction settlement amount.</p></li><li><p>Fixed ETH amount.</p></li><li><p>Other options you think make sense? Please let us know</p></li></ul><h3 id="h-creating-proposals" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Creating proposals</h3><p>Having great proposal creation tools is important, supporting good previews, different transaction types, etc.</p><h4 id="h-how-to-mitigate-gaming" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">How to mitigate gaming?</h4><p>We don’t want to pay for every proposal creation because it may incentivize people to create spam proposals just to get the payment.</p><p>A few options on how to avoid it:</p><ul><li><p>Only pay for successful proposals that get executed.</p></li><li><p>Only pay for proposals that pass quorum.</p></li><li><p>Let us know if you have more ideas.</p></li></ul><h4 id="h-options-for-calculating-payouts" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Options for calculating payouts</h4><ul><li><p>Fixed ETH amount per proposal.</p></li><li><p>Fixed percentage of the amount of funding asked in the proposal. This is problematic because it creates weird incentives, and not all proposals are directly asking for funding.</p></li><li><p>Allocate a percentage of the DAO’s income to pay for proposals created, e.g. X% of auction revenue per month is used to pay governance clients for new valid proposals (valid meaning passed anti-gaming filters mentioned above).</p></li><li><p>Pay out disproportionately to top clients (e.g. 1st place gets 2x more than 2nd place).</p></li></ul><h3 id="h-voting" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Voting</h3><h4 id="h-how-to-mitigate-gaming" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">How to mitigate gaming?</h4><p>In order to prevent spam proposals created just for voting payments, we can use the same method as mentioned above, i.e. only count votes made on “valid” proposals.</p><h4 id="h-options-for-calculating-payouts" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Options for calculating payouts</h4><ul><li><p>Fixed ETH amount per vote transaction.</p></li><li><p>Fixed ETH amount per vote, i.e. if voting with 2 nouns, client gets paid double.</p></li><li><p>Fixed ETH amount per proposal: e.g. if 1 ETH is paid out per proposal, and a proposal had 100 votes, then for each vote, the originating client gets 0.01 ETH.</p></li></ul><h3 id="h-other-interactions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Other interactions</h3><p>We think the interactions listed above are the key interactions the DAO should pay for and those should be in the scope of the first iteration of this model.</p><p>Other interactions and possible payment options:</p><ul><li><p>Proposal updates (<code>updateProposal</code>)</p><ul><li><p>We don’t want to incentivize updating proposals for payouts because that’s easily gamed by doing no-op updates. Perhaps it makes sense to pay the client which originated the most recent version of a proposal. If a proposal was updated, we would update the originating client for that proposal. It makes sense for clients to support both functionalities.</p></li></ul></li><li><p>Proposal candidates</p><ul><li><p>All the interactions related to candidates have the goal of eventually turning the candidate into a Proposal via <code>proposeBySigs</code>.</p></li><li><p>Payouts for proposal creation provide incentive for clients to support all the functionality of proposal candidates.</p></li><li><p>Assuming this is enough incentive, perhaps the specific candidate interactions (creating, updating, signing, feedback) don’t need payouts.</p></li></ul></li><li><p>Delegation</p><ul><li><p>Don’t have a good idea on how to prevent spam delegations for payouts. Open to suggestions!</p></li></ul></li><li><p>Forking</p><ul><li><p>Probably makes sense for fork-related interactions to be paid for by both OG DAO and the fork DAO.</p></li><li><p>Probably makes sense to pay per forking Noun, whether put in escrow or joining after fork DAO creation; this allows multiple clients to contribute to a single fork event and be fairly compensated.</p></li><li><p>How much should be paid per forking Noun? Should it be a nominal amount, e.g. 0.01 ETH? Or should it be a percentage of BV? Any other ideas?</p></li></ul></li></ul><h3 id="h-avoiding-fake-clients" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Avoiding fake clients</h3><p>A more general way to try to game the system, is to pretend to be a client by putting your own wallet address when interacting with the DAO contracts. This gets worse if people actually use clients, but swap the client address with their own when posting transactions.</p><p>One way to mitigate this risk is for the DAO to maintain a list of approved clients that can be paid. Whenever a new client wants to be added to this list, they can put up a proposal. It also serves as a way to advertise that this client exists.</p><p>Alternatively there could be some algorithmic way to determine that a client is likely not fake, e.g. condition payout on a minimum number of interactions, from different wallets, etc.</p><p>We’d like your feedback here. Do you think it’s better to keep a list of approved clients or rather take the permissionless route of codifying some rules to identify “real” clients? If the latter, what rules do you think will work well?</p><h1 id="h-budget" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Budget</h1><p>How much would the DAO need to pay to make it worthwhile for teams to develop clients?</p><p>We invite existing client teams to share some stats of their development and maintenance costs. Based on these numbers the DAO can pick some reasonable amounts to set as payouts.</p><h1 id="h-technical-considerations" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Technical considerations</h1><p>We wanted to share some interim thoughts we had on how to implement this, and we welcome any feedback.</p><p>These are the requirements we had in mind so far:</p><ol><li><p>Changing the amounts and formulas for payouts should not require an audit, i.e. should be outside the core DAO contracts</p></li><li><p>It should be possible to delegate the ability to change the payout scheme to a trusted multisig, e.g. Tech Grants Pod.</p></li><li><p>Small (ideally zero) additional gas cost for interacting with contracts.</p></li></ol><p>In order to meet requirements (1) &amp; (2), we imagine the payout being outside of the core DAO contracts. The DAO would explicitly fund this side contract via proposals.</p><p>The core DAO contracts would introduce a new <code>client</code> parameter in the relevant functions, which would be either an ID or a wallet address to which to send payouts.</p><p>Regarding gas costs, we considered some methods that wouldn’t require writing to storage during the interactions:</p><ol><li><p>Send a message to an L2 with the client id and interaction details; write it to storage on L2; payout calculation and disbursement on L2.</p></li><li><p>Use storage-proofs to provide evidence of the client ids to a contract on mainnet or an L2.</p></li></ol><p>Both of these options add a certain degree of complexity and dependency on third parties.At the moment we’re leaning towards keeping everything on mainnet if it’s not too gas intensive.</p><p>For those interested, see a rough estimate for gas costs at the bottom of this post.</p><h1 id="h-whats-next" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What’s next?</h1><p>Please share your thoughts and feedback with us. Any ideas on better economics or technical solutions are very welcome.</p><p>We’re currently leaning towards implementing everything on mainnet for simplicity. Let us know if you think there’s a better way.</p><p>We want to hear your feedback before we move on to implementation:</p><ul><li><p>Do you think our ideas to mitigate gaming are good? Should the DAO keep a list of approved clients? Do you have better ideas?</p></li><li><p>We plan to deploy everything on mainnet. Do you think we should use an L2 instead?</p></li><li><p>We want to focus on proposals, voting &amp; auction bids at first. Do you think the V1 scope should be different?</p></li><li><p>What do you think would be the best payouts schemes?</p></li><li><p>How much would the DAO need to pay to make it worthwhile for teams to develop and maintain clients?</p></li></ul><hr><h1 id="h-appendix-gas-costs" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Appendix: gas costs</h1><h3 id="h-what-would-be-the-minimum-gas-footprint-to-keep-everything-on-mainnet" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">What would be the minimum gas footprint to keep everything on mainnet?</h3><p>A rough estimate of the additional gas cost based on the pseudocode below:</p><ol><li><p>AuctionHouse.createBid</p><ol><li><p><strong>One expensive SSTORE* per auction</strong> (setting a zeroed storage slot). By default that would be done by the first bidder, but we could also move it to be done by the <code>settleCurrentAndCreateNewAuction</code> function.</p></li><li><p>Subsequent bids have minimal extra gas cost</p></li></ol></li><li><p>DAO.propose</p><ol><li><p><strong>One expensive SSTORE per proposal</strong> to store the client address.</p></li><li><p>The current storage layout of proposals is not optimized so we can probably “squeeze-in” the client parameter without incurring extra gas cost.</p></li></ol></li><li><p>DAO.castVote</p><ol><li><p><strong>One expensive SSTORE per client per proposal:</strong> the first vote cast from a client.</p></li><li><p>This can be reimbursed as part of vote refunds, so the cost is shifted to the DAO.</p></li></ol></li></ol><p>*expensive SSTORE: storage write of a non-zero value into a zero slot; about 20K gas, which at 100 gwei gas price and ETH at $1600 would be ~$3.2.</p><p>Below is some rough pseudocode of the changes required in the DAO’s core contracts to save the necessary data onchain:</p><pre data-type="codeBlock" text="createBid(uint nounId, address client) {
  biddingClient[nounId] = client;
  // regular bid code continues...
}

propose(targets, values, signatures, calldatas, description, address client) {
  clientProposals[proposalId] = client;
  // regular propose code continues...
}

castVoteWithReason(uint proposalId, uint support, string reason, address client) {
  // record how many votes were cast per client, per proposal
  clientVotes[proposalId][client].votes += votes;
  // record how many voting txs were made per client, per proposal
  clientVotes[proposalId][client].txs += 1;

  // regular voting code continues...
}
"><code>createBid(<span class="hljs-keyword">uint</span> nounId, <span class="hljs-keyword">address</span> client) {
  biddingClient[nounId] <span class="hljs-operator">=</span> client;
  <span class="hljs-comment">// regular bid code continues...</span>
}

propose(targets, values, signatures, calldatas, description, <span class="hljs-keyword">address</span> client) {
  clientProposals[proposalId] <span class="hljs-operator">=</span> client;
  <span class="hljs-comment">// regular propose code continues...</span>
}

castVoteWithReason(<span class="hljs-keyword">uint</span> proposalId, <span class="hljs-keyword">uint</span> support, <span class="hljs-keyword">string</span> reason, <span class="hljs-keyword">address</span> client) {
  <span class="hljs-comment">// record how many votes were cast per client, per proposal</span>
  clientVotes[proposalId][client].votes <span class="hljs-operator">+</span><span class="hljs-operator">=</span> votes;
  <span class="hljs-comment">// record how many voting txs were made per client, per proposal</span>
  clientVotes[proposalId][client].txs <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;

  <span class="hljs-comment">// regular voting code continues...</span>
}
</code></pre><p>Example pseudocode of a payout contract:</p><pre data-type="codeBlock" text="payoutForWinningBid(uint nounId) {
  require(!payoutDone[nounId], ‘already paid’);
  require(auctionHouse.auction().nounId &gt; nounId, ‘auction not settled’);

  payoutDone[nounId] = true;

  // send fixed amount as payout
  // to send a % of auction settlement price, we need to store the history of auction prices, which we plan to do in the next version of auction-house
  sendETH(auctionHouse.biddingClient[nounId], PAYOUT_FOR_BIDDING);
}

payoutForProposal(uint proposalId) {
  require(!payoutForProposalPaid[proposalId], ‘already paid’);
  require(dao.state(proposalId) == EXECUTED);
  payoutForProposalPaid[proposalId] = true;

  // send fixed amount to the client
  sendETH(dao.clientProposals[proposalId], PAYOUT_FOR_PROPOSAL);
}

payoutForVotes(uint proposalId, address client) {
  require(!payoutForVotesPaid[proposalId], ‘already paid’);
  require(state(proposalId) == EXECUTED);
  payoutForVotesPaid[proposalId] = true;

  Proposal proposal = dao.proposals(proposalId);
  uint totalVotes = proposal.forVotes + proposal.againstVotes + proposal.abstainVotes;

  sendETH(client, (dao.clientVotes[proposalId][client] / totalVotes) * PAYOUT_FOR_VOTES_PER_PROPOSAL);
}
"><code>payoutForWinningBid(<span class="hljs-keyword">uint</span> nounId) {
  <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>payoutDone[nounId], ‘already paid’);
  <span class="hljs-built_in">require</span>(auctionHouse.auction().nounId <span class="hljs-operator">></span> nounId, ‘auction not settled’);

  payoutDone[nounId] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;

  <span class="hljs-comment">// send fixed amount as payout</span>
  <span class="hljs-comment">// to send a % of auction settlement price, we need to store the history of auction prices, which we plan to do in the next version of auction-house</span>
  sendETH(auctionHouse.biddingClient[nounId], PAYOUT_FOR_BIDDING);
}

payoutForProposal(<span class="hljs-keyword">uint</span> proposalId) {
  <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>payoutForProposalPaid[proposalId], ‘already paid’);
  <span class="hljs-built_in">require</span>(dao.state(proposalId) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> EXECUTED);
  payoutForProposalPaid[proposalId] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;

  <span class="hljs-comment">// send fixed amount to the client</span>
  sendETH(dao.clientProposals[proposalId], PAYOUT_FOR_PROPOSAL);
}

payoutForVotes(<span class="hljs-keyword">uint</span> proposalId, <span class="hljs-keyword">address</span> client) {
  <span class="hljs-built_in">require</span>(<span class="hljs-operator">!</span>payoutForVotesPaid[proposalId], ‘already paid’);
  <span class="hljs-built_in">require</span>(state(proposalId) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> EXECUTED);
  payoutForVotesPaid[proposalId] <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;

  Proposal proposal <span class="hljs-operator">=</span> dao.proposals(proposalId);
  <span class="hljs-keyword">uint</span> totalVotes <span class="hljs-operator">=</span> proposal.forVotes <span class="hljs-operator">+</span> proposal.againstVotes <span class="hljs-operator">+</span> proposal.abstainVotes;

  sendETH(client, (dao.clientVotes[proposalId][client] <span class="hljs-operator">/</span> totalVotes) <span class="hljs-operator">*</span> PAYOUT_FOR_VOTES_PER_PROPOSAL);
}
</code></pre>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Nouns Governor: Design Alternatives]]></title>
            <link>https://paragraph.com/@verbsteam/nouns-governor-design-alternatives</link>
            <guid>HGFqQAne5txVEQ61TgxW</guid>
            <pubDate>Mon, 11 Sep 2023 16:28:57 GMT</pubDate>
            <description><![CDATA[Welcome to the second post in the Nouns Governor series; Please check out the first post for more context. This time we’d like to share three different design directions we have in mind, with some high level details on how each direction might work. Our hope is the same as last time: to receive feedback from the community; do you have a preferred design direction? Do you think none of them are good enough? The current focus is on how delegation information is encoded and presented. The curren...]]></description>
            <content:encoded><![CDATA[<p>Welcome to the second post in the Nouns Governor series; Please check out <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/verbsteam.eth/tQ64cUYlf9hwdDvY8HLs3uw2vs_XwJelp8cY9leMO6c">the first post</a> for more context.</p><p>This time we’d like to share three different design directions we have in mind, with some high level details on how each direction might work. Our hope is the same as last time: to receive feedback from the community; do you have a preferred design direction? Do you think none of them are good enough?</p><p>The current focus is on how delegation information is encoded and presented. The current delegation system stores wallets and their voting power balance; in an NFT-based governor we need to store delegation information per NFT.</p><p>Other requirements and design details seem more straightforward, and we’re happy to elaborate on them in future posts.</p><h2 id="h-a-couple-of-new-concepts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">A couple of new concepts</h2><p>These are new ideas that are mentioned below in the details of the different approaches. Here’s a quick intro to what they mean to help you better imagine the alternatives at the heart of this post. Assume they are applicable no matter the approach we end up choosing.</p><h3 id="h-delegation-admin" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Delegation Admin</h3><p>Nouners can set a “delegation admin” wallet, giving it full control over delegation decisions; delegation admins can transfer this role to any other wallet; Nouners can revoke this role at any time.</p><p>The primary use case is holding Nouns in cold storage while managing delegations using a hot wallet.</p><p>It seems useful to also allow the delegation admin to vote with any of the owner’s Nouns that haven’t been specifically delegated. We’d love your feedback on this design dilemma.</p><h3 id="h-subdelegation" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Subdelegation</h3><p>We think additional degrees of freedom could be great for the community, yet still unsure how open it should be.</p><p>We’re confident the Nouner should be able to revoke delegation rights at any time, making themselves the only valid voter. We’re still debating how delegation transfers should work.</p><p>The simplest approach is to let a Noun’s current delegate transfer their rights to anyone else.</p><p>More complex designs might include: limiting subdelegation to only one degree (Nouner -&gt; delegate -&gt; subdelegate); or an infinite delegation chain where any preceding delegate can revoke delegation down the line.</p><p>We’re leaning towards keeping the base design simple, while affording more advanced requirements through composition with other projects like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/voteagora/liquid-delegator">Agora’s Alligator</a>.</p><p>We’re excited to get lots of community feedback on this one.</p><h2 id="h-approach-1-delegation-nfts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Approach 1: Delegation NFTs</h2><p>This approach uses a new NFT, where each token represents the right to vote and propose with the Noun bearing the same token ID. More details below.</p><h3 id="h-delegation-nft-details" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Delegation NFT details</h3><ul><li><p>It’s a new ERC721 enumerable token.</p></li><li><p>Nouners (inc. their delegation admin wallet) can mint delegation tokens with the same IDs as the Nouns they own, and transfer them to other wallets, thereby delegating voting rights of those Nouns to those wallets.</p></li><li><p>Nouners (and their delegation admin wallet) can burn delegation tokens, reverting back to the default state that only the Noun-owning wallet can vote.</p></li><li><p>Nouners can transfer delegation tokens mirroring their Nouns from their delegates to any other wallet at any time; it’s akin to them have ERC721 approval from their delegates on their delegate tokens.</p></li><li><p>Subdelegation would be simply a delegate transfering their delegation tokens to any other wallet. We could complicate the design with extra permissions if needed, as discussed in the above subdelegation section.</p></li></ul><h3 id="h-stale-tokens" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Stale tokens</h3><p>This design is the only one that has the stale tokens property. To better understand what stale tokens are, let&apos;s explore how it works, starting with the use case of selling a Noun to someone else.</p><h4 id="h-alice-selling-to-bob" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Alice selling to Bob</h4><ol><li><p>Alice delegates Noun 142 to Diva, by transfering delegation NFT 142 to her wallet.</p></li><li><p>Then Alice sells Noun 142 to Bob; the delegation NFT is still in Diva&apos;s wallet.</p></li><li><p>Diva continues to vote and propose with Noun 142 until Bob delegates it to someone else (or burns the delegation NFT).</p></li></ol><p>Stale tokens can also benefit Nouners, specifically when transferring Nouns among their own wallets.</p><h4 id="h-alice-transferring-to-a-new-wallet" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Alice transferring to a new wallet</h4><ol><li><p>Alice delegates Noun 142 to Diva.</p></li><li><p>Alice transfers Noun 142 to her new hardware wallet, wanting the delegation to Diva to persist.</p></li><li><p>Diva continues to vote with Noun 142, and Alice simply does nothing.</p></li></ol><p>In today&apos;s design, and potentially the WrappedNouns design (described below), we automatically delegate upon transfer. When transferring to a new wallet, Alice would then need to submit another transaction to delegate from her new hardware wallet to Diva.</p><p>In summary, in most cases this property adds an explicit delegation step after transfers between different people, and removes a step after transfers among wallets of the same person.</p><h3 id="h-how-to-determine-a-nouns-current-delegate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">How to determine a Noun&apos;s current delegate</h3><ul><li><p>If a delegation NFT exists, its owner is the current delegate.</p></li><li><p>If it doesn&apos;t exist, the Nouner wallet is the current delegate.</p></li></ul><p>We&apos;re still unsure whether stale tokens should be allowed to vote or not (leaning towards yes).</p><h3 id="h-open-questions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Open Questions</h3><ul><li><p>How should we treat stale delegation NFTs? Should the owner of that delegation NFT be allowed to continue voting until the new owner transfers or burns the delegation token? or should it be considered invalid immediately after the Noun transfer?</p></li><li><p>How should we solve for forked Nouns?</p><ul><li><p>They are owned by the DAO treasury and should not be participating in governance.</p></li><li><p>Potential solution: have explicit logic that prevents voting with treasury-owned Nouns, and allow anyone to burn treasury-owned delegation NFTs.</p></li></ul></li><li><p>How should we solve for burned Nouns?</p><ul><li><p>Probably the same treatment as forked Nouns.</p></li></ul></li></ul><h2 id="h-approach-2-track-delegation-in-governor-state" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Approach 2: track delegation in Governor state</h2><p>This approach is the minimalistic one, moving delegation functions from the NounsToken contract to Nouns Governor contract, and keeping track in governor contract storage state. It meets all the original motivations of NFT-based voting, without the added legibility and fun UX the delegation NFTs approach adds.</p><p>The governor contract manages delegation state, using a delegates mapping from owner wallet to tokenId to a Delegation struct; the Delegation struct stores a delegate and subdelegate addresses.</p><h3 id="h-how-to-determine-a-nouns-current-delegate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">How to determine a Noun&apos;s current delegate</h3><ul><li><p>Get the Noun’s current owner from the token contract.</p></li><li><p>Check the delegates mapping of the owner per voting tokenId, if it’s not address zero - that’s the current delegate.</p></li><li><p>Otherwise, the current delegate (or subdelegate) is the token owner.</p></li></ul><h2 id="h-approach-3-wrapped-nouns" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Approach 3: Wrapped Nouns</h2><p>This approach asks Nouners to wrap their Nouns in a new NFT, so that the new NFT can help meet the requirements the current immutable Nouns contract doesn’t support.</p><p>This approach can employ either of the previous two in storing and determining a Noun&apos;s current delegate wallet. It is different in that it aims to replace the current NounsToken contract in most usage, so that we gain new upgradeable hooks pre and post transfer events, to optimize user experience.</p><p>The key improvement is the ability to auto-update delegations upon transfers.</p><h3 id="h-wrappednouns-details" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WrappedNouns details</h3><p>Compatibility:</p><ul><li><p>Original Nouns are transferred to WrappedNouns, and a WrappedNoun is minted to the owner of that original Noun. There is a reverse redeem function that burns the WrappedNoun and sends the original Noun to the WrappedNoun’s owner.</p></li><li><p>WrappedNoun art reflects the original Noun’s art.</p></li><li><p>Nouns auction still sells OG Nouns.</p></li><li><p>To maintain backwards compatibility with the current Governor contract, the owner can delegated their deposited Nouns to an wallet of their choice.</p></li></ul><p>Delegation:</p><ul><li><p>Nouns can set a “default delegate” wallet, to which any new WrappedNoun they receive is automatically delegated.</p></li><li><p>The rules of who can delegate and subdelegate would be very similar to approach 1; meaning we would keep track for each WrappedNoun which wallet is its delegate or subdelegate.</p></li><li><p>The technical details of how we keep this state can vary:</p><ul><li><p>It could be simple storage mappings in the WrappedNouns contract, or</p></li><li><p>It could be delegation NFTs similar to approach 1, slightly improved because we have hooks on WrappedNouns transfers; for example, upon a transfer of a WrappedNoun we could auto-transfer the relevant delegation NFT to the new Nouner&apos;s default delegate wallet.</p></li></ul></li></ul><p>Hooks:</p><ul><li><p>This is a technical point we haven&apos;t fully explored yet: this design allows us to deploy new upgradeable and configurable code that could run before or after each WrappedNoun transfer.</p></li><li><p>The obvious use case is mentioned above, an improved UX when selling Nouns: to auto-delegate Nouns upon transfer per some recipient configuration, e.g. delegate all newly received Nouns to a specific wallet.</p></li><li><p>We&apos;re hoping to hear more exciting ideas from the community.</p></li></ul><h3 id="h-how-to-determine-a-nouns-current-delegate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">How to determine a Noun&apos;s current delegate</h3><ul><li><p>If a WrappedNoun does not exist for that Noun, the owner is the only account that can vote.</p></li><li><p>If a WrappedNoun exists, we can take either direction:</p><ul><li><p>Like approach 2, except the delegation mapping would be stored in the WrappedNoun contract rather that the governor contract, or</p></li><li><p>Like approach 1, except the WrappedNoun contract would determine the current delegate rather than the governor contract.</p></li></ul></li></ul><h3 id="h-open-questions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Open Questions</h3><ul><li><p>How do we treat WrappedNouns where their backing ON Noun has been burned?</p><ul><li><p>Probably similar to delegation NFTs, with specific logic in the governor contract to prevent voting and proposing, and allowing anyone to burn such WrappedNouns.</p></li></ul></li></ul><h2 id="h-noteworthy-differences" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Noteworthy differences</h2><ul><li><p>Delegation NFTs is the only design that has the stale tokens property, as discussed in detail above.</p></li><li><p>Delegation NFTs might also be the coolest, as the only design that puts NFTs in delegates&apos; wallets. It seems like the most composable design; for example, crypto wallets that support NFT transfers will then support delegation and subdelegation out of the box; and delegates can know which Nouns they can vote with just by looking at the NFTs in their wallet. Delegation NFT art is another open design space.</p></li><li><p>Wrapped Nouns is the only design that can give us hooks on transfers (it&apos;s not complete because some Nouns might never wrap). Such hooks allow us to auto-delegate newly received Wrapped Nouns similar to today&apos;s token design; hooks might also be a new opportunity for great ideas and teams we haven&apos;t seen yet.</p></li></ul><h2 id="h-our-take" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Our take</h2><p>WrappedNouns feel too complex. Tracking delegation in the Governor&apos;s state feels like a missed opportunity.</p><p>Delegation NFTs feel the most exciting, as a tangible UX upgrade for Nouners, delegates and even just curious fans. This approach still has its issues, but our current gut feeling says going down this path will be worth it.</p><p>Assuming sufficient conviction in the delegation NFTs approach, we would flesh out all the open issues and share a detailed design post with everyone, to make sure the juice is indeed worth the squeeze.</p><h2 id="h-whats-next" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What’s next?</h2><p>We want your feedback. Do you have a preferred design direction? Do you think none of them are good enough? How should we approach subdelegation? What additional detail should we add to help you form your opinion?</p><p>In the meantime we’re working on additional posts, including:</p><ul><li><p>Fork V2 additional details.</p></li><li><p>Gas comparison of the current state vs these design alternatives.</p></li><li><p>And possibly a few more, ending with an update on final decisions.</p></li></ul><p>Thank you for your attention,</p><p>the verbs ⌐◨-◨</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Nouns Governor]]></title>
            <link>https://paragraph.com/@verbsteam/nouns-governor</link>
            <guid>KapTmwNOEE92KQ8XBnf1</guid>
            <pubDate>Fri, 08 Sep 2023 18:36:36 GMT</pubDate>
            <description><![CDATA[Nouns GovernorThis is the first post in a series in which we’re trying something new: to design a new Nouns DAO version in public, in collaboration with the community. The new Nouns Governor will be our first break away from Compound Governor Bravo we’ve been relying on since day one. At its core, Nouns Governor is about NFTs voting, rather than wallets. Let’s dive into the problems NFT voting can solve, and explore the opportunities it may open up.A bit of personal historyWe started working ...]]></description>
            <content:encoded><![CDATA[<h1 id="h-nouns-governor" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Nouns Governor</h1><p>This is the first post in a series in which we’re trying something new: to design a new Nouns DAO version in public, in collaboration with the community.</p><p>The new Nouns Governor will be our first break away from Compound Governor Bravo we’ve been relying on since day one. At its core, Nouns Governor is about NFTs voting, rather than wallets. Let’s dive into the problems NFT voting can solve, and explore the opportunities it may open up.</p><h2 id="h-a-bit-of-personal-history" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">A bit of personal history</h2><p>We started working on Nouns contracts in the spring of 2022, and in the early days of studying the code, we noticed things worked different from what we intuitively expected in an NFT DAO. The first example was that Nouners couldn’t delegate individual Nouns; to do so they have to transfer a Noun to a separate wallet and then delegate. Another example was that Nouners couldn’t override how their delegates voted, and while it didn’t seem urgent it did feel important since we knew bribe markets (e.g. Federation’s governance pools) were inevitable.</p><p>In those early days we were managed directly by the Tech Grants Pod, and shipped the new art contracts, and DAO V2 with dynamic quorum and voting gas refunds. Shortly after we started managing our backlog, and with community help decided to ship other improvements that ultimately became DAO V3, including propose by sigs and the renowned (reNouned!) Fork mechanism. The NFT voting design was on our minds, but never made it to the top of the list, until now.</p><h2 id="h-why-build-nouns-governor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Why build Nouns Governor?</h2><p>So why now? Why build it at all? What changed?</p><p>The main thing is the Fork; the spark has always been minority protection from a majority attack, and say in the case of a majority passing a malicious proposal, the minority should be able to fork <em>without</em> the malicious majority following them into the new DAO. However we hit a technical limitation: the Nouns token contract does not store per Noun which account can vote with it in each snapshot block, so we can’t discern which Nouns should be allowed to fork and which should be blocked. Our plan is to ship NFT voting and then ship an improved Fork V2. More details on Fork V2 will come in a future post.</p><p>A much older reason is the aforementioned delegate override problem: we think token holders should be able to override their delegates’ votes, primarily from a security perspective. Governance pools make attacks potentially much cheaper than the alternative of buying Nouns. The limitation mentioned above, not knowing how each Noun voted or even who delegated to whom, is why we haven’t implemented the override to date.</p><p>For personal security, we don’t like the current constraint that Nouners must use their Noun-owning wallets to update delegations; they should be able to update delegations from their hot wallets, to minimize the risk of losing their assets.</p><p>Beyond security, there are several user experience annoyances and confusions NFT voting can improve upon. Let’s run through them.</p><p>New Nouners who buy a Noun on auction are often disappointed to discover they can’t vote on current proposals; wouldn’t it be way more delightful to allow them to participate immediately?</p><p>Snapshots are confusing for Nouns veterans as well; we’ve seen many messages expressing confusion after transfers or delegations, not being sure which wallet to use or how many votes their wallet has for a given proposal. It can and should be much easier.</p><p>We’ve also seen a proposal getting cancelled because the proposer delegated their Nouns and went below proposal threshold; we’re partially solving this with propose by sigs, because Nouners won’t have to delegate just to sponsor a proposer, but with NFT voting Nouners can propose and delegate and not have to go below threshold.</p><p>We also hope to solve several problems related to granularity: subDAOs should be able to easily split their votes (e.g. if subDAO vote on a prop is 50/50, let them split their Noun votes both ways); a whale should be able to delegate at a single-Noun granularity without transferring to individual wallets; and a whale with many times proposal threshold’s worth Nouns balance should be able to submit multiple proposals from the same wallet.</p><p>Subdelegation is another use case we’d like to enable; in many cases in Nouns there is high trust in delegation relationships, such that the token holder is happy to let their delegate further delegate their votes, whether for a specific proposal with domain expertise, or just because the delegate is going on a long offline vacation. Fun experiments are also made possible, e.g. Nouncil can have a primary wallet for all their delegations, then periodically vote to subdelegate some of their votes to individual members.</p><p>Finally, a bit on legibility. In the current state it’s hard to read onchain, e.g. with Etherscan, which account can vote with which Nouns at any given time, or how a certain Noun voted on a specific proposal. This information is available using indexers and webapps; however we think it’s even better if it’s legible with nothing but Etherscan.</p><h2 id="h-but-arent-these-annoying-checkpoints-important" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">But aren’t these annoying checkpoints important?</h2><p>The Nounders’ decision to use Compound Bravo with snapshots was great! It allowed them to ship the project with high security and low cost. We would have done the same thing. And for ERC20 DAOs checkpoints make perfect sense, since they don’t have the non-fungibility property we can rely on.</p><p>Checkpoints were added to Compound to solve two major problems:</p><ol><li><p>Double voting: otherwise you could easily vote, transfer your tokens to another wallet, and vote again.</p></li><li><p>Flashloan voting: a sequence done in a single block that costs near-zero: borrow gov tokens or borrow money and buy gov tokens on Uniswap, vote, repay the loan with a small fee.</p></li></ol><p>Checkpoints prevent double voting simply by looking at a single point in time; and flashloan voting is prevented by making sure voters vote at least one block after their latest snapshot.</p><p>In NFT voting we prevent double voting easily, by storing which NFTs already voted. And we prevent flashloan voting with a minimal version of snapshots, allowing an NFT to vote only if at least one block passed since its latest transfer block.</p><h2 id="h-what-about-other-solutions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What about other solutions?</h2><p>Some of the problems we’ve outlined have been solved in different approaches, while some are more specific to NFTs and Nouns in particular. Some solutions we’re aware of:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.scopelift.co/blog/introducing-flexible-voting">ScopeLift’s flexible voting</a>, which allows a wallet holding ERC20 governance tokens submit a vote with data indicating how to split the vote, e.g. 60% For and 40% against.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/NoahZinsmeister/franchiser/blob/main/spec.md">Franchiser</a>, which allows holders of COMP-style voting tokens to selectively delegate portions of their voting power to third parties, and allows delegates to further sub-delegate.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.axiom.xyz/zero-knowledge-proofs/introduction-to-zk">ZK storage proofs</a>, can allow users to submit a proof to the DAO showing who delegated to whom at a certain block. There are several concerns with storage proofs, such as the time and compute resources to generate proofs and the gas costs of verifying proofs; however we’re curious to explore this direction down the line.</p></li></ul><p>Worth noting we’re also taking time to explore other DAO projects like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/code-423n4/2023-06-llama">Llama</a>, OpenZeppelin, Aave and others.</p><h2 id="h-new-possibilities" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">New possibilities</h2><p>This is another less tangible reason we&apos;re excited to ship Nouns Governor; we believe the Nouns community will find unexpected ways to build cool things with it.</p><p>One example from a recent chat is that proposers could bake into their props temporary art modifications based on how Nouns vote on their prop; e.g. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://red.org">red.org</a> could add custom noggles to all Nouns that vote For their proposal if it passes, and then send them a physical copy of those custom noggles.</p><p>Please reach out if you have other cool ideas!</p><h2 id="h-whats-next" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What’s next?</h2><p>We want your feedback. Do you find this direction interesting? What are we missing?</p><p>In the meantime we’re working on additional posts, including:</p><ul><li><p>NFT voting designs: should we have a delegation NFT? should we wrap Nouns in a new token? or keep it super simple?</p></li><li><p>Gas comparison of the current state vs the potential designs.</p></li><li><p>Fork V2 additional details.</p></li><li><p>And possibly a few more, ending with an update on final decisions.</p></li></ul><p>Thank you for your attention, <br>the verbs ⌐◨-◨</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[A Short Analysis of Auction-Price-Based Ragequit]]></title>
            <link>https://paragraph.com/@verbsteam/a-short-analysis-of-auction-price-based-ragequit</link>
            <guid>ti7Exljkw84JmClT0d13</guid>
            <pubDate>Mon, 21 Aug 2023 15:39:38 GMT</pubDate>
            <description><![CDATA[IntroductionThis is a quick analysis we composed with the help of community members, to try and make more tangible sense of wag’s original post, and feedback on twitter these past few weeks. Our hope is this analysis will help voters in their decision making and discussions. We’re available for any feedback, and especially to any corrections or additions community members think we should make. Find us on twitter @davidbrai and @eladmallel.TLDRDifferent calculation approaches boil down to the ...]]></description>
            <content:encoded><![CDATA[<h1 id="h-introduction" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction</h1><p>This is a quick analysis we composed with the help of community members, to try and make more tangible sense of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/0xwag">wag’s</a> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discourse.nouns.wtf/t/noun-ritual-sacrifice-ie-ragequit/316">original post</a>, and feedback on twitter these past few weeks.</p><p>Our hope is this analysis will help voters in their decision making and discussions.</p><p>We’re available for any feedback, and especially to any corrections or additions community members think we should make. Find us on twitter <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/davidbrai">@davidbrai</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/eladmallel">@eladmallel</a>.</p><h1 id="h-tldr" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">TLDR</h1><ul><li><p>Different calculation approaches boil down to the analogy of dilutive purchase of shares at current valuation on auction (see below).</p></li><li><p>Implementation feels feasible, no need to agree on the exact approach now (gut leans towards explicitly allocating shares on auction settlement to make it super explicit).</p></li><li><p>To do this well the DAO would need to value all its assets in ETH, requiring oracles for every asset it holds or wants to hold - adds complexity to new assets, which might incentivize the DAO to hold fewer assets and avoid NFTs.</p></li><li><p>Nounder rewards: give those nouns zero shares or allocate them shares per some average (see more below); it&apos;s a political decision, technically not hard.</p></li><li><p>Splits voting and financial shares, creating new incentive risks that require further research.</p></li><li><p>Feels legally concerning at initial gut reaction; legal advice needed.</p></li></ul><h2 id="h-step-by-step-example" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Step-by-step example</h2><ul><li><p>Assume the treasury currently has 990 ETH.</p></li><li><p>New auction is settled, Alice bought a noun for 10 eth; Treasury now has 1000 ETH.</p></li><li><p>At this exact moment, if Alice ragequits, she should get 10 ETH.</p></li><li><p>Then say the DAO spends 10% of its funds, and now has 900 ETH; all nouners’ redeemable value should be reduced by 10%. Alice’s redeemable amount is now 9 ETH, so she maintained her 1% redeemable value.</p></li><li><p>Then say Bob buys a Noun on auction for 10 ETH; Treasury now has 910 ETH.</p></li><li><p>Bob’s redeemable value is 10 ETH, which is 1.0989011%.</p></li><li><p>Alice’s redeemable value should still be 9 ETH, which is now 0.989011%.</p></li></ul><h3 id="h-analogy-to-acquisition-of-shares-at-current-valuation" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Analogy to acquisition of shares at current valuation</h3><ul><li><p>Another way to model this, is that each time a noun is sold on auction, it’s like a fund raise at current valuation.</p></li><li><p>Let’s imagine Nouns have shares, call them NS (Nouns shares).</p></li><li><p>Whenever someone buys a Noun on auction, new shares are allocated to that Noun, proportional to its auction’s ETH contribution to the treasury.</p></li><li><p>So if the treasury currently has 990 ETH and there are a total of 1M NS created, and Alice buys a new Noun for 10 ETH, Alice would get 10101.01010101 NS.</p></li><li><p>Alice’s share of NS determines what % of the treasury she can redeem.</p></li><li><p>Somewhat similar to tokenized vaults (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-4626">EIP-4626</a>).</p></li></ul><h1 id="h-key-problem-valuing-all-assets-in-a-unified-denomination" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Key problem: valuing all assets in a unified denomination</h1><ul><li><p>If the DAO has assets other than ETH, as is currently the case with stETH and soon rETH, we need a conversion rate oracle to know what the value of the treasury denominated in ETH.</p></li><li><p>If the DAO buys an NFT, it also needs to be able to be valued in order to determine the new ETH contribution to treasury value.</p></li><li><p>In other words, if we want to evaluate the ETH contribution from an auction we need to be able to value all the DAO assets in ETH.</p></li></ul><h1 id="h-exploring-wags-recursive-idea" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Exploring wag’s recursive idea</h1><p><em>Disclaimer: our understanding of </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discourse.nouns.wtf/t/noun-ritual-sacrifice-ie-ragequit/316"><em>wag’s idea</em></a><em> has not been verified with wag; we’ll update this post if we learn we misunderstood.</em></p><p>Is there a different approach with the recursion formula from wag’s post?</p><ul><li><p>The formula: rd(day+1) = rd(day) * nc(day+1) + rd(day), where</p><ul><li><p>“days” are settlement-delineated</p></li><li><p>nc = % Change to Treasury from post settlement balance to EOD</p></li><li><p>rd(day0) = Noun Auction Price</p></li><li><p>daymin (first calculation)= Noun Auction settlement day + 1</p></li><li><p>daymax (last calculation)= ‘current’ day - 1</p></li></ul></li><li><p>For a particular Noun, at the moment it was purchased from auction, the redeemable value (rd) is equal to the amount of ETH it was purchased for.</p></li><li><p>Then to calculate the value of the next day, you need to calculate `nc`, which is the % change in treasury value during that day. It’s a way to decrease or increase `rd` proportionately to the change in treasury value.</p></li><li><p>Seems like auction sales are not considered change in treasury value.</p></li><li><p>Seems like there’s no real reason to do this recursively; a simpler way would be:</p><ul><li><p>T0 = Time of acquiring a Noun</p></li><li><p>TRQ = Time of doing ragequit</p></li><li><p>rd(TRQ) = nounAuctionPrice * (TreasuryValue(TRQ) / TreasuryValue(T0))</p></li></ul></li><li><p>In words: a Noun’s redeemable value is equal to that Noun’s acquisition price, multiplied by the relative change in the DAO’s treasury assets value between day of acquisition and day of ragequit.</p></li><li><p>In this case we still have the problem of needing to be able to evaluate the treasury assets in ETH, i.e. `TreasuryValue` returns a value denominated in ETH.</p></li></ul><p>While this approach avoids explicit allocation of shares, redeemable value ends up being the same as the fund raise at current valuation described above.</p><h1 id="h-additional-problems" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Additional problems</h1><h3 id="h-nounder-rewards" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Nounder rewards</h3><p>How are nounder reward nouns valued?</p><ol><li><p>They could be valued at zero. Meaning that they get 0 if they ragequit. This can be a problem for those who purchased them on secondary, and is discussed below.</p></li><li><p>They could be assigned an “average value”. If we use the idea of shares, it could be:</p><ol><li><p>Average shares per Noun across the board:</p><ol><li><p>If there are 1M shares outstanding, assigned to 100 nouns. So each noun has 10,000 shares on average.</p></li><li><p>A nounder reward is minted, it gets assigned 10,000 new shares.</p></li></ol></li><li><p>Average shares per recent auctions, making it more responsive to the market:</p><ol><li><p>Take the last N auctioned Nouns and the shares they acquired (e.g. last 7 auctions)</p></li><li><p>Give the newly minted Nouner reward Noun a share count equal to the average of those last N auctions</p></li></ol></li></ol></li></ol><h3 id="h-secondary-market-valuation" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Secondary market valuation</h3><p>Existing nouns will suddenly have different value on secondary markets. Owners who bought nouns that were acquired for relatively low values will object to this change.</p><p>We could assign all existing nouns the same number “shares” as a way to bootstrap this.</p><h3 id="h-dao-owned-nft-oracles" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">DAO-owned NFT oracles</h3><p>What if the DAO holds NFTs that don’t have oracles to assign value to them?</p><ul><li><p>It means that if someone joins the DAO when the DAO is holding that NFT, they get assigned shares as if that NFT doesn’t exist.</p></li><li><p>Later, if the DAO sells that NFT, the new member of the DAO will have a high % ownership of that Noun because it will be considered like income.</p></li><li><p>If there’s enough value locked in an NFT, it will attract actors that will want to join the DAO, sell the NFT and then ragequit with the revenue from that asset.</p></li></ul><h3 id="h-economic-incentives" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Economic incentives</h3><ul><li><p>Economic and voting shares are split.</p></li><li><p>Anyone can buy as many economic shares as they want at any time, diluting everyone else.</p></li><li><p>Anyone expecting Nouns to receive an influx of non-auction revenue in the near future can steal as much of it for themselves as they have capital.</p></li><li><p>Those with cheaper voting shares will be incentivized to pass proposals for their own benefit, rather than for Nouns&apos; collective interest, or at least will have less risk of spending.</p></li></ul><h1 id="h-interim-conclusion" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Interim conclusion</h1><p>The main challenge is to value all the DAO assets in a single denominator (e.g. ETH). This would require having oracles for all assets. Even if there are oracles, they could be potentially manipulated.</p><p>Another concern is that treating Nouns this way could significantly increase regulatory risks (this is a dev gut feeling, legal advice is needed).</p><p>The economic incentives seem worrisome and require further thinking to potentially mitigate new risks.</p><h1 id="h-reference-material" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Reference material</h1><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discourse.nouns.wtf/t/noun-ritual-sacrifice-ie-ragequit/316">Wag’s original post on discourse</a>.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ir.law.fsu.edu/cgi/viewcontent.cgi?article=1127&amp;context=articles">Capital Accounts in LLCs and Partnerships</a>, a doc <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/0xwag/status/1691539131267190784?s=20">wag linked on twitter</a>.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.law.cornell.edu/wex/capital_account">A definition of capital accounts</a>.</p><ul><li><p><em>“At the most elemental level, then, each owner’s capital account reflects how much the owner has a right to receive from firm equity”</em></p></li><li><p><em>“They [capital accounts] usually reflect a mix of hard cash entries and entries that involve estimates of the value assigned to assets or, on occasion, to services.”</em></p></li></ul></li></ul>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Introducing Nouns Fork: A Last-Resort Minority Protection Mechanism]]></title>
            <link>https://paragraph.com/@verbsteam/introducing-nouns-fork-a-last-resort-minority-protection-mechanism</link>
            <guid>yZciWCh675raXsuyIYm8</guid>
            <pubDate>Thu, 11 May 2023 16:19:48 GMT</pubDate>
            <description><![CDATA[Forking is the crypto-native way for groups of token holders to exit together into a new instance of their protocol, resulting in maximal conservation of momentum in the ecosystem; famous examples include the Ethereum Classic fork and the Bitcoin Cash fork. We believe it&apos;s time to enable DAO forks as well, starting here at Nouns. To date, there has been no DAO version of forking, but it is needed. How can we protect a minority against a tyrannical majority? Or, in less extreme cases, how...]]></description>
            <content:encoded><![CDATA[<p>Forking is the crypto-native way for groups of token holders to exit together into a new instance of their protocol, resulting in maximal conservation of momentum in the ecosystem; famous examples include the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/history/#dao-fork">Ethereum Classic fork</a> and the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://decrypt.co/resources/bitcoin-cash">Bitcoin Cash fork</a>. We believe it&apos;s time to enable DAO forks as well, starting here at Nouns.</p><p>To date, there has been no DAO version of forking, but it is needed. How can we protect a minority against a tyrannical majority? Or, in less extreme cases, how can groups amicably part ways on a conflict of visions? <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://moloch.daohaus.fun/features/ragequit">Ragequit</a> has been used in some cases, allowing individuals to leave with a pro rata share of the treasury, but it comes with a variety of legal and incentive risks, e.g. overemphasis on individuals.</p><p>Today we’re excited to share a solution Nouns has been working on: Nouns Fork. In our model, any token holder can signal to fork (exit) in response to a governance proposal. If a quorum of 20% of tokens signals to exit, the fork will succeed. We discuss further below.</p><p>We encourage Nouners and delegates to familiarize themselves with Nouns Fork in anticipation of the upcoming upgrade proposal once the feature is complete and audited. Please reach out with questions and feedback, so we can make sure to fix any bugs in the design or how it’s communicated. We’ve been careful to minimize the scope of this initial version for the sake of shipping fast; there’s ample room for improvement in future versions.</p><h2 id="h-how-nouns-fork-works" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How Nouns Fork Works</h2><p>Nouns Fork introduces a new forking user flow. This flow enables Nouners to start a fork as soon as the <strong>Fork Threshold</strong> is reached. The feature operates in one of two states: (1) Escrow Period and (2) Forking Period.</p><h3 id="h-escrow-period" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Escrow Period</h3><p>During the Escrow Period:</p><ul><li><p>Any Nouner can put their tokens in escrow, contributing towards reaching the fork threshold.</p></li><li><p>Nouners can provide context why they are forking by providing proposal IDs that led to their forking, as well as a free text reason.</p></li><li><p>Nouners can withdraw their tokens from escrow as long as the forking period hasn&apos;t started.</p></li><li><p>The forking period commences when the number of escrowed tokens meets the fork threshold, and someone calls the fork DAO function.</p></li><li><p>Nouners cannot vote nor propose with tokens in escrow.</p></li></ul><h3 id="h-forking-period" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Forking Period</h3><p>The Forking Period:</p><ul><li><p>Begins when the fork function is called; the fork function deploys a new Nouns DAO.</p></li><li><p>Lasts for several days (e.g. 7 days), allowing additional token holders to send their Nouns to the DAO and join the newly forked DAO.</p></li><li><p>During this period original DAO proposals can&apos;t be executed, to prevent race conditions between the forking flow and any malicious proposals.</p></li><li><p>Once forking starts it cannot be canceled.</p></li><li><p>New DAOs are deployed with vanilla ragequit in place, allowing any token holder to quit on their own at any time. Otherwise it&apos;s possible for a new DAO majority to collude to hurt a minority, and the minority wouldn&apos;t have any last resort if they can&apos;t reach the forking threshold; furthermore bullies/attackers can recursively chase minorities into fork DAOs in an undesired attrition war.</p></li><li><p>Funds (ETH &amp; ERC20 tokens) are sent from the original DAO to the new DAO.</p></li><li><p>Forking Nouners claim new DAO tokens with the same IDs and same art as the Nouns they returned to the original DAO.</p></li></ul><h2 id="h-fork-dao-initial-configuration" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Fork DAO Initial Configuration</h2><p>Before diving into the fork initial configuration, it&apos;s important to highlight <strong>all fork DAO contracts are upgradable, giving its token holders full freedom to adjust</strong> code and parameters through proposals. For more technical details you&apos;re invited to read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/verbsteam/nouns-fork-spec/blob/main/spec.md">this spec</a>.</p><h3 id="h-governor" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Governor</h3><ul><li><p><strong>Basis</strong>: Nouns DAO V1 (no dynamic quorum, no voting gas refunds).</p></li><li><p><strong>Vetoer</strong>: not set.</p></li><li><p><strong>Delayed Governance</strong>: waits for all escrowed Nouners to claim their new tokens or until the delay expiration timestamp (e.g., 30 days after creation) is reached; to prevent abuse by quick claimers targeting those who need more time.</p></li><li><p><strong>Vanilla ragequit</strong>: fork DAOs have vanilla ragequit instead of forking; otherwise it&apos;s possible for a majority to collude to hurt a minority, and the minority wouldn&apos;t have any last resort if they can&apos;t reach the fork threshold; furthermore bullies/attackers can recursively chase minorities into fork DAOs in an undesired attrition war.</p></li></ul><h3 id="h-token" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Token</h3><ul><li><p><strong>Art &amp; Descriptor</strong>: the same as current Nouns.</p></li><li><p><strong>Token IDs</strong>: forkers get new tokens with the same IDs of the tokens they had in current Nouns.</p></li><li><p><strong>Founders Reward</strong>: removed.</p></li></ul><h3 id="h-auction" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Auction</h3><ul><li><p><strong>Paused</strong>: token holders need to pass a proposal to kick it off, giving them time to reconfigure.</p></li><li><p><strong>Start ID</strong>: set to the last ID on current Nouns auction.</p></li></ul><h3 id="h-ui" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">UI</h3><ul><li><p>This release will not include a dedicated UI for fork DAOs.</p></li><li><p>For governance forks can use existing tools like Agora, HouseOfNous, Tally, etc.</p></li><li><p>For a complete solution forks can deploy a modified version of nouns.wtf.</p></li></ul><h2 id="h-faqs" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">FAQs</h2><p><strong>Q: What happens to the tokens that were escrowed?</strong></p><p>A: Once the fork happens, the DAO can transfer them to any account it chooses to, including an auction contract, individuals&apos; accounts, etc. Tokens held in the escrow contract or in the treasury contract are excluded from total-supply-dependent calculations, e.g. proposal threshold and quorum.</p><p><strong>Q: What about NFTs in the treasury, e.g. LilNouns?</strong></p><p>A: They are kept in the original DAO&apos;s treasury. Future versions may introduce some fair forking mechanism, e.g. random permutations.</p><p><strong>Q: Why the big change from the previous design? Why do owners fork and not delegates, and why can&apos;t we tie a fork decision to a vote?</strong></p><p>A: We had a wrong assumption. Nouns token delegation doesn&apos;t store which Nouns are delegated to each account, so we can&apos;t identify which Nouns participated in each vote. Moreover, the action of forking seems more appropriate for owners, as it involves transferring their Nouns.</p><p>Another challenge: an attacker could create multiple malicious proposals, making it hard for honest actors to establish a clear shelling point for everyone to fork on. We belive this type of attack is easily mitigated by having a dedicated track for forking.</p><p><strong>Q: Why allow vanilla ragequit in fork DAOs, versus deploying them with the same forking mechanism as the OG DAO?</strong></p><p>A: Forking would allow an attacker to follow forkers into their new DAO in a recursive attrition war. While we have ideas on how to dilute the attacker, they introduce undesired UX complexities. Additionally, a fork design might lead to token distributions in the new DAO where a majority can bully a minority that doesn&apos;t have enough tokens to meet the fork threshold (e.g., 140 Nouns fork, 130 collude to bully the other 10).</p><p><strong>Q: Why add a &apos;no proposal execution&apos; constraint instead of making sure the forking flow ends in time?</strong></p><p>A: We considered an alternative where the fork creator would set an end timestamp. However, this approach might result in forking ending too early or too late. Ending too early could prevent enough people from joining, while ending too late might enable a malicious proposal to execute ahead of the fork. The timestamp approach could also lead to situations where people participate in two parallel forks and move from one to another. Overall, this UX seems risky.</p><p><strong>Q: Can an attacker follow into the new forked DAO?</strong></p><p>A: Yes, this griefing vector is a known issue. It stems from a NounsToken contract limitation where we can&apos;t easily know which Noun IDs are part of each vote; this limitation means we can&apos;t prevent an attacker from joining the fork where Nouners are trying to run away from an attack. In this version your final recourse would be to quit the forked DAO on your own, using the simple quit mechanism built into fork DAOs.</p><p>This could be fixed in future versions; a couple of technical directions like storage proofs or moving to NFT-based voting, could let us query in smart contract code per Noun how it voted, and therefore block an attacker from joining a fork (e.g. you can&apos;t fork on a proposal if you voted for it).</p><p>We&apos;re choosing to compromise in this version for the sake of shipping to mainnet quickly.</p><p><strong>Q: Why base fork DAOs on V1 and not V2/V3?</strong></p><p>A: V3 is not ready yet, and V2 is at Ethereum&apos;s contract size limit, and would require a lot of refactoring to allow any new code to be added. Any fork that wants can pretty easily upgrade their governor, hopefully to a stable V3.</p><p><strong>Q: Why the 20% fork threshold? And why not just vanilla ragequit?</strong></p><p>A: It&apos;s important that forking happen rarely, and by a large group of Nouners, to prevent potential financial abuse.</p><h2 id="h-whats-next" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What’s Next</h2><ul><li><p>There’s still time for feedback! Please let us know if you identify any problems or if you have better ideas.</p></li><li><p>We&apos;re already coding this design and are in touch with auditors; next we&apos;re planning to run a bunch of tests, get it audited, and finally submit a proposal to upgrade the DAO to this new version.</p></li></ul><h2 id="h-special-thanks" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Special Thanks</h2><p>We’re grateful for the support we’ve been getting from several Nouns community members: solimander, will price, digital oil, 4156, Noun 40, vapeape and Chris.</p><p>verbs ⌐◨-◨ <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/davidbrai">@davidbrai</a> &amp; <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/eladmallel">@eladmallel</a></p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Nouns’ next governance iteration: dynamic quorum]]></title>
            <link>https://paragraph.com/@verbsteam/nouns-next-governance-iteration-dynamic-quorum</link>
            <guid>Ail5VsPPeABqryCRh7Ys</guid>
            <pubDate>Wed, 31 Aug 2022 13:52:45 GMT</pubDate>
            <description><![CDATA[If you’re new to Nouns, check out the official website and this explainer video.TLDRDynamic quorum is an upcoming governance change that reduces the tradeoff space between friction and security, making proposals harder to pass the more Nouners vote against them.This is an important step towards turning off the foundation’s right to veto.This change has been reviewed internally and is currently being audited on code4rena.The final parameters decision will be made closer to deployment time.Intr...]]></description>
            <content:encoded><![CDATA[<p>If you’re new to Nouns, check out the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nouns.wtf/">official website</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://youtu.be/4dYkjYiitcw">this explainer video</a>.</p><h2 id="h-tldr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">TLDR</h2><ul><li><p>Dynamic quorum is an upcoming governance change that reduces the tradeoff space between friction and security, making proposals harder to pass the more Nouners vote against them.</p></li><li><p>This is an important step towards turning off the foundation’s right to veto.</p></li><li><p>This change has been reviewed internally and is currently being audited on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://code4rena.com/contests/2022-08-nouns-dao-contest">code4rena</a>.</p></li><li><p>The final parameters decision will be made closer to deployment time.</p></li></ul><h2 id="h-introduction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction</h2><p>The primary attack Nouns DAO is worried about is someone passing a proposal to drain the treasury (currently at ~26K ETH). The last line of defense is the Nouns Foundation’s right to veto any proposal. The Nounders and Nouners (DAO members) seem aligned on the goal of turning this veto right off.</p><p>Dialectic wrote two great posts about <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dialectic.ch/editorial/nouns-governance-attack">this attack</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dialectic.ch/editorial/nouns-governance-attack-2">potential mitigations</a>, and from those ideas dynamic quorum bubbled up as the safest one to try first (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discourse.nouns.wtf/t/proposal-nip-1-dynamic-quroum/562">credit to wag for first sharing the idea</a>). Dynamic quorum is not meant to solve the biggest of attacks (e.g. malicious owner of 51% proposes to drain the treasury), but smaller versions which target voter apathy.</p><p>We wanted to share how the upcoming dynamic quorum upgrade works, the parameters the DAO needs to decide on, and a bit on what’s next.</p><h2 id="h-dynamic-quorum" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Dynamic quorum</h2><p>Quorum is the minimal number of For votes a proposal must have to pass, currently set to 10% of total supply, e.g. as of August 22 2022 there are 417 Nouns, meaning a proposal created today would need at least 41 For votes to pass.</p><p>Dynamic quorum determines a proposal’s quorum as a function of its contentiousness; simply put: more against votes → higher quorum.</p><blockquote><p>This will ensure a reasonable degree of agility on the DAO governance, where uncontested proposals will require a low quorum whereas highly contentious ones will require a higher quorum.</p></blockquote><blockquote><p>This proposal is a reasonable improvement overall compared to the fixed quorum in terms of scalability since it reduces the tradeoff space between friction and security. However, it’s still ineffective against a great dishonest majority voting power.</p></blockquote><p>(Quotes from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dialectic.ch/editorial/nouns-governance-attack-2">Dialectic’s 2nd post</a>).</p><p><strong>In its simplest form: every against vote increases quorum votes by one</strong> (we’ll complicate things later). Using the numbers above, a proposal with no against votes needs 41 for votes to pass; if it receives one against vote it would need 42 for votes, and if receives 10 against votes it would need 51 for votes to pass.</p><p>Launching dynamic quorum requires setting a few important parameters. We will start with briefly defining them, diving deeper later in this post.</p><ul><li><p><strong>Minimum quorum votes BPs</strong>: similar to v1’s “quorum votes BPs” which is set to 10%, this parameter determines the quorum votes required for a proposal to pass even with zero against votes.</p></li><li><p><strong>Maximum quorum votes BPs</strong>: determines the upper bound value of quorum BPs, e.g. when set to 2,000 quorum votes cannot exceed 20% of total supply.</p></li><li><p><strong>Coefficient</strong>: determines how many quorum votes each against vote adds (until maximum is reached).</p></li></ul><p>The final values of these three parameters will be further discussed among DAO members, and will be visible as part of the proposal to upgrade the DAO contract. You’re invited to duplicate <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.google.com/spreadsheets/d/1t_BlBIiVr4eq4Wa8Ck_kSRTtsWwx7s88BWS7wyBlPzk/edit#gid=999443709">the simulation spreadsheet</a> and tinker with the inputs, and see <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.google.com/spreadsheets/d/1t_BlBIiVr4eq4Wa8Ck_kSRTtsWwx7s88BWS7wyBlPzk/edit#gid=1547630847">their impact on past proposals</a>.</p><p>Next we’ll present some tinkering to help cultivate intuitions ahead of the on-chain configuration proposal.</p><h2 id="h-gaining-a-deeper-intuition" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Gaining a deeper intuition</h2><p>Imagine you’ve submitted a Nouns DAO proposal and you want to advocate for it to be successful; you might consider the question “how many against votes are needed to defeat my proposal?”</p><p>In v1 (the current DAO logic) it looks like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3f0e5c0878c1568cdb8bf764bda6b3cc72b0c35c91fcd7fd7fe0e8042881683c.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>As long as you’re below quorum, your proposal is defeated; once you have quorum (currently set to 10%) then for votes must exceed against votes for the proposal to succeed. In all the graphs in this section: above the line means defeated and below the line means successful.</p><h3 id="h-v1-versus-v2-baseline" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">v1 versus v2 baseline</h3><p>We’ll now review v1 versus v2, tinkering with one parameter at a time to better understand their impact. We’ll start with a baseline configuration:</p><p><code>coefficient = 1; minimum quorum BPs = 1,000; maximum quorum BPs = 2,000</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/35bcef8deafec0fd6d7546fcf86ce4b56b37857f59f603163dc068e81a920db1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>This graph helps visualize three distinct parts:</p><ol><li><p><strong>Before hitting minimum quorum BPs</strong>: v1 &amp; v2 behave the same, i.e. the proposal is defeated without any against votes due to quorum (we complicate this a bit later).</p></li><li><p><strong>Between minimum quorum BPs and maximum quorum BPs</strong>: this is dynamic quorum in action, making proposals easier to defeat with less against votes (they raise quorum).</p></li><li><p><strong>After maximum quorum BPs</strong>: dynamic quorum is capped and we default to the most intuitive behavior where for votes must exceed against votes for the proposal to succeed.</p></li></ol><p>We’ll attempt to further explain dynamic quorum parameters through their impact on this graph’s shape.</p><h3 id="h-minimum-quorum-bps" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Minimum quorum BPs</h3><p>Two charts with different minimum BPs values:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/485ba1679ca7102c27632ebe87e612234d083fcdca36b5573666052b363abee8.png" alt="minimum quorum BPs = 500; maximum quorum BPs = 2,000; coefficient = 1" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">minimum quorum BPs = 500; maximum quorum BPs = 2,000; coefficient = 1</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b970b280d5e3c5bec25b9859dc311e3c71b1cdd4af8a51beb158bdd52873ed7b.png" alt="minimum quorum BPs = 1,500; maximum quorum BPs = 2,000; coefficient = 1" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">minimum quorum BPs = 1,500; maximum quorum BPs = 2,000; coefficient = 1</figcaption></figure><p>Increasing the value of minimum quorum BPs grows that space in the middle of the graph where proposals would be defeated in v2 despite being successful in v1, making it much easier to defeat proposals until the maximum quorum BPs point where v1 and v2 are both decided by simple majority. Decreasing minimum quorum BPs creates this cool new graph shape, where below v1 quorum (10%) it’s actually harder to defeat a proposal in v2.</p><p>Probably an initial value of 10% (1,000 BPs) will be acceptable to the DAO, as its preserving the current minimal quorum.</p><h3 id="h-maximum-quorum-bps" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Maximum quorum BPs</h3><p>Two charts with different maximum BPs values:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0f5deb4c222eed836600b76c856175ea233a0a22f1389c202ecfd7e22a5c580d.png" alt="maximum quorum BPs = 2,000; minimum quorum BPs = 1,000; coefficient = 1" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">maximum quorum BPs = 2,000; minimum quorum BPs = 1,000; coefficient = 1</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/66399c01ceda197661686e536406f39025dab19e095bcf630348924618d44206.png" alt="maximum quorum BPs = 3,000; minimum quorum BPs = 1,000; coefficient = 1" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">maximum quorum BPs = 3,000; minimum quorum BPs = 1,000; coefficient = 1</figcaption></figure><p>Increasing maximum quorum BPs delays that point the graph where v2 reverts back to simple majority, prolonging that middle area where it’s easier to defeat proposals. Perhaps a useful question in setting this parameter is “when do we want to revert from dynamic quorum to simple majority?”</p><p>Important to note that the sum of both axis is the total participation rate, which has recently ranged between <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.tally.xyz/governance/eip155:1:0x6f3E6272A167e8AcCb32072d08E0957F9c79223d/proposal/129">14%</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.tally.xyz/governance/eip155:1:0x6f3E6272A167e8AcCb32072d08E0957F9c79223d/proposal/125">38%</a>. In the higher setting graph for example, we only revert back to simple majority at 30%+ against votes, meaning against votes are extra powerful until we hit a 60%+ participation rate, which is probably too high given current rates.</p><p>Say we’re targeting at 36% participation rate, it might make sense to set maximum quorum BPs to 18% (1800 bps). <code>max quorum BPs = participation rate / 2</code>.</p><h3 id="h-coefficient" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Coefficient</h3><p>Two charts with different coefficient values:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5d8dfa20d2d6bd44c383ae0cef9e2c2bf1c7e8d1b929fced1d731c28a5e0e4c2.png" alt="coefficient = 0.5; maximum quorum BPs = 2,000; minimum quorum BPs = 1,000" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">coefficient = 0.5; maximum quorum BPs = 2,000; minimum quorum BPs = 1,000</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8aa476e965f6d0f4356850397deb4ba9ad7aaf828748528a9725fb5f4e2d8068.png" alt="coefficient = 2; maximum quorum BPs = 2,000; minimum quorum BPs = 1,000" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">coefficient = 2; maximum quorum BPs = 2,000; minimum quorum BPs = 1,000</figcaption></figure><p>Different coefficient change the shape of that famous middle section, with an obtuse triangle at 0.5, a parallelogram at 1, and an obtuse trapezoid at 2. Notice it pushes the v2 line down, making each against vote stronger, so less are required to defeat a proposal.</p><p>Probably setting coefficient around 1 is the easiest place to start, since it’s easiest to predict intuitively, because each against vote adds one quorum vote (up to the maximum limit).</p><h2 id="h-recap-and-potential-guiding-questions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Recap and potential guiding questions</h2><p>Referring back to thinking in 3 parts:</p><ol><li><p><strong>Before hitting minimum quorum BPs</strong>: minimal for votes to pass a proposal with no opposition.</p></li><li><p><strong>Between minimum quorum BPs and maximum quorum BPs</strong>: dynamic quorum in action, making proposals easier to defeat with less against votes.</p></li><li><p><strong>After maximum quorum BPs</strong>: simple majority.</p></li></ol><p>Perhaps start by estimating a highest-realistic participation rate; <strong>maximum quorum BPs</strong> should probably be less than half that rate with a bit of a margin, otherwise with higher values the risk is minority holders stalling DAO decisions. Similarly consider by what participation rate should simple majority determine the outcome rather than the rising quorum.</p><p>Next perhaps consider whether a proposal with no against votes should be easier or harder to pass compared to today with v1. It might also be useful to think of <strong>minimum quorum BPs</strong> as a reflection of whether the DAO leans more towards yes or more towards no given a proposal that has passed the proposal threshold, which is currently configured to 25 BPs or one vote.</p><p>The coefficient parameter seems most intuitively understood as how many quorum votes should each against vote add. The value one seems intuitive as it’s easiest to predict without a spreadsheet, however it’s worth considering further, perhaps by asking how much power do you think should a minority have to deter proposals. Important to highlight that the coefficient can be set to odd values like 1.3 or 0.75.</p><p>Ultimately, our hope is to achieve a higher rate of consensus on successful proposals.</p><h2 id="h-what-are-other-daos-doing" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What are other DAOs doing</h2><p>We are aware of other governance systems that employ dynamic inputs:</p><ul><li><p>Celo’s quorum (“participation”) is set using an <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.celo.org/celo-codebase/protocol/governance#referendum">exponential moving average of final participation in previous proposals</a>.</p></li><li><p>Maker DAO uses <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://makerdao.world/en/learn/governance/how-voting-works/#continuous-approval-voting">continuous approval voting</a>, where active proposals compete for the same pool of votes.</p></li></ul><p>As far as we’re aware, this is the first implementation of dynamic quorum as a function of contentiousness. If this experiment is successful for Nouns, we believe it could become a public good useful for other DAOs.</p><h2 id="h-whats-next" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What’s next</h2><p>In the next few weeks the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://code4rena.com/">code4rena</a> audit results will come in, and we will address any bugs or other issues we might have missed. Once we’ve handled the contest feedback and received the final audit report, we’ll update the DAO with plans to deploy this change to mainnet.</p><p>Beyond dynamic quorum, we will continue doing research on the path to disabling veto, including ideas like defending against last-minute vote swings, making malicious proposal more expensive, and more to come.</p><p>We’re excited to continue exploring this design space of DAO resilience!</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
        <item>
            <title><![CDATA[Deploying a Nouns fork is now 4.20 times cheaper]]></title>
            <link>https://paragraph.com/@verbsteam/deploying-a-nouns-fork-is-now-4-20-times-cheaper</link>
            <guid>ECp7b9CemBV6RtyHVgJ1</guid>
            <pubDate>Fri, 29 Jul 2022 12:38:07 GMT</pubDate>
            <description><![CDATA[→ Nouns DAO is an NFT based DAO on Ethereum, auctioning one noun a day, forever. For more info go here and here.Deploying Nouns forks is used to be expensiveOne of the key features of Nouns is that their art is stored completely on-chain. Since storing data on Ethereum is expensive, the Nouns protocol uses a run-length encoding (RLE) compression algorithm to compactly store all the pixel information required to render Nouns. You can read how it works here (a bit outdated, but still helpful). ...]]></description>
            <content:encoded><![CDATA[<p>→ Nouns DAO is an NFT based DAO on Ethereum, auctioning one noun a day, forever. For more info go <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nouns.wtf/">here</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nouns.center/intro">here</a>.</p><h3 id="h-deploying-nouns-forks-is-used-to-be-expensive" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Deploying Nouns forks <s>is</s> <em>used to be</em> expensive</h3><p>One of the key features of Nouns is that their art is stored completely on-chain. Since storing data on Ethereum is expensive, the Nouns protocol uses a run-length encoding (RLE) compression algorithm to compactly store all the pixel information required to render Nouns. You can read how it works <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nouns.notion.site/Nouns-Protocol-32e4f0bf74fe433e927e2ea35e52a507#7a76d4f87dcf4174bb39472bd31a46c5">here</a> (a bit outdated, but still helpful).</p><p>Even after encoding the art, it cost 67.3M gas <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/txs?a=0xfd16f84e1f9bb5ec33b52d0133d61f7d20699658">to deploy the descriptor contract and add the art data to it</a>. That is ~3.7 ETH at the gas prices in August 2021 (55 gwei).</p><p>This cost can be a source of friction for projects who want to deploy forks of Nouns. Nouns DAO wants to see Nouns proliferate and used as much as possible, so reducing this cost is a great way to reduce friction.</p><p>Nouns DAO has recently upgraded to a new version of its descriptor contract, the contract in charge of the art. This contract cost 15.9M gas to deploy, including storing all the art on-chain.</p><p>In this post we will walk you through the recent changes in the way the Nouns art is stored on chain and how we achieved a reduction from ~67M gas to ~16M gas needed to deploy it.</p><h2 id="h-methods-used-to-reduce-storage-cost" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Methods used to reduce storage cost</h2><p>There were 3 methods we used to improve upon the original Nouns protocol:</p><ol><li><p>Multiline RLE: improve the RLE encoding by supporting multiline runs</p></li><li><p>SSTORE2: store data using CREATE instead of SSTORE to reduce gas cost</p></li><li><p>DEFLATE: use general purpose compression to reduce the size of the data</p></li></ol><h3 id="h-1-multiline-rle" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. Multiline RLE</h3><p>RLE works by encoding each consecutive “run” of pixels with the same color into a tuple of (color, length). For example, the array of pixels: <code>R R R R R R B B B</code> (R is red, B is blue) would be encoded as: <code>(R, 6) (B, 3)</code>.</p><p>The <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/blob/aacd39c2e071c528c760d71445103068ea61b0d0/packages/nouns-sdk/src/image/image.ts#L55">initial RLE algorithm</a> used by Nouns was encoding each row of pixels separately. For example, for an image with these pixels:</p><pre data-type="codeBlock" text="R R B B
B B B B
"><code>R R <span class="hljs-selector-tag">B</span> <span class="hljs-selector-tag">B</span>
<span class="hljs-selector-tag">B</span> <span class="hljs-selector-tag">B</span> <span class="hljs-selector-tag">B</span> <span class="hljs-selector-tag">B</span>
</code></pre><p>the encoding would be: <code>(R, 2) (B, 2) (B, 4)</code>.</p><p>This was improved by encoding this 2-D array in its flattened form:</p><p><code>R R B B B B B B</code> would be encoded as <code>(R, 2) (B, 6)</code>.</p><p>This improvement reduced the amount of image data needed to be stored from ~60KB to ~52KB, and the gas required to deploy from ~67M to ~60M (10% reduction).</p><p>The updated encoder can be found <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/blob/1d146acb56200755679ff46ea20d0dab23507819/packages/nouns-sdk/src/image/image.ts#L36">here</a> and the decoder <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/blob/1d146acb56200755679ff46ea20d0dab23507819/packages/nouns-contracts/contracts/SVGRenderer.sol#L86">here</a>.</p><h3 id="h-2-sstore2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. SSTORE2</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/0xsequence/sstore2">SSTORE2</a> is a solidity library to “Read and write to persistent storage at a fraction of the cost”.</p><p>Instead of using the SSTORE op-code to store data in contract storage slots, it uses the CREATE op-code, which is usually used to deploy contract code, to store arbitrary data. You can see a comparison of the gas cost of using SSTORE vs SSTORE2 in the library’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/0xsequence/sstore2#sstore-cost-data-writes">README</a>.</p><p>SSTORE2 becomes cheaper when using it to write bigger chunks of data, so instead of write each image individually, we decided to batch all the images of a trait together.</p><p>When batching the images together, we need to know where one image ends and the next one starts. For convenience we used ABI encoding to encode the data as a <code>bytes[]</code> which can be easily decoded in solidity using <code>abi.decode</code>. It’s very likely that there are more efficient ways of encoding the array of images, but we decided to use the convenience of ABI encoding.</p><p>This improvement reduces the gas cost to deploy the art from ~60M to ~28M (53% reduction).</p><p>You can see the usage of SSTORE2 in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/nounsDAO/nouns-monorepo/blob/daa58afc1eb3c7503200644d892f4812bab5e0ae/packages/nouns-contracts/contracts/NounsArt.sol">NounsArt contract</a>.</p><h3 id="h-3-deflate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. DEFLATE</h3><p>As part of looking for ways to compress the data more, we were searching for general purpose compression algorithms implemented in solidity.</p><p>Thankfully we found the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/adlerjohn/inflate-sol">inflate-sol</a> library by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/adlerjohn">@adlerjohn</a> which implements a decompression algorithm of DEFLATE, which is the common compression algorithm use in zlib/gzip.</p><p>Our plan was to compress the batched data as describe in (2) and write it using SSTORE2. When accessing the data, the data would be read using SSTORE2, decompressed using inflate-sol, and finally decode using <code>abi.decode</code>.</p><p>The concern we had here is that inflate-sol is quite gas intensive when decompressing data. Theoretically that wouldn’t be a concern since it would be used in read-only functions of the contracts, and not as a part of a transaction. Practically it is an issue because when performing an <code>eth_call</code>, Ethereum nodes often have a gas limit on it. Specifically the nodes used by NFT marketplaces (e.g opensea, looksrare) have gas limits when calling <code>tokenURI</code> on the NFT contract.</p><p>These gas limits are not documented anywhere that we could find. In order to find the limits we deployed an <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rinkeby.etherscan.io/address/0x5040a7692a21c7dae82db60e7bef9d46ee79e989#code">NFT contract</a> where each consecutive NFT consumes 1M addition gas in its’ <code>tokenURI</code> method. For our experiments, we saw that NFT marketplaces and popular node providers (infura, alchemy) can handle at least ~400M gas.</p><p>With a few low-hanging gas optimizations, we were able to get the <code>tokenURI</code> method to about 110M gas which felt safe to use.</p><p>We deployed the inflate-sol library as a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xa2acee85Cd81c42BcAa1FeFA8eD2516b68872Dbe">standalone contract</a> to enable anyone to access without needing to redeploy it.</p><p>This improvement reduces the gas cost to deploy the art from ~28M to ~14M (50% reduction).</p><p>Hope you enjoyed reading. If you have any feedback or question, drop by the Nouns <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://discord.gg/nouns">discord</a> at #54-tech-grants.</p>]]></content:encoded>
            <author>verbsteam@newsletter.paragraph.com (verbs)</author>
        </item>
    </channel>
</rss>