<?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>Andrew Hong</title>
        <link>https://paragraph.com/@ilemi</link>
        <description>On the composition of a decentralized future</description>
        <lastBuildDate>Fri, 03 Apr 2026 15:27:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Andrew Hong</title>
            <url>https://storage.googleapis.com/papyrus_images/1e8626b3ccf8c196036a22b6649dd2c6b582e674b36e07a3dc5abe71ae2cbfcf.jpg</url>
            <link>https://paragraph.com/@ilemi</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[The Landscape of Web3 Scores and Algorithms]]></title>
            <link>https://paragraph.com/@ilemi/the-landscape-of-web3-scores-and-algorithms</link>
            <guid>CY7JiWegUuxqM2k0t4iy</guid>
            <pubDate>Thu, 08 Sep 2022 15:16:42 GMT</pubDate>
            <description><![CDATA[We’ve seen algorithms become the lifeblood of the internet - driving infinite recommendations on top of infinite feeds. In web2, these algorithms are complete black boxes (end-to-end), used for one specific application, and manipulated by some interested party. No one knows exactly what inputs are used, what scores are given to people and content, or what models are used for curation. And you can be sure there’s no API to run their models and get their outputs yourself. Web3 algorithms are st...]]></description>
            <content:encoded><![CDATA[<p>We’ve seen algorithms become the lifeblood of the internet - driving infinite recommendations on top of infinite feeds. In web2, these algorithms are complete black boxes (end-to-end), used for one specific application, and manipulated by some interested party. No one knows exactly what inputs are used, what scores are given to people and content, or what models are used for curation. And you can be sure there’s no API to run their models and get their outputs yourself.</p><p>Web3 algorithms are still nascent, but we’re close to a tipping point due to a combination of:</p><ol><li><p><strong>Bigger Blockchains</strong>: The blockchain data behemoth is growing exponentially due to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/scaling/">transaction capacity scaling</a> and the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://l2beat.com/scaling/tvl/">number of layer 2 chains launched</a>.</p></li><li><p><strong>Modular Evolution</strong>: Web3 protocols are being <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://opensea.io/blog/announcements/launching-seaport-saving-the-community-millions-in-fees/">optimized</a>/<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.comp.xyz/t/initialize-compound-iii-usdc-on-ethereum/3499">simplified</a> while actually emphasizing modular composability. That means anything that was the protocol team’s choice is now up to individual communities - everything from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.sudoswap.xyz/pricing/">pricing curves</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/fullyallocated/status/1518690264419819522">token and voting permissions</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.0x.org/introducing-multi-chain-nft-swaps/">customizable</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=juP22m8kiKM&amp;t=840s">conditional</a> token marketplaces.</p></li><li><p><strong>Hyperbundling</strong>: With increased composability comes heavy aggregation - across defi, NFTs, and DAOs. It should be no surprise that <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://uniswap.org/blog/genie">Uniswap</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://opensea.io/blog/announcements/opensea-acquires-gem-to-invest-in-pro-experience/">Opensea</a> are already heavily focused here.</p></li><li><p><strong>Maturing Data Infra:</strong> Everyone and their grandma knows how to do auto-generated decoded tables already. Data providers like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/browse/dashboards">Dune</a> are maturing to compete at the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/spellbook">aggregated tables</a> level instead, across many chains.</p></li></ol><p>All this means more data, more cross-app and cross-domain intricacies, and more powerful ways to index and analyze data. It’s inevitable that we’ll see this data leveraged to create curated and tiered experiences for communities and users alike.</p><p>Currently, web3 algorithms focus on calculating scores targeting different facets of a user’s profile (using aggregate activity across multiple chains/apps). Protocol teams and communities can then decide how to use those scores to enhance their product experience, governance processes, or tokenomics.</p><p><strong>In this article, I’ll cover a framework for comparing scores and understanding the interlinked data stacks behind them.</strong></p><p><em>⚠️ What I’m covering is separate from </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://future.com/reputation-based-systems/"><em>token-based reputation score systems</em></a><em>. While they are related, I’m not interested in exploring tokenomics in this article. Most of the scores here don’t directly translate to some balance or distribution of tokens. I’ll have a follow on article at some point discussing how to possibly model tokenomics with various kinds of categorical scores, but I believe trying too hard to attach them at the start will lead to perverse incentives and difficulty growing organically.</em></p><h2 id="h-modeling-the-web3-score-landscape" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Modeling the Web3 Score Landscape</h2><p>Let’s start by defining some of the current main categories for user scores:</p><ul><li><p><strong>Creators/Curators:</strong> Scoring someone’s ability to create or curate content</p></li><li><p><strong>DeFi/Credit Management:</strong> Scoring someone’s ability to deploy and manage capital</p></li><li><p><strong>Contributors:</strong> Scoring someone’s contributions to a protocol/DAO and their skill set</p></li><li><p><strong>Rule-based:</strong> Scoring someone based on a defined set of actions taken</p></li><li><p><strong>Sybil (Identity):</strong> Scoring someone based on how likely they are to be human</p></li></ul><p>We’ll likely see Sybil scores that combine with credit scores for enhanced access in DeFi, or contributor scores that combine with rule-based scores for prioritized onboarding to DAOs. However, scores can differ a lot even within the same category, so let’s compare them on two axes:</p><ul><li><p><strong>Contextual &lt;&gt; Generalized:</strong> how generalizable is a score across the communities its used in? The more contextual the score is, the more it doesn’t translate well across communities or applications. Generalized scores are good for comparisons across communities and protocols, while contextual scores are better for analyzing health over time granularly.</p></li><li><p><strong>Elo Scores &lt;&gt; Levels:</strong> is the score constantly adjusted and normalized, or is it a number that only goes up? Elo scores mean your score is more dependent/ranked against the actions of others in the ecosystem. For the most part, levels will be more beginner friendly and better understood than elo scores.</p></li></ul><p>Here are some examples of scores from the real world, placed in our four quadrants:</p><ul><li><p><em>Contextual + Elo Score:</em> Your competitive ranking in a game like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.chess.com/terms/elo-rating-chess">Chess</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://leagueoflegends.fandom.com/wiki/Elo_rating_system">League of Legends</a></p></li><li><p><em>Contextual + Level:</em> Your level in a rewards program, like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://citibikenyc.com/bike-angels/rewards">Citibike Bike Angels</a></p></li><li><p><em>Generalized + Elo Score:</em> Your <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ncvhs.hhs.gov/wp-content/uploads/2014/05/120622lt.pdf">socioeconomic status</a> (combination of education, income, health)</p></li><li><p><em>Generalized + Level:</em> Your years of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://help.nfc.usda.gov/publications/EPICWEB/6592.htm">education/degrees earned</a></p></li></ul><p>Here’s where some of the top web3 scoring systems/protocols sit along the axes:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/29c6a13a4bef3d9144b32a395973c1054de58caa17d9f229598ba8163e518b1b.png" alt="Thanks Nir (@nir_III) for brainstorming the framework with me!" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Thanks Nir (@nir_III) for brainstorming the framework with me!</figcaption></figure><p>I’ll briefly describe what each score provider does, hopefully explaining their placement. Note that I placed each provider based on how I interpreted their main offerings (as of September 1st, 2022):</p><ul><li><p>Creators/Curators:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.yup.io/protocol/score-api">yup.io</a>: Action adapters that are combined in a weighted score.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/CdU80CItQr-qTZgTzymfFDEBSnz2YbgnwXGYgkQJfCs">$WRITE airdrop</a>: Betweenness centrality algorithm to give you a weighted score of your Mirror activity.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.jokedao.io/contest/polygon/0x90E63E19d64f4CBd92ceD44af0572AA6ee25CC53">jokedao</a>: Round-based voting on best jokes.</p></li></ul></li><li><p>DeFi/Credit:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.spectral.finance/introduction-to-macro-score/">MACRO</a>: Creates a market conditions time-weighted score of your defi actions.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wiki.arcx.money/application/defi-credit-score">ARCx</a>: A gamified and clearly defined three-part defi scoring system.</p></li><li><p>Degenscore: Ranks how much of a degen you are compared to other protocol users with a score and percentile format</p></li></ul></li><li><p>Contributors:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://beta.layer3.xyz/leaderboard">layer3xyz</a>: Experience earned by fulfilling bounties and winning contests.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pitch.com/public/61902937-6253-4bcd-ba38-61940d35af03/087a3e41-5d7d-4e64-a778-01aeeee8c1eb">0xStation</a>: DAO passports where defined actions become a part of a searchable system of records (slide 10).</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://metropolis.mirror.xyz/ozkx0ZMwIzyahRJiQKpNv_8r7vAhOo-8tucjONhXJHI">metropolis</a>: Building generalized identity around gnosis safes to build more context-rich data around on-chain group interactions.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.tecommons.org/t/coordinape-an-overview/616">Coordinape</a>: Your fellow contributors vote on your level of contribution per epoch (interval of time).</p></li></ul></li><li><p>Rule-based:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.rabbithole.gg/skills/intro-to-nfts">Rabbithole</a>: Custom skill trees with specific completable actions.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://logbook.themetagame.xyz/">Metagame</a>: Activity logs of various categories of (decoded) transaction types.</p></li></ul></li><li><p>Sybil:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/BrightID/BrightID-AntiSybil">BrightID</a>: A vote-in system where you get a fluctuating health score based on the SybilRank of the network closest to you</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.kleros.io/proof-of-humanity-an-explainer/">PoH</a>: Also a vote-in system, but with deposit minimums. You’re either in the network or you’re out (challenged/voted out). <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://union.finance/">Union</a> kind of builds off of this.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://techcrunch.com/2021/10/21/sam-altmans-worldcoin-wants-to-scan-every-humans-eyeball-and-give-them-crypto-in-exchange/">Worldcoin</a>: Scans your eye to give you a private key. Don’t lose either one!</p></li></ul></li></ul><p>Right now we’re mostly seeing scores used in tiered protocol access and leaderboards/ranked feeds, but more powerful curation algorithms are right around the corner. To understand how they’ll emerge, we need to take a look at both the score data stack and score aggregators.</p><h2 id="h-from-data-provider-to-score-provider-then-back" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">From data provider to score provider - then back</h2><p>Below is my simplified interpretation of the data stack used by score providers - I’ll walk through it from the bottom to the top.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3151ccb88af891cd2c9a3d99704b57dd73be79d9e95bbf4a01d2585208f48258.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><h3 id="h-sourcing-data" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Sourcing Data:</h3><p>While you can still build your own events/transactions indexer off of node providers like Alchemy, a few web3 product teams are open-sourcing their decoding indexers (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://api.zora.co/">zora</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gallery.mirror.xyz/CC926szCICnwa908S4r1B2hk_q-mTSjeQUUGnO1b6QI">gallery</a>). This trend will continue for most standard contract types, such that direct JSON RPC calls get abstracted more and more.</p><p>For nicely aggregated data, you’d likely use the Graph (for mapped <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/querying/graphql-api/#schema">graphQL subscriptions</a>) or Dune Analytics (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/spellbook">for cross-protocol/chain abstractions</a>).</p><h3 id="h-feature-engineering" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Feature Engineering:</h3><p>Unlike data mappers such as Dune that capture every on-chain data point since genesis, score providers usually ingest just a subset of data depending on the protocols they’re interested in. From there, we have three steps of feature engineering:</p><ol><li><p>Splitting actions into binary and continuous components, such as “borrowed USDC” versus “health factor of loan over time”.</p></li><li><p>Generalize variables (usually complex structs) across protocols of the same type; for example, loan health factors across DeFi protocols must be generalized based on respective <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.aave.com/risk/asset-risk/risk-parameters">risk parameters</a>.</p></li><li><p>Wallet normalization means choosing a score or level distribution you want wallets to fit into. Binary variables can be used to boost or decay scores for more custom distributions.</p></li></ol><p>There are more steps if you consider including external datasets that are already preprocessed, but I’ve left that out of the diagram.</p><h3 id="h-model" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Model:</h3><p>While inputs/outputs are much more transparent in web3, some models are still privately developed right now (either for IP or Sybil/gamification reasons). I don’t have much to say on the models themselves since we’re still using the same web2 academic algorithms and libraries, however, I do believe that open-source models will win in the long run.</p><p>At the end of the day, everyone needs to be able to trust and interpret these scores - especially if there’s any sort of tokenomics/value involved. You need both builder and consumer communities to buy into using your scores - there’s no way for you to just force it upon them (yet, and hopefully never). Once you generate that trust, then you’ll have an extremely strong flywheel of more applications, more data, more builders, and more users.</p><p>Most people already understand that it’s not the technology that’s special or proprietary in web3 - it’s the community. It doesn’t matter how strong your team is, you won’t win by keeping things private.</p><h3 id="h-service" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Service:</h3><p>On top of their basic score offerings, score providers also act as special data providers. All their engineered features can be re-used as a tiered data service similar to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://huggingface.co/models">hugging face NLP libraries</a>.</p><p>There are three main data consumers:</p><ul><li><p><em>Apps:</em> Some products/protocols/communities will integrate directly with base scores, most likely the contextual scores (especially contributor scores). Features within the model will likely be useful for various UI elements and forums/discords.</p></li><li><p><em>Aggregators:</em> Improving the developer experience for integrations is a no-brainer. Some examples out currently are:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.chain.link/docs/jobs/types/flux-monitor/">Chainlink flux aggregator</a>: for on-chain score deployment, you might want to take a weighted Sybil score from multiple sources.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://passport.gitcoin.co/">Gitcoin passport</a>: for social apps, you’ll likely want easy access to multiple types of scores to enhance user profiles. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://idx.xyz/">Ceramic</a> fits here too.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.orangeprotocol.io/">Orange Protocol</a>: for complex protocols (i.e. defi) you might need an ensemble model approach where you have complete control of inputs, models, and output variability.</p></li></ul><p>My guess is that aggregators will probably end up having larger and larger says in the governance and tech stack of score providers over time.</p></li><li><p><em>Analytics Platforms:</em> Wallet labeling has already proven <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.nansen.ai/guides/wallet-labels-emojis-what-do-they-mean">extremely powerful</a> for various analytics use cases. Having scores as joinable tables would give us completely new ways of measuring adoption/market share, user segments, and product-community-fit across protocols.</p></li></ul><p>I believe that the more generalizable the score, the more valuable the final outputs are (compared to the features). Vice versa, the more contextual the score, the more valuable the engineered features are. This should be intuitive given that a community would likely have more use for contextual features in their forums and membership processes than something general like who voted for who in a Sybil network.</p><h2 id="h-concluding-thoughts-on-the-future-of-scores" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Concluding thoughts on the future of scores</h2><p>There’s a ton we can extrapolate about where scores are heading and what they’ll be used for. I’m personally excited about how score providers will enhance web3 native profile search and contributor relationship management systems (web3 CRM).</p><p>Transaction hashes and addresses give us strong anchors for finding relationships between users, but individual activity isn’t easily searchable. For example, you can see an address has some number of tokens and transactions, but you can’t search for their first ENS registered, first liquidation, or when they fulfilled their first bounty. These require the data to be more semantically layered, which is what score providers do when they engineer features into binary/continuous variables most relevant to their models. A transaction that’s just a USDC transfer would now have standardized metadata around what grant proposal it was tied to, and a transaction showing an ETH deposit into Compound is now classified as “avoiding liquidation”. It might not seem like much on its own, but combining all the features across score providers gives us the ability to do a top-down search starting from some “category” to get a “proof of action” - rather than trying to filter bottoms-up manually for specific function calls or transactions.</p><p>Combing scores allow us to filter through large clusters of users and create flexible metrics for measuring community health. Each <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/4WoFuC78ew4XSXBB20u8BLhTpq8yrpZU9pyhUjrETJc">segment within a web3 community</a> will have a sliding scale for understanding underlying users and their activity. Younger communities would likely check generalized + level scores more often to see if overall health is going up compared to others, while mature communities would rely more on contextual + elo scores to track the pulse and retention of top members. You could prioritize your onboarding funnel for voters by layering Sybil scores on top of historical governance activity (proposals, delegations, votes), or for builders by layering contribution levels on top of their historical compensation distributions (payment rate, token diversity). I’m sure there are many teams working on contributor relationship management systems, where contributor activity is layered on top of score-based filtering to build out a more accurate understanding of which contributors (old, new, or tangential) are most active and likely to be interested in taking on a new project.</p><p>Both activity search and score combinations go towards scaling membership - an article I have planned for later this year! As always, thanks for reading this far - if you enjoyed this piece, please collect and subscribe for more 🙂</p><p>My <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/andrewhong5297">DMs are always open</a> if you have questions or want to discuss anything I’ve written here (especially if you’re currently building or researching this topic).</p><p>*thanks to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/serenalihere">Serena</a> for her feedback on this article! *😊</p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[Web3 Data Guide: Sudoswap]]></title>
            <link>https://paragraph.com/@ilemi/web3-data-guide-sudoswap</link>
            <guid>nt0hVgiaQldUXauMYhO6</guid>
            <pubDate>Tue, 23 Aug 2022 03:02:45 GMT</pubDate>
            <description><![CDATA[This is the first of many Web3 data guides I plan on doing. The goal here is to explain the protocol from a data analyst/engineer’s perspective. These guides aim to bring transparency to the data you see on dashboards, as well as awareness of how well (or not well) protocols are built for data analysis. In these guides, I’ll cover protocols in three sections:Protocol overview and high-level statisticsMain protocol interactions and how to derive the important data points from themSome of the m...]]></description>
            <content:encoded><![CDATA[<p><em>This is the first of many Web3 data guides I plan on doing. The goal here is to explain the protocol from a data analyst/engineer’s perspective. These guides aim to bring transparency to the data you see on dashboards, as well as awareness of how well (or not well) protocols are built for data analysis.</em></p><p><em>In these guides, I’ll cover protocols in three sections:</em></p><ol><li><p><em>Protocol overview and high-level statistics</em></p></li><li><p><em>Main protocol interactions and how to derive the important data points from them</em></p></li><li><p><em>Some of the more complex queries and abstractions created</em></p></li></ol><p><em>All data is sourced from </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/browse/dashboards"><em>Dune Analytics</em></a><em>, a platform for building cross-chain queries and dashboards - most of which is open source.</em></p><p><em>I’ve also recorded a video walk through everything mentioned in this article:</em></p><div data-type="youtube" videoId="7zReSzVdV2s">
      <div class="youtube-player" data-id="7zReSzVdV2s" style="background-image: url('https://i.ytimg.com/vi/7zReSzVdV2s/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=7zReSzVdV2s">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><p><strong>If you collect this entry, you can get access to my web3 data degens telegram group by </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://guild.xyz/web3-data-degens"><strong>clicking here</strong></a><strong>! We discuss the newest protocols, debug general query questions, and help analysts find jobs (freelance and fulltime).</strong></p><p>collect://</p><p>A big shoutout to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/j__dude">Jeff</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Dot2DotSeurat">Meghan</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/rob_0x">Rob</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/hildobby_">hildobby</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/sui414">Danning</a> for their help! 😊</p><h2 id="h-protocol-overview" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Protocol Overview:</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://sudoswap.xyz/">Sudoswap NFT AMM</a> is a flexible liquidity pool solution for NFT (ERC721s) to token (ETH or ERC20) swaps using customizable bonding curves. This basically means you set discrete price changes per swap (i.e. 0.1 ETH price increase for each NFT sold), and you choose the side of liquidity you want to provide (NFTs to sell, or ETH for others to sell their NFTs into). Everyone’s pools are separate and only aggregated at a router level - kind of like Uniswap V3.</p><p>Over the last month, the protocol has generated a lot of momentum (some of which is wash trading, but consistently around 500 ETH a day of swaps is organic volume.</p><div data-type="twitter" tweetId="1560141123988905984" tweetData="{&quot;__typename&quot;:&quot;Tweet&quot;,&quot;in_reply_to_screen_name&quot;:&quot;sudoswap&quot;,&quot;in_reply_to_user_id_str&quot;:&quot;1321867612435869696&quot;,&quot;lang&quot;:&quot;en&quot;,&quot;favorite_count&quot;:112,&quot;possibly_sensitive&quot;:false,&quot;created_at&quot;:&quot;2022-08-18T05:46:44.000Z&quot;,&quot;display_text_range&quot;:[0,267],&quot;entities&quot;:{&quot;hashtags&quot;:[],&quot;urls&quot;:[],&quot;user_mentions&quot;:[{&quot;id_str&quot;:&quot;1321867612435869696&quot;,&quot;indices&quot;:[0,9],&quot;name&quot;:&quot;sudoswap&quot;,&quot;screen_name&quot;:&quot;sudoswap&quot;}],&quot;symbols&quot;:[],&quot;media&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/y5w3AQT0GK&quot;,&quot;expanded_url&quot;:&quot;https://x.com/andrewhong5297/status/1560141123988905984/photo/1&quot;,&quot;indices&quot;:[267,290],&quot;url&quot;:&quot;https://t.co/y5w3AQT0GK&quot;}]},&quot;id_str&quot;:&quot;1560141123988905984&quot;,&quot;text&quot;:&quot;@sudoswap has passed 10k ETH in volume! 🎉\n\nSome other impressive stats:\n- 1k+ ETH daily volume\n- 10k traders\n- 66k NFTs exchanged\n- 1.5k ETH and 63k NFTs are currently liquid in pairs, across 2.7k NFT collections\n- 50 ETH in protocol fees, 300 ETH in pair owner fees https://t.co/y5w3AQT0GK&quot;,&quot;user&quot;:{&quot;id_str&quot;:&quot;801246156340740096&quot;,&quot;name&quot;:&quot;ilemi&quot;,&quot;screen_name&quot;:&quot;andrewhong5297&quot;,&quot;is_blue_verified&quot;:true,&quot;profile_image_shape&quot;:&quot;Circle&quot;,&quot;verified&quot;:false,&quot;profile_image_url_https&quot;:&quot;https://storage.googleapis.com/papyrus_images/f903871b38b5a4c8fb81a65b362af213e8c3ab3e83ead7e3da32e5f80fa4d7a9.jpg&quot;},&quot;edit_control&quot;:{&quot;edit_tweet_ids&quot;:[&quot;1560141123988905984&quot;],&quot;editable_until_msecs&quot;:&quot;1660803404000&quot;,&quot;is_edit_eligible&quot;:false,&quot;edits_remaining&quot;:&quot;5&quot;},&quot;mediaDetails&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/y5w3AQT0GK&quot;,&quot;expanded_url&quot;:&quot;https://x.com/andrewhong5297/status/1560141123988905984/photo/1&quot;,&quot;ext_media_availability&quot;:{&quot;status&quot;:&quot;Available&quot;},&quot;indices&quot;:[267,290],&quot;media_url_https&quot;:&quot;https://pbs.twimg.com/media/Faa3qpKXgAASL1B.png&quot;,&quot;original_info&quot;:{&quot;height&quot;:385,&quot;width&quot;:927,&quot;focus_rects&quot;:[{&quot;x&quot;:142,&quot;y&quot;:0,&quot;w&quot;:688,&quot;h&quot;:385},{&quot;x&quot;:294,&quot;y&quot;:0,&quot;w&quot;:385,&quot;h&quot;:385},{&quot;x&quot;:317,&quot;y&quot;:0,&quot;w&quot;:338,&quot;h&quot;:385},{&quot;x&quot;:390,&quot;y&quot;:0,&quot;w&quot;:193,&quot;h&quot;:385},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:927,&quot;h&quot;:385}]},&quot;sizes&quot;:{&quot;large&quot;:{&quot;h&quot;:385,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:927},&quot;medium&quot;:{&quot;h&quot;:385,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:927},&quot;small&quot;:{&quot;h&quot;:282,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:680},&quot;thumb&quot;:{&quot;h&quot;:150,&quot;resize&quot;:&quot;crop&quot;,&quot;w&quot;:150}},&quot;type&quot;:&quot;photo&quot;,&quot;url&quot;:&quot;https://t.co/y5w3AQT0GK&quot;}],&quot;photos&quot;:[{&quot;backgroundColor&quot;:{&quot;red&quot;:204,&quot;green&quot;:214,&quot;blue&quot;:221},&quot;cropCandidates&quot;:[{&quot;x&quot;:142,&quot;y&quot;:0,&quot;w&quot;:688,&quot;h&quot;:385},{&quot;x&quot;:294,&quot;y&quot;:0,&quot;w&quot;:385,&quot;h&quot;:385},{&quot;x&quot;:317,&quot;y&quot;:0,&quot;w&quot;:338,&quot;h&quot;:385},{&quot;x&quot;:390,&quot;y&quot;:0,&quot;w&quot;:193,&quot;h&quot;:385},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:927,&quot;h&quot;:385}],&quot;expandedUrl&quot;:&quot;https://x.com/andrewhong5297/status/1560141123988905984/photo/1&quot;,&quot;url&quot;:&quot;https://storage.googleapis.com/papyrus_images/0646c4697d1de27e425ec45371866a317c4961c9bb0d944d9f21fc0eb27643b5.png&quot;,&quot;width&quot;:927,&quot;height&quot;:385}],&quot;conversation_count&quot;:6,&quot;news_action_type&quot;:&quot;conversation&quot;,&quot;isEdited&quot;:false,&quot;isStaleEdit&quot;:false}"> 
  <div class="twitter-embed embed">
    <div class="twitter-header">
        <div style="display:flex">
          <a target="_blank" href="https://twitter.com/andrewhong5297">
              <img alt="User Avatar" class="twitter-avatar" src="https://storage.googleapis.com/papyrus_images/f903871b38b5a4c8fb81a65b362af213e8c3ab3e83ead7e3da32e5f80fa4d7a9.jpg" />
            </a>
            <div style="margin-left:4px;margin-right:auto;line-height:1.2;">
              <a target="_blank" href="https://twitter.com/andrewhong5297" class="twitter-displayname">ilemi</a>
              <p><a target="_blank" href="https://twitter.com/andrewhong5297" class="twitter-username">@andrewhong5297</a></p>
    
            </div>
            <a href="https://twitter.com/andrewhong5297/status/1560141123988905984" target="_blank">
              <img alt="Twitter Logo" class="twitter-logo" src="https://paragraph.com/editor/twitter/logo.png" />
            </a>
          </div>
        </div>
      
    <div class="twitter-body">
      <a class="twitter-content-link"  href="https://twitter.com/sudoswap" target="_blank">@sudoswap</a> has passed 10k ETH in volume! <img class="twitter-emoji" draggable="false" alt="🎉" src="https://abs-0.twimg.com/emoji/v2/72x72/1f389.png"/><br /><br />Some other impressive stats:<br />- 1k+ ETH daily volume<br />- 10k traders<br />- 66k NFTs exchanged<br />- 1.5k ETH and 63k NFTs are currently liquid in pairs, across 2.7k NFT collections<br />- 50 ETH in protocol fees, 300 ETH in pair owner fees 
      <div class="twitter-media"><img class="twitter-image" src="https://storage.googleapis.com/papyrus_images/0646c4697d1de27e425ec45371866a317c4961c9bb0d944d9f21fc0eb27643b5.png" /></div>
      
       
    </div>
    
     <div class="twitter-footer">
          <a target="_blank" href="https://twitter.com/andrewhong5297/status/1560141123988905984" style="margin-right:16px; display:flex;">
            <img alt="Like Icon" class="twitter-heart" src="https://paragraph.com/editor/twitter/heart.png">
            112
          </a>
          <a target="_blank" href="https://twitter.com/andrewhong5297/status/1560141123988905984"><p>12:46 AM • Aug 18, 2022</p></a>
        </div>
    
  </div> 
  </div><p>They’re sure to take off more as ERC20 pairs and ERC1155 pairs are launched, especially once aggregators integrate their markets.</p><p>I’ve created two dashboards on Dune for Sudoswap:</p><ol><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/ilemi/sudoswap">A general overview</a> of swap volumes, trader activity, fees, and trending collections.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/ilemi/sudoswap-collection">A collection-specific view</a> that dives deeper into liquidity depth, trading prices, and pair activity on top of the basic metrics.</p></li></ol><p>You can read (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/episode/7CCpzED51Bff6A7ZfAotAb">or listen</a>) about <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.sudoswap.xyz/deep-dive-1-sudoamm-vs-the-other-amms-they-told-u-not-to-worry-about.html">why this design is better than other NFT AMMs</a> out there, or go directly to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.sudoswap.xyz/create/">the docs</a>. For those wanting to gain a deeper understanding of the Solidity behind the protocol, I recommend you read the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Protocol_Review">Protocol Review</a> piece here (coming soon!).</p><h2 id="h-data-sourcing-guide" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Data Sourcing Guide</h2><p>Usually, there are a few elements that factor into the difficulty of data analysis:</p><ul><li><p>Complexity of contract patterns (standards like proxies, clones, diamonds)</p></li><li><p>Complexity of mid-function states (if there’s a swap, how easy is it to calculate the price)</p></li><li><p>Completeness of data across function parameters and event parameters</p></li><li><p>Number of token interactions (one token in, one in one out, wrapping, bridging)</p></li><li><p>How much math (interest rates, pricing curves, rebases, and anything that updates continuously even if no on-chain interactions occur)</p></li><li><p>Documentation and code/developer accessibility (how quickly can I find answers to questions)</p></li></ul><p>I won’t go into a complete scorecard in this guide, but will probably build up to one in the future. Usually, when I start my analysis, I figure out the main user interactions and then list out all the variables I can get about each one.</p><p>Below is my breakdown of interactions for Sudoswap. My <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/andrewhong5297">DMs are always open</a> for feedback on what could make this more clear/informative!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/27a33211f6f69b8cdfa9b70f5f7a9563fb0412773b26269a8d699e3d75b101a8.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><strong><em>Some contextual callouts that don’t fit in the diagram:</em></strong></p><p><strong><em>Contract patterns:</em></strong></p><p>While the basic contract pattern is simple (factory produces a pair as a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=3Mw-pMmJ7TA">proxy clone</a>, only the pair creator has ownership of tokens in that pair), there are actually many different variations of the pair contract based on the type of ERC721 and ERC20/ETH token.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0d2566891df54fd92e014a011e3a170914287af5997d7fb9049f462c1e40db49.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>They all inherit from <code>LSSVMPair.sol</code>, and all the functions/swaps we care about are on that contract. To make our lives easier in Dune, we want all data to get decoded to the same contract table instead of seven different ones we then have to UNION over. I did this by compiling <code>LSSVMPair.sol</code> using hardhat, and pasting the ABI artifact in the contract decode request field under the name <code>LSSVMPair_General</code>.</p><p><strong><em>Prices and parameters:</em></strong></p><p>Spot price is set at the pair deployment, after each swap, and can also be set manually. The same <code>SpotPriceUpdated()</code> event is used for swaps and manual changes, but not emitted on deployment. This means we have to do an extra join when getting price histories, and also an extra join if we want to remove custom spot price changes from swaps data. It would be nice if there was a <code>SpotPriceChanged()</code> event for deploy and manual changes, so the data is cleaner. Same feedback for price delta.</p><p><strong><em>Events, events, events:</em></strong></p><p>My main gripe is that the router has 0 events for swaps, and the pair has empty events for swapping in and out. Including <code>spotPriceOld</code>, <code>spotPriceNew</code>, <code>protocolFee</code>, <code>ownerFee</code>, and <code>tokenIds</code> transferred in the swap events would have saved a lot of time and warehouse compute.</p><p>Thankfully Sudoswap has great docs and 0xmons was very responsive, so I was able to eventually piece together the data by manually going through internal traces for each transaction.</p><p>Internal traces are the function calls that happen within the main function call. In this case, the pair contract calls the NFT contract to transfer the NFT to the pair, then the pair contract makes an opcode call to transfer ETH from the contract to your wallet to complete the swap. Get price info and other read function calls also show up in internal txs as long as its a call across contracts (internal functions won’t show up in traces).</p><p>The best way to visualize this is using an explorer like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://tools.blocksec.com/tx/eth/0xeed19c4c0540a3891e51b2f0bca609621452ec7843345826c384fd3bf15ba469">Versatile blocksec</a>, which visualizes transactions really well:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/788c1a605703663a59231fbb8ad59b2c25d6bb50662b0bc730ceb7801c821296.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>Dune v2 engine tables include the <code>call_trace_address</code> for all decoded functions, which means we can join with <code>ethereum.traces</code> and then filter for ETH calls (look at call value) and <code>safeTransferFrom()</code> call (<code>0x42842e0e</code> funcsig) within that subtrace stack. Then add on some simple math, and we can back into protocol fees and owner fees paid per swap.</p><p>You can find the full query below, which has some extra logic to fit into the <code>nft.trades</code> schema.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/98640c0dda1dfc19719848a51d25a8b7fcebaf23c042fe3705f00b87cd91273a.png" alt="https://dune.com/queries/1153457" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.com/queries/1153457</figcaption></figure><p><strong>You can get started querying these tables yourself using any of the</strong> <code>sudo_amm_ethereum</code> <strong>tables or the abstraction</strong> <code>sudoswap_ethereum.events</code> <strong>, both on the v2 Dune engine!</strong></p><h2 id="h-creating-the-spellbook-abstraction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Creating the Spellbook Abstraction</h2><p>Dune’s v1 engine used <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/abstractions">an abstractions repo</a> to create tables such as <code>dex.trades</code> and <code>nft.trades</code> by putting together enhanced tables out of decoded contract tables. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/abstractions/tree/master/spellbook">Spellbook</a> is for the v2 engine, this time built off of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.getdbt.com/blog/next-layer-of-the-modern-data-stack/">dbt (data build tool)</a>.</p><p>It’s a powerful way to semantically manage relationships between tables, easily generate documentation, and run tests. You also get to leverage <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.getdbt.com/docs/building-a-dbt-project/jinja-macros">Jinja</a> to have more programmability around your SQL code (if, while, for loops, etc).</p><p>If you’re looking to contribute you can start with the Spellbook readme <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/abstractions/blob/master/CONTRIBUTING.md">here</a>, I’ll cover an example for Sudoswap trades below.</p><h3 id="h-getting-your-local-environment-set-up" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>Getting your local environment set up:</strong></h3><p>First, you’ll need to install python and pipenv. I use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.anaconda.com/products/distribution">anaconda</a> to install and manage my python packages. Make sure you add the relevant scripts folders to your environmental PATH variable to be able to call commands globally. Once you’re able to call <code>pip --version</code> without errors, then you’re good to go!</p><ol><li><p>fork and create a branch of abstractions on GitHub; we’ll PR back to main later.</p></li><li><p>Run <code>pip install pipenv</code> and add it to your environmental PATH variable (you should be able to find the folder path by searching for <code>pipenv.exe</code> ).</p></li><li><p>Make sure you’re pointing to the spellbook folder path, and then run <code>pipenv install</code> .</p></li><li><p>Run <code>dbt init</code>, you can put <code>n</code> for all responses and put anything for credentials. Make sure you put <code>wizard</code> in for schema</p></li><li><p>Now you can run <code>dbt docs generate</code> and <code>dbt docs serve</code> to look through the models (tables):</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2b523df866a4c0c0216b18f6334d7a82ab23e45b7e760659d04a69db45b8fb63.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>Anytime you want to test your queries in the dune engine, you can run <code>dbt compile</code> and look in the <code>target</code> folder for the compiled SQL.</p><h3 id="h-sudoswap-prs" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>Sudoswap PRs:</strong></h3><p>Here are the two PRs I made for Sudoswap. You can look at the “files changed” tab to see all the code I added. Most of what I changed can be found within the <code>Sudoswap/ethereum</code> folders within <code>models</code> and <code>tests</code>.</p><ol><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/abstractions/pull/1364">First one</a> with all the main logic</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/abstractions/pull/1397">Second one</a> with some lines changed to fix prices and explode swaps so each token id gets its own row</p></li></ol><p>For simple models, you just need a few steps:</p><ol><li><p>define a <code>sources.yml</code> with the decoded tables you want to use (base tables like <code>ethereum.transactions</code> are already defined elsewhere so you don’t need to specify them again.</p></li><li><p>create a <code>some_model.sql</code> file with the filename as the table name you want to create. Don’t worry too much about the config for now; just use the following:</p><pre data-type="codeBlock" text="{{ config(
        alias = &apos;some_model&apos;,
        materialized = &apos;incremental&apos;,
        file_format = &apos;delta&apos;,
        incremental_strategy = &apos;merge&apos;,
        unique_key = [&apos;some_unique_key&apos;]
        )
}}
"><code>{{ config(
        <span class="hljs-attr">alias</span> = <span class="hljs-string">'some_model'</span>,
        <span class="hljs-attr">materialized</span> = <span class="hljs-string">'incremental'</span>,
        <span class="hljs-attr">file_format</span> = <span class="hljs-string">'delta'</span>,
        <span class="hljs-attr">incremental_strategy</span> = <span class="hljs-string">'merge'</span>,
        <span class="hljs-attr">unique_key</span> = [<span class="hljs-string">'some_unique_key'</span>]
        )
}}
</code></pre></li><li><p>These tables usually update incrementally as defined in config, unless you’re just creating a static table like <code>tokens_ethereum_erc20.sql</code> . All you need to do is place the following filter wherever it makes the most sense (to transform all of the new rows). In my case we apply this on all swap functions since we only want to add the newest swaps to the table.</p><pre data-type="codeBlock" text="{% if is_incremental() %}
-- this filter will only be applied on an incremental run. We only want to update with new swaps.
AND call_block_time &gt;= (select max(block_time) from {{ this }})
{% endif %}
"><code>{<span class="hljs-operator">%</span> <span class="hljs-keyword">if</span> is_incremental() <span class="hljs-operator">%</span>}
<span class="hljs-operator">-</span><span class="hljs-operator">-</span> <span class="hljs-built_in">this</span> filter will only be applied on an incremental run. We only want to update with <span class="hljs-keyword">new</span> swaps.
AND call_block_time <span class="hljs-operator">></span><span class="hljs-operator">=</span> (select max(block_time) <span class="hljs-keyword">from</span> {{ <span class="hljs-built_in">this</span> }})
{<span class="hljs-operator">%</span> endif <span class="hljs-operator">%</span>}
</code></pre></li><li><p>Make sure to add your new model into a <code>schema.sql</code> file with all your final columns defined. The more description and documentation you can add, the better!</p></li><li><p>Add your folder models/schema into the <code>dbt_project.yml</code> file.</p></li><li><p>Lastly, you should make sure to have some tests. I recommend adding <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/abstractions/pull/1364/files#diff-c7e98023eddcd63bc79faf1599faaa7c00492e132ed1e07d391ce165064970ae:~:text=tests%3A-,%2D%20not_null,-%2D%20%26trade_type">some not_null tests</a> to key columns in your schema file, but you can also make more <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.getdbt.com/docs/building-a-dbt-project/tests">custom SQL tests</a>.</p></li></ol><p>After you compile your models and test them in the dune v2 engine interface, go create a PR and wait for reviews!</p><h2 id="h-simulating-liquidity-depth-across-pairs-ie-routing" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Simulating Liquidity Depth Across Pairs (i.e. Routing)</h2><p>One of the more fun and complex queries I made for Sudoswap was simulating buying or selling X number of NFTs across all pairs to get total profits, costs, liquidity, and slippage.</p><p>You can observe the steepness of the price curve for any NFT collection that has pairs on Sudoswap, and see where there are inflection points once liquidity for pairs pricing at the same spot price, delta, and curve runs out (basically like moving between ticks on Uniswap v3, but not following a <code>xy=k</code> constant product curve).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/119ec257e0bcc0cabb11bef0f42d0a1a3d75609370bf0c60b27be37471b7e577.png" alt="https://dune.com/ilemi/sudoswap-collection (Scroll down to middle)" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.com/ilemi/sudoswap-collection (Scroll down to middle)</figcaption></figure><p>The main simulation query can be found <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/queries/1122973/1959269">here</a>. The full walkthrough and creation of the buy side of this query can be found <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=IPPaV8lBkMM&amp;t=232s">on YouTube here</a>. Sell side simulation was a little more complicated since we have to calculate maximum NFTs that can be sold into a pair based on ETH liquidity, spot price, and delta. For exponential curves, we can calculate it directly with geometric finite series summation formulas. For linear curves, because the pair stops processing trades if <code>spotPrice</code> is going negative, we calculate for the nth term where <code>spotPrice = 0</code> and then truncate by ETH balance. The key logic is in the <code>pairs_max_sell</code> CTE, if you have questions or suggestions on how to calculate it more exactly/efficiently please let me know!</p><p>You’ll notice that <code>Total ETH Liquidity</code> is greater than the total profits you can make by selling NFTs (left side of cumulative area chart) - this is because some pairs have a spot price higher than the ETH held in the pair, so it’s technically illiquid.</p><p>There’s also one protocol technical nuance in this query is how the buy price and sell price are calculated. Pair bonding curves work by incrementing/decrementing the spot price by some delta along the curve. So if it’s linear, you do <code>newPrice = spotPrice + delta</code>, and if it’s exponential then you do <code>newPrice = spotPrice^delta</code> instead.</p><p>While the sell price is the <code>current spotPrice</code>, the buy price is the <code>current spotPrice + one delta</code>. 0xmons explained the rationale behind this decision as</p><blockquote><p>“if <code>spotPrice</code> was both the price to buy <em>and</em> sell, lps could be arbed (e.g. buy at 1 eth, spot price goes up to 1.1 eth, then sell for 1.1 eth)” - 0xmons</p></blockquote><p>You’ll see this logic used in the parts of the query where I calculate <code>simulated_prices</code>, <code>slippage nominal</code> and <code>slippage_percentage</code>.</p><h1 id="h-thats-a-wrap" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">That’s a wrap!</h1><p>I’m excited for the protocol to release ERC1155 and ERC20 support, as well as more bonding curves (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.paradigm.xyz/2022/04/gda">Gradual Dutch Auctions</a> have been teased 👀). I’ll do a part 2 of this guide once those come out.</p><p>I hope you enjoyed this data guide - please collect, subscribe, and share if you did! I’m open to any feedback on how to make these guides better so don’t hesitate to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/andrewhong5297">DM me on Twitter</a>.</p><p><strong>Again, If you collect this entry, you can get access to my web3 data degens telegram group by </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://guild.xyz/web3-data-degens"><strong>clicking here</strong></a><strong>!</strong> <strong>We discuss the newest protocols, debug general query questions, and help analysts find jobs (freelance and fulltime).</strong></p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[On Web3 Membership and  Composable Monetization]]></title>
            <link>https://paragraph.com/@ilemi/on-web3-membership-and-composable-monetization</link>
            <guid>4kX5bTAfIGahvlJBhois</guid>
            <pubDate>Tue, 26 Jul 2022 17:57:14 GMT</pubDate>
            <description><![CDATA[We’ve seen various combinations of NFT (ERC721) auctions, ERC20 airdrops, open sales of both, tiered access to the open sales, etc. - all under the guise of making you a “member of the community”. Some have worked well, while others have been flaming piles of garbage. I believe each monetization method has its place, but we need to be more intentional about:who in the community they’re targetinghow they’re composed togetherIn this piece, I want to propose some frameworks and implementation to...]]></description>
            <content:encoded><![CDATA[<p>We’ve seen various combinations of NFT (ERC721) auctions, ERC20 airdrops, open sales of both, tiered access to the open sales, etc. - all under the guise of making you a “member of the community”. Some have worked well, while others have been flaming piles of garbage.</p><p>I believe each monetization method has its place, but we need to be more intentional about:</p><ol><li><p>who in the community they’re targeting</p></li><li><p>how they’re composed together</p></li></ol><p>In this piece, I want to propose some frameworks and implementation tools/examples for monetizing membership across clusters in a community.</p><blockquote><p>I recommend <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/Olq6VS57xDFWDlxRdQwBKy05xdU2TJHXyk75y-ZxGNg">reading my previous piece</a> on the <strong>membership stack</strong> (defined as <code>access → permissions → status</code>) for some background. That piece is focused on what can be built on top of tokens, this one is focused on how the tokens get into the community.</p></blockquote><p><em>Note that I use the words sale/monetization/distribution interchangeably throughout this piece.</em></p><h2 id="h-who-is-in-your-community" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Who is in your community?</h2><p>There are tons of ways to visualize a token community’s social circles, usually shown in the way Brian has illustrated below as an “anatomy”:</p><div data-type="twitter" tweetId="1433216047516114950" tweetData="{&quot;__typename&quot;:&quot;Tweet&quot;,&quot;lang&quot;:&quot;en&quot;,&quot;favorite_count&quot;:224,&quot;possibly_sensitive&quot;:false,&quot;created_at&quot;:&quot;2021-09-01T23:51:48.000Z&quot;,&quot;display_text_range&quot;:[0,20],&quot;entities&quot;:{&quot;hashtags&quot;:[],&quot;urls&quot;:[],&quot;user_mentions&quot;:[],&quot;symbols&quot;:[],&quot;media&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/Osq4GvDlxl&quot;,&quot;expanded_url&quot;:&quot;https://x.com/Flynnjamm/status/1433216047516114950/photo/1&quot;,&quot;indices&quot;:[21,44],&quot;url&quot;:&quot;https://t.co/Osq4GvDlxl&quot;}]},&quot;id_str&quot;:&quot;1433216047516114950&quot;,&quot;text&quot;:&quot;the anatomy of a DAO https://t.co/Osq4GvDlxl&quot;,&quot;user&quot;:{&quot;id_str&quot;:&quot;777685806437785601&quot;,&quot;name&quot;:&quot;brian flynn&quot;,&quot;screen_name&quot;:&quot;Flynnjamm&quot;,&quot;is_blue_verified&quot;:true,&quot;profile_image_shape&quot;:&quot;Circle&quot;,&quot;verified&quot;:false,&quot;profile_image_url_https&quot;:&quot;https://storage.googleapis.com/papyrus_images/3d0a63512a840d707683b3bc82e3f9968ade5837cc53fc062534d3ce4562aa70.jpg&quot;},&quot;edit_control&quot;:{&quot;edit_tweet_ids&quot;:[&quot;1433216047516114950&quot;],&quot;editable_until_msecs&quot;:&quot;1630542108251&quot;,&quot;is_edit_eligible&quot;:true,&quot;edits_remaining&quot;:&quot;5&quot;},&quot;mediaDetails&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/Osq4GvDlxl&quot;,&quot;expanded_url&quot;:&quot;https://x.com/Flynnjamm/status/1433216047516114950/photo/1&quot;,&quot;ext_media_availability&quot;:{&quot;status&quot;:&quot;Available&quot;},&quot;indices&quot;:[21,44],&quot;media_url_https&quot;:&quot;https://pbs.twimg.com/media/E-POWf9XIAQO9pF.png&quot;,&quot;original_info&quot;:{&quot;height&quot;:506,&quot;width&quot;:1012,&quot;focus_rects&quot;:[{&quot;x&quot;:54,&quot;y&quot;:0,&quot;w&quot;:904,&quot;h&quot;:506},{&quot;x&quot;:253,&quot;y&quot;:0,&quot;w&quot;:506,&quot;h&quot;:506},{&quot;x&quot;:284,&quot;y&quot;:0,&quot;w&quot;:444,&quot;h&quot;:506},{&quot;x&quot;:380,&quot;y&quot;:0,&quot;w&quot;:253,&quot;h&quot;:506},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:1012,&quot;h&quot;:506}]},&quot;sizes&quot;:{&quot;large&quot;:{&quot;h&quot;:506,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:1012},&quot;medium&quot;:{&quot;h&quot;:506,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:1012},&quot;small&quot;:{&quot;h&quot;:340,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:680},&quot;thumb&quot;:{&quot;h&quot;:150,&quot;resize&quot;:&quot;crop&quot;,&quot;w&quot;:150}},&quot;type&quot;:&quot;photo&quot;,&quot;url&quot;:&quot;https://t.co/Osq4GvDlxl&quot;}],&quot;photos&quot;:[{&quot;backgroundColor&quot;:{&quot;red&quot;:204,&quot;green&quot;:214,&quot;blue&quot;:221},&quot;cropCandidates&quot;:[{&quot;x&quot;:54,&quot;y&quot;:0,&quot;w&quot;:904,&quot;h&quot;:506},{&quot;x&quot;:253,&quot;y&quot;:0,&quot;w&quot;:506,&quot;h&quot;:506},{&quot;x&quot;:284,&quot;y&quot;:0,&quot;w&quot;:444,&quot;h&quot;:506},{&quot;x&quot;:380,&quot;y&quot;:0,&quot;w&quot;:253,&quot;h&quot;:506},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:1012,&quot;h&quot;:506}],&quot;expandedUrl&quot;:&quot;https://x.com/Flynnjamm/status/1433216047516114950/photo/1&quot;,&quot;url&quot;:&quot;https://storage.googleapis.com/papyrus_images/0d942beb4b8a615b654da54528ad658e6ebc73322a1571739a4ba38812ae3f94.png&quot;,&quot;width&quot;:1012,&quot;height&quot;:506}],&quot;conversation_count&quot;:14,&quot;news_action_type&quot;:&quot;conversation&quot;,&quot;isEdited&quot;:false,&quot;isStaleEdit&quot;:false}"> 
  <div class="twitter-embed embed">
    <div class="twitter-header">
        <div style="display:flex">
          <a target="_blank" href="https://twitter.com/Flynnjamm">
              <img alt="User Avatar" class="twitter-avatar" src="https://storage.googleapis.com/papyrus_images/3d0a63512a840d707683b3bc82e3f9968ade5837cc53fc062534d3ce4562aa70.jpg" />
            </a>
            <div style="margin-left:4px;margin-right:auto;line-height:1.2;">
              <a target="_blank" href="https://twitter.com/Flynnjamm" class="twitter-displayname">brian flynn</a>
              <p><a target="_blank" href="https://twitter.com/Flynnjamm" class="twitter-username">@Flynnjamm</a></p>
    
            </div>
            <a href="https://twitter.com/Flynnjamm/status/1433216047516114950" target="_blank">
              <img alt="Twitter Logo" class="twitter-logo" src="https://paragraph.com/editor/twitter/logo.png" />
            </a>
          </div>
        </div>
      
    <div class="twitter-body">
      the anatomy of a DAO 
      <div class="twitter-media"><img class="twitter-image" src="https://storage.googleapis.com/papyrus_images/0d942beb4b8a615b654da54528ad658e6ebc73322a1571739a4ba38812ae3f94.png" /></div>
      
       
    </div>
    
     <div class="twitter-footer">
          <a target="_blank" href="https://twitter.com/Flynnjamm/status/1433216047516114950" style="margin-right:16px; display:flex;">
            <img alt="Like Icon" class="twitter-heart" src="https://paragraph.com/editor/twitter/heart.png">
            224
          </a>
          <a target="_blank" href="https://twitter.com/Flynnjamm/status/1433216047516114950"><p>6:51 PM • Sep 1, 2021</p></a>
        </div>
    
  </div> 
  </div><p>I think this is a good framework for approaching any community, but we can take it further. Let’s start with the building blocks of a web2 corporate structure:</p><ol><li><p><strong>Stock</strong>: “known as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.investopedia.com/terms/e/equity.asp#:~:text=Equity%20represents%20the%20value%20that,debts%20associated%20with%20that%20asset.">equity</a>, is a security that represents the ownership of a fraction of the issuing corporation”</p></li><li><p><strong>Governance:</strong> defined here as public-facing decisions, so mainly assigning board seats and other related shareholders proposals.</p></li><li><p><strong>Service:</strong> the core business output(s) of the company</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/71a7aa4378415f4b919b3a2ebe4ac9a0074e6b820c0e5213dbfb70447894c7ab.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>I’ll admit that this is a very US-centric/capitalist view that may not translate well to everyone reading this, but it should still make sense at a high level. We can see how various stakeholders are defined across stock, corporate governance, and the business itself.</p><p>There’s a ton of inefficiency and misalignment across all groups here due to resource, time, information, and permission constraints (if you want a short primer <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.amazon.com/gp/product/0131735349/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;psc=1">this book is a really good summary</a>).</p><p>Now let’s redefine these circles for a web3 community:</p><ol><li><p><strong>Tokens</strong>: the building blocks of ownership; these can be community-specific or something more general. Usually a combination of ERC20 and ERC721 standards. Does not have to represent equity.</p></li><li><p><strong>Governance</strong>: a contract or set of contracts that collect and manage incoming token revenue/contributions. Usually some combination of a multi-sig and a governor contract (propose, queue, vote, execute).</p></li><li><p><strong>Service</strong>: tokens alone don’t create a service - normally the service is built separately and integrated (hopefully enhanced) by tokens + governance. Some examples:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.waterandmusic.com/">Water &amp; Music</a> services include database access + special reports. Tokens are used and distributed in various ways, including airdrops and open sales.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nouns.wtf/">NounsDAO</a> (and affiliates) services are capital allocation (in the form of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://prop.house/">Prop House</a>). Tokens are auctioned off periodically and used for governance.</p></li></ul></li></ol><p>Putting it together we get:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c2ee06c137ee085f19aaa0ef73527dc3635d4d39f218a7a961f8b70fd914b050.png" alt="these groups aren’t always mutually exclusive" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">these groups aren’t always mutually exclusive</figcaption></figure><p>It might seem like it’s just wordsmithing and all these words represent the same web2 groups as earlier - and to an extent you’re right. However, Web2 corporates run on sluggish tech (lol banks), are mostly human-operated (excel and ppt input goes brrr), and have little capital raising flexibility (due to legal structures). Web3 communities move as fast as transactions get confirmed, can be augmented by smart contracts, and have flexible tokens (not tied to equity, and have programmable distribution + supply mechanics).</p><p>This all adds up to make the behaviors enabled of each web3 community segment really different from their web2 counterparts!</p><h2 id="h-monetizing-the-membership-stack" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Monetizing the Membership Stack</h2><p>Because of the malleability of the web3 infrastructure stack, it isn’t immediately clear what tokens should represent what and how they should be distributed to the community. In the last few years, we’ve seen a slew of attempts that independently use different monetization methods - from airdrops to auctions, some <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://earni.fi/airdrops/uniswap">immediate</a> and others <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://artblocks.wiki/Community/Dutch-Auction-Results">time</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/54ea31f688734819954bfa13b88f7f7f">round-based</a>.</p><p>“Membership” has been the main utility lauded by tons of projects, alongside some opaque roadmap. Besides being a smart marketing tactic, using a membership-based perspective does provide clarity on how to distribute/leverage tokens across a community.</p><p>Let’s first map the membership stack on top of the community circles:</p><ol><li><p><code>Tokens &lt;&gt; Access</code>: You typically need to own core community tokens to access anything within a community. Other segments will still interact with these core tokens, but in a secondary/vertical manner instead.</p></li><li><p><code>Governance &lt;&gt; Permissions</code>: There have been all sorts of explorations around on-chain governance that play with levels of permissioning, and use a combination of ownership and delegation.</p></li><li><p><code>Service &lt;&gt; Status</code>: Status applies most closely to anyone who is using or building the service itself. Tiers and levels are what we want to capture here.</p></li></ol><p>Now we layer different monetization methods across each segment:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bce7f66bd6294604ed79d785fe94ee0207f33d0857d2ebeadc88dcf7d1250ac1.png" alt="Personally in love with all these tools and teams ❤️" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Personally in love with all these tools and teams ❤️</figcaption></figure><p><strong>Let’s start with the three groups that are more “benefactors” than “builders” of the community.</strong> These groups should have as simple a system as possible since they are unlikely to have continuous context.</p><ul><li><p><code>Supporters/Investors &lt;&gt; Edition Sales</code>: This largely homogenous group has capital they want to allocate purely for investment or public good purposes.</p><p>Fixed editions help to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereumfilm.mirror.xyz/3SV8gLXHIW8Ot45h3RL7aOgDINxN2hjLfFVOvyatB2A">reach some one-time funding goal and quickly sell a set supply of NFTs</a> (Mirror) without taking away too much time and attention from the community or the funders. If no funding goal is set, then you can do a time-limited supply as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mobile.twitter.com/poolynft">Pooly NFTs</a> did.</p></li><li><p><code>Power Users/DAO Partners &lt;&gt; Fractional NFTs</code>: These are users who want to shape the service in some way that benefits them/their products. There’s a limited number of partners you can realistically take on (marginal benefit decreases at some point), but you still want to tier them so set supply/price edition sales don’t make sense.</p><p>So for example, let’s take the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/nounsprophouse">NounsDAO prop house</a> which operates weekly and has some level of topic segmentation. Assume there are a few large DAOs who want to integrate with Nouns in some way - instead of what we’ve typically seen with large treasury swaps or open market buying of tokens, these large DAOs could join a single <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.partybid.app/about">party bid</a> on a “seasonal partnership NFT”. As a start, holding these tokens could act as a simple multiplier when proposals go to vote.</p><p>This works better than something like a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://artblocks.wiki/Community/Dutch-Auction-Results">Dutch auction</a> because prices are decided competitively versus some monotonically decreasing - and all parties are guaranteed to get some allocation. You can set some threshold of # of tokens you need to qualify for a prop house proposal and anyone who doesn’t make it can carry on (swap) their tokens in the next party bid. If you add in <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.fractional.art/fractional/">baskets</a> with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://Fractional.art">Fractional.art</a>, you could get some really fun combinations across houses.</p><p>For power users of your service, you could imagine that what they’re bidding on is an extra “tier” of technical support for a season (3 months). Some simple composability would be using your fractional “tier” multiplied by your streaming rate as a method of “locking in a contract”. Typically longer-term contracts for a service come with a lump sum payment + monthly scaling extra costs and have an array of discounts. This web3 version combines a large bid w/ payments streams, and then could calculate scaling discounts as a factor of the two.</p></li><li><p><code>Normie Users &lt;&gt; Token Streams</code>: These users just want to use the core part of your service, so you want the experience for both them buying in and you managing payments to be as seamless as possible (so no auctions or bidding lol).</p><p>Assuming you’re some X-as-a-service provider, I believe that streaming tokens (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.superfluid.finance/home">SuperfluidHQ</a>) are the strongest access solution because <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.superfluid.finance/superfluid/developers/interactive-tutorials/money-streaming-1">you can control the rate required (tokens paid per second/block)</a>. Streams are also highly composable with each other because of their asynchronous nature (combining streams for group access or varied requirements) and can be enhanced by mapping <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/superfluid-blog/collab-land-enables-communities-to-create-ongoing-revenue-with-superfluid-streams-b3653feff640">to dynamic identity solutions across the space</a> (collab.land). This is much better for managing large groups of people than lump-sum payments or static POAPs. It’s worth mentioning that checking the current rate, adjusting the rate, or adjusting the rate requirement are each only one action - super easy to manage and communicate!</p><p>Obviously, this one varies a lot depending on the service, and wouldn’t apply as well to fee-based models.</p></li></ul><p><strong>These next four groups are all “builders”, focused on building and governing the service and community.</strong> These groups should have more context generally, so we can make their systems more complex.</p><ul><li><p><code>Treasury Managers + Grant Proposers &lt;&gt; Permissioned NFT Auctions</code>: These are token holders who want an immediate and larger say in the community, so usually governance is the best next step for them.</p><p>I’ve started becoming a bigger believer in gradually scaling governance (NounsDAO) versus airdrop + delegate kickoff governance (literally every other protocol). Doing an airdrop + delegate kickoff is like taking a ton of caffeine all at once - your community will be super energized but constantly clashing against each other for attention and funds for a long time to find equilibrium.</p><p>Instead, if you “release” governance power over time you can allow the most interested and motivated parties to continuously buy in. Uninterested parties will just slowly unwind their tokens in secondary markets, which will become a smoother process as NFT AMMs (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/sudoswap/status/1545535667597295616?t=DsKx0YqTSW85K6lSQqit5g&amp;s=19">sudoswap</a>) and aggregators (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.genie.xyz/">Genie</a>) improve. We’ll take a deeper data dive into this in the next section.</p><p>Even bribes/loans which are popular for ERC20 governance tokens are becoming possible to replicate with NFTs through innovations like the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://code4rena.com/contests/2022-07-fractional-v2-contest#modules">new renting module</a> from Fractional.art.</p></li><li><p><code>DAO Operators &lt;&gt; Delegated Permissioned NFTs</code>: DAO operators are insanely important and they need better ways to manage all the chaos. Unlike the auctioned NFTs above where each one gives you the same weight/powers, these NFTs should have much more specific permissions which are granted.</p><p>I think there are two approaches that make sense here:</p><ul><li><p>Setting up governance pods (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.orcaprotocol.org/orca/pod-basics/what-are-pods">Orca</a>) that can be adjusted. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://lilnouns.wtf/vote/25">Delegating NFTs</a> from the DAO treasury instead of just gifting them ensures representatives don’t become too comfortable or complacent.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/metagov/constitution-template/tree/main/constitutions">DAO constitutions and manifestos</a> have become <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.makerdao.com/t/simple-makerdao-governance-from-first-principles/16207">increasingly important as a guiding framework</a> for DAOs with growing complexity across tokens, governance, and services. This is a perfect use case for an on-chain tied language document (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://lib.openlaw.io/web/default/template/Voxel%20Lease">OpenLaw example</a>). Adding editing permissions (through NFTs) to both on-chain parameters and accompanying off-chain language will make rules and operations much more flexible and easily understood (as opposed to forcing people to dig through old proposals and forums to track changes in both the parameters and the rationale).</p></li></ul></li><li><p><code>Niche Contributors &lt;&gt; SBT and Credit</code>: For contributors who pop in and out of various communities and contribute where they can, building a credit system is a benefit for both the contributors and the community at large.</p><p>We could expect it to be built with a simple scorecard system that’s level-based (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0xbac4edFAB0FFBD3344B163fAd587F07261c6CD7E/R2DO7M_8q8FHbHKnEHmAOQyhaJoWllf4rzaJhrbgqh0">Backed</a>), using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://otterspace.mirror.xyz/6qSvCLD-Fch_-XREYO9ALsd14HvizAacp2wqeZovhwI">soulbound tokens</a>. Once you have a basic score system, you could then utilize peer-to-peer undercollateralized lending. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.union.finance/user-guides/becoming-a-member-on-arbitrum">Union protocol</a> is a great example of this, where contributors could gain delegated access to portions of the DAO’s treasury.</p><p>The undercollateralized loan is “secured” by the symbiotic working relationship between the contributor and the DAO - assuming the contributor’s work is useful and the service continues to do well.</p></li><li><p><code>Core Contributors &lt;&gt; Passport</code>: These are your main “employees”. This group should get identity “passports” that are stronger (more complex) than the basic credit systems niche contributors get.</p><p>The key difference between the passport and basic SBTs is their <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.pitch.com/app/public/player/61902937-6253-4bcd-ba38-61940d35af03/087a3e41-5d7d-4e64-a778-01aeeee8c1eb">direct integration with all layers of the DAOs operating system</a>. The deck in the previous link explains it much better than I can; I highly recommend taking a look!</p></li></ul><p>And last but not least, our tokenomic favorites:</p><ul><li><p><code>everyone &lt;&gt; airdrops and staking</code><strong>:</strong> I believe these methods do apply to all community segments - but need to be experimented with and tiered accordingly.</p><ul><li><p>Airdrops will likely become more round-based (like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://community.optimism.io/docs/governance/airdrop-1/#background">Optimism</a>) and targeted towards either specific community segments (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://waterandmusic.mirror.xyz/xfzEiBHzj77JZkjUW2pEoxpdLOEmDN97GqqOvttR7-8">Water &amp; Music $STREAM</a>) or community structures (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/CdU80CItQr-qTZgTzymfFDEBSnz2YbgnwXGYgkQJfCs">community reputation score $WRITE</a>). <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.coinvise.co/">Coinvise</a> is a great tool for executing this.</p></li><li><p>Staking should be applied to something like reputation staking around key decisions, especially longer time-horizon ones (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.nati.wtf/introducing-koop">Koop</a>).</p></li></ul></li></ul><p>Whew - that was dense! If you have any suggestions or arguments on stuff I’ve missed, please reach out because I’d love to discuss them.</p><p>There’s still one big elephant in the room - who is going to manage and implement all these methods? There are already some ongoing interesting experiments we can study to build monitoring metrics for “monetization overhead”.</p><h2 id="h-on-scaling-and-managing-membership" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">On Scaling and Managing Membership</h2><p>We now have a cleaner way of segmenting our communities and some preferred monetization methods to go along with each one. It’s worth mentioning that there are some <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://coinvise.mirror.xyz/_bJ6GDo0gMh9bwGsVZb-oLqinaL4_coMuyXiy0WAWqo">all-in-one-token approaches</a> that look promising for starter communities. Scaling membership and community in sync is a topic I’m very interested in, and will be keeping a close eye on for the next year or so.</p><p>And with scaling membership comes the increasing complexity of managing implementations. A good start would be creating monitoring metrics for “monetization overhead”. This is separate from “contract/token composability overhead”, which is a contract architecture issue that will just take many iterations to get right. Contract modules have already been implemented in evolving fashion to make it easier to add management capabilities to tokens, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gnosis/zodiac">gnosis zodiac</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/fullyallocated/Default">default core OS</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://tributedao.com/">tributeDAO</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/code-423n4/2022-07-fractional/tree/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/modules">fractional V2 modules</a>. Various interfaces are being created to make it easier and easier to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/4.x/wizard">compose and deploy contracts too</a>.</p><p>Monetization overhead is focused on the social elements, such as noise, frequency, and energy within the context of token interactions. An example of bad overhead is a large about of ETH requested in governance proposals multiple times a month (high noise + frequency), where voter turnout is minimal (low energy). There’s likely some combination of metrics unique to each monetization method that would make it much easier to monitor over time. Layering these metrics upon something like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.terminal.co/community/featured/ffdao.eth">Forefront Terminal</a> could further enhance operator understanding of the community health.</p><p>These metrics would also eventually help tune on-chain parameters such as quorum and minimum proposal thresholds. Instead of static thresholds, I’d imagine we’d scale thresholds based on noise levels:</p><ul><li><p>You could make things independent and linear: For every additional 1% of treasury requested in just this proposal, 1 more permissioned NFT is required by the proposer.</p></li><li><p>Or you could make it dependent and non-linear: For every additional 1% of treasury requested in total across the proposal queue, we could use <code>n^2 - (n-1)^2</code> additional NFTs required where <code>n = total % treasury requested in the queue</code> . So if 5% of the treasury is already being requested and you’re requesting 1% in your proposal, then 11 more NFTs are required (36 - 25).</p></li></ul><p>There are plenty of interesting experiments such as NounsDAO already happening for us to study, and I have more fun news coming next month regarding how I’d like to engage the data community as a whole to study this deeper.</p><p><strong>But for now, that’s a wrap!</strong> Please challenge me and let me know where you think differently (or where I’ve missed something).</p><p>I really do appreciate each and every one of you who read this far. <strong>If you’d like to support more of this kind of writing then don’t forget to collect this entry, subscribe, and share! 😊</strong></p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[Learning to Work With Ethereum Storage and State Data]]></title>
            <link>https://paragraph.com/@ilemi/learning-to-work-with-ethereum-storage-and-state-data</link>
            <guid>2rSsoq1MrLRlZg7fwnxP</guid>
            <pubDate>Fri, 04 Mar 2022 02:01:36 GMT</pubDate>
            <description><![CDATA[If you’re completely new to SQL and Ethereum I recommend starting with my full beginners’ overview or breaking down an Ethereum transaction first. Feel free to support my work by buying a Data Landscape edition at the end of the article, or sending a tip to ilemi.eth! Most explanations of storage and state on Ethereum are diagram heavy and don’t get into the meat and bones of how to access or work with that data. I’m going to avoid the diagrams and theoretical explanations, but you should sti...]]></description>
            <content:encoded><![CDATA[<p><em>If you’re completely new to SQL and Ethereum I recommend starting with </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://towardsdatascience.com/your-guide-to-basic-sql-while-learning-ethereum-at-the-same-time-9eac17a05929"><em>my full beginners’ overview</em></a><em> or </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/mbR1n_CvflL1KIKCTG42bnM4HpfGBqDPNndH8mu2eJw"><em>breaking down an Ethereum transaction</em></a><em> first. Feel free to support my work by buying a Data Landscape edition at the end of the article, or sending a tip to </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x2Ae8c972fB2E6c00ddED8986E2dc672ED190DA06"><em>ilemi.eth</em></a><em>!</em></p><p>Most explanations of storage and state on Ethereum are diagram heavy and don’t get into the meat and bones of how to access or work with that data. I’m going to avoid the diagrams and theoretical explanations, but you should still have some understanding of data tries so skim <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/@eiki1212/ethereum-state-trie-architecture-explained-a30237009d4e">this</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://applicature.com/blog/blockchain-technology/ethereum-smart-contract-storage">this</a> if you know absolutely nothing about how data gets into blocks.</p><p>Essentially, what you need to know is that every time you make a transaction with a contract involved, there will be <strong>state</strong> and <strong>storage</strong> changes saved to the block. State changes involve things like an addresses’ Ether balance or Nonce, storage changes involve storage slots on contracts such as your balance of ERC20 tokens in a contract.</p><p>To access these changes from an Ethereum node, you’ll need to use a replay VM - meaning you have to replay a transaction or block to get the raw diffs in state and storage. This is easily done using Infura or Alchemy, without running your own node. You can go to Alchemy’s API composer to play with the <code>trace_replayTransaction</code> endpoint (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dashboard.alchemyapi.io/composer">here</a>). If you want to read more about how traces works, read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://openethereum.github.io/JSONRPC-trace-module">the standards here</a> - but I’ll run through one example.</p><p>Let’s use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/tx/0x8e5cd4d97881b558b7c4a120c41193b944db0612bc45807ae056d5488b82700e">this ERC20 transfer</a>, whose contract code includes the following:</p><pre data-type="codeBlock" text="function transfer(address to, uint256 value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

function _transfer(
        address from,
        address to,
        uint256 value
    ) private {
        balanceOf[from] = balanceOf[from] - value;
        balanceOf[to] = balanceOf[to] + value;
        emit Transfer(from, to, value);
    }
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> value</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        _transfer(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, to, value);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_transfer</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> value
    </span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        balanceOf[<span class="hljs-keyword">from</span>] <span class="hljs-operator">=</span> balanceOf[<span class="hljs-keyword">from</span>] <span class="hljs-operator">-</span> value;
        balanceOf[to] <span class="hljs-operator">=</span> balanceOf[to] <span class="hljs-operator">+</span> value;
        <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-keyword">from</span>, to, value);
    }
</code></pre><p>You can see that there are two storage changes, the balance of the <code>from</code> address and the balance of the <code>to</code> address. Here’s your JSON rpc request:</p><pre data-type="codeBlock" text="{
    &quot;jsonrpc&quot;:&quot;2.0&quot;
    &quot;id&quot;:0
    &quot;method&quot;:&quot;trace_replayTransaction&quot;
    &quot;params&quot;:[
        0:&quot;0x8e5cd4d97881b558b7c4a120c41193b944db0612bc45807ae056d5488b82700e&quot;
        1:[
            0:&quot;trace&quot;
            1:&quot;stateDiff&quot;
        ]
    ]
}
"><code><span class="hljs-punctuation">{</span>
    <span class="hljs-attr">"jsonrpc"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"2.0"</span>
    <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span><span class="hljs-number">0</span>
    <span class="hljs-attr">"method"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"trace_replayTransaction"</span>
    <span class="hljs-attr">"params"</span><span class="hljs-punctuation">:</span><span class="hljs-punctuation">[</span>
        <span class="hljs-number">0</span><span class="hljs-punctuation">:</span><span class="hljs-string">"0x8e5cd4d97881b558b7c4a120c41193b944db0612bc45807ae056d5488b82700e"</span>
        <span class="hljs-number">1</span><span class="hljs-punctuation">:</span><span class="hljs-punctuation">[</span>
            <span class="hljs-number">0</span><span class="hljs-punctuation">:</span><span class="hljs-string">"trace"</span>
            <span class="hljs-number">1</span><span class="hljs-punctuation">:</span><span class="hljs-string">"stateDiff"</span>
        <span class="hljs-punctuation">]</span>
    <span class="hljs-punctuation">]</span>
<span class="hljs-punctuation">}</span>
</code></pre><p>And here’s the response you’d get from Alchemy, I’ll explain it briefly here:</p><ul><li><p>state diffs for <code>0x320d83769eb64096ea74b686eb586e197997f930</code> are balance changes in the mapping of <code>balanceOf</code></p></li><li><p>state diffs for <code>0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5</code> are addition to balance of gas fees being paid to miner</p></li><li><p>state diffs for <code>0xdad3fd6c9fb0c2b56228e58ae191b62bfb1bec83</code> are subtraction from balance of gas fees being paid by the sender for this transfer</p></li><li><p>the first trace action is the actual <code>transfer()</code> call</p></li><li><p>the second trace action is a <code>delegatecall</code> because a proxy pattern is used for this contract, and the logic is stored somewhere else (like forwarding an email).</p></li></ul><pre data-type="codeBlock" text="{
  &quot;jsonrpc&quot;: &quot;2.0&quot;,
  &quot;id&quot;: 0,
  &quot;result&quot;: {
    &quot;output&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000001&quot;,
    &quot;stateDiff&quot;: {
      &quot;0x320d83769eb64096ea74b686eb586e197997f930&quot;: {
        &quot;balance&quot;: &quot;=&quot;,
        &quot;code&quot;: &quot;=&quot;,
        &quot;nonce&quot;: &quot;=&quot;,
        &quot;storage&quot;: {
          &quot;0x108f03599a018b41696aad07e2100369d10122c70bf27d8e9fe3e425885a246b&quot;: {
            &quot;*&quot;: {
              &quot;from&quot;: &quot;0x0000000000000000000000000000000000000000000000357bdcd5b903c454ce&quot;,
              &quot;to&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;
            }
          },
          &quot;0xdc7fafdc41998a74ecacb8f8bd877011aba1f1d03a3a0d37a2e7879a393b1d6a&quot;: {
            &quot;*&quot;: {
              &quot;from&quot;: &quot;0x000000000000000000000000000000000000000000000215d691e79c0df07a6f&quot;,
              &quot;to&quot;: &quot;0x00000000000000000000000000000000000000000000024b526ebd5511b4cf3d&quot;
            }
          }
        }
      },
      &quot;0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5&quot;: {
        &quot;balance&quot;: {
          &quot;*&quot;: {
            &quot;from&quot;: &quot;0xfdc72883cded567d93&quot;,
            &quot;to&quot;: &quot;0xfdc728a1a08db20db3&quot;
          }
        },
        &quot;code&quot;: &quot;=&quot;,
        &quot;nonce&quot;: &quot;=&quot;,
        &quot;storage&quot;: {}
      },
      &quot;0xdad3fd6c9fb0c2b56228e58ae191b62bfb1bec83&quot;: {
        &quot;balance&quot;: {
          &quot;*&quot;: {
            &quot;from&quot;: &quot;0x59e417e4aa86a74&quot;,
            &quot;to&quot;: &quot;0x599f683b630a274&quot;
          }
        },
        &quot;code&quot;: &quot;=&quot;,
        &quot;nonce&quot;: {
          &quot;*&quot;: {
            &quot;from&quot;: &quot;0x159&quot;,
            &quot;to&quot;: &quot;0x15a&quot;
          }
        },
        &quot;storage&quot;: {}
      }
    },
    &quot;trace&quot;: [
      {
        &quot;action&quot;: {
          &quot;from&quot;: &quot;0xdad3fd6c9fb0c2b56228e58ae191b62bfb1bec83&quot;,
          &quot;callType&quot;: &quot;call&quot;,
          &quot;gas&quot;: &quot;0x938c&quot;,
          &quot;input&quot;: &quot;0xa9059cbb000000000000000000000000000000000000000000000000000000000000dead0000000000000000000000000000000000000000000000357bdcd5b903c454ce&quot;,
          &quot;to&quot;: &quot;0x320d83769eb64096ea74b686eb586e197997f930&quot;,
          &quot;value&quot;: &quot;0x0&quot;
        },
        &quot;result&quot;: {
          &quot;gasUsed&quot;: &quot;0x45d0&quot;,
          &quot;output&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000001&quot;
        },
        &quot;subtraces&quot;: 1,
        &quot;traceAddress&quot;: [],
        &quot;type&quot;: &quot;call&quot;
      },
      {
        &quot;action&quot;: {
          &quot;from&quot;: &quot;0x320d83769eb64096ea74b686eb586e197997f930&quot;,
          &quot;callType&quot;: &quot;delegatecall&quot;,
          &quot;gas&quot;: &quot;0x7e24&quot;,
          &quot;input&quot;: &quot;0xa9059cbb000000000000000000000000000000000000000000000000000000000000dead0000000000000000000000000000000000000000000000357bdcd5b903c454ce&quot;,
          &quot;to&quot;: &quot;0x5b5746f6f5e2db8bf5e260829ca7a004c876b167&quot;,
          &quot;value&quot;: &quot;0x0&quot;
        },
        &quot;result&quot;: {
          &quot;gasUsed&quot;: &quot;0x323b&quot;,
          &quot;output&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000001&quot;
        },
        &quot;subtraces&quot;: 0,
        &quot;traceAddress&quot;: [
          0
        ],
        &quot;type&quot;: &quot;call&quot;
      }
    ],
    &quot;vmTrace&quot;: null
  }
}
"><code>{
  "jsonrpc": <span class="hljs-string">"2.0"</span>,
  <span class="hljs-string">"id"</span>: <span class="hljs-number">0</span>,
  <span class="hljs-string">"result"</span>: {
    "output": <span class="hljs-string">"0x0000000000000000000000000000000000000000000000000000000000000001"</span>,
    <span class="hljs-string">"stateDiff"</span>: {
      "<span class="hljs-number">0</span>x320d83769eb64096ea74b686eb586e197997f930": {
        "balance": <span class="hljs-string">"="</span>,
        <span class="hljs-string">"code"</span>: <span class="hljs-string">"="</span>,
        <span class="hljs-string">"nonce"</span>: <span class="hljs-string">"="</span>,
        <span class="hljs-string">"storage"</span>: {
          "<span class="hljs-number">0</span>x108f03599a018b41696aad07e2100369d10122c70bf27d8e9fe3e425885a246b": {
            "*": {
              "<span class="hljs-selector-tag">from</span>": <span class="hljs-string">"0x0000000000000000000000000000000000000000000000357bdcd5b903c454ce"</span>,
              <span class="hljs-string">"to"</span>: <span class="hljs-string">"0x0000000000000000000000000000000000000000000000000000000000000000"</span>
            }
          },
          "<span class="hljs-number">0</span>xdc7fafdc41998a74ecacb8f8bd877011aba1f1d03a3a0d37a2e7879a393b1d6a": {
            "*": {
              "<span class="hljs-selector-tag">from</span>": <span class="hljs-string">"0x000000000000000000000000000000000000000000000215d691e79c0df07a6f"</span>,
              <span class="hljs-string">"to"</span>: <span class="hljs-string">"0x00000000000000000000000000000000000000000000024b526ebd5511b4cf3d"</span>
            }
          }
        }
      },
      "<span class="hljs-number">0</span>x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": {
        "balance": {
          "*": {
            "<span class="hljs-selector-tag">from</span>": <span class="hljs-string">"0xfdc72883cded567d93"</span>,
            <span class="hljs-string">"to"</span>: <span class="hljs-string">"0xfdc728a1a08db20db3"</span>
          }
        },
        "<span class="hljs-selector-tag">code</span>": <span class="hljs-string">"="</span>,
        <span class="hljs-string">"nonce"</span>: <span class="hljs-string">"="</span>,
        <span class="hljs-string">"storage"</span>: {}
      },
      "<span class="hljs-number">0</span>xdad3fd6c9fb0c2b56228e58ae191b62bfb1bec83": {
        "balance": {
          "*": {
            "<span class="hljs-selector-tag">from</span>": <span class="hljs-string">"0x59e417e4aa86a74"</span>,
            <span class="hljs-string">"to"</span>: <span class="hljs-string">"0x599f683b630a274"</span>
          }
        },
        "<span class="hljs-selector-tag">code</span>": <span class="hljs-string">"="</span>,
        <span class="hljs-string">"nonce"</span>: {
          "*": {
            "<span class="hljs-selector-tag">from</span>": <span class="hljs-string">"0x159"</span>,
            <span class="hljs-string">"to"</span>: <span class="hljs-string">"0x15a"</span>
          }
        },
        "storage": {}
      }
    },
    "trace": [
      {
        "action": {
          "<span class="hljs-selector-tag">from</span>": <span class="hljs-string">"0xdad3fd6c9fb0c2b56228e58ae191b62bfb1bec83"</span>,
          <span class="hljs-string">"callType"</span>: <span class="hljs-string">"call"</span>,
          <span class="hljs-string">"gas"</span>: <span class="hljs-string">"0x938c"</span>,
          <span class="hljs-string">"input"</span>: <span class="hljs-string">"0xa9059cbb000000000000000000000000000000000000000000000000000000000000dead0000000000000000000000000000000000000000000000357bdcd5b903c454ce"</span>,
          <span class="hljs-string">"to"</span>: <span class="hljs-string">"0x320d83769eb64096ea74b686eb586e197997f930"</span>,
          <span class="hljs-string">"value"</span>: <span class="hljs-string">"0x0"</span>
        },
        "result": {
          "gasUsed": <span class="hljs-string">"0x45d0"</span>,
          <span class="hljs-string">"output"</span>: <span class="hljs-string">"0x0000000000000000000000000000000000000000000000000000000000000001"</span>
        },
        "subtraces": <span class="hljs-number">1</span>,
        <span class="hljs-string">"traceAddress"</span>: [],
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"call"</span>
      },
      {
        "action": {
          "<span class="hljs-selector-tag">from</span>": <span class="hljs-string">"0x320d83769eb64096ea74b686eb586e197997f930"</span>,
          <span class="hljs-string">"callType"</span>: <span class="hljs-string">"delegatecall"</span>,
          <span class="hljs-string">"gas"</span>: <span class="hljs-string">"0x7e24"</span>,
          <span class="hljs-string">"input"</span>: <span class="hljs-string">"0xa9059cbb000000000000000000000000000000000000000000000000000000000000dead0000000000000000000000000000000000000000000000357bdcd5b903c454ce"</span>,
          <span class="hljs-string">"to"</span>: <span class="hljs-string">"0x5b5746f6f5e2db8bf5e260829ca7a004c876b167"</span>,
          <span class="hljs-string">"value"</span>: <span class="hljs-string">"0x0"</span>
        },
        "result": {
          "gasUsed": <span class="hljs-string">"0x323b"</span>,
          <span class="hljs-string">"output"</span>: <span class="hljs-string">"0x0000000000000000000000000000000000000000000000000000000000000001"</span>
        },
        "subtraces": <span class="hljs-number">0</span>,
        <span class="hljs-string">"traceAddress"</span>: [
          <span class="hljs-number">0</span>
        ],
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"call"</span>
      }
    ],
    "vmTrace": null
  }
}
</code></pre><p><em>vmTrace is a deeper trace, which tells you the order in which opcodes were executed by the EVM. I won’t cover that in this article (mainly since I am not familiar enough with those yet lol)</em></p><p>You can check the <code>balanceOf</code> changes using hex to num <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.rapidtables.com/convert/number/hex-to-decimal.html">here</a>, remember to div by 1e18. If you’re curious about how subtraces work, they are nested function calls:</p><ul><li><p><strong>subtraces</strong> = number of sub-calls by function</p></li><li><p><strong>type</strong> = <code>call</code> (normal call), <code>staticcall</code> (doesn’t mod state), <code>delegatecall</code> (proxies calling logic), <code>create</code> (contract deploys)</p><p><strong>traceAddress</strong> = order of call execution, see example below from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://openethereum.github.io/JSONRPC-trace-module">open Ethereum</a>:</p><pre data-type="codeBlock" text="A
  CALLs B
    CALLs G
  CALLs C
    CALLs G
"><code>A
  <span class="hljs-built_in">CALLs</span> B
    <span class="hljs-built_in">CALLs</span> G
  <span class="hljs-built_in">CALLs</span> C
    <span class="hljs-built_in">CALLs</span> G
</code></pre><p>then it should look something like:</p><p><code>[ {A: []}, {B: [0]}, {G: [0, 0]}, {C: [1]}, {G: [1, 0]} ]</code></p></li></ul><p>A good tool to use is the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://versatile.blocksecteam.com/tx/eth/0x6b67117fe7d282aa5fc3f5c4406b72474dca108c05c68042e005c2dc2f1c99b2">Versatile block explorer</a>, where you can check the “Invocation Flow” for a more detailed view of traces than Etherscan provides.</p><p>Don’t worry too much if that doesn’t all make sense, we’ll dive into the data here using a data warehouse instead of RPC calls from here on out.</p><h3 id="h-accessing-state-and-storage-data-using-ethereum-data-warehouse-edw" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Accessing State and Storage Data using Ethereum Data Warehouse (EDW)</h3><p>EDW is events, calls, transactions, state, and storage data in a Snowflake shared database. You can get <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mcusercontent.com/bd95a458bec63a9ef2c731fe3/files/22fed5eb-77d9-c180-5af7-88cc4292169d/EDW_SDW_Beta_manual.pdf">setup here</a> with a custom app or just start querying on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.flipsidecrypto.com/">Flipside</a> by changing the schema to <code>tokenflow_eth</code>. There are <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://tokenflow.live/blog/querying-state">some example queries here</a>. I’m assuming you’ve already used something like Dune Analytics or Flipside, so I’ll only cover the new tables.</p><ul><li><p><strong>state_diffs</strong>: use this for tracking ETH balances. here are the main state fields and reasons they change:</p><ul><li><p>I like to use this table for wallet balances analysis - much faster than trying to aggregate on ETH calls from traces.</p></li></ul></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4731aa3b2d57e2854446ec4a25abca78a601b989142d302b79dd97362859b3e9.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><ul><li><p><strong>storage_diffs</strong>: tells you current and last value for different storage slots, with mappings nicely nested already in dict formats.</p><ul><li><p>Contract storage layout comes from solc compiler. you can use a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.npmjs.com/package/hardhat-storage-layout?activeTab=readme">hardhat plugin</a> to do this to get the following on each compile (or the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#json-output">raw JSON output</a>):</p></li></ul></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/99ba24e22f847937e0a60c9481d43f4bafbfcb92186ad71d59c7b1c40331b9da.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><ul><li><p>This table is useful for tracking variables on contracts, most commonly would be stuff like historical balances.</p></li><li><p><strong>storage_reads</strong>: this tells you when a certain slot of storage was read during a transaction.</p><ul><li><p>useful for assessing contract interoperability/dependencies, when joined on <code>call_id</code> and <code>tx_hash</code> with traces (calls)</p></li><li><p>exploring what variables are read when a certain function is called, when joined on transactions with a selected funcsig in <code>call_data</code>.</p></li><li><p>sometimes it&apos;s easier to use calls table (traces) when the value you want is in a function output, instead of the storage variables.</p></li></ul></li></ul><h2 id="h-example-queries-looking-at-on-chain-price-oracles" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Example Queries: Looking at On-ch<strong>ain Price Oracles</strong></h2><p><em>I used the data outputted from these queries in further analysis, you can read and play with the code in the repo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/andrewhong5297/uniswapv2_v3-oracle-analysis/blob/main/Oracle%20Analysis%20ETH-USDC%20Uniswap%20vs%20Chainlink.ipynb"><em>here</em></a><em>.</em></p><p>Let’s run through a harder example than just balances and transfers: looking at price oracles on-chain. If you have no familiarity with Oracles, check out <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.uniswap.org/protocol/V2/concepts/core-concepts/oracles">this explainer</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/linda-xie/defi-oracles">this repo of older oracles</a>.</p><p><strong>tldr;</strong> Chainlink pushes prices from the real world on-chain so smart contracts can access it, Uniswap V2 and V3 have methods for calculating the token price purely on-chain. There are likely differences in prices at any given moment for a variety of reasons.</p><p><em>All the queries I’m going through below are public </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/andrewhong5297/uniswapv2_v3-oracle-analysis/blob/main/EDW_queries/price_queries_edw.txt"><em>here</em></a><em>, you can run them once you have EDW set up - just remember to change</em> <code>EDW_SNOWFLAKE_SECURE_SHARE_1645732350028</code> to whatever your secure share instance name is! I also set up udfs on a new database in Snowflake, since you can’t create udfs in a shared db.</p><h3 id="h-chainlink-query" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Chainlink Query</h3><p>Let’s start with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.chain.link/docs/architecture-decentralized-model/">Chainlink data feeds</a>! <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419#code">The contract</a> is set up such that the proxy itself doesn’t store historical prices - it calls aggregator contracts instead. There have been five such aggregators used for the ETH/USDC price feed, which I queried for here:</p><pre data-type="codeBlock" text="SELECT * --use curr_value for aggregator addresses to use in the next query
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_diffs 
WHERE contract = lower(&apos;0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419&apos;) --ETH/USDC proxy aggregator, ref https://data.chain.link/popular 
AND location LIKE &apos;4[%].0&apos;
ORDER BY timestamp ASC;
"><code><span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-comment">--use curr_value for aggregator addresses to use in the next query</span>
<span class="hljs-keyword">FROM</span> EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_diffs 
<span class="hljs-keyword">WHERE</span> contract <span class="hljs-operator">=</span> <span class="hljs-built_in">lower</span>(<span class="hljs-string">'0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'</span>) <span class="hljs-comment">--ETH/USDC proxy aggregator, ref https://data.chain.link/popular </span>
<span class="hljs-keyword">AND</span> location <span class="hljs-keyword">LIKE</span> <span class="hljs-string">'4[%].0'</span>
<span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> <span class="hljs-type">timestamp</span> <span class="hljs-keyword">ASC</span>;
</code></pre><p>I queried for any address in slot 4 mapping. Mappings in EDW are stored as slot[value].keys where keys apply to structs in mappings. Here there is no struct, so we take <code>.0</code> instead. The variable this tracks is:</p><pre data-type="codeBlock" text="&quot;4&quot;: [
    {
      &quot;from&quot;: 0,
      &quot;name&quot;: &quot;phaseAggregators&quot;,
      &quot;to&quot;: 31,
      &quot;type&quot;: &quot;mapping(uint16, address)&quot;
    }
  ],
"><code>"<span class="hljs-number">4</span>": [
    {
      "<span class="hljs-selector-tag">from</span>": <span class="hljs-number">0</span>,
      <span class="hljs-string">"name"</span>: <span class="hljs-string">"phaseAggregators"</span>,
      <span class="hljs-string">"to"</span>: <span class="hljs-number">31</span>,
      <span class="hljs-string">"type"</span>: <span class="hljs-string">"mapping(uint16, address)"</span>
    }
  ],
</code></pre><p>Then, I plugged the five addresses manually into a query over the <code>calls</code> table, so I could get the values from each time the proxy contract called an aggregator.</p><pre data-type="codeBlock" text="SELECT 
    distinct 
    timestamp, 
    block,
    udf.public.hextoint(return_value)/1e8 as eth_price
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.calls 
WHERE from_address= lower(&apos;0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419&apos;) --ETH/USDC proxy aggregator
AND to_address IN (&apos;0x37bc7498f4ff12c19678ee8fe19d713b87f6a9e6&apos;,    &apos;0xd3fcd40153e56110e6eeae13e12530e26c9cb4fd&apos;, &apos;0xb103ede8acd6f0c106b7a5772e9d24e34f5ebc2c&apos;, &apos;0xf79d6afbb6da890132f9d7c355e3015f15f3406f&apos;, &apos;0xc7a37b03690fb9f41b5c5af8131735c7275446&apos;) --historical phaseaggregators for ETH/USDC as of 3/1/2022
AND substring(call_data,1,10) = &apos;0x50d25bcd&apos; --funcsig for getting latestRoundData
AND block &gt;= 12381343
AND status = 1
ORDER BY 1 ASC;
"><code>SELECT 
    distinct 
    timestamp, 
    <span class="hljs-built_in">block</span>,
    udf.public.hextoint(return_value)<span class="hljs-operator">/</span><span class="hljs-number">1e8</span> <span class="hljs-keyword">as</span> eth_price
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.calls 
WHERE from_address<span class="hljs-operator">=</span> lower(<span class="hljs-string">'0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'</span>) <span class="hljs-operator">-</span><span class="hljs-operator">-</span>ETH<span class="hljs-operator">/</span>USDC proxy aggregator
AND to_address IN (<span class="hljs-string">'0x37bc7498f4ff12c19678ee8fe19d713b87f6a9e6'</span>,    <span class="hljs-string">'0xd3fcd40153e56110e6eeae13e12530e26c9cb4fd'</span>, <span class="hljs-string">'0xb103ede8acd6f0c106b7a5772e9d24e34f5ebc2c'</span>, <span class="hljs-string">'0xf79d6afbb6da890132f9d7c355e3015f15f3406f'</span>, <span class="hljs-string">'0xc7a37b03690fb9f41b5c5af8131735c7275446'</span>) <span class="hljs-operator">-</span><span class="hljs-operator">-</span>historical phaseaggregators <span class="hljs-keyword">for</span> ETH<span class="hljs-operator">/</span>USDC <span class="hljs-keyword">as</span> of <span class="hljs-number">3</span><span class="hljs-operator">/</span><span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">2022</span>
AND substring(call_data,<span class="hljs-number">1</span>,<span class="hljs-number">10</span>) <span class="hljs-operator">=</span> <span class="hljs-string">'0x50d25bcd'</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>funcsig <span class="hljs-keyword">for</span> getting latestRoundData
AND <span class="hljs-built_in">block</span> <span class="hljs-operator">></span><span class="hljs-operator">=</span> <span class="hljs-number">12381343</span>
AND status <span class="hljs-operator">=</span> <span class="hljs-number">1</span>
ORDER BY <span class="hljs-number">1</span> ASC;
</code></pre><p><em>Chainlink oracle usage queries are just an aggregation change, so I’m not including it here.</em></p><h3 id="h-uniswap-v2-query" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Uniswap V2 Query</h3><p>Uniswap V2 pairs track token prices separately, in variable <code>price1CumulativeLast</code> and <code>price0CumulativeLast</code> for token1 and token0 respectively (and in storage slots 10 and 9 respectively)</p><p>For <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc#readContract">this pair</a>, I queried storage at slot 10 and parsed <code>curr_value</code> into an integer:</p><pre data-type="codeBlock" text="SELECT 
    block, 
    timestamp, 
    -- location, 
    -- tx_hash, 
    udf.public.hextoint(curr_value) as cumulative_last
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_diffs 
WHERE contract = lower(&apos;0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc&apos;)
AND location = &apos;10&apos; -- token1 price slot, which is WETH
AND block &gt;= 12381343
AND status = 1
ORDER BY block, timestamp, order_index;
"><code>SELECT 
    <span class="hljs-built_in">block</span>, 
    timestamp, 
    <span class="hljs-operator">-</span><span class="hljs-operator">-</span> location, 
    <span class="hljs-operator">-</span><span class="hljs-operator">-</span> tx_hash, 
    udf.public.hextoint(curr_value) <span class="hljs-keyword">as</span> cumulative_last
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_diffs 
WHERE <span class="hljs-class"><span class="hljs-keyword">contract</span> = <span class="hljs-title">lower</span>(<span class="hljs-params"><span class="hljs-string">'0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc'</span></span>)
<span class="hljs-title">AND</span> <span class="hljs-title">location</span> = '10' -- <span class="hljs-title">token1</span> <span class="hljs-title">price</span> <span class="hljs-title">slot</span>, <span class="hljs-title">which</span> <span class="hljs-keyword">is</span> <span class="hljs-title">WETH</span>
<span class="hljs-title">AND</span> <span class="hljs-title"><span class="hljs-built_in">block</span></span> >= 12381343
<span class="hljs-title">AND</span> <span class="hljs-title">status</span> = 1
<span class="hljs-title">ORDER</span> <span class="hljs-title">BY</span> <span class="hljs-title"><span class="hljs-built_in">block</span></span>, <span class="hljs-title">timestamp</span>, <span class="hljs-title">order_index</span>;
</span></code></pre><p><em>The rest of the data processing to get price was done in Python (see repo from top of section). V2 Oracle usage queries are basically the same as in v3, so I won’t go over them here.</em></p><h3 id="h-uniswap-v3-query" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Uniswap V3 Query</h3><p>Uniswap V3 is much more complex, because of two reasons:</p><ul><li><p>prices are tracked in ticks now</p></li><li><p>historical prices are stored in the contract now to make accessing them easier, but this means dealing with a struct array. This is the <code>observations[]</code> array, created using the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/Oracle.sol">Oracle.sol library</a> and implemented on the pair contract.</p></li></ul><p>Because the array is the last slot initialized in the contract (the 9th slot), we know the index of the array is <code>slot - 8</code>. Structs are stored in reverse and tightly packed within each slot, such that for the struct:</p><pre data-type="codeBlock" text="struct Observation {
        uint32 blockTimestamp;
        int56 tickCumulative;
        uint160 secondsPerLiquidityCumulativeX128;
        bool initialized;
    }
"><code><span class="hljs-keyword">struct</span> <span class="hljs-title">Observation</span> {
        <span class="hljs-keyword">uint32</span> blockTimestamp;
        <span class="hljs-keyword">int56</span> tickCumulative;
        <span class="hljs-keyword">uint160</span> secondsPerLiquidityCumulativeX128;
        <span class="hljs-keyword">bool</span> initialized;
    }
</code></pre><p>The slot can be decoded into: first two bytes have <code>initialized</code> then 40 for <code>secondsPerLiquidityCumulativeX128</code>, 14 for <code>tickCumulative</code> and 8 for <code>blockTimestamp</code>. The query I used was:</p><pre data-type="codeBlock" text="SELECT timestamp, 
       location::integer - 8 as index, 
       -- substr(curr_value, 3, 2) = &apos;0x01&apos; as initialized,
       -- hextoint(substr(curr_value, 5, 40)) as secondsPerLiquidityCumulativeX128, 
       hextoint(substr(curr_value, 45, 14)) as tickCumulative
       -- hextoint(substr(curr_value, 59, 8)) as blockTimestamp
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_diffs 
WHERE contract = lower(&apos;0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8&apos;)
      and location not like &apos;_[%&apos; and location::integer &gt; 8
      AND block &gt;= 12381343 
      AND status = 1
ORDER BY block asc, order_index asc;
"><code>SELECT timestamp, 
       location::integer <span class="hljs-operator">-</span> <span class="hljs-number">8</span> <span class="hljs-keyword">as</span> index, 
       <span class="hljs-operator">-</span><span class="hljs-operator">-</span> substr(curr_value, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>) <span class="hljs-operator">=</span> <span class="hljs-string">'0x01'</span> <span class="hljs-keyword">as</span> initialized,
       <span class="hljs-operator">-</span><span class="hljs-operator">-</span> hextoint(substr(curr_value, <span class="hljs-number">5</span>, <span class="hljs-number">40</span>)) <span class="hljs-keyword">as</span> secondsPerLiquidityCumulativeX128, 
       hextoint(substr(curr_value, <span class="hljs-number">45</span>, <span class="hljs-number">14</span>)) <span class="hljs-keyword">as</span> tickCumulative
       <span class="hljs-operator">-</span><span class="hljs-operator">-</span> hextoint(substr(curr_value, <span class="hljs-number">59</span>, <span class="hljs-number">8</span>)) <span class="hljs-keyword">as</span> blockTimestamp
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_diffs 
WHERE <span class="hljs-class"><span class="hljs-keyword">contract</span> = <span class="hljs-title">lower</span>(<span class="hljs-params"><span class="hljs-string">'0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8'</span></span>)
      <span class="hljs-title">and</span> <span class="hljs-title">location</span> <span class="hljs-title">not</span> <span class="hljs-title">like</span> '<span class="hljs-title"><span class="hljs-keyword">_</span></span>[%' <span class="hljs-title">and</span> <span class="hljs-title">location</span>::<span class="hljs-title">integer</span> > 8
      <span class="hljs-title">AND</span> <span class="hljs-title"><span class="hljs-built_in">block</span></span> >= 12381343 
      <span class="hljs-title">AND</span> <span class="hljs-title">status</span> = 1
<span class="hljs-title">ORDER</span> <span class="hljs-title">BY</span> <span class="hljs-title"><span class="hljs-built_in">block</span></span> <span class="hljs-title">asc</span>, <span class="hljs-title">order_index</span> <span class="hljs-title">asc</span>;
</span></code></pre><p><em>The rest of the data price processing was done in Python.</em></p><p>I also made a query to get daily reads/unique contracts reliant on the Uniswap V3 oracle, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/andrewhong5297/uniswapv2_v3-oracle-analysis/blob/main/EDW_queries/read_queries_edw.txt">found here</a>. First, I had to filter out transactions where there was a call to mint, burn, swap, or flash in the pool. Then, I joined the <code>storage_reads</code> table with the <code>calls</code> table on <code>call_id</code> and <code>tx_hash</code> to figure out which contracts were reading the <code>tickCumulative</code> data values, presuming they did so to get ETH prices.</p><pre data-type="codeBlock" text="WITH 
    --ignore calls that affect observation state as that doesn&apos;t count as oracle usage
    ignore_interactions as (
        SELECT 
            *
            --distinct tx_hash
        FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.calls
        WHERE to_address = lower(&apos;0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc&apos;)
        AND substring(call_data,1,10) IN (&apos;0x6a627842&apos;,&apos;0x89afcb44&apos;,&apos;0x022c0d9f&apos;) --mint, burn, swap
    )

-- query top contracts using calls instead of txs, we count distinct tx_hash since otherwise reads might be cheating with multiple reads per oracle use. 
SELECT 
    call.from_address , 
    COUNT(distinct call.tx_hash) as total_times_queried
FROM EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_reads read 
LEFT JOIN EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.calls call 
    ON call.tx_hash = read.tx_hash AND call.call_id = read.call_id
WHERE contract = lower(&apos;0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc&apos;)
    AND location = &apos;10&apos;
    AND read.status = 1
    AND read.block &gt;= 12381343
    AND NOT EXISTS (SELECT 1 FROM ignore_interactions ii --ignore non-oracle interactions
               WHERE ii.tx_hash = read.tx_hash)
GROUP BY 1
ORDER BY total_times_queried DESC
LIMIT 100;
"><code><span class="hljs-keyword">WITH</span> 
    <span class="hljs-comment">--ignore calls that affect observation state as that doesn't count as oracle usage</span>
    ignore_interactions <span class="hljs-keyword">as</span> (
        <span class="hljs-keyword">SELECT</span> 
            <span class="hljs-operator">*</span>
            <span class="hljs-comment">--distinct tx_hash</span>
        <span class="hljs-keyword">FROM</span> EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.calls
        <span class="hljs-keyword">WHERE</span> to_address <span class="hljs-operator">=</span> <span class="hljs-built_in">lower</span>(<span class="hljs-string">'0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc'</span>)
        <span class="hljs-keyword">AND</span> <span class="hljs-built_in">substring</span>(call_data,<span class="hljs-number">1</span>,<span class="hljs-number">10</span>) <span class="hljs-keyword">IN</span> (<span class="hljs-string">'0x6a627842'</span>,<span class="hljs-string">'0x89afcb44'</span>,<span class="hljs-string">'0x022c0d9f'</span>) <span class="hljs-comment">--mint, burn, swap</span>
    )

<span class="hljs-comment">-- query top contracts using calls instead of txs, we count distinct tx_hash since otherwise reads might be cheating with multiple reads per oracle use. </span>
<span class="hljs-keyword">SELECT</span> 
    call.from_address , 
    <span class="hljs-built_in">COUNT</span>(<span class="hljs-keyword">distinct</span> call.tx_hash) <span class="hljs-keyword">as</span> total_times_queried
<span class="hljs-keyword">FROM</span> EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.storage_reads read 
<span class="hljs-keyword">LEFT</span> <span class="hljs-keyword">JOIN</span> EDW_SNOWFLAKE_SECURE_SHARE_1645732350028.raw.calls <span class="hljs-keyword">call</span> 
    <span class="hljs-keyword">ON</span> call.tx_hash <span class="hljs-operator">=</span> read.tx_hash <span class="hljs-keyword">AND</span> call.call_id <span class="hljs-operator">=</span> read.call_id
<span class="hljs-keyword">WHERE</span> contract <span class="hljs-operator">=</span> <span class="hljs-built_in">lower</span>(<span class="hljs-string">'0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc'</span>)
    <span class="hljs-keyword">AND</span> location <span class="hljs-operator">=</span> <span class="hljs-string">'10'</span>
    <span class="hljs-keyword">AND</span> read.status <span class="hljs-operator">=</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">AND</span> read.block <span class="hljs-operator">>=</span> <span class="hljs-number">12381343</span>
    <span class="hljs-keyword">AND</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span> (<span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span> <span class="hljs-keyword">FROM</span> ignore_interactions ii <span class="hljs-comment">--ignore non-oracle interactions</span>
               <span class="hljs-keyword">WHERE</span> ii.tx_hash <span class="hljs-operator">=</span> read.tx_hash)
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> <span class="hljs-number">1</span>
<span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> total_times_queried <span class="hljs-keyword">DESC</span>
LIMIT <span class="hljs-number">100</span>;
</code></pre><p>*I highly encourage you to check out the longer deep dive into oracle prices <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/andrewhong5297/uniswapv2_v3-oracle-analysis/blob/main/Oracle%20Analysis%20ETH-USDC%20Uniswap%20vs%20Chainlink.ipynb">here</a> to get a sense of how this data is then applied in real analysis.*</p><h2 id="h-concluding-thoughts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Concluding Thoughts</h2><p>I believe working with storage and state data is harder than events/function call data at the start because you need more familiarity with Solidity. Many variables are encoding in weird ways to make manipulation easy between smart contracts - so they really aren’t human interpretable at all. There are also a bunch of different storage patterns that people use, which take time to get used to.</p><p>However, this data does provide two primary benefits:</p><ul><li><p>allow you to avoid a ton of expensive event/call aggregations, which will become increasingly important for wallet analysis in the future.</p></li><li><p>it captures cross-contract interoperability and dependencies. I think this enables us to do much deeper ecosystem analysis and risk analysis, as well as more accurate simulations.</p></li></ul><p>I can’t wait for the production release of this product, huge kudos to the TokenFlow insights team (and thanks a bunch for answering all my questions! 🙂 )</p><p>(here’s the edition I mentioned at the start!)</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xDF5b5ee15CC96ba7d0CB6BD9b2c0fc4417ab6445">edition://0xDF5b5ee15CC96ba7d0CB6BD9b2c0fc4417ab6445?editionId=4053</a></p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/3acd040995a219dfd51ece2a33bac8aadf86249e549d35da4c08f620c5af5850.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[[2022] Guide to Web3 Data: Thinking, Tools, and Teams]]></title>
            <link>https://paragraph.com/@ilemi/2022-guide-to-web3-data-thinking-tools-and-teams</link>
            <guid>JCghBaAKjLiqKPNF2V9j</guid>
            <pubDate>Tue, 08 Feb 2022 14:29:48 GMT</pubDate>
            <description><![CDATA[Welcome! I’m assuming you’re a data analyst who is new to web3, starting to build your web3 analytics team, or have just taken an interest in web3 data in general. Either way, you should already be loosely familiar with how APIs, databases, transformations, and models work in web2. For this inaugural guide, I’m going to try to keep things very concise and highlight my thoughts across these three pillars:Thinking: why an open data pipeline re-shapes how data work gets doneTools: an overview of...]]></description>
            <content:encoded><![CDATA[<p>Welcome! I’m assuming you’re a data analyst who is new to web3, starting to build your web3 analytics team, or have just taken an interest in web3 data in general. Either way, you should already be loosely familiar with how APIs, databases, transformations, and models work in web2.</p><p>For this inaugural guide, I’m going to try to keep things very concise and highlight my thoughts across these three pillars:</p><ol><li><p><strong>Thinking</strong>: why an open data pipeline re-shapes how data work gets done</p></li><li><p><strong>Tools</strong>: an overview of tools along the web3 data stack, and how to leverage them</p></li><li><p><strong>Teams</strong>: basic considerations and skills to have in a web3 data team</p></li></ol><p>This is probably a good time to say that this is all just my view of the space, and I’ve showcased only a few facets of the tools/communities mentioned below.</p><p>Let’s get into it!</p><h2 id="h-on-data-thinking" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">On Data Thinking</h2><p>Let’s start by summarizing how data is built, queried, and accessed in web2 (i.e. accessing Twitter’s API). We have four steps for a simplified data pipeline:</p><ol><li><p>events API triggered (some tweet sent out)</p></li><li><p>ingestion to the database (connection to existing user models/state changes)</p></li><li><p>transformations of data for specific product/analytics use cases (addition of replies/engagement metrics over time)</p></li><li><p>model training and deployment (for curating your Twitter feed)</p></li></ol><p>The only step when the data is sometimes open-sourced is after transformations are done. Communities like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.kaggle.com/competitions">Kaggle</a> (1000’s of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.kaggle.com/c/nfl-health-and-safety-helmet-assignment">data science</a>/<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://towardsdatascience.com/feature-engineering-for-machine-learning-3a5e293a5114">feature engineering</a> competitions) and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://huggingface.co/models">Hugging Face</a> (26,000 top-notch NLP models) use some subset of exposed data to help corporates build better models. There are some domain-specific cases like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://joemorrison.medium.com/openstreetmap-is-having-a-moment-dcc7eef1bb01">open street maps</a> that open up data in the earlier three steps - but these still have limits around write permissions.</p><p>I do want to clarify that I’m only talking about the data here, I’m not saying web2 doesn’t have any open-source at all. Like most other engineering roles, web2 data has tons of open-source tools for <em>building</em> their pipelines (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/dbt-labs/dbt-core">dbt</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://airflow.apache.org/">anything apache</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.tensorflow.org/">TensorFlow</a>). We still use all these tools in web3. In summary, their tooling is open but their data is closed.</p><p><strong>Web3 open-sources the data as well</strong> - this means that it&apos;s no longer just data scientists working in the open but analytics engineers and data engineers as well! Instead of a mostly black-box data cycle, everyone gets involved in a more continuous workflow.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cf8a2a9118b1c5c02471347ee3259fff939f373a5366bc5a4f7f7458e5bf2525.jpg" 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>The shape of work has gone from web2 data dams to web3 data rivers, deltas, and oceans. It’s also important to note that this new cycle affects <em>all products/protocols in the ecosystem at once</em>.</p><p>Let’s look at an example of how web3 analysts work together. There are dozens of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.coinbase.com/learn/crypto-basics/what-is-a-dex">DEX</a>’s out there which use different exchange mechanisms and fees for allowing you to swap token A for token B. If these were typical exchanges like Nasdaq, each exchange would report their own data in a 10k or some API, and then some other service like capIQ would do the work of putting all exchange data together and charge $$$ for you to access their API. Maybe once in a while, they’ll run an innovation competition so that they can have an extra data/chart feature to charge for in the future.</p><p>With web3 exchanges, we have this data flow instead:</p><ol><li><p><code>dex.trades</code> is a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/duneanalytics/abstractions/tree/master/ethereum/dex/trades">table on Dune</a> (put together by many community analytics engineers over time) where all DEX swap data is aggregated - so you can very easily search for something like a single token’s swap volume across all exchanges.</p></li><li><p>A data analyst comes along and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.xyz/hagaetc/dex-metrics">creates a dashboard using a bunch of community open-sourced queries</a>, and now we have a public overview of the entire DEX industry.</p><ol><li><p>even if all the queries look like they’re written by one person, you can bet that there was tons of discussion in a discord somewhere to piece it together accurately.</p></li></ol></li><li><p>A DAO scientist takes a look at the dashboard and starts segmenting the data in their own queries, looking at specific pairs such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/stablecoins/#how">stablecoins</a>. They take a look at user behaviors and business models, and start building a hypothesis.</p></li><li><p>Since the scientist can see which DEX is taking a larger share of trading volume, they’ll then come up with a new model and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gov.uniswap.org/t/discussion-adding-1-basis-point-fee-pools-in-v3/14216">propose changes to governance parameters</a> to get voted on and executed on-chain (s/o <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/alex_kroeger">Alex Kroeger</a> for the proposal example here).</p></li><li><p>Afterwards, we can check the public queries/dashboards at anytime to see how the proposal <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/alex_kroeger/status/1460684569523339267">created a more competitive product</a></p></li><li><p>In the future, if another DEX comes out (or upgrades to a new version), the process will repeat. Someone will create the insert query to update this table. This will in turn reflect in all the dashboards and models (without anyone having to go back and manually fix/change anything). Any other analyst/scientist can just build upon the work Alex has already done.</p></li></ol><p>Discussion, collaboration, and learning happen in a much tighter feedback loop due to the shared ecosystem. I will admit this gets very overwhelming at times, and the analysts I know basically all rotate data burnout. However, as long as one of us keeps pushing the data forward (i.e. someone creates that insert DEX query) then else everyone benefits.</p><p>It doesn’t always have to be complicated abstracted views either, sometimes its just utility functions like making it easy to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.xyz/queries/230953">search up an ENS reverse resolver</a> or improvements in tooling like auto-generating most of the graphQL mapping <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/developer/create-subgraph-hosted/">with a single CLI command</a>! All of it is reusable by everyone, and can be adapted for API consumption in some product frontend or your own personal trading models.</p><p>While the possibilities unlocked here are amazing, I do acknowledge that the wheel isn’t running that smoothly yet. The ecosystem is still really immature on the data analyst/science side compared to data engineering. I think there are a few reasons for this:</p><ul><li><p>Data engineering was the core focus of web3 for years, from client RPC API improvements to basic SQL/graphQL aggregations. Work on products like theGraph and Dune really exemplifies the effort they’ve put into this.</p></li><li><p>For analysts, there’s a tough ramp-up to understand the unique cross-protocol relational tables of web3. For example, analysts can understand how to analyze just Uniswap but then struggle with adding in aggregators, other DEXs, and different token types into the mix. On top of that, the tools to do all this weren’t really there until last year.</p></li><li><p>Data scientists are used to basically going to a raw data dump and working through all of it solo (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.kubeflow.org/docs/started/architecture/">building their own pipelines</a>). I don’t think they’re used to working so closely and openly with analysts and engineers earlier on in the pipeline. This took a while to click for me personally.</p></li></ul><p>On top of learning to work together, the web3 data community is also still learning how to work across this new data stack. You don’t get to control the infrastructure or slowly build up from excel to data lake or data warehouse anymore - as soon as your product is live then your data is live everywhere. Your team is basically thrown into the deep end of data infrastructure.</p><h2 id="h-on-data-tools" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">On Data Tools</h2><p>Here’s what most of you came here for:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ddad84c0e229a6d1f31eb86ba9dfa53c4bb573587dad64cbcaa5853f476e7bdc.jpg" alt="This is available as a collectible edition at the end of the entry!" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">This is available as a collectible edition at the end of the entry!</figcaption></figure><p>*<em>These tools are not comprehensive of the entire space - they’re just the ones that I’ve found myself or others consistently using and referencing in the Ethereum ecosystem (some of them cover other chains as well).</em></p><p>*<em>The “decentralized” tag means there’s either an infrastructure network or guideline framework to stop changes from happening unilaterally. I like to think of it as decoupled infra versus cloud infra, but that will need to be its own article.</em></p><p><strong>Let’s walk through when you would need to use each layer/category:</strong></p><ul><li><p>Interaction + Data Source: This is mostly used in frontends, wallets, and data ingestion to lower layers.</p><ul><li><p><em>Clients</em>: while the underlying implementation of Ethereum is the same (with Geth as the canonical repo), each client has different extra features. For example, Erigon is heavily optimized for data storage/sync, and Quorum supports <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.tessera.consensys.net/en/stable/">spinning up privacy chains</a>.</p></li><li><p><em>Nodes-as-a-Service</em>: You don’t get to choose which client they run, but using these services will save you the headache of maintaining nodes and API uptime yourself. Nodes have a lot of complexity depending on how much data you want to capture (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/nodes-and-clients/">light → full → archive</a>).</p></li></ul></li><li><p>Query + Data Mapping: The data in this layer is either referenced in the contract as a URI or comes from using the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#:~:text=The%20Contract%20Application%20Binary%20Interface,contract%2Dto%2Dcontract%20interaction.&amp;text=We%20assume%20the%20interface%20functions,at%20compilation%20time%20and%20static.">contract ABI</a> to map transaction data from bytes to table schemas. A contract ABI tells us what functions and events are contained in the contract since otherwise, all we can see is the deployed bytecode (you can’t reverse engineer/decode contract transactions without this ABI).</p><ul><li><p><em>Transaction Data:</em> These are the most popularly used, mostly for dashboards and reports. theGraph and Flipside APIs are used in frontends as well. Some tables are 1:1 mappings of contracts, and some allow extra transformations in the schema.</p></li><li><p><em>Metadata “Protocols”:</em> These aren’t really data products, but exist for storage of DIDs or file storage. Most NFTs will use one or more of these, and I think we’ll start using these data sources more and more to enhance our queries this year.</p></li><li><p><em>Specialty Providers:</em> Some of these are very robust data streaming products, Blocknative for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.blocknative.com/explorer">mempool data</a> and Parsec for on-chain trading data. Others aggregate both on-chain and off-chain data, like DAO governance or treasury data (I’m pretty confident Boardroom and DeepDAO will have more expansive APIs/query-ability in the future).</p></li></ul></li><li><p>High Touch Data Providers: You can’t query/transform their data, but they’ve done all the heavy lifting for you.</p><ul><li><p><em>“Enterprise” Services</em>: You’ll use these a lot if you’re a VC, investigator, or reporter. You can go deep into wallets and wallet relationships using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.nansen.ai/nansen-101/introducing-wallet-profiler">Nansen’s wallet profiler</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.chainalysis.com/chainalysis-kyt/">Chainanalysis’s KYT</a>. Or use Tolken Terminal for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.tokenterminal.com/">beautiful out-of-the-box charts</a> on tons of projects/chains.</p></li><li><p><em>Enhanced APIs</em>: These are products that bundle what would be many queries into just one, such as all token balances of an ERC20 token or pulling the contract ABI for a given address.</p></li></ul></li></ul><p><strong>It wouldn’t be web3 without strong, standout communities to go alongside these tools!</strong> I’ve put some of the top communities next to each layer:</p><ul><li><p>Flashbots: Working on everything <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/mev/">MEV</a>, providing everything from a custom RPC for protecting transactions to professional whitehat services. MEV refers mostly to the issue of frontrunning, when someone pays more gas than you (but directly to the miners) so that they can get their transaction mined first. A great story to learn about this is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://samczsun.com/escaping-the-dark-forest/">written here by Samczsun</a>.</p><ul><li><p><em>how to get involved:</em> read through the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.flashbots.net/">docs</a> to figure out which vertical interests you and jump in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.com/invite/7hvTycdNcK">discord</a></p></li><li><p><em>contact</em>: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/bertcmiller">Bert Miller</a></p></li></ul></li><li><p>Dune Wizards: Handpicked wizards who have contributed something significant to the Dune data ecosystem.</p><ul><li><p><em>how to get involved:</em> start off in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.com/invite/ErrzwBz">discord</a> and tag @DuneAnalytics on Twitter with your work.</p></li><li><p><em>contact</em>: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/0xBoxer">Boxer</a></p></li></ul></li><li><p>Flipside Gunslingers: Handpicked gunslingers who have contributed something significant to the web3 data ecosystem.</p><ul><li><p><em>how to get involved</em>: start off in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.com/invite/ZmU3jQuu6W">discord</a> and create <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://flipsidecrypto.xyz/showcase">cool custom reports</a>.</p></li><li><p><em>contact</em>: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/theericstone">Eric</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/GJFlannery19">GJ</a></p></li></ul></li><li><p>MetricsDAO: Working across the ecosystem to tackle various data bounties on multiple chains.</p><ul><li><p><em>how to get involved:</em> read through their <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x3138165f8d21d4869dbD406CD8bc8055CAC8fb6E/cQtRNHKaXr2OnX0X3QNsDGSusykYkw9D5XwY1PHvvZ4">intro</a> and jump in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://discord.gg/metrics">discord</a></p></li><li><p><em>contact</em>: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/drakedanner">Danner</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/GJFlannery19">GJ</a></p></li></ul></li><li><p>DiamondDAO: Stellar data science work on governance, treasury, and token management in DAOs.</p><ul><li><p><em>how to get involved:</em> they literally have an organized “join” page <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.diamonddao.xyz/#join">here</a>.</p></li><li><p><em>contact</em>: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/c_lemp">Christian Lemp</a></p></li></ul></li><li><p>IndexCoop: Lots of token and domain specific analysis to create the best indexes in crypto.</p><ul><li><p><em>how to get involved:</em> jump into the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.com/invite/BcqYxdNC3R">discord</a>, and read some of their index proposals like the metaverse index (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gov.indexcoop.com/t/metaverse-index/122">MVI</a>).</p></li><li><p><em>contact</em>: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/BigSky_7">BigSky</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/josephdcook">JD Cook</a></p></li></ul></li><li><p>OurNetwork: Consistent data coverage of protocols and other verticals across web3 each week.</p><ul><li><p><em>how to get involved:</em> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ournetwork.substack.com/">subscribe to the newsletter</a>, if you do stellar analysis you’ll end up in our telegram eventually 😉</p></li><li><p><em>contact</em>: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/spencernoon">Spencer Noon</a></p></li></ul></li></ul><p><em>(yes, we need to do better on diversity. Go follow/reach out to </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/sui414"><em>Danning</em></a><em> and </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Nifty_Table"><em>Kofi</em></a><em> too, they’re amazing!)</em></p><p>Every one of these communities has done immense work to better the web3 ecosystem. It almost goes without saying that the products with a community around them grow at 100x the speed. This is still a heavily underrated competitive edge, one I think people don’t get unless they’ve built something within one of these communities.</p><h2 id="h-on-data-teams" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">On Data Teams</h2><p>It should also go without saying that you want to look within these communities for the people to hire onto your teams. Let’s go further and break down the important web3 data skills and experiences, so you actually know what you’re searching for. And if you’re looking to be hired, view this as the skills and experiences to go after!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/82992f7f400c2d24e775d6bb28e64ddfd01131fc875fd130659be3e9398a720c.jpg" 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>If you’re new and want to dive in, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ournetwork.mirror.xyz/gP16wLY-9BA1E_ZuOSv1EUAgYGfK9mELNza8cfgMWPQ">start with the free recordings of my 30-day data course</a> which is purely focused on the first pillar. I’ll hopefully have educational content on everything here and be able to run cohorts with it one day!</p><p>At a minimum, an analyst should be an Etherscan detective and know how to read Dune dashboards. This takes maybe 1 month to ramp up to leisurely, and 2 weeks if you’re really booking it and binge studying.</p><p><strong>There’s a little more context you should have in your mind as well, specifically on time allocations and skill transferability.</strong></p><ol><li><p><em>On Time:</em> In web3, about 30-40% of a data analyst&apos;s time is going to be spent keeping up with other analysts and protocols across the ecosystem. Please make sure you aren’t suffocating them, otherwise, it’ll become a long-term detriment to everyone. Learning, contributing, and building with the larger data community are absolutely essential.</p></li><li><p><em>On Transferability:</em> Skills and domain are both highly transferrable in this space. If I went to a different protocol, likely the ramp-up time would be minimal since the table schemas for on-chain data are all the same. If anything, I’ve probably already worked with that protocol’s data before even joining!</p></li></ol><p>Remember, it’s less about knowing how to use the tools - every analyst should more-or-less be able to write SQL or create dashboards. It’s all about knowing how to contribute and work with the communities. <em>If the person you’re interviewing isn’t a part of any of web3 data communities (and don’t seem to express any interest to start doing so), you may want to ask yourself if that’s a red flag.</em></p><p><strong>And a final tip for hiring</strong>: pitching the analyst using your data will work much better than pitching them with a role. Graeme had originally approached me with a really fun project and set of data, and after working through it I was fairly easily convinced to join the Mirror team.</p><p>Disclaimer: I would not recommend taking my word as definitive criteria for everyone, but at least it’s the frame of mind I’ll be using to hire data friends at Mirror <em>(sometime soon</em> 🙂).</p><p>I’d also have loved to talk about team structure, but to my knowledge, most product data teams have been 0 and 2 analysts full-time. I’m sure I’ll have better-informed thoughts on this in a year or two.</p><h2 id="h-thanks-for-reading" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Thanks for reading!</h2><p>It’s honestly quite amazing how far data in web3 has come over the last year, and I’m very excited to see where the ecosystem grows to by 2023. I’ll try and make this a yearly thing - if you want to support me and this kind of work, feel free to collect an edition of this entry (at the top) or one of the landscape NFTs below:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xDF5b5ee15CC96ba7d0CB6BD9b2c0fc4417ab6445">edition://0xDF5b5ee15CC96ba7d0CB6BD9b2c0fc4417ab6445?editionId=4053</a></p><p>If you have ideas/questions on web3 data topics you’d like to learn more about, just dm me on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/andrewhong5297">Twitter</a>. I’m always looking for educational partners as well!</p><p><em>Special thanks to </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/VirtualElena"><em>Elena</em></a><em> as always for reviewing and making great suggestions!</em></p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/91aa0a3c103ae7ed1c719174973b8520c984fde583eb960915f4a6d9a04eb604.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Request for DAOs: Providing Token Context and a Pulse to Communities]]></title>
            <link>https://paragraph.com/@ilemi/request-for-daos-providing-token-context-and-a-pulse-to-communities</link>
            <guid>ruB8IaLkMfTSpewhM1M2</guid>
            <pubDate>Wed, 17 Nov 2021 17:00:33 GMT</pubDate>
            <description><![CDATA[Why does token context matter?Hopefully, you&apos;re familiar with the Web3 product stack, and why it&apos;s considered composable. If not, then here&apos;s a quick refresher that explains the following layers:Frontend Layer: Webpages and/or wallets that allow us to interact abstractly with everything web3Smart Contract Layer: The protocols that hold interaction logic and storage, like UniswapBlockchain Layer: Layer ones like Ethereum, or L2&apos;s like OptimismAnother precursor for this arti...]]></description>
            <content:encoded><![CDATA[<h2 id="h-why-does-token-context-matter" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Why does token context matter?</h2><p>Hopefully, you&apos;re familiar with the Web3 product stack, and why it&apos;s considered composable. If not, then <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/crypto-and-web-3-0-are-the-future-of-product-and-work-3d19e3733181">here&apos;s a quick refresher</a> that explains the following layers:</p><ul><li><p><em>Frontend Layer:</em> Webpages and/or wallets that allow us to interact abstractly with everything web3</p></li><li><p><em>Smart Contract Layer:</em> The protocols that hold interaction logic and storage, like Uniswap</p></li><li><p><em>Blockchain Layer</em>: Layer ones like Ethereum, or L2&apos;s like Optimism</p></li></ul><p>Another precursor for this article that will be helpful is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/Olq6VS57xDFWDlxRdQwBKy05xdU2TJHXyk75y-ZxGNg">how web3 communities create tokens that become the membership structure that platforms are built off of</a>, whereas web2 communities are forced into membership structures of existing platforms.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8a1a72ab217c87884652651a6be76fd2d57cf5014744feceab8aee990794d94c.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>Communities in web3 issue tokens which are primitives used for defining membership - and if platforms want communities to use them, then they must support flexible membership structures.</p><p><strong>Now if you follow all the concepts above, you&apos;ll start to realize that web3 communities already have two sources of contextual complexity:</strong></p><ol><li><p>They live on many different frontends, many different smart contracts, and many different chains. <em>It isn&apos;t clear where the community lives or where to start.</em></p></li><li><p>While they might only have one ERC20 token right now, we&apos;re entering a phase where they might have seasonal sets of NFTs as well (or multiple ERC20 tokens). <em>It isn&apos;t clear what the tokens are for/value they hold.</em></p></li></ol><p>At least that&apos;s a lot of contexts (data and storytelling) to play with! So what do community entry points look like? Well...</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dd1da1aa0bfc7e9e62ff937bd58ea5a14f5eae681072faf0125775b014d5970a.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>...that doesn&apos;t really help me understand the community or token much at all. It doesn&apos;t really feel fun either - but that isn&apos;t FWB&apos;s or Uniswap&apos;s fault. After all, how is FWB supposed to know where I&apos;m going to enter from and how is Uniswap supposed to know (or care) which ERC20 tokens represent what community (or the tokens&apos; significance)?</p><p><strong>That brings me to the point of this article:</strong></p><blockquote><p>How do we comb through the complexity of web3 communities such that we can provide helpful context about what people are &quot;buying&quot; into when they go to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://app.uniswap.org">app.uniswap.org</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://opensea.io">opensea.io</a> or any other marketplace/exchange?</p></blockquote><p><em>I&apos;m not using the term &quot;DAO&quot; here, but you can mentally swap that with &quot;web3 community&quot; if you&apos;d like.</em></p><h2 id="h-what-is-the-token-context" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What is the token context?</h2><p>Web2 communities are mostly stadiums, where everyone is fighting to appear on one surface (Twitter feeds, subreddits, GitHub repo PRs/issues, Medium publications, etc.). What happens on that one surface gives us most of the community interaction, with only one layer beneath it for discussion (sometimes it&apos;s a comment section, sometimes a separate Discord server).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cc31369354d2e631d5506879e846f4424b6f0ab3531ccdec5120d2f348bbbb18.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>The discovery surface is fairly shallow, but community managers/leaders have full admin control of these main surfaces on the platform. This &quot;control&quot; is a bit of a farce since they don&apos;t really have control of the rest of the community stack. Community leaders have limited say in the stability or features of tooling, and have no way to change payment infrastructure or support/incentive structures. As a result, the ability to cohesively bring together those different community subsets is rarely well supported. Even though the underlying relationship graph across communities is probably a fairly distributed web, that network pattern is only really leveraged by the algorithms.</p><p><strong>In Web3, there are many different community contexts (surfaces) - all linked by the token(s).</strong> Communities pool around different facets of the token, becoming more uniform as you move down the token context stack.</p><p>My working assumption is that token context 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/659c0421772a10cd68435578494145fd95515902c88af31fa5c8a3f106ff5a08.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>Anyone can create a new application using &quot;X&quot; token, and it will be fully composable with the existing systems around &quot;X&quot; token. But that new application is now tied to that token ecosystem, where changes at the tokenomics/token/utility levels can affect the applications at the surface. Here are some examples:</p><ul><li><p>The team that manages or deployed the token has little say about what can or can&apos;t be built. For Mirror, anyone can build discovery or interaction layers on top of our entries or economic blocks. This has led to projects like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://askmirror.xyz">askmirror.xyz</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror-feed.vercel.app/">mirror-feed</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://alpha.backdrop.so/ilemi.eth">backdrop</a> which use different curation methods. You may say &quot;this is just like Facebook showing content from New York Times,&quot; but the difference is Mirror can reward and work with them through our tokens/treasury, as well as build their membership status into our utility tools and discussion platforms.</p></li><li><p>Sometimes what&apos;s built takes advantage of the existing system, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/bantg/status/1403863030094499843">pooling user deposits together in Yearn before depositing in PoolTogether</a>, leading to a higher chance of payout and higher yield for Yearn users. But even this is symbiotic, leading to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/pooltogether_/status/1253025782735220742">PoolTogether building a better and more fair system</a> from the bottom upwards. This is a bit of an optimistic take, but users will earn Pool tokens even while abusing strategies like Yearns, which should incentivize them to take a more long-term health viewpoint on the PoolTogether ecosystem.</p></li><li><p>Some applications are still team-led, for example, FWB partnering with SquiggleDAO and TileDAO to combine token applications for a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://emamo.com/event/nftnyc/s/tiledao-squiggledao-o6dmxa">live event in NYC</a>. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.brightmoments.io/">BrightMoments</a> partnering with leading artists from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.artblocks.io/">ArtBlocks</a> like Tyler Hobbs and Jeff Davis is another great example that also showcases how building off of NFT based systems works just as well as ERC20 tokens.</p></li><li><p>Some tokens start with a fixed subset of communities. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/">TheGraph</a> uses one token (GRT) to bond together Subgraph Developers (mapping smart contract events into data schemas), Indexers (running the nodes that run subgraphs), and Curators (signalers who stake GRT on subgraphs). Each community continues to build and improve on its own tools but is incentivized to work with each other to maintain data composability. Compare this to the less cohesive effort across Ethereum clients (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/go-ethereum">Geth</a>), infrastructure providers (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://infura.io/">Infura</a>), and data mappers (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://dune.xyz/">Dune Analytics</a>) who aren&apos;t tied together by a token (ETH doesn&apos;t really count).</p></li></ul><p>Bottom-up management in token context is a key difference from the top-down management of traditional web2 communities. The team has control over treasury/token distribution economics, as well as the base membership definitions (token utility) that govern the community. However, while the team&apos;s decisions have a lot of power, they are inherently low discovery. With the discovery stack so deep, how do we choose and represent what to show?</p><h2 id="h-how-do-we-show-token-context" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How do we show token context?</h2><p>The difficulty here is not just in capturing and displaying the elements in token context but in doing so concisely. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forefront.market/creators/friends-with-benefits-pro">Forefront DAO profiles</a> do a great job of showing stuff like access benefits, historical events, and general token stats. But I think we also need to capture something more dynamic.</p><p>Let&apos;s say I&apos;m deciding whether or not to move into a new city. Pretty pictures, testimonials from friends, and statistics on job opportunities/economics may convince me to visit - but they won&apos;t be the reason that I choose to stay. What convinces me to stay is that first-week impression of the &quot;pulse&quot; of the city. You hear people say all the time, &quot;the air is electrifying!&quot; or that &quot;you can just feel that the pace, culture, and emotion&quot; in one city is different from another. That &quot;pulse&quot; is the dynamic bit we want to try and capture and show about tokens.</p><p><strong>Continuing with the city model, I&apos;ll suggest four themes to work with as research jump-off points:</strong></p><p><em>Bridges/Doors:</em> If I&apos;m buying a token, I obviously am curious about thresholds. But how many times have they been changed and applied? For what purposes? At what pace do I need to accumulate?</p><p><em>People/Politics:</em> I want to know about the history and momentum of proposals, participation, and execution. What tools were used and token/delegation structures?</p><p><em>Public Parks/Spaces</em>: What does the community composition look like and where do they live? What is the relationship graph of interactions across different surfaces?</p><p><em>Energy Consumption/Production</em>: Which tokens are moving and which aren&apos;t? Are any of them interlinked/dependent on each other? What about the token&apos;s relationships with other communities tokens?</p><p>Ultimately, these questions should get us closer to the <strong>pulse</strong> across the layers of a token&apos;s context, in a more concise way than just listing everything or joining a flooded discord. <strong>With this data, we get community activation effects alongside more meaningful token trading volume:</strong></p><ul><li><p><em>Prospective members:</em> give those on the sidelines an active and energized interest in some layer of context at the same time as they buy the token.</p></li><li><p><em>Inactive members:</em> convince passive token holders to accumulate tokens and find a new interest. Or alternatively, give them a reason to dump so that new blood is more likely to come in and contribute.</p></li><li><p><em>Prospective partners:</em> convince builders/communities to build their applications into your token ecosystem (either symbiotically or parasitically) to drive long-term community health up.</p></li></ul><p>Some of this sounds harsh, but I believe the worst is when both the community and the token holders are stagnant. Web3 communities can&apos;t really bankrupt like a typical company, but they can definitely still become zombies - no pulse at all. And if your token is trading actively but has no pulse/context - well that’s a clear warning sign too. Pulse and token context can help both initiate and revitalize communities!</p><p><em>On a more technical level, I think this means being able to map and track token activity (across all context layers) - using some sort of changepoint or momentum algorithm. Maybe token context can be represented in pulse as a couple values/models, maybe it can&apos;t</em> 🤷‍♂️</p><h2 id="h-creating-a-data-guild-for-tackling-the-pulse-and-token-context-quest" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Creating a data guild for tackling the &quot;pulse and token context&quot; quest</h2><p>Now, I&apos;d like to start a data guild for studying all this within Mirror DAO. Note that you don&apos;t need to agree with my viewpoints in order to join, in fact, I would see that as a plus!</p><p>There will be roughly three main goals, using a few case-study DAOs as our base research data:</p><ul><li><p>Create a clean way to store a community membership registry over time</p><ul><li><p>Probably following some epochs/seasons format</p></li></ul></li><li><p>Find and define data points for token context (likely split into groups based on earlier themes).</p><ul><li><p>Standardize data points into inputs/outputs or a list of tools.</p></li><li><p>Find a way to push them onto an open data source like Ceramic API.</p></li></ul></li><li><p>Work with these data points to represent the &quot;pulse&quot; of a community&apos;s token(s)</p><ul><li><p>Make a cohesive story behind these</p></li><li><p>Design mockups</p></li></ul></li></ul><p>On top of providing context to newer or inactive community members, having this data will also help us unlock more comprehensive <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/c_lemp/status/1442892006368309251">community health dashboards</a> and better <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/mDu_nGsWpjvF-KaPLADwxeAMfze3UJOtTAQi2CwPwWc">context around decentralized digital identities</a>.</p><p><strong>Please fill out </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forms.gle/hoR9HUGfwk9LTvDm8"><strong>this form</strong></a><strong> if you are interested in being a core contributor.</strong> Looking for anyone with experience in DAOs from a data, storytelling, design, or tool liaison background!</p><p>Even if you don&apos;t make it into the core group, we&apos;ll still find ways for everyone who wants to be involved to contribute or lurk.</p><p><strong>The form will stay open until November 26th, 6 pm EST.</strong></p><p><em>For what it&apos;s worth, I think this is a strong step towards providing better </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/mDu_nGsWpjvF-KaPLADwxeAMfze3UJOtTAQi2CwPwWc"><em>context to decentralized digital identities</em></a><em> as well.</em></p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/3ccc0395d3c8a551a8e8c490f2f3bf10e5b201a1792491b6b75dfed634584f5b.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[SQL on Ethereum: How to Work With All the Data from a Transaction ]]></title>
            <link>https://paragraph.com/@ilemi/sql-on-ethereum-how-to-work-with-all-the-data-from-a-transaction</link>
            <guid>K51WM3fsW9583s9koUss</guid>
            <pubDate>Mon, 04 Oct 2021 13:39:55 GMT</pubDate>
            <description><![CDATA[if you’re looking for more web3 data content, check out my 30-day free course (with videos)!What&apos;s in your wallet?If you&apos;ve ever made a transaction on Ethereum (or any smart contract enabled blockchain), then you&apos;ve probably looked it up on a block explorer and seen this heap of information:and that&apos;s just the information on the first tabLearning to read the details of a transaction will be the foundation for all your Ethereum data analysis and knowledge, so let&apos;s cov...]]></description>
            <content:encoded><![CDATA[<p><em>if you’re looking for more web3 data content, check out my </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ournetwork.mirror.xyz/gP16wLY-9BA1E_ZuOSv1EUAgYGfK9mELNza8cfgMWPQ"><em>30-day free course (with videos)</em></a><em>!</em></p><h2 id="h-whats-in-your-wallet" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What&apos;s in your wallet?</h2><p>If you&apos;ve ever made a transaction on Ethereum (or any smart contract enabled blockchain), then you&apos;ve probably looked it up on a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/8e12aac74db238ebf11252740c3f65a8">block explorer</a> and seen this heap of information:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a7bcc5d836922c4fedae1ecf588aff8396942522d368793dfbe539cfb8955066.png" alt="and that&apos;s just the information on the first tab" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">and that&apos;s just the information on the first tab</figcaption></figure><p>Learning to read the details of a transaction will be the foundation for all your Ethereum data analysis and knowledge, so let&apos;s cover all the pieces and how to work with them in SQL. I&apos;ll be using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.xyz/browse/dashboards">Dune Analytics</a> to run my queries, but there are many other tools you can use to query the chain such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cloud.google.com/blog/products/data-analytics/ethereum-bigquery-public-dataset-smart-contract-analytics">Big Query</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.flipsidecrypto.com/">Flipside Crypto</a>.</p><p><em>If you&apos;re completely new to SQL and Ethereum I recommend starting with </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://towardsdatascience.com/your-guide-to-basic-sql-while-learning-ethereum-at-the-same-time-9eac17a05929"><em>my full beginners&apos; overview</em></a><em> first.</em></p><h2 id="h-guide-overview" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Guide Overview</h2><p>We&apos;re going to cover transactions in four layers:</p><ol><li><p>Transaction basics</p></li><li><p>Function calls and state</p></li><li><p>Internal Transactions (Traces)</p></li><li><p>Logs (Events Emitted)</p></li></ol><p>As the base for our transaction examples, we&apos;ll be using the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x320d83769Eb64096Ea74B686Eb586E197997f930">Mirror Crowdfund</a> contract. Put simply, this is a smart contract that allows you to get ERC20 (fungible) or ERC721 (NFTs) tokens in exchange for donating ETH to the contract. The creator of the contract can then withdraw those funds by closing the crowdfund. This is by no means a simple contract, but the point I want to make here is that you don&apos;t need to understand all the solidity code to start your analysis - you just need to know how to navigate the four layers above.</p><p><strong>The three transactions we&apos;ll study are:</strong></p><ol><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/a80c56a2e510d95f41984e6b7af1b8db">Creation/deployment</a> of the crowdfund contract</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/51c8f3ef63ea0e4b65a1abfdbbb9d1ef">Contributions of ETH</a> to the contract</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/8e12aac74db238ebf11252740c3f65a8">Closing and withdrawing funds</a> from the contract</p></li></ol><p><em>Side note, we also just opened up crowdfunds for anyone to use, so if you&apos;re curious or want to create a crowdfund head to </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/dashboard"><em>mirror.xyz/dashboard</em></a><em> to get started. Hop into </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/xsxhV9rkWA"><em>our discord</em></a><em> while you&apos;re at it!</em></p><h2 id="h-creationdeployment-of-the-crowdfund-contract" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Creation/Deployment of the crowdfund contract</h2><p><strong>First Transaction:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/tx/0x5e5ef5dd9d147028f9bc21127e3de774a80c56a2e510d95f41984e6b7af1b8db">0x5e5ef5dd9d147028f9bc21127e3de774a80c56a2e510d95f41984e6b7af1b8db</a></p><p>Let&apos;s start with the transaction basics.</p><ol><li><p>Each transaction has a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.stackexchange.com/questions/29936/what-happens-on-hash-collisions-for-e-g-transactions-blocks-and-contracts">unique keccak256</a> <code>transaction hash</code> of a few different variables</p></li><li><p>There&apos;s a <code>blocknumber</code> associated based on when the transaction was mined, typically a new block is created every 15 seconds.</p></li><li><p><code>From</code> is the one who signed the transaction, <code>To</code> is the contract address that was interacted with</p></li><li><p><code>Value</code> is the ETH value that was transferred <em>from the signer&apos;s wallet. Even if that value is 0 that doesn&apos;t mean that no ETH was transferred during the transaction.</em></p></li><li><p>Gas is a bit complicated (especially with EIP-1559), but just keep this formula in mind:</p><p><code>Gas Price * Gas Used by Transaction = Transaction Fee</code></p></li></ol><p>Now for the meat and bones, the <code>input data</code> of a transaction:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3ee50cc8bc2bafeee93586f7e52ab8645acd7a57fe5f72b9044174b3b7c49685.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 is just bytecode for any function call and the parameters passed in. The first 8 characters (4 bytes) are the function signature <code>0x849a3aa3</code>, essentially <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.ethers.io/v5/api/utils/abi/interface/#Interface--selectors">a hash of the function name and parameter types</a>. And no, these are <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rattibha.com/thread/1425217046636371969?lang=en">not always unique which can lead to hacks/security issues</a>. In this case, this function calls the factory contract to create the crowdfund contract (it&apos;s a proxy, but we won&apos;t get into that).</p><pre data-type="codeBlock" text="createCrowdfund((uint256,uint256,bytes32)[], (address,uint256), string, string, address, address, uint256, uint256, uint256)
"><code>createCrowdfund((<span class="hljs-keyword">uint256</span>,<span class="hljs-keyword">uint256</span>,<span class="hljs-keyword">bytes32</span>)[], (<span class="hljs-keyword">address</span>,<span class="hljs-keyword">uint256</span>), <span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>, <span class="hljs-keyword">address</span>, <span class="hljs-keyword">address</span>, <span class="hljs-keyword">uint256</span>, <span class="hljs-keyword">uint256</span>, <span class="hljs-keyword">uint256</span>)
</code></pre><p>This shows up if you click &quot;decode input data&quot;, and you can see the various variables values set as well. Every subsequent 64 characters (32 bytes) is a different input variable. The crowdfund comes with three tiers of editions. In this crowdfund for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blvkhvnd.mirror.xyz/">BLVKHVND</a> they used quantities of 1000, 250, and 50 with prices of 0.1, 0.3, and 1 ETH respectively.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/84a9550abf0d385009094fe2b54ed55cdad3c81afe97ca4b393f2713a3740711.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>Notice that the price actually shows up as <code>100000000000000000</code> , which is because the first 18 zeroes represent decimals. We&apos;ll have to do the conversions by dividing by <code>10^18</code> in our data.</p><p><strong>That was a lot, let&apos;s get to querying</strong>. Dune has a table called <code>ethereum.transactions</code> which has all the variables we&apos;ve talked about above for every transaction since the first block. We can query this table for the appearance of <code>0x849a3aa3</code> in the last few months:</p><pre data-type="codeBlock" text="SELECT * FROM ethereum.transactions 
WHERE &quot;block_time&quot; &gt; now() - interval &apos;3 months&apos;
AND &quot;data&quot; is not null
AND SUBSTRING ( encode(&quot;data&quot;, &apos;hex&apos;), 1, 8 ) = &apos;849a3aa3&apos;
"><code>SELECT <span class="hljs-operator">*</span> FROM ethereum.transactions 
WHERE <span class="hljs-string">"block_time"</span> <span class="hljs-operator">></span> <span class="hljs-built_in">now</span>() <span class="hljs-operator">-</span> interval <span class="hljs-string">'3 months'</span>
AND <span class="hljs-string">"data"</span> <span class="hljs-keyword">is</span> not null
AND SUBSTRING ( encode(<span class="hljs-string">"data"</span>, <span class="hljs-string">'hex'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">8</span> ) <span class="hljs-operator">=</span> <span class="hljs-string">'849a3aa3'</span>
</code></pre><p><code>ethereum.transactions</code> is a very large table, so if you query without filters the query is going to timeout (taking more than 30 minutes). Filtering by <code>block_time</code> is usually most useful, and in this case we&apos;re taking all the rows that have occurred within 3 months. Also, many transactions are just ETH transfers without any <code>data</code> attached so we&apos;ll filter that out by only keeping <code>data is not null</code>. Now for checking for the function signature, we need to <code>encode</code> the data into a string from hexadecimal, then take only the characters from position 1 to position 8 using <code>SUBSTRING</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b057977370934c4090d80fe2792c974c1a24cc0e2909877b2d5d963c2fb6fdaf.png" alt="https://dune.xyz/queries/192453 " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.xyz/queries/192453</figcaption></figure><p><strong>Now the complicated parts,</strong> internal transactions and events emitted. For this, it&apos;ll be easier to look at the code. If you go to the <code>contract</code> tab on etherscan and do a ctrl+f on file 1 of 10 you&apos;ll find the following code (I&apos;ve edited out some bits to make this more readable).</p><pre data-type="codeBlock" text="function createCrowdfund(
        ...variables...
    ) external returns (address crowdfundProxy) {
        ...some variable prep code...

        crowdfundProxy = address(
            new CrowdfundWithPodiumEditionsProxy{
                salt: keccak256(abi.encode(symbol_, operator_))
            }(treasuryConfig, operator_)
        );

        emit CrowdfundDeployed(crowdfundProxy, name_, symbol_, operator_);

        ...register to treasury code...
    }
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createCrowdfund</span>(<span class="hljs-params">
        ...variables...
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">address</span> crowdfundProxy</span>) </span>{
        ...some variable prep code...

        crowdfundProxy <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(
            <span class="hljs-keyword">new</span> CrowdfundWithPodiumEditionsProxy{
                <span class="hljs-built_in">salt</span>: <span class="hljs-built_in">keccak256</span>(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encode</span>(symbol_, operator_))
            }(treasuryConfig, operator_)
        );

        <span class="hljs-keyword">emit</span> CrowdfundDeployed(crowdfundProxy, name_, symbol_, operator_);

        ...register to treasury code...
    }
</code></pre><p><strong>The first key line here is</strong> <code>crowdfundProxy = address(contract_to_be_created)</code>, which is what deploys the new contract and creates an internal transaction of type <code>CREATE 0</code>. Transferring ETH also creates an internal transaction of type <code>CALL</code> , which we&apos;ll see in the next transaction we study.</p><p>We can query for all the crowdfund contracts created with:</p><pre data-type="codeBlock" text="SELECT tx.&quot;block_time&quot;, tx.&quot;from&quot;, tr.&quot;type&quot;, tr.&quot;code&quot;
FROM ethereum.transactions tx 
LEFT JOIN ethereum.traces tr ON tx.&quot;hash&quot;=tr.&quot;tx_hash&quot; --tracks internal transactions
WHERE tx.&quot;to&quot; = &apos;\x15312b97389a1dc3bcaba7ae58ebbd552e606ed2&apos; -- crowdfund podiums edition
AND tr.&quot;type&quot; = &apos;create&apos; 
"><code>SELECT <span class="hljs-built_in">tx</span>."block_time<span class="hljs-string">", tx."</span><span class="hljs-keyword">from</span><span class="hljs-string">", tr."</span><span class="hljs-keyword">type</span><span class="hljs-string">", tr."</span>code<span class="hljs-string">"
FROM ethereum.transactions tx 
LEFT JOIN ethereum.traces tr ON tx."</span>hash<span class="hljs-string">"=tr."</span>tx_hash<span class="hljs-string">" --tracks internal transactions
WHERE tx."</span>to<span class="hljs-string">" = '\x15312b97389a1dc3bcaba7ae58ebbd552e606ed2' -- crowdfund podiums edition
AND tr."</span><span class="hljs-keyword">type</span><span class="hljs-string">" = 'create' 
</span></code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ae4a5268c443462f14f71c0a648bfc04c0646c54dba2678e324bc92927489b60.png" alt="https://dune.xyz/queries/192466" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.xyz/queries/192466</figcaption></figure><p>We need <code>ethereum.transactions</code> because we want to filter for traces (internal transactions) only related to transactions on the factory contract. We need this since an internal transaction will not always have the same <code>to</code> as that of the overall transaction. We can JOIN the tables on the transaction hash, and then filter for only internal transactions of the <code>create</code> type.</p><p><strong>The second key line here is</strong> <code>emit CrowdfundDeployed</code>, which creates a log that is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.stackexchange.com/questions/1302/where-do-contract-event-logs-get-stored-in-the-ethereum-architecture">stored in the node but not in the block</a>. If you look at the logs, you&apos;ll notice that <code>EditionCreated</code> events are also emitted, but this is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xc4e0f3ec24972c75df7c716922096f4270b7bb4e">from another contract that</a> actually creates the ERC721 tokens (hence a different address).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/236c02eb110a89dbb618a607ce21587e6136da0e3e19824df600059371b85c8c.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>Similar to a function signature, events have a unique hash as well that sits in <code>Topic 0</code>. So in the events above, <code>0x5133bb164b64ffa4461bc0c782a5c0e71cdc9d6c6ef5aa9af84f7fd2cd966d8e</code> is the hash for <code>CrowdfundDeployed</code> and <code>0xbaf1f6ab5aa5406df2735e70c52585e630f9744f4ecdedd8b619e983e927f0b6</code> is the hash for <code>EditionCreated</code>.</p><p>We can query the <code>ethereum.logs</code> table in dune to see all crowdfunds created as well:</p><pre data-type="codeBlock" text="SELECT * FROM ethereum.logs
WHERE &quot;topic1&quot;=&apos;\x5133bb164b64ffa4461bc0c782a5c0e71cdc9d6c6ef5aa9af84f7fd2cd966d8e&apos;::bytea
"><code>SELECT <span class="hljs-operator">*</span> FROM ethereum.logs
WHERE <span class="hljs-string">"topic1"</span><span class="hljs-operator">=</span><span class="hljs-string">'\x5133bb164b64ffa4461bc0c782a5c0e71cdc9d6c6ef5aa9af84f7fd2cd966d8e'</span>::bytea
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e0cae204c1ac6c7b1253b8e46b478492e31d3b84e4a02c10b92d3555045b968a.png" alt="https://dune.xyz/queries/192553" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.xyz/queries/192553</figcaption></figure><p><code>topic2</code> and <code>topic3</code> typically hold the data for ETH transfers, otherwise, event data will show up in the <code>data</code> column. We&apos;ll get more into how to work with this later.</p><p>Logs are very helpful, as they can be used to emit state variables instead of just the function call values (TheGraph <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/developer/create-subgraph-hosted">uses logs to model subgraphs</a> for GraphQL queries). Next, we&apos;ll utilize everything we&apos;ve covered to study the contributions of ETH to our newly created crowdfund contract (sitting at the address <code>0x320d83769eb64096ea74b686eb586e197997f930</code> ).</p><p><em>If you&apos;ve made it this far, then you&apos;re already through all the tough concepts. Give yourself a pat on the back! We&apos;ll really be getting into the details in the next two sections, so take a breather if you need to.</em></p><h3 id="h-contributions-of-eth-to-the-contract" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Contributions of ETH to the contract</h3><p><strong>Second Transaction:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/tx/0xd4ce80a5ee62190c5f5d5a5a7e95ba7751c8f3ef63ea0e4b65a1abfdbbb9d1ef">0xd4ce80a5ee62190c5f5d5a5a7e95ba7751c8f3ef63ea0e4b65a1abfdbbb9d1ef</a></p><p>This one is fairly simple to read. Jesse paid 1 ETH to mint an edition of tokenId 167 from the BLVKHVND crowdfund. He also got 1000 HVND, the ERC20 token the crowdfund gives out based on the size of the donation.</p><p>But what if we wanted to see how much ETH has been contributed over time, or how many editions have been sold? Sometimes contracts will have a view function in <code>Read Contract</code> on etherscan where you can get total balances. But in this case, the contract doesn&apos;t have that.</p><p>Remember that function calls change the state data, which we&apos;ll need to piece together the overall state data by aggregating over transaction history. Sometimes the overall state of a contract can be emitted in events, such as with Compound V2&apos;s <code>AccrueInterest</code> event.</p><p>In our case, we&apos;ll need to do two things in one query to get to total ETH contributed:</p><ol><li><p>get the transactions that have the &quot;contribute&quot; method called</p></li><li><p>sum the total ETH transferred by filtering for internal transactions which have the type <code>CALL</code></p></li></ol><p><em>Remember, I can get the method function signature by decoding the</em> <code>input data</code> on etherscan.</p><pre data-type="codeBlock" text="SELECT SUM(tr.&quot;value&quot;/1e18) as contribution FROM ethereum.transactions tx 
LEFT JOIN ethereum.traces tr ON tx.&quot;hash&quot; = tr.&quot;tx_hash&quot;
--transactions filtering 
WHERE tx.&quot;to&quot; = &apos;\x320d83769eb64096ea74b686eb586e197997f930&apos;::bytea
AND tx.&quot;data&quot; is not null
AND SUBSTRING ( encode(tx.&quot;data&quot;, &apos;hex&apos;), 1, 8 ) IN (&apos;a08f793c&apos;, &apos;ce4661bb&apos;)
--traces filtering 
AND tr.&quot;success&quot;
AND tr.&quot;value&quot; &gt; 0
AND tr.&quot;call_type&quot; = &apos;call&apos;
"><code><span class="hljs-keyword">SELECT</span> <span class="hljs-built_in">SUM</span>(tr."value"<span class="hljs-operator">/</span><span class="hljs-number">1e18</span>) <span class="hljs-keyword">as</span> contribution <span class="hljs-keyword">FROM</span> ethereum.transactions tx 
<span class="hljs-keyword">LEFT</span> <span class="hljs-keyword">JOIN</span> ethereum.traces tr <span class="hljs-keyword">ON</span> tx."hash" <span class="hljs-operator">=</span> tr."tx_hash"
<span class="hljs-comment">--transactions filtering </span>
<span class="hljs-keyword">WHERE</span> tx."to" <span class="hljs-operator">=</span> <span class="hljs-string">'\x320d83769eb64096ea74b686eb586e197997f930'</span>::bytea
<span class="hljs-keyword">AND</span> tx."data" <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">null</span>
<span class="hljs-keyword">AND</span> <span class="hljs-built_in">SUBSTRING</span> ( encode(tx."data", <span class="hljs-string">'hex'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">8</span> ) <span class="hljs-keyword">IN</span> (<span class="hljs-string">'a08f793c'</span>, <span class="hljs-string">'ce4661bb'</span>)
<span class="hljs-comment">--traces filtering </span>
<span class="hljs-keyword">AND</span> tr."success"
<span class="hljs-keyword">AND</span> tr."value" <span class="hljs-operator">></span> <span class="hljs-number">0</span>
<span class="hljs-keyword">AND</span> tr."call_type" <span class="hljs-operator">=</span> <span class="hljs-string">'call'</span>
</code></pre><p>There was technically another method called <code>contributeForPodium</code>, which is why we check for two function signatures above. The <code>CALL</code> type actually has subtypes as well at the opcode level, so we need the specific base <code>call_type</code> of <code>call</code> (if you&apos;re familiar with a delegatecall, then you&apos;ll know that would give us a double count). We joined on transaction hash, and then divided by 10^18 to get the right decimals of ETH value.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/15f1bf4745cb0f5485e481384d09ebad7e36093e87554a0ae779decd0ea97845.png" alt="https://dune.xyz/queries/192577" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.xyz/queries/192577</figcaption></figure><p>Let&apos;s move on to the last transaction, where the data starts to get really tricky on us.</p><h3 id="h-closing-and-withdrawing-funds-from-the-contract" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Closing and withdrawing funds from the contract</h3><p><strong>Third Transaction:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/tx/0xe9d5fefde77d4086d0f64dd1403f9b6e8e12aac74db238ebf11252740c3f65a8">0xe9d5fefde77d4086d0f64dd1403f9b6e8e12aac74db238ebf11252740c3f65a8</a></p><p>Here, we can see that 337 ETH was transferred and 1,012,965 HVND tokens (the latter of which was decided by <code>operatorPercent_</code> in the first transaction). After this function is called, the contract just operates the way any normal ERC20 would.</p><p>In the case that a crowdfund was already closed, we could have gotten the total raised from the data in this transaction - such as value transferred in an internal transaction of <code>CALL</code> type. It&apos;s better to tie this to an event though, in case there are some transfer behaviors that we don&apos;t know about. <em>But wait, why are the logs not readable?</em></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/03164cfdab0936fa943bc5f826269dccf663d04ffe60ff7be87d8e2c53feae27.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>Well, this is where we start to get into some pretty confusing patterns. Earlier I mentioned that this crowdfund is deployed as a proxy - that means it’s just like an empty USB that plugs into a computer that actually holds the logic. It&apos;s much cheaper to create USBs than computers - and that logic holds for on-chain too (except the cost is in gas). If you want to read about proxy patterns, I&apos;d check out <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades/">this great article by the OpenZeppelin team</a>.</p><p>The computer in this case is known as the <em>logic</em> and is only deployed once. The proxy is deployed many times, and it doesn&apos;t have the logic functions or events in the contract code. Therefore, etherscan isn&apos;t equipped to show the decoded data in logs. So then how do we piece this together? We could take the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://codeburst.io/deep-dive-into-ethereum-logs-a8d2047c7371">keccak256 hash of the event</a>, just like we did for function signatures. But here&apos;s where reading the code will help save you some time. If you go to <code>Read Contract</code> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x15312b97389a1dc3bcaba7ae58ebbd552e606ed2">on the factory contract</a>, you&apos;ll see the address of the logic contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/31491d542c768f5d5d019466575a63c20055ff4cb7d927049c571513fe2ebe88.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>From there, we can look for the <code>closeFunding()</code> function in the code:</p><pre data-type="codeBlock" text="function closeFunding() external onlyOperator nonReentrant {
        ...code...

        _mint(operator, operatorTokens);
        // Announce that funding has been closed.
        emit FundingClosed(address(this).balance, operatorTokens);

        ...ETH value transfers...
    }
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">closeFunding</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOperator</span> <span class="hljs-title">nonReentrant</span> </span>{
        ...<span class="hljs-built_in">code</span>...

        _mint(operator, operatorTokens);
        <span class="hljs-comment">// Announce that funding has been closed.</span>
        <span class="hljs-keyword">emit</span> FundingClosed(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>, operatorTokens);

        ...ETH value transfers...
    }
</code></pre><p>ETH value transfers don&apos;t emit events since they are just internal transactions. And if you are familiar with how the ERC20 standard works, you&apos;ll know that <code>_mint</code> actually creates a <code>Transfer</code> event (meaning that covers our first event). That means that <code>FundingClosed</code> must be the second log, with the topic of <code>0x352ce94da8e3109dc06c05ed84e8a0aaf9ce2c4329dfd10ad1190cf620048972</code>. Can you figure out why else it couldn&apos;t be the third log (<strong>hint:</strong> what&apos;s a key difference between the first two logs and the third log)?</p><p>With that knowledge, we can query this just like any other event, with some fancy data decoding (remember parameters are every 64 characters (32 bytes). We have to turn it into a string to slice it, and then we change it into a number and divide by 10^18 to get rid of decimals.</p><pre data-type="codeBlock" text="SELECT &quot;contract_address&quot;, 
        bytea2numeric( decode ( SUBSTRING ( encode(&quot;data&quot;, &apos;hex&apos;) , 1, 64 ), &apos;hex&apos;))/1e18 as eth_raised, 
        bytea2numeric ( decode ( SUBSTRING ( encode(&quot;data&quot;, &apos;hex&apos;) , 65 , 64 ), &apos;hex&apos;))/1e18 as tokens_allocated_owned
FROM ethereum.logs
WHERE &quot;topic1&quot;=&apos;\x352ce94da8e3109dc06c05ed84e8a0aaf9ce2c4329dfd10ad1190cf620048972&apos;::bytea
AND &quot;contract_address&quot;=&apos;\x320d83769eb64096ea74b686eb586e197997f930&apos;::bytea
"><code>SELECT <span class="hljs-string">"contract_address"</span>, 
        bytea2numeric( decode ( SUBSTRING ( encode(<span class="hljs-string">"data"</span>, <span class="hljs-string">'hex'</span>) , <span class="hljs-number">1</span>, <span class="hljs-number">64</span> ), <span class="hljs-string">'hex'</span>))<span class="hljs-operator">/</span><span class="hljs-number">1e18</span> <span class="hljs-keyword">as</span> eth_raised, 
        bytea2numeric ( decode ( SUBSTRING ( encode(<span class="hljs-string">"data"</span>, <span class="hljs-string">'hex'</span>) , <span class="hljs-number">65</span> , <span class="hljs-number">64</span> ), <span class="hljs-string">'hex'</span>))<span class="hljs-operator">/</span><span class="hljs-number">1e18</span> <span class="hljs-keyword">as</span> tokens_allocated_owned
FROM ethereum.logs
WHERE <span class="hljs-string">"topic1"</span><span class="hljs-operator">=</span><span class="hljs-string">'\x352ce94da8e3109dc06c05ed84e8a0aaf9ce2c4329dfd10ad1190cf620048972'</span>::bytea
AND <span class="hljs-string">"contract_address"</span><span class="hljs-operator">=</span><span class="hljs-string">'\x320d83769eb64096ea74b686eb586e197997f930'</span>::bytea
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/60a3e3027416a7fe23444c2156655d82febec28a2d5b34e36d6bd32f12f01822.png" alt="https://dune.xyz/queries/192560 " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.xyz/queries/192560</figcaption></figure><p>Congrats, you now know your way around <code>ethereum.transactions</code>, <code>ethereum.traces</code>, and <code>ethereum.logs</code>. They can always be joined by transaction hash, and then the rest is just knowing how to manipulate the data with <code>encode/decode</code>, <code>substring</code>, and some <code>bytea</code> operators. Woohoo!</p><p><em>We could have done this exercise for the</em> <code>contribute</code> method in the last transaction too. Since this is all happening on the proxy contract.</p><h3 id="h-putting-it-all-together" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Putting it all together</h3><p>Now, if we had to go and keep track of function signatures and event topics - as well as decoding all the variables in each query - I think we would have all quit data analysis by now. Luckily, most data services have some variation of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://duneanalytics.com/decode"><strong>contract decoding</strong></a><strong>,</strong> meaning I can give a contract address and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.7/abi-spec.html#:~:text=The%20Contract%20Application%20Binary%20Interface,contract%2Dto%2Dcontract%20interaction.&amp;text=This%20specification%20does%20not%20address,known%20only%20at%20run%2Dtime.">the ABI</a> and Dune will take care of the decoding for me. That way, events/functions become their own tables and I can easily make the same &quot;total contributions&quot; query from earlier with this:</p><pre data-type="codeBlock" text="WITH 
    union_sum as (
        SELECT SUM(&quot;amount&quot;)/1e18 as raised FROM mirror.&quot;CrowdfundWithPodiumEditionsLogic_evt_Contribution&quot;
        WHERE &quot;contract_address&quot;=&apos;\x320d83769eb64096ea74b686eb586e197997f930&apos;
        
        UNION ALL 
        
        SELECT SUM(&quot;amount&quot;)/1e18 as raised FROM mirror.&quot;CrowdfundWithPodiumEditionsLogic_evt_ContributionForEdition&quot;
        WHERE &quot;contract_address&quot;=&apos;\x320d83769eb64096ea74b686eb586e197997f930&apos;
    )
    
SELECT SUM(&quot;raised&quot;) FROM union_sum
"><code><span class="hljs-keyword">WITH</span> 
    union_sum <span class="hljs-keyword">as</span> (
        <span class="hljs-keyword">SELECT</span> <span class="hljs-built_in">SUM</span>("amount")<span class="hljs-operator">/</span><span class="hljs-number">1e18</span> <span class="hljs-keyword">as</span> raised <span class="hljs-keyword">FROM</span> mirror."CrowdfundWithPodiumEditionsLogic_evt_Contribution"
        <span class="hljs-keyword">WHERE</span> "contract_address"<span class="hljs-operator">=</span><span class="hljs-string">'\x320d83769eb64096ea74b686eb586e197997f930'</span>
        
        <span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span> 
        
        <span class="hljs-keyword">SELECT</span> <span class="hljs-built_in">SUM</span>("amount")<span class="hljs-operator">/</span><span class="hljs-number">1e18</span> <span class="hljs-keyword">as</span> raised <span class="hljs-keyword">FROM</span> mirror."CrowdfundWithPodiumEditionsLogic_evt_ContributionForEdition"
        <span class="hljs-keyword">WHERE</span> "contract_address"<span class="hljs-operator">=</span><span class="hljs-string">'\x320d83769eb64096ea74b686eb586e197997f930'</span>
    )
    
<span class="hljs-keyword">SELECT</span> <span class="hljs-built_in">SUM</span>("raised") <span class="hljs-keyword">FROM</span> union_sum
</code></pre><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.xyz/queries/192571">https://dune.xyz/queries/192571</a></p><p>Thankfully this query is much more readable and easier to write. They even take care of proxy/factory logic patterns - thanks team! Without this abstraction, I guarantee that data analysis would be ten times messier to write and one hundred times worse to debug. Dune has plenty of other useful tables as well, such as <code>prices.usd</code> for daily token prices and <code>dex.trades</code> for all token trades across all main exchanges (and event <code>nft.trades</code> for OpenSea NFT actions).</p><p>While most of the time you&apos;ll be playing with decoded data, knowing what really sits underneath it all will help you level up a lot faster in Web3! Plus, you&apos;re now etherscan fluent - which I promise will be a part of every crypto job description in the future. I hope you found this helpful, and as always feel free to reach out if you need some help getting started.</p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/dd3e22f924c708f12df7bc56208e66f06cc717cb461bad4884c30b33400ed99d.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Composable Membership and its Role in Generating Social Capital]]></title>
            <link>https://paragraph.com/@ilemi/composable-membership-and-its-role-in-generating-social-capital</link>
            <guid>fVH04Ci34JB6SeFUvo0D</guid>
            <pubDate>Mon, 27 Sep 2021 13:11:12 GMT</pubDate>
            <description><![CDATA[Having a token brings a community together loosely with a financial stake, but composable membership holds a community together long term with social capital. That&apos;s a lot of buzzwords, so let’s explore this in three parts:How access, permissions, and status are the primary components of membership (and the role of tokens)Membership in Web2 versus Web3 platforms, and why composability matters hereDesigning a membership system to generate social capitalAccess, Permissions, and StatusOur d...]]></description>
            <content:encoded><![CDATA[<p>Having a token brings a community together loosely with a financial stake, but composable membership holds a community together long term with social capital. That&apos;s a lot of buzzwords, so let’s explore this in three parts:</p><ol><li><p>How access, permissions, and status are the primary components of membership (and the role of tokens)</p></li><li><p>Membership in Web2 versus Web3 platforms, and why composability matters here</p></li><li><p>Designing a membership system to generate social capital</p></li></ol><h3 id="h-access-permissions-and-status" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>Access, Permissions, and Status</strong></h3><p>Our <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/mDu_nGsWpjvF-KaPLADwxeAMfze3UJOtTAQi2CwPwWc">data and actions give us identity and relationships</a>, but having a social graph does not give you community. Put in a Web3 context, a group of people holding or trading the same token does not mean you are a community - at best, it gives you clusters. **An actual community has fairly clear boundaries for growth (in more than a financial sense). You&apos;ve probably seen some variation on the chart below...</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/60eda2052a0bd927d823c2e0f7e7ce88bda7ba9ee915f1aa47b2c761ae9f5ca5.png" alt="https://github.com/orbit-love/orbit-model" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://github.com/orbit-love/orbit-model</figcaption></figure><p>... where you can identify your core contributors, and try to reward or incentivize them accordingly. Pet3rpan has put this concentric community chart nicely in a Web3 context, showcasing the funnel of activities a participant might engage in during their lifecycle in a community:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8f3589c1be8bc9fc98d05a18016a9ed5451dee63697bf51dfe11eb1b1bcd40d0.png" alt="https://medium.com/1kxnetwork/how-to-grow-decentralized-communities-1bf1044924f8 " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://medium.com/1kxnetwork/how-to-grow-decentralized-communities-1bf1044924f8</figcaption></figure><p>But just because someone has participated in any of the above events, doesn&apos;t mean they feel like they&apos;re part of the community. Even giving them tokens for their participation doesn&apos;t really move the needle.</p><p>Tokens are open primitives that membership should be built upon, and just issuing more POAPs or tokens based on events and then moving on is like distributing the raw materials for a house and expecting the people to build up a town. Without a blueprint, people will just stash the materials and leave (or sell them to someone else). In crypto, we’re supply rich, but guidance poor.</p><p>Some communities at least take the first step to have some sort of access dependent on your token activities, usually a Discord server or channel. But access is only the first step to membership. Permissions are too closely tied to access right now, and status is left as too abstract a concept.</p><p>So let&apos;s improve on the current model. <strong><em>Access is discovery, permissions are responsibility, status is weight.</em></strong> This membership funnel is shaped different from the activity funnel above, as the customizable design area gets larger the deeper you go:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1ffb709b4081cab7d6fe333638d12bab5d68b5e7ec7af7359610611c9fead085.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>These are basic examples, but they help lay the groundwork for how each layer could be tied to different types (and combinations) of tokens. Let&apos;s look at some token design examples for each level:</p><ul><li><p><strong>Access:</strong> For the most part, <em>ERC20&apos;s are best for access because requirements are fluid and the tokens are more liquid.</em> Today I might require 50 tokens to join, but in the future, I may drop it to 25 or increase it to 75 based on community needs (going wide versus deep). NFTs are cultural assets, so if you use that as the gate then it&apos;ll be tough to say you need two or more to have access now. Even if you implement project derivatives, liquidity becomes fragmented and confusing. This is project-dependent though, and Creator Cabins did a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://creators.mirror.xyz/V7Ucba89-3qV9yFxj7Spj7YxjKAhc6TOd8nUcCp9n6k">great overview of some of the tradeoffs</a>.</p></li><li><p><strong>Permissions:</strong> <em>I personally believe permissions should be tightly coupled to a stake.</em> To be given the responsibility for some set of actions, there should be risk involved. Unlike access, permissions should evolve and can be revoked. If I&apos;m making proposals, allowing staking will show my commitment and also give others the opportunity of <em>joining my stake</em>. This line of design can help a community better balance abuse of power and opportunities for discovery (of great new contributors).</p></li><li><p><strong>Status:</strong> <em>This layer has the largest area because it is tied to attributes and metadata.</em> Status in a community has the highest amount of variance, as it will likely be event-dependent. Taking the treasury &quot;weighted voting power&quot; example, if you give status based on what is being voted on that highlights specific community members while also ensuring that it isn&apos;t always the participant with the most tokens has the most sway. NFTs are a great place to play with these attributes, especially through derivative and forge-based projects. <em>To clarify, this is not the same as reputation since reputation needs to be less fluid as to not confuse people. We&apos;ll get more into that later.</em></p></li></ul><p>Different combinations of these layers could be bundled into &quot;roles&quot; for easier management and assignment. I&apos;d love to dive right into a membership system, but first we need to clear out the current mental heuristics around how Web2 &quot;membership&quot; works.</p><h3 id="h-composable-membership-and-the-role-of-platforms-web2-vs-web3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Composable <strong>Membership and the Role of Platforms (Web2 vs Web3)</strong></h3><p><em>In Web2, membership forms around services. In Web3, services from around membership.</em> Put simply, being a YouTube subscriber does not affect your privileges when engaging in a Twitch chat or a subreddit. This kind of membership interoperability is certainly possible in Web2, and I think Patreon was the closest to getting a hierarchical membership structure in place. We could have seen a world that 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/2733d60a206f33cdfbf8d4e60da89ae560d0fe5933fcdb57999b0cdbdebad49e.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>But obvious arguments would ensue over who owns the master API, and economic flow incentives also act as a blocker since the platform at the top of the hierarchy likely has the highest money-in/money-out flow and take-rate. So in the end we have like 7 or more different memberships to manage! No one actually wants that besides the platforms themselves.</p><p>In Web3, no one is fighting to be at the top of the membership hierarchy because the primitives (tokens) aren&apos;t owned by any one platform. Smart contracts are our APIs and we can code revenue splits right into them. If that isn&apos;t enough, we can devise governance and attribution systems over the treasury to ensure the services and tooling built around membership continuously benefits communities that rely on them. In the end, the above Web2 platforms will naturally fall lower on the hierarchy. <strong>They will be forced to fit around the composable membership systems that we all enable and create. In other words, the community is the platform:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/76a9cb5d42617e9db6a724c6a2b52dac73d2fad3bb71f6ae66f3c716a18d006b.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>There&apos;s an argument to be made that in the end, apps will just be a bunch of composable components where each piece is owned by a different platform. But in the interim, it&apos;ll be Web3 communities plugging into the currently better interfaces of Web2. When planning a membership system, we&apos;ll need to think about membership as bundles of access, permission, and status across these Web2 services. If I&apos;m a multisig member, what roles will I need across all these services and how can that be managed in a single token/membership model? To figure this out, we&apos;d need to experiment. And to experiment, we need social capital.</p><h3 id="h-a-membership-system-for-generating-social-capital" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">A <strong>Membership System for Generating Social Capital</strong></h3><p>We&apos;ve defined the components of membership and situated them within the Web2 and Web3 context. Now, let&apos;s have fun designing a system that could actually go into implementation. <strong><em>We&apos;ll define social capital as building an allowance for trust, experimentation, and flexibility within a community.</em></strong> This means having a membership system that improves ownership of decisions and prevents a social fork. For now, my guess is there are three main steps to execute membership and generate this new capital:</p><ol><li><p><strong>Define Roles:</strong> Roles are bundles of the different layers of membership and are tied to specific participant personas. There are likely hundreds of combinations (especially if you layer token types on top), but some immediate roles that come to mind are:</p><ul><li><p><code>Low Access (ERC20) + Low Permissions (ERC20 Stake) = new member</code></p></li><li><p><code>High Permissions (ERC20 Stake) + High Status (NFT) = long time contributor</code></p></li><li><p><code>High Access (NFT) + High Status (NFT) = subject matter expert</code></p></li><li><p><code>High Access (ERC20) + High Permissions (ERC20 Stake) + High Status (NFT) = founding member</code></p></li></ul><p>Doing this well opens up a pathway for growth and also clarity for all members. This starts to give us history too, as I can clearly see how a community has matured by its role definitions and distribution (much more so than if I just look at the token price).</p></li><li><p><strong>Specify Incentivizes:</strong> Pet3rpan mentioned in the article linked earlier that <em>trust and engagement are key to participation.</em> Financial incentives are a great starting point - if you airdropped me $1000 of your community&apos;s tokens, I&apos;d definitely come to take a look and see what I can help with. But if these drops/bounties are filtered by role or membership history, we can be much more flexible with asks and rewards and I&apos;d likely feel more fulfilled. This is the difference between me tackling a data bounty as a nobody versus as a Dune Wizard.</p><p>This could also look like a hackathon where teams are built based on role/membership history, such that newer members are matched with older members. Or imagine if hackathon bounties rewarded community roles instead of just $$$, I think we&apos;d end up seeing an even larger diversity of projects and teams in hackathons than we do today.</p><p>Also, I cannot stress enough the importance of history here. <code>Membership + Identity + Relationships</code> will probably be the best proxy for a reputation score, which opens up the path to more creatively weighted incentives.</p></li><li><p><strong>Assign Roles:</strong> This step is more technically difficult than the others, given the challenge of plugging membership systems into existing platforms. I think this is similar to the integration problems that any wallet aggregator already faces, for example, Zapper&apos;s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://features.zapper.fi/">protocol requests</a>. Integrating into existing Web2 platforms shouldn&apos;t be difficult, but as more Web3 platforms are built the composability will be difficult to manage.</p><p>But as long as we have an identity solution (connecting addresses to user metadata across platforms) and a membership solution (managing roles and tokens intuitively), I think we&apos;ll be able to tackle the platform integration problem elegantly. Besides, building the first two will take the ecosystem the next six months anyway.</p></li></ol><p>Hopefully, this system helps show how much we can bring a community together while experimenting by using membership built off of tokens. I know for some people this is all still too fluffy, so I plan on doing data-driven case studies to better inform this kind of membership system in the future (and to try to be more quantitative about social capital). Some communities I&apos;m interested in studying under this lens are Yearn, Blitmaps, and Superfluid - but if you have other case studies that come to mind, please do let me know.</p><h2 id="h-concluding-thoughts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Concluding Thoughts</h2><p>Composable membership shapes more than just communities, it will shape ecosystems and platforms as well. In crypto, we&apos;re all building platforms that give communities the tooling for implementation, visibility, collaboration, and much more. Ecosystems are forming around metadata already, and this will force a reorganization of Web2 platforms to provide a much more open surface to be built upon.</p><p>Mirror is one platform trying to improve the tooling for communities to implement a rewarding membership system:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3c016b3c0e24334374b35ea742caea25c178c155d02c556bb6d14ddd77fb7684.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>Seed Club is a good example of the model above, where they <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://club.mirror.xyz/dnN3Dwe-iD6jBpzkase4YLHTxYtnuFnmUbSoOfPEkjI">deploy ERC20 tokens for specific communities and causes</a>, and once members are more defined they move on to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://club.mirror.xyz/token-race/bafkreidnqdtyls7q62w6mvfuaiwzn52ivlvephw4wul7g5ph2lqbjzymom">specialized token distribution methods such as the token race</a> for engaging the community and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://club.mirror.xyz/Q5QwN3Uol03pOK8MhAVsfwc0ektDlrkrl6sVSoC2UwA">adding new cohorts</a>. I think there is a lot more we all can do to standardize the membership implementation process laid out in this article, using Mirror and ecosystem tooling.</p><p>But none of what I&apos;ve written about can sustainably happen unless communities take their thinking around membership more seriously (and that goes for me too). If any of this interests you, please reach out so that we can build out this future together. My <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/andrewhong5297">twitter DMs</a> are always open! 🙂</p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/d6e75a3725cf375c29d9f7ae06e45eb94842a37894cb73d1dedbf868701c3850.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[thoughts from my first year in crypto and on joining mirror]]></title>
            <link>https://paragraph.com/@ilemi/thoughts-from-my-first-year-in-crypto-and-on-joining-mirror</link>
            <guid>60fhUoKTVYh2m0E0AH7I</guid>
            <pubDate>Mon, 30 Aug 2021 22:30:52 GMT</pubDate>
            <description><![CDATA[It&apos;s been almost one year since I really entered crypto, which I count as the day I first subscribed to @bankless. It&apos;s been quite a fun journey, and I&apos;d love to share the path I took and some of the lessons learned.First Bankless ReceiptLife Before Crypto:Before I entered crypto, I worked at a large investment bank in their rotational grad program. Over two years, I worked with different teams on everything from managing the bank&apos;s liquidity to our commercial real estate ...]]></description>
            <content:encoded><![CDATA[<p>It&apos;s been almost one year since I really entered crypto, which I count as the day I first subscribed to @bankless. It&apos;s been quite a fun journey, and I&apos;d love to share the path I took and some of the lessons learned.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b1242dad271df6707b59dc16ce4edf6cfb1b3a6f9f392aaa6b7f970691a02220.png" alt="First Bankless Receipt" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">First Bankless Receipt</figcaption></figure><h2 id="h-life-before-crypto" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Life Before Crypto:</h2><p>Before I entered crypto, I worked at a large investment bank in their rotational grad program. Over two years, I worked with different teams on everything from managing the bank&apos;s liquidity to our commercial real estate portfolio.</p><p>When I started there in the Summer of 2019, I saw there was a lot of unstructured data both public and internal that could be leveraged with the right tools. I quickly decided I needed to upskill from just Excel, and immediately began learning Python to do some time series forecasting for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.investopedia.com/terms/l/liquidityrisk.asp">liquidity risk</a>. I would read every day about <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://machinelearningmastery.com/arima-for-time-series-forecasting-with-python/">autoregressive and moving average models</a>, try to implement them for some basic dataset, and then do a presentation to my few coworkers to get their feedback. That feedback would lead to lessons learned on how I could better apply and communicate my findings, but also would usually end with &quot;here&apos;s this other person who you can learn from about this&quot;. This would create multiple avenues of learning to then go down again, repeating the process. I eventually called this a <code>learn-build-teach</code> cycle, and it helped me stay motivated and keep momentum.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/801d29c4264b03419cd98ebd67c078fb59c703c177822d05c6fa93f26dc7014f.png" alt="&quot;present&quot; was probably more accurate than &quot;teach&quot; in the early days" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">&quot;present&quot; was probably more accurate than &quot;teach&quot; in the early days</figcaption></figure><p>After a while, I realized that I did most of my learning through reading other peoples&apos; presentations on what they had already built (mostly on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://towardsdatascience.com/">Towards Data Science</a>). Around May of 2020, I wanted to try and give back to the data science community and write about the skills and projects I&apos;d developed over time. This was a great way to learn in the open where I would get comments or messages giving me feedback, and also led to many new connections on LinkedIn who were farther out from my usual network.</p><p>I was heavily reliant on developer communities when learning various Python packages, and could clearly tell the difference between a product that was loved by its community versus one that didn&apos;t really connect as well with newer developers. Seeing the stark differences, I decided to go deep down the community software-as-a-service rabbit hole to find out what tools were being built to help dev tool product teams with building their communities. This research led me to conversations with builders like John Yen (Yeniverse), and Patrick Woods (orbit.love). They inspired me to try and improve the developer onboarding experience for dev tooling communities.</p><p>This started with building an NLP analysis product that could help with three things:</p><ol><li><p>identify the most commonly asked questions to enhance or auto-generate an FAQ page.</p></li><li><p>match questions and answers to create an auto-response discord bot. The idea here was just to try and save the team time.</p></li><li><p>identity the questions developers ask over time in the discord to map out when users try and develop with different features. This could help with user research and also product road mapping.</p></li></ol><p>While that endeavor of mine didn&apos;t get too far, this had planted a seed in me to continue observing and thinking about community building. Fall of 2020 came along, and I began to tap into one of the most well-connected and vibrant communities out there: Ethereum. Right away I could see that everything was open, from the data to the code to the people. This was a large departure from traditional finance, <em>where it often takes months just to get a conversation or data partnership going within the same bank</em>.</p><h2 id="h-how-i-got-started" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How I Got Started:</h2><p>It took many many tries over the years to start &quot;getting into&quot; Ethereum. In July of 2020 I took a more serious stab at it; I tried reading and re-reading the Ethereum and Uniswap whitepapers, digesting my transactions on Etherscan, and listening to various podcast interviews. Bankless helped me understand the people and ideas to follow, but things didn&apos;t fully click until I started learning Solidity. Some helpful soul linked me to a tweet from Linda Xie mentioning an Ethereum developer onboarding session happening over the weekend, and that one-hour session led by Linda, Trent, and Austin probably contributed a lot to me changing my career path.</p><div data-type="youtube" videoId="uCk9-KG9cJA">
      <div class="youtube-player" data-id="uCk9-KG9cJA" style="background-image: url('https://i.ytimg.com/vi/uCk9-KG9cJA/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=uCk9-KG9cJA">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><p>I barely knew what &quot;full-stack development&quot; meant, since most of my experience up to then was purely analytics of financial statements (writing scripts that didn&apos;t even remotely resemble building an app). But in that short session, we were all walked through the smart contract dapp development process and tools, and then given a clear guide to start with. The exact path I took during that September to November period looked like this:</p><ol><li><p>Watch all of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://eth.build">eth.build</a> to understand wallets, transactions, and proof of work/authority consensus mechanisms in an interactive way</p></li><li><p>Go through all six lessons of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://cryptozombies.io">Cryptozombies.io</a> (the web3.js chapter may be a bit dated, so skipping it and learning to use ethers.js could be better instead)</p></li><li><p>Go through <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=eUAc2FtC0_s">Austin&apos;s Bowtie Friday videos</a> to learn scaffold-eth basics.</p></li><li><p>Go through all of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/">solidity-by-example</a> to understand common use cases like transferring ETH and working with ERC20 and ERC721 tokens. This is also a good intro to some common security risks in smart contracts such as reentrancy.</p></li><li><p>Participate in ETHOnline 2020 Hackathon (by the way <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethglobal.online/">ETHOnline 2021 is kicking off soon</a>), <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/LucidityDev/DFTP-core">creating a full-stack dapp in under 30 days</a> while also <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=yaDzifphaLc">pitching the final product</a> to a panel of judges.</p><ol><li><p>I asked tons of questions in the hardhat discord to help me learn test suites and ethers.js concepts (thank you bunches @alcuadrado and @fvictorio)</p></li><li><p>the hackathon sponsor list is helpful for both using bounties to define the project and also to motivate studying the various products and tooling available (I remember <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/7904bf1ccd294aa286f3fec7fb0cfde4">setting up this page</a> at the start)</p></li><li><p>after <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/gnosisPM/status/1322240602369597443">winning the Gnosis prize</a>, my partner Diego and I ended up <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.gitbook.com/@ath310/s/lucidity/">taking this to a UNICEF MVP</a> over the following months.</p></li><li><p>I wrote about my <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/six-lessons-learned-as-a-prize-winner-from-the-ethonline-2020-hackathon-4c291ed49738">first Ethereum hackathon experience</a> to cap it all off</p></li></ol></li></ol><p>After this experience, I was convinced that crypto was indeed the future and I needed to go much deeper into the ecosystem. This was very exhausting though, with about 6-7 hours of learning and coding every day after work during that period.</p><p><em>As a side note, if I was to go back in time I would have started by looking at Dune dashboards before diving into solidity development since I think looking at data from events and function calls is a much easier starting point for learning Ethereum than reading contracts on Etherscan or trying to understand the protocol level elements right away.</em></p><h2 id="h-the-compounding-power-of-learning-and-contribution" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Compounding Power of Learning and Contribution</h2><p>I continued with on-off momentum through the rest of November and December, until I joined Kernel Block 2 in January. @KERNEL0x has an element of referrals/applications - but getting noticed happens largely through contributing publicly. @sm_judge reached out to me because I&apos;d started participating more in hackathons with @ethglobal:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8ac4ae9e9d705468bdce7326b68c642b52a959c3c7c8506d0a85bd1485f546c1.png" alt="On LinkedIn, since that&apos;s where I networked for traditional finance" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">On LinkedIn, since that&apos;s where I networked for traditional finance</figcaption></figure><p>Shortly after KB2 started, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/__sishir">Sishir</a> found me in the KB2 slack channel and asked if I wanted to join the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spectral.finance/">Spectral team</a> to do solidity research and architecture - on-chain credit scoring sounded pretty interesting and close to my finance knowledge domain, so I joined them part-time. Around the same time, I took up a business analyst role at Consensys both to learn product management and to see how enterprises really thought about blockchain. By early March I was fairly comfortable with the basics of Ethereum/Solidity and was getting more familiar with the teams of many larger projects in the space.</p><p>This career shift from an investment bank to crypto/tech kicked off a three-month full ecosystem mapping period, which was formative for helping me figure out what problems there were to solve and which communities I vibed with the most.</p><p>There were three main reasons I needed to spend the time doing this:</p><ol><li><p><em>It isn&apos;t clear how things got to where they are today.</em> For example, what are the different parts of the crypto wallet, and which were built first and why? How did certain communities form around or leave behind different problems?</p></li><li><p><em>It isn&apos;t clear where things are going in the short or medium term.</em> There are so many different solutions proposed and attempted every day that it&apos;s hard for a generalist to understand things at a glance. This was especially true for me when I was studying interchain bridges.</p></li><li><p><em>I had no idea what I wanted to do within crypto, but I knew it likely wasn&apos;t going to be in defi.</em> Spectral was much closer to the identity side of defi, which is what had initially piqued my interest.</p></li></ol><p>The big idea I kept hearing about since day one was &quot;composability&quot;, so I decided to dive in and see just how composable every part of the Ethereum ecosystem was. I think things were already loosely clear to me, but researching and writing it out helped me really understand <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/crypto-and-web-3-0-are-the-future-of-product-and-work-3d19e3733181">which elements of the product stack were composable</a>, how <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/how-to-network-and-make-friends-in-crypto-796e123e9584">open communities means fractals form elegantly around problem spaces</a>, and the incredible importance of infrastructure composability when it comes to both <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/1the-importance-of-composable-wallets-for-users-and-developers-accb2aadff49">wallets</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/Y2XBh3HRu5B0S3qw974txvIv0JDz7Tu-yIKVTes7DUU">interchain bridges</a>. All this exploration culminated in my research on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/mDu_nGsWpjvF-KaPLADwxeAMfze3UJOtTAQi2CwPwWc">composability of identity</a>, where I connected my thinking across all of the previous dimensions.</p><p>Along the way, I had many helpful conversations across a dozen communities and leaders, who gave me insight into how they thought about problems (or how they didn&apos;t). As I watched these communities grow, I started to notice a strong trend with their hires. Oftentimes, these new hires were already strong contributors within the community. This went against my notion that you should build up your resume first and then apply to a company/job. This is a very important frame of mind that anyone trying to break into crypto needs to quickly build up: <strong>contribute, don&apos;t apply.</strong></p><p>One good example is @artblocks, which has one of the strongest and most vibrant communities in crypto. Their hires of @ponyo and @druid are perfect examples of contributors who were always present.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/aff5a0ba9886263aba6d61ab2e4794c62f3f3d30ac94dfa0e87544ecaf897b3a.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><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cce68470c81d3b3f5c6c29ac13ee92e850bf1af650c5d3b714f968c0c4887f4a.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>Another obvious shill for me is @DuneAnalytics. Becoming a @DuneAnalytics wizard 🧙🏼‍♂️ requires consistently showing up in the discord, making helpful dashboards or queries, and otherwise contributing to the community in a meaningful way. Over time, you&apos;ll be exposed to many bounty opportunities, get reached to by other companies looking for data/crypto experts, and maybe get tapped for hire by the Dune team. You can tell that the community and team are closely aligned and working together, purely based on the fact that outsiders have trouble separating the two:</p><div data-type="embedly" src="https://twitter.com/drakedanner/status/1415327134143426567" data="{&quot;provider_url&quot;:&quot;https://x.com&quot;,&quot;title&quot;:&quot;JavaScript is not available.&quot;,&quot;url&quot;:&quot;https://x.com/drakedanner/status/1415327134143426567&quot;,&quot;version&quot;:&quot;1.0&quot;,&quot;provider_name&quot;:&quot;X (formerly Twitter)&quot;,&quot;type&quot;:&quot;link&quot;}" format="small"></div><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/andrewhong5297/status/1420775190724755460">My recent collaboration</a> and constant engagement with the Mirror community led directly to my eventual hire. It all started with a single tweet analyzing the $WRITE race.</p><div data-type="twitter" tweetId="1415055142928490500" tweetData="{&quot;__typename&quot;:&quot;Tweet&quot;,&quot;lang&quot;:&quot;en&quot;,&quot;favorite_count&quot;:17,&quot;possibly_sensitive&quot;:false,&quot;created_at&quot;:&quot;2021-07-13T21:06:51.000Z&quot;,&quot;display_text_range&quot;:[0,276],&quot;entities&quot;:{&quot;hashtags&quot;:[],&quot;urls&quot;:[],&quot;user_mentions&quot;:[],&quot;symbols&quot;:[],&quot;media&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/ZyVzFWH4iw&quot;,&quot;expanded_url&quot;:&quot;https://x.com/andrewhong5297/status/1415055142928490500/photo/1&quot;,&quot;indices&quot;:[277,300],&quot;url&quot;:&quot;https://t.co/ZyVzFWH4iw&quot;}]},&quot;id_str&quot;:&quot;1415055142928490500&quot;,&quot;text&quot;:&quot;Each week 10 new writers gain access to the platform, meaning a potential 10,000 more votes to spread around. It&apos;s currently round 20, so we should have 200,000 available votes from winning writers alone. Here&apos;s the distribution of how many votes you needed to get to top ten: https://t.co/ZyVzFWH4iw&quot;,&quot;user&quot;:{&quot;id_str&quot;:&quot;801246156340740096&quot;,&quot;name&quot;:&quot;ilemi&quot;,&quot;screen_name&quot;:&quot;andrewhong5297&quot;,&quot;is_blue_verified&quot;:true,&quot;profile_image_shape&quot;:&quot;Circle&quot;,&quot;verified&quot;:false,&quot;profile_image_url_https&quot;:&quot;https://storage.googleapis.com/papyrus_images/f903871b38b5a4c8fb81a65b362af213e8c3ab3e83ead7e3da32e5f80fa4d7a9.jpg&quot;},&quot;edit_control&quot;:{&quot;edit_tweet_ids&quot;:[&quot;1415055142928490500&quot;],&quot;editable_until_msecs&quot;:&quot;1626212211184&quot;,&quot;is_edit_eligible&quot;:true,&quot;edits_remaining&quot;:&quot;5&quot;},&quot;mediaDetails&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/ZyVzFWH4iw&quot;,&quot;expanded_url&quot;:&quot;https://x.com/andrewhong5297/status/1415055142928490500/photo/1&quot;,&quot;ext_media_availability&quot;:{&quot;status&quot;:&quot;Available&quot;},&quot;indices&quot;:[277,300],&quot;media_url_https&quot;:&quot;https://pbs.twimg.com/media/E6NJE7dXsAU8hsd.png&quot;,&quot;original_info&quot;:{&quot;height&quot;:388,&quot;width&quot;:564,&quot;focus_rects&quot;:[{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:316},{&quot;x&quot;:176,&quot;y&quot;:0,&quot;w&quot;:388,&quot;h&quot;:388},{&quot;x&quot;:224,&quot;y&quot;:0,&quot;w&quot;:340,&quot;h&quot;:388},{&quot;x&quot;:370,&quot;y&quot;:0,&quot;w&quot;:194,&quot;h&quot;:388},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:388}]},&quot;sizes&quot;:{&quot;large&quot;:{&quot;h&quot;:388,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:564},&quot;medium&quot;:{&quot;h&quot;:388,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:564},&quot;small&quot;:{&quot;h&quot;:388,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:564},&quot;thumb&quot;:{&quot;h&quot;:150,&quot;resize&quot;:&quot;crop&quot;,&quot;w&quot;:150}},&quot;type&quot;:&quot;photo&quot;,&quot;url&quot;:&quot;https://t.co/ZyVzFWH4iw&quot;}],&quot;photos&quot;:[{&quot;backgroundColor&quot;:{&quot;red&quot;:204,&quot;green&quot;:214,&quot;blue&quot;:221},&quot;cropCandidates&quot;:[{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:316},{&quot;x&quot;:176,&quot;y&quot;:0,&quot;w&quot;:388,&quot;h&quot;:388},{&quot;x&quot;:224,&quot;y&quot;:0,&quot;w&quot;:340,&quot;h&quot;:388},{&quot;x&quot;:370,&quot;y&quot;:0,&quot;w&quot;:194,&quot;h&quot;:388},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:388}],&quot;expandedUrl&quot;:&quot;https://x.com/andrewhong5297/status/1415055142928490500/photo/1&quot;,&quot;url&quot;:&quot;https://storage.googleapis.com/papyrus_images/9f372eff36624d3c7294ca98d2d6bacce64f87ef7a75b6048a445e642850d6f4.png&quot;,&quot;width&quot;:564,&quot;height&quot;:388}],&quot;conversation_count&quot;:1,&quot;news_action_type&quot;:&quot;conversation&quot;,&quot;parent&quot;:{&quot;lang&quot;:&quot;en&quot;,&quot;reply_count&quot;:10,&quot;retweet_count&quot;:8,&quot;favorite_count&quot;:92,&quot;created_at&quot;:&quot;2021-07-13T21:05:16.000Z&quot;,&quot;display_text_range&quot;:[0,196],&quot;entities&quot;:{&quot;hashtags&quot;:[],&quot;urls&quot;:[],&quot;user_mentions&quot;:[{&quot;id_str&quot;:&quot;1314619820399353857&quot;,&quot;indices&quot;:[40,50],&quot;name&quot;:&quot;Mirror&quot;,&quot;screen_name&quot;:&quot;viamirror&quot;}],&quot;symbols&quot;:[{&quot;indices&quot;:[177,183],&quot;text&quot;:&quot;WRITE&quot;}]},&quot;id_str&quot;:&quot;1415054747778920456&quot;,&quot;text&quot;:&quot;📊 I&apos;ve started my dive into data behind @viamirror, one of the only web3/web2 social graphs that exist today. Articles are coming soon, but for today I have a few charts on the $WRITE race. -&amp;gt;&quot;,&quot;user&quot;:{&quot;id_str&quot;:&quot;801246156340740096&quot;,&quot;name&quot;:&quot;ilemi&quot;,&quot;screen_name&quot;:&quot;andrewhong5297&quot;,&quot;is_blue_verified&quot;:true,&quot;profile_image_shape&quot;:&quot;Circle&quot;,&quot;verified&quot;:false,&quot;profile_image_url_https&quot;:&quot;https://pbs.twimg.com/profile_images/1724513825293017088/-QsTay3l_normal.jpg&quot;},&quot;edit_control&quot;:{&quot;edit_tweet_ids&quot;:[&quot;1415054747778920456&quot;],&quot;editable_until_msecs&quot;:&quot;1626212116973&quot;,&quot;is_edit_eligible&quot;:true,&quot;edits_remaining&quot;:&quot;5&quot;},&quot;isEdited&quot;:false,&quot;isStaleEdit&quot;:false},&quot;isEdited&quot;:false,&quot;isStaleEdit&quot;:false}"> 
  <div class="twitter-embed embed">
    <div class="twitter-header">
        <div style="display:flex">
          <a target="_blank" href="https://twitter.com/andrewhong5297">
              <img alt="User Avatar" class="twitter-avatar" src="https://storage.googleapis.com/papyrus_images/f903871b38b5a4c8fb81a65b362af213e8c3ab3e83ead7e3da32e5f80fa4d7a9.jpg" />
            </a>
            <div style="margin-left:4px;margin-right:auto;line-height:1.2;">
              <a target="_blank" href="https://twitter.com/andrewhong5297" class="twitter-displayname">ilemi</a>
              <p><a target="_blank" href="https://twitter.com/andrewhong5297" class="twitter-username">@andrewhong5297</a></p>
    
            </div>
            <a href="https://twitter.com/andrewhong5297/status/1415055142928490500" target="_blank">
              <img alt="Twitter Logo" class="twitter-logo" src="https://paragraph.com/editor/twitter/logo.png" />
            </a>
          </div>
        </div>
      
    <div class="twitter-body">
      Each week 10 new writers gain access to the platform, meaning a potential 10,000 more votes to spread around. It's currently round 20, so we should have 200,000 available votes from winning writers alone. Here's the distribution of how many votes you needed to get to top ten: 
      <div class="twitter-media"><img class="twitter-image" src="https://storage.googleapis.com/papyrus_images/9f372eff36624d3c7294ca98d2d6bacce64f87ef7a75b6048a445e642850d6f4.png" /></div>
      
       
    </div>
    
     <div class="twitter-footer">
          <a target="_blank" href="https://twitter.com/andrewhong5297/status/1415055142928490500" style="margin-right:16px; display:flex;">
            <img alt="Like Icon" class="twitter-heart" src="https://paragraph.com/editor/twitter/heart.png">
            17
          </a>
          <a target="_blank" href="https://twitter.com/andrewhong5297/status/1415055142928490500"><p>4:06 PM • Jul 13, 2021</p></a>
        </div>
    
  </div> 
  </div><p>I want to stress that contributing can be literally anything: engineering product 🏗️, data analytics 📊, shipping memes 🍍, coordinating the masses ☎️, etc. Don&apos;t overcomplicate the task, but do take the time to find the missing links within or between communities 🔗. Once this contribution lightbulb clicks, you&apos;ll start to see opportunities everywhere and the whole crypto space will start to open up to you. From finding your way into a community to eventually joining the team, it&apos;s all about finding a way to contribute. Contributions may sound a little too transactional, so I like to think about it as community building.</p><h2 id="h-community-community-community" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Community, Community, Community</h2><p>Earlier I called <code>learn-build-teach</code> a cycle, but it looks more like a branching tree because the work is spread over a wide breadth of topics and audiences (most of whom you never really interact with repeatedly). However, once you understand the connection between contribution and community you can build a learning flywheel that brings you closer to the community and its mission. In a great <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://station.mirror.xyz/xlPSC6PYsazGxjo-pqyaV8M4ujtWapxhCmVQfBjmN9o">0xSTATION article</a>, this product flywheel came up in relation to a person&apos;s lifecycle in a community:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1a3117e61078ff25dfa28baa80e30d6b3bb9927af6945458cd20b4c39d64a605.png" alt="https://station.mirror.xyz/xlPSC6PYsazGxjo-pqyaV8M4ujtWapxhCmVQfBjmN9o" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://station.mirror.xyz/xlPSC6PYsazGxjo-pqyaV8M4ujtWapxhCmVQfBjmN9o</figcaption></figure><p>The new community-contribution driven flywheel I leverage is a linear and actionable version of the <code>contribution &lt;&gt; consumption</code> portion in the flow above:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/085fee15fe5b13bcad05826a5a797a5c7b5e0c3661f18dd53f09018bbe39c79d.png" alt="Thanks to Emily for helping me put this together" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Thanks to Emily for helping me put this together</figcaption></figure><p>One example of this cycle is the story <em>behind</em> how I became a Dune Wizard. When I first started learning about Dune and hopping around the Discord in April, I noticed that most people were struggling with learning SQL, Ethereum, or both. Pointing to guides that taught only one of the two domains led to a large learning friction. So, I decided to learn Dune with some simple example queries, and then use those to write articles on how to learn SQL and Ethereum at the same time on Dune. I started with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://towardsdatascience.com/your-guide-to-basic-sql-while-learning-ethereum-at-the-same-time-9eac17a05929">a beginner</a> and then <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://towardsdatascience.com/your-guide-to-intermediate-sql-while-learning-ethereum-at-the-same-time-7b25119ef1e2">an advanced</a> guide, which together has now garnered over 20k views on Medium (expert guide coming later this year). I&apos;ve continued using and improving this teaching-as-contribution methodology over the last few months, doing deep dives with my friend 0xkowloon on interesting new protocols like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://towardsdatascience.com/learning-sql-and-ethereum-part-3-5422f080ad36">barnbridge</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/dissecting-the-fractional-protocol-dc3867584bdb">fractional_art</a>.</p><p><strong>The larger point here I want to make about contributions is that what you create doesn&apos;t have to be crazy innovative or even tackle the core product/problem of a community.</strong> Building an intrapreneur skillset and perspective will serve you much better 90% of the time instead of focusing on an entrepreneurial approach when trying to contribute to a community for the first time. Since in crypto we see innovations every day, I think this creates a pressure that makes it hard for most people (me included) to balance the two ways of thinking. If this feels abstract, then think about it as building something for the ease of use or building of a product rather than just extending the use of the product itself. Intrapreneurs are usually born from environments where there are lots of silos and collective improvements that can be made. This is typically found at a large enterprise company, where a lot of your efforts are around making collaboration and knowledge sharing more accessible by creating a mix of solutions such as clearer standards, working groups, or dashboards/applications. Open communities in Ethereum make intrapreneurship a lot easier to learn as there is usually less bureaucracy around budgets and more political will to chase and implement changes, even though the communities are large in size.</p><h2 id="h-looking-forward-and-joining-mirror" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Looking Forward and Joining Mirror</h2><p>Joining Mirror means that for the first time in my professional life, I&apos;ll be devoting all my efforts to one thing instead of multitasking many projects at once. It&apos;s a big decision for me, one that&apos;s driven by my interest to understand exactly what community building looks like over time and how the process can be made more fluid or fun.</p><p>I&apos;ve thought for almost a year now about the kinds of issues communities face while growing, starting from developer communities and now more recently on DAOs. Over time, my goal has become more refined: I want to build tools that enable and incentivize contributions within a community, and also make it easier to see the full context of and leverage a community&apos;s social graph. These are key elements to strong community building, and I believe will be core to Mirror&apos;s mission. Having the opportunity to build up a strong community around this tooling is a huge motivator for my move as well.</p><p>Those are some pretty dense sentences, so let me break down my decision to join Mirror further:</p><ul><li><p><strong>The Product:</strong></p><ul><li><p>So far I&apos;ve only worked on/with various defi protocols, and seeing/using the creator block contracts produced by the team (such as edition crowdfund and splits) felt like such a breath of fresh air. I&apos;m excited to see further iterations leverage what has been built in defi already.</p></li><li><p>There&apos;s a lot of creative space in NFTs and transactions that build connections to people instead of pools. This includes variations on the NFTs themselves, auction mechanisms, ownership structures, and much more.</p></li></ul></li><li><p><strong>The Team:</strong></p><ul><li><p>I&apos;ve spoken with Patrick, Graeme, Jon-Kyle, and Denis over the past few months, and I found myself constantly inspired by our conversations. They have a lot more experience than me in building and thinking about products (especially in consumer), so I greatly look forward to learning more from them and the rest of the team.</p></li><li><p>The team has a rare balance I haven&apos;t seen that often, which is a willingness to think big but the ability to still execute quickly. I experienced this firsthand while working with them on the $WRITE token airdrop.</p></li></ul></li><li><p><strong>The Community:</strong></p><ul><li><p>Sybil resistance methods can be useful for a lot more than just unique identities, and I think the $WRITE race is a perfect example of this. When what you&apos;re signaling is much more than just &quot;I think this is a real person,&quot; the implications on the strength of a community are tenfold. I still remember those who gave me even just one vote in the race, and I&apos;m sure others feel the same. It&apos;s also probably one of the only &quot;governance&quot; functions that have an active voting participation of greater than 30% (without using delegation).</p></li><li><p>While right now I think the community is already very strong on Twitter and Discord, I&apos;m very excited by how the physical world will eventually play a role in this too. I&apos;d imagine one day we&apos;d have a coworking space, and be able to work together with DAOs and creators who want to sit in for a day or two. I see Mirror as being a natural fit for this, given the product and community ethos.</p></li></ul></li><li><p><strong>The Data:</strong></p><ul><li><p>It goes without saying that the possibilities within the data played a huge factor in my decision. First and foremost that lies in the potential applications of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/aYOJc8pihb9wxI___QR9qmM5mQ4caUyQhHJIlevspjw">graph data science</a>, essentially analyzing our interaction networks on various levels for insights that further collaboration and contribution. The fact that the data could easily drive new products or economic distributions is extremely exciting to me.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/l_-4fQ08cpxUZpn9V9S5R27wfKvNgdnrXlZAWZWvdlg">Crypto-native UX research</a> is also a fairly unexplored field, I think there are some very creative data and user group applications we can make here. For one, user behaviors can be put together from across various platforms (instead of just studying behaviors on my platform like you would in Web2). I can understand auction behaviors using Artblocks, Mirror, and Opensea data to get even stronger user personas to drive product development. I do hope to collaborate with other teams across crypto to collectively improve the UX of Web3.</p></li><li><p>Lastly, the creative space within <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/CdU80CItQr-qTZgTzymfFDEBSnz2YbgnwXGYgkQJfCs">data-driven design of tokenomics</a> (with a focus on continual distributions) cannot be understated. Closely studying the repeated game theory and micro-economies that will come from Mirror should lead to some innovative token mechanisms and tools. I&apos;m keen to explore how protocol token distributions can inform different approaches for creator/DAO tokens on the platform (and vice versa).</p></li></ul></li></ul><p>Now I want to emphasize that there is no single path through crypto, but I hope that sharing my experiences and how my thinking/methods of navigating the space led me to my dream job will be helpful to someone out there. I want to give a huge thank you to everyone who has supported me and come along on this journey thus far!</p><p><em>Thank you to </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/VirtualElena"><em>Elena</em></a><em> for proofreading and providing very helpful comments</em> 🙂</p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[UX Research to Improve NFT Auction Experience, using Mempool Data]]></title>
            <link>https://paragraph.com/@ilemi/ux-research-to-improve-nft-auction-experience-using-mempool-data</link>
            <guid>c6nMGqaf33Deq6gUmlMr</guid>
            <pubDate>Sun, 22 Aug 2021 15:38:48 GMT</pubDate>
            <description><![CDATA[User experience (UX) describes how people feel when they interact with a system or service and encompasses several factors including usability, design, marketing, accessibility, performance, comfort, and utility. Don Norman once said,“Everything has a personality; everything sends an emotional signal. Even where this was not the intention of the designer, the people who view the website infer personalities and experience emotions. Bad websites have horrible personalities and instill horrid em...]]></description>
            <content:encoded><![CDATA[<p>User experience (UX) describes how people feel when they interact with a system or service and encompasses several factors including usability, design, marketing, accessibility, performance, comfort, and utility. Don Norman once said,</p><blockquote><p>“Everything has a personality; everything sends an emotional signal. Even where this was not the intention of the designer, the people who view the website infer personalities and experience emotions. Bad websites have horrible personalities and instill horrid emotional states in their users, usually unwittingly. We need to design things — products, websites, services — to convey whatever personality and emotions are desired.”</p></blockquote><p>Ethereum&apos;s personality is someone who is extremely inscrutable and easily misunderstood. To make matters worse, most users don&apos;t even think about it as interacting with Ethereum when they&apos;re using your interface or a wallet. If you&apos;re ever in the live chat of an Artblock&apos;s auction, you&apos;ll notice as soon as an auction ends there are at least a dozen people complaining that it is Metamask&apos;s fault that they didn&apos;t get a mint. I think in the last year the UX of many dapps on Ethereum has improved greatly in both product interaction and explainability of transactions. For the most part, dapps don&apos;t just leave you with a loading spinner after you sign the transaction anymore.</p><p>Even with the design of dapps is generally improving, I&apos;m not sure how deep UX research has gone yet. When I see data analytics or research on various protocols, users are mostly treated as homogenous. This is somewhat shifting with some of the analysis I&apos;ve seen of Uniswap V3 liquidity providers and Rabbithole Questers, but even those are still heavily focused on just confirmed transactions on-chain. From my own experience, most of the emotion evoked and behavioral quirks happen when I&apos;m submitting, waiting, speeding up, or canceling my transaction. For some applications, the user might leave and go do something else after submitting a transaction. But for a product like Artblock&apos;s auctions, they&apos;re going to stay around until the confirmation has happened, likely checking anything they can for updates and with compounding anxiety.</p><p>I think we can do a much better job of understanding user behaviors and frictions by starting to leverage the mempool more. The <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://compassmining.io/education/what-is-a-mempool/">mempool</a> is where unconfirmed transactions are temporarily stored by a node. This means if you submit, speed up, or cancel your transaction then those actions will show up in the mempool first. It&apos;s important to note that the data from the mempool is not stored in the node, so you can&apos;t query historical data the same way you could on confirmed transactions. For example, you could observe that someone submitted a few transactions, sped up the transactions quite a few times at the same gas price, and saw confirmations 20 blocks later. I believe studying their behavior throughout the transaction lifecycle is a pretty good proxy for user experience and likely emotions they were feeling throughout the whole process. If we understand how different groups of users behave in this cycle, we can figure out how to supplement their decision-making or ease their anxiety. To my knowledge, pretty much only the Ethereum Foundation, All Core Devs, and some wallet teams leverage the mempool data for UX reasons.</p><p><strong>UX Research Thesis:</strong> By looking at a user&apos;s behavior through auctions over time and also their wallet history, we can start to give behavioral identities to different groups of users. From here, we can identify the main issues to try and alleviate. We&apos;ll do this by taking a month of Artblocks Auctions data using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.blocknative.com/">Blocknative</a>, and layering in the history of these addresses using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.xyz/">Dune queries</a>.</p><p>This article will be more technical than some of my previous ones since I believe the work can and should be generalized fairly easily. <em>I want to emphasize that my background is not in UX research, I&apos;m purely experimenting with what I think crypto-native UX research could look like.</em></p><h2 id="h-data-sourcing-and-preprocessing-all-auction-data" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Data Sourcing and Preprocessing All Auction Data</h2><p><em>If you have no interest in the technical bits, skip to the next section on Feature Engineering</em></p><h3 id="h-blocknative-and-mempool-data-streaming" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Blocknative and Mempool Data Streaming</h3><p>Using Blocknative&apos;s Mempool explorer, you can filter for transactions submitted to specific contracts or from specific wallets. In my case, I wanted to listen to the whitelisted minter contracts for Artblock&apos;s NFT contract. You can find the stream that I used <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://tinyurl.com/yftus9h2">here</a>, and save it down if you want to use the exact same setup.</p><p>You can find the whitelisted minter addresses with the following query <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/legacy-explorer/subgraph/artblocks/art-blocks">in their subgraph</a>:</p><pre data-type="codeBlock" text="{
  contracts(first: 2) {
    id
    mintWhitelisted
  }
}
"><code>{
  <span class="hljs-title function_">contracts</span>(<span class="hljs-params">first: <span class="hljs-number">2</span></span>) {
    id
    mintWhitelisted
  }
}
</code></pre><p>There were three steps to get to a subscription filter for all purchases:</p><ol><li><p>Add the new address with the &quot;create new subscription&quot; button</p></li><li><p>Add the ABIs by clicking the &quot;ABI&quot; button next to the address. In my case I just needed the &quot;purchase&quot; function.</p></li></ol><pre data-type="codeBlock" text="{
    &quot;inputs&quot;: [
      {
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;_projectId&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;name&quot;: &quot;purchase&quot;,
    &quot;outputs&quot;: [
      {
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;_tokenId&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;stateMutability&quot;: &quot;payable&quot;,
    &quot;type&quot;: &quot;function&quot;
  }
"><code><span class="hljs-punctuation">{</span>
    <span class="hljs-attr">"inputs"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">"internalType"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"uint256"</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"_projectId"</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">"type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"uint256"</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"purchase"</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">"outputs"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span>
        <span class="hljs-attr">"internalType"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"uint256"</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"_tokenId"</span><span class="hljs-punctuation">,</span>
        <span class="hljs-attr">"type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"uint256"</span>
      <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">"stateMutability"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"payable"</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">"type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"function"</span>
  <span class="hljs-punctuation">}</span>
</code></pre><ol><li><p>Add filters for the <code>methodName</code> matches <code>purchase</code> (make sure you don&apos;t do a global filter)</p></li></ol><p>In the end, your setup should look like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/83a24f8c4fc57f06e1770788886eceeba02d87a0196beb0feeb55f8027dd933b.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>To store this data down, I created a ngrok/express endpoint to store in an SQLite database, run locally. I&apos;ve created a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/andrewhong5297/blocknative_stream_to_sql">GitHub template with steps to replicate this setup</a>. Probably the most important point to remember here is that you need to include the POST endpoint as part of the ngrok URL when adding it as a webhook in the Blocknative account page.</p><h3 id="h-key-preprocessing-functions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Key Preprocessing Functions</h3><p><strong>Multiple Transaction Hashes</strong></p><p>When you speed up or cancel a transaction, the original transaction hash is replaced with the new transaction. This means if you want to track a users&apos; transaction through its full lifecycle, you need to reconcile the new transaction hashes with the original one. Assuming you speed up a transaction five times, you&apos;ll have six hashes total (the original hash + five new hashes). I reconciled this by getting a dictionary mapping of <code>tx_hash</code> to the new <code>replaceHash</code>, and then replaced recursively.</p><pre data-type="codeBlock" text="replaceHashKeys = dict(zip(auctions[&quot;replaceHash&quot;],auctions[&quot;tx_hash&quot;])) #assign tx_hash based on replacements, just to keep consistency. 
replaceHashKeys.pop(&quot;none&quot;) #remove none key

def recursive_tx_search(key):
    if key in replaceHashKeys:
        return recursive_tx_search(replaceHashKeys[key])
    else:
        return key

auctions[&quot;tx_hash&quot;] = auctions[&quot;tx_hash&quot;].apply(lambda x: recursive_tx_search(x))
"><code>replaceHashKeys = <span class="hljs-built_in">dict</span>(<span class="hljs-built_in">zip</span>(auctions[<span class="hljs-string">"replaceHash"</span>],auctions[<span class="hljs-string">"tx_hash"</span>])) <span class="hljs-comment">#assign tx_hash based on replacements, just to keep consistency. </span>
replaceHashKeys.pop(<span class="hljs-string">"none"</span>) <span class="hljs-comment">#remove none key</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">recursive_tx_search</span>(<span class="hljs-params">key</span>):
    <span class="hljs-keyword">if</span> key <span class="hljs-keyword">in</span> replaceHashKeys:
        <span class="hljs-keyword">return</span> recursive_tx_search(replaceHashKeys[key])
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> key

auctions[<span class="hljs-string">"tx_hash"</span>] = auctions[<span class="hljs-string">"tx_hash"</span>].apply(<span class="hljs-keyword">lambda</span> x: recursive_tx_search(x))
</code></pre><p><strong>Blocknumber Issues</strong></p><p>Dropped transactions have a <code>blocknumber</code> of 0, so to deal with this I sorted my dataframe by <code>timestamp</code> in ascending order, and then did a backward fill so the 0 would be replaced by the correct <code>blocknumber</code> it was dropped in. This is important fix for feature engineering.</p><pre data-type="codeBlock" text="auctions = auctions.sort_values(by=&quot;timestamp&quot;,ascending=True)
auctions[&quot;blocknumber&quot;] = auctions[&quot;blocknumber&quot;].replace(to_replace=0, method=&apos;bfill&apos;) #deal with dropped txs that show as blocknumber 0
"><code>auctions <span class="hljs-operator">=</span> auctions.sort_values(by<span class="hljs-operator">=</span><span class="hljs-string">"timestamp"</span>,ascending<span class="hljs-operator">=</span>True)
auctions[<span class="hljs-string">"blocknumber"</span>] <span class="hljs-operator">=</span> auctions[<span class="hljs-string">"blocknumber"</span>].replace(to_replace<span class="hljs-operator">=</span><span class="hljs-number">0</span>, method<span class="hljs-operator">=</span><span class="hljs-string">'bfill'</span>) #deal with dropped txs that show <span class="hljs-keyword">as</span> blocknumber <span class="hljs-number">0</span>
</code></pre><p><strong>Dealing with Mints Outside of Main Auction Period</strong></p><p>For most projects, the artist will mint a few pieces before the auction opens up to the public. Some projects don&apos;t sell out right away, so you will get mints still occurring a few days after the auction has opened. My analysis is focused on the key auction period, mostly the first 30 minutes. To get rid of the two mint cases above, I removed outliers based on <code>blocknumber</code>.</p><pre data-type="codeBlock" text="to_remove_indicies = []
for project in list(set(auctions[&quot;projectId&quot;])):
    auction_spec = auctions[auctions[&quot;projectId&quot;]==project]
    all_times = pd.Series(list(set(auction_spec.blocknumber)))
    to_remove_blocktimes = all_times[(np.abs(stats.zscore(all_times)) &gt; 2.5)]
    if len(to_remove_blocktimes)==0:
        break
    to_remove_indicies.extend(auction_spec.index[auction_spec[&apos;blocknumber&apos;].isin(to_remove_blocktimes)].tolist())
auctions.drop(index=to_remove_indicies, inplace=True)
"><code>to_remove_indicies <span class="hljs-operator">=</span> []
<span class="hljs-keyword">for</span> project in list(set(auctions[<span class="hljs-string">"projectId"</span>])):
    auction_spec <span class="hljs-operator">=</span> auctions[auctions[<span class="hljs-string">"projectId"</span>]<span class="hljs-operator">=</span><span class="hljs-operator">=</span>project]
    all_times <span class="hljs-operator">=</span> pd.Series(list(set(auction_spec.blocknumber)))
    to_remove_blocktimes <span class="hljs-operator">=</span> all_times[(np.abs(stats.zscore(all_times)) <span class="hljs-operator">></span> <span class="hljs-number">2.5</span>)]
    <span class="hljs-keyword">if</span> len(to_remove_blocktimes)<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-number">0</span>:
        <span class="hljs-keyword">break</span>
    to_remove_indicies.extend(auction_spec.index[auction_spec[<span class="hljs-string">'blocknumber'</span>].isin(to_remove_blocktimes)].tolist())
auctions.drop(index<span class="hljs-operator">=</span>to_remove_indicies, inplace<span class="hljs-operator">=</span>True)
</code></pre><p><strong>Adding on Dutch Auction Prices</strong></p><p>For all projects in the dataset besides project 118, a Dutch auction price format was used. I took the mint price data using a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.xyz/queries/113834">dune query</a>, and then merged it onto the dataset. I had to use a forward and backward fill for the blocks that had mempool actions but no confirmations during the auction.</p><pre data-type="codeBlock" text="auction_prices = pd.read_csv(r&apos;artblock_auctions_analytics/datasets/dune_auction_prices.csv&apos;, index_col=0)
auctions = pd.merge(auctions,auction_prices, how=&quot;left&quot;, left_on=[&quot;projectId&quot;,&quot;blocknumber&quot;],right_on=[&quot;projectId&quot;,&quot;blocknumber&quot;])
auctions.sort_values(by=[&quot;projectId&quot;,&quot;blocknumber&quot;], ascending=True, inplace=True)
auctions[&quot;price_eth&quot;].fillna(method=&quot;ffill&quot;, inplace=True)
auctions[&quot;price_eth&quot;].fillna(method=&quot;bfill&quot;, inplace=True)
"><code>auction_prices <span class="hljs-operator">=</span> pd.read_csv(r<span class="hljs-string">'artblock_auctions_analytics/datasets/dune_auction_prices.csv'</span>, index_col<span class="hljs-operator">=</span><span class="hljs-number">0</span>)
auctions <span class="hljs-operator">=</span> pd.merge(auctions,auction_prices, how<span class="hljs-operator">=</span><span class="hljs-string">"left"</span>, left_on<span class="hljs-operator">=</span>[<span class="hljs-string">"projectId"</span>,<span class="hljs-string">"blocknumber"</span>],right_on<span class="hljs-operator">=</span>[<span class="hljs-string">"projectId"</span>,<span class="hljs-string">"blocknumber"</span>])
auctions.sort_values(by<span class="hljs-operator">=</span>[<span class="hljs-string">"projectId"</span>,<span class="hljs-string">"blocknumber"</span>], ascending<span class="hljs-operator">=</span>True, inplace<span class="hljs-operator">=</span>True)
auctions[<span class="hljs-string">"price_eth"</span>].fillna(method<span class="hljs-operator">=</span><span class="hljs-string">"ffill"</span>, inplace<span class="hljs-operator">=</span>True)
auctions[<span class="hljs-string">"price_eth"</span>].fillna(method<span class="hljs-operator">=</span><span class="hljs-string">"bfill"</span>, inplace<span class="hljs-operator">=</span>True)
</code></pre><h2 id="h-feature-engineering-for-each-auction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Feature Engineering For Each Auction</h2><p><em>If you have no interest in the technical bits, just read the parts in bold and skip the rest.</em></p><p>In data science, a feature is a variable that is calculated from the larger dataset to be used as an input in some sort of model or algorithm. All features are calculated in the <code>preprocess_auction</code> function and are calculated <em>per auction rather than combining all the auctions into a feature set.</em></p><p><strong>The first set of features are the totals for transaction states</strong>, and was a simple <code>pivot_table</code> function:</p><ul><li><p><code>number_submitted</code> : total number of transactions submitted</p></li><li><p><code>cancel</code> : count of transactions that ended in canceled</p></li><li><p><code>failed</code>: count of transactions that ended in failed</p></li><li><p><code>dropped</code>: count of transactions that ended in dropped</p></li><li><p><code>confirmed</code>: count of transactions that ended in confirmed</p></li></ul><p>I mentioned earlier some data was not captured for auctions due to various issues, these transactions were dropped from the dataset.</p><p><strong>The next set of features included their gas behavior.</strong> The key concept here was capturing how far away their transaction gas was from the average confirmed gas per block (shifted by 1 block). <strong>Then we can create features for the average, median, and standard deviation of gas price distance over the whole auction.</strong> There are a bunch of transposes and index resets to get the <code>blocknumber</code> columns in the right order, but the important function is <code>fill_pending_values_gas</code> which forward fills the gas price between actions captured. This means that if I put in a transaction at <code>blocknumber</code> 1000 with a gas of 0.05 ETH and my next action wasn&apos;t until <code>blocknumber</code> 1005 where I sped up to 0.1 ETH gas, then this function will fill in the blocks between 1000-1005 with 0.05 ETH.</p><pre data-type="codeBlock" text="def fill_pending_values_gas(x):
    first = x.first_valid_index()
    last = x.last_valid_index()
    x.loc[first:last] = x.loc[first:last].fillna(method=&quot;ffill&quot;)
    return x
"><code>def fill_pending_values_gas(x):
    first <span class="hljs-operator">=</span> x.first_valid_index()
    last <span class="hljs-operator">=</span> x.last_valid_index()
    x.loc[first:last] <span class="hljs-operator">=</span> x.loc[first:last].fillna(method<span class="hljs-operator">=</span><span class="hljs-string">"ffill"</span>)
    <span class="hljs-keyword">return</span> x
</code></pre><p><strong>The third set of features were calculating the total number and frequency of actions taken in the auction.</strong> Here we start with a pivot of total actions (speed ups) per block, with some special calculations for getting the first instance of pending for each transaction:</p><pre data-type="codeBlock" text="get_first_pending = df[df[&quot;status&quot;]==&quot;pending&quot;] #first submitted 
get_first_pending = get_first_pending.drop_duplicates(subset=[&quot;tx_hash&quot;,&quot;status&quot;], keep=&quot;first&quot;)
auctions_time_data = pd.concat([get_first_pending,df[df[&quot;status&quot;]==&quot;speedup&quot;]], axis=0)
time_action = auctions_time_data.pivot_table(index=[&quot;sender&quot;,&quot;tx_hash&quot;], columns=&quot;blocknumber&quot;,values=&quot;status&quot;,aggfunc=&quot;count&quot;) \
                    .reindex(set(df[&quot;blocknumber&quot;]), axis=1, fill_value=np.nan)
"><code>get_first_pending <span class="hljs-operator">=</span> df[df[<span class="hljs-string">"status"</span>]<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-string">"pending"</span>] #first submitted 
get_first_pending <span class="hljs-operator">=</span> get_first_pending.drop_duplicates(subset<span class="hljs-operator">=</span>[<span class="hljs-string">"tx_hash"</span>,<span class="hljs-string">"status"</span>], keep<span class="hljs-operator">=</span><span class="hljs-string">"first"</span>)
auctions_time_data <span class="hljs-operator">=</span> pd.concat([get_first_pending,df[df[<span class="hljs-string">"status"</span>]<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-string">"speedup"</span>]], axis<span class="hljs-operator">=</span><span class="hljs-number">0</span>)
time_action <span class="hljs-operator">=</span> auctions_time_data.pivot_table(index<span class="hljs-operator">=</span>[<span class="hljs-string">"sender"</span>,<span class="hljs-string">"tx_hash"</span>], columns<span class="hljs-operator">=</span><span class="hljs-string">"blocknumber"</span>,values<span class="hljs-operator">=</span><span class="hljs-string">"status"</span>,aggfunc<span class="hljs-operator">=</span><span class="hljs-string">"count"</span>) \
                    .reindex(set(df[<span class="hljs-string">"blocknumber"</span>]), axis<span class="hljs-operator">=</span><span class="hljs-number">1</span>, fill_value<span class="hljs-operator">=</span>np.nan)
</code></pre><p>From here we get to <code>average_action_delay</code> in three steps:</p><ol><li><p>we take the number of actions per block (yes some people sped up transactions multiple times in the same block)</p></li><li><p>we drop the blocks with no actions, and then take the difference between the blocknumbers that remain. We add a 0 for each additional action taken per block.</p></li><li><p>Taking the mean across the differences and added zeroes gives us the <code>average_action_delay</code></p></li></ol><pre data-type="codeBlock" text="def get_actions_diff(row):
    row = row.dropna().reset_index()
    actions_diff_nominal =list(row[&quot;blocknumber&quot;].diff(1).fillna(0))
 
    #take the blocks with muliple actions and subtract one, then sum up. 
    zeros_to_add = sum([ actions - 1 if actions &gt; 1 else 0 for actions in row[row.columns[1]]])
    actions_diff_nominal.extend(list(np.zeros(int(zeros_to_add))))
    actions_diff = np.mean(actions_diff_nominal)
    if (actions_diff==0) and (zeros_to_add==0):
        return 2000 #meaning they never took another action
    else:
        return actions_diff
"><code>def get_actions_diff(row):
    row <span class="hljs-operator">=</span> row.dropna().reset_index()
    actions_diff_nominal <span class="hljs-operator">=</span>list(row[<span class="hljs-string">"blocknumber"</span>].diff(<span class="hljs-number">1</span>).fillna(<span class="hljs-number">0</span>))
 
    #take the blocks with muliple actions and subtract one, then sum up. 
    zeros_to_add <span class="hljs-operator">=</span> sum([ actions <span class="hljs-operator">-</span> <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> actions <span class="hljs-operator">></span> <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> <span class="hljs-number">0</span> <span class="hljs-keyword">for</span> actions in row[row.columns[<span class="hljs-number">1</span>]]])
    actions_diff_nominal.extend(list(np.zeros(<span class="hljs-keyword">int</span>(zeros_to_add))))
    actions_diff <span class="hljs-operator">=</span> np.mean(actions_diff_nominal)
    <span class="hljs-keyword">if</span> (actions_diff<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-number">0</span>) and (zeros_to_add<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-number">0</span>):
        <span class="hljs-keyword">return</span> <span class="hljs-number">2000</span> #meaning they never took another action
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> actions_diff
</code></pre><p><code>total_actions</code> is much simpler, as it is just the sum of actions across the pivot.</p><pre data-type="codeBlock" text="time_action[&quot;total_actions&quot;] = time_action.iloc[:,:-1].sum(axis=1)
"><code>time_action[<span class="hljs-string">"total_actions"</span>] <span class="hljs-operator">=</span> time_action.iloc[:,:<span class="hljs-number">-1</span>].sum(axis<span class="hljs-operator">=</span><span class="hljs-number">1</span>)
</code></pre><p><strong>The last time-dependent feature is</strong> <code>block_entry</code>, which is an important one due to the introduction of Dutch auctions. Essentially this tracks what block the transaction was submitted on since the start.</p><pre data-type="codeBlock" text="get_first_pending[&quot;block_entry&quot;] =   get_first_pending[&quot;blocknumber&quot;] - get_first_pending[&quot;blocknumber&quot;].min()

entry_pivot = get_first_pending.pivot_table(index=&quot;sender&quot;,values=&quot;block_entry&quot;,aggfunc=&quot;min&quot;)
"><code>get_first_pending[<span class="hljs-string">"block_entry"</span>] <span class="hljs-operator">=</span>   get_first_pending[<span class="hljs-string">"blocknumber"</span>] <span class="hljs-operator">-</span> get_first_pending[<span class="hljs-string">"blocknumber"</span>].<span class="hljs-built_in">min</span>()

entry_pivot <span class="hljs-operator">=</span> get_first_pending.pivot_table(index<span class="hljs-operator">=</span><span class="hljs-string">"sender"</span>,values<span class="hljs-operator">=</span><span class="hljs-string">"block_entry"</span>,aggfunc<span class="hljs-operator">=</span><span class="hljs-string">"min"</span>)
</code></pre><p><code>price_eth</code> is added as a feature as well, which is tied to the <code>block_entry</code> point.</p><p><strong>The last set of features were based on a Dune query, specifically the days since the first transaction, total gas used in transactions, and the total number of transactions.</strong> To get the address array in the right format I used the following line of code after reading in the SQL data:</p><pre data-type="codeBlock" text="all_users = list(set(auctions[&quot;sender&quot;].apply(lambda x: x.replace(&apos;0x&apos;,&apos;\\x&apos;))))
all_users_string = &quot;(&apos;&quot; + &quot;&apos;),(&apos;&quot;.join(all_users) + &quot;&apos;)&quot;
"><code>all_users <span class="hljs-operator">=</span> list(set(auctions[<span class="hljs-string">"sender"</span>].apply(lambda x: x.replace(<span class="hljs-string">'0x'</span>,<span class="hljs-string">'\\x'</span>))))
all_users_string <span class="hljs-operator">=</span> <span class="hljs-string">"('"</span> <span class="hljs-operator">+</span> <span class="hljs-string">"'),('"</span>.join(all_users) <span class="hljs-operator">+</span> <span class="hljs-string">"')"</span>
</code></pre><p>The dune query for this is fairly simple. I pasted the addresses string under <code>VALUES</code>, and made some CTEs to get the features I wanted. In the final <code>SELECT</code> I tried to add each address&apos;s ens as well. You can find the query here: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.xyz/queries/96523">https://dune.xyz/queries/96523</a></p><p>Lastly, we just merge in the per wallet data on days active, total gas used, and the total number of transactions.</p><pre data-type="codeBlock" text="auctions_all_df = pd.merge(auctions_all_df,wh,on=&quot;sender&quot;,how=&quot;left&quot;)
auctions_all_df.set_index([&quot;sender&quot;,&quot;ens&quot;],inplace=True)
"><code>auctions_all_df <span class="hljs-operator">=</span> pd.merge(auctions_all_df,wh,on<span class="hljs-operator">=</span><span class="hljs-string">"sender"</span>,how<span class="hljs-operator">=</span><span class="hljs-string">"left"</span>)
auctions_all_df.set_index([<span class="hljs-string">"sender"</span>,<span class="hljs-string">"ens"</span>],inplace<span class="hljs-operator">=</span>True)
</code></pre><p><em>With all this done, we&apos;re finally ready to run some fun unsupervised learning algorithms and try and validate our hypothesis on user groups.</em></p><h2 id="h-clustering-and-visualizing-user-groups" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Clustering and Visualizing User Groups</h2><p>Before I started this project, I had expected to see the following user groups pop out of the data:</p><ul><li><p><strong>Set and Forget:</strong> There should be two groups here, those who set a transaction with really high gas and an average/low gas and then don&apos;t touch it for the rest of the auction.</p></li><li><p><strong>Speed Up:</strong> There should be two groups here as well, those who are speeding up often and updating the transaction directly as a factor of gas prices and those who are speeding up often but with basically no change in gas price.</p></li></ul><p>I was very interested in validating these groups, seeing how large each group was, and seeing if any users moved between groups over the course of many auctions. The easiest way to do this was to use unsupervised machine learning to identify clusters of user groups based on the variability across all features. Essentially this is like looking at the distribution of income in a state and then splitting it into sub-distributions for different income concentrations, geographic coordinates, and age. Note that this isn&apos;t binning, where the distribution is split into equal ranges - it is instead calculated based on the density of observations within the whole range. The approach we will take is called &quot;unsupervised&quot; because our dataset doesn&apos;t have any existing labels, rather than something like a regression where there is a value being predicted that can be verified as right or wrong.</p><p>The algorithm I decided to use is called <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://stanford.edu/~cpiech/cs221/handouts/kmeans.html">k-means</a>, where k stands for the number of clusters you are expecting to identify. Each cluster has a &quot;centroid&quot;, which is like the center of a circle. There are various methods for figuring out how many clusters are optimal, and the two I used were elbow points and silhouette scores. Those are both fancy ways of asking,</p><blockquote><p>&quot;does each additional cluster help increase the density of the cluster (calculated as the average distance of points in a cluster from the centroid) and maintain adequate separation between clusters (no overlap between two clusters)?&quot;</p></blockquote><p>I found that 3 clusters were optimal in terms of most inertia improvement while keeping a high silhouette score (around 0.55).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e9399725bdcd5dc20dfba8ce4a401a9a9e58d841dffd9c02e642627d55de6f25.png" alt="6 auctions were used for this analysis" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">6 auctions were used for this analysis</figcaption></figure><p>With clusters chosen, we want to be able to visualize and verify their existence. There are over 15 variables, so we need to reduce the number of dimensions in order to plot it. Dimension reduction typically relies on either PCA or t-SNE algorithms, in our case I went with t-SNE. Don&apos;t worry too much about understanding this part, these algorithms essentially capture the variance across all features to give us X and Y components that maximize the spread of points from each other.</p><p><strong>Let&apos;s look at project 118, LeWitt Generator Generator, from August 4th:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7ceaa2e291caa39167e33fb4906acf2ddb323713e9b2c41447f3d8fcaeda6206.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><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/90bdfcbf0f29d7a021764c8659261aebbd32d96f848249bd493860aad4385c52.png" alt="These are the sub-distributions for each variable by cluster, calculated using a KDE. The colors match those in the above clusters." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">These are the sub-distributions for each variable by cluster, calculated using a KDE. The colors match those in the above clusters.</figcaption></figure><p>After taking a look at the sub-distributions for each variable and some data examples, I was able to categorize the clusters. The Orange cluster is the group that is speeding up the most while also submitting slightly lower gas transactions on average. Blue and Green clusters exhibit similar behavior to each other, but addresses in Blue typically have less history than addresses in the Green cluster.</p><p>Looking at the overall picture, it seems the original hypothesis on &quot;speed-up&quot; and &quot;set high and set low&quot; producing two groups each was wrong. Instead, we have a single &quot;speed-up&quot; group (Orange) and a single &quot;set-and-forget&quot; group (Blue and Green are behaviorally the same). I think the new (Blue) versus old wallets (Green) in the &quot;set and forget&quot; group probably carries a lot of overlap in actual users, where users just created new wallets to bid on more mints. Based on their impatience in <code>average_action_delay</code> and lower-than-average <code>average_gas_behavior</code>, the &quot;speed-up&quot; group reads to me as less experienced and more anxious than other users. <em>What did surprise me is that the speed-up group makes up a smaller proportion (30%) of total bidders, as I had expected that group to make up 60-70% of bidders instead.</em></p><p><strong>Now, where this user behavior study gets really interesting is when comparing project 118 (the set price of 0.75 ETH) to project 140 (Dutch auction with the price decreasing from 1.559 to .159 ETH).</strong></p><p><strong>Here&apos;s the clustering for project 140, Good Vibrations from August 21st:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/12d4192c3e34d300787dd35262532ac5bac8539a4701b17a649646c90ae2c070.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><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/24af4be5ac43145433768051f685983ac17c790f5bc46bb36a8e7d3405a456e8.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>We can see that now most of the clustering variability comes from <code>block_entry</code>, <code>price_eth</code>, and all of the <code>gas_behavior</code> features. This is a big departure from the main variables for project 118. In 118, the set price meant that people entered the auction in a fairly uniform distribution (quantity left didn&apos;t seem to matter), and the &quot;speed-up&quot; group submitted actions up fairly endlessly.</p><p>In project 140, we don&apos;t see the same difference in actions within <code>average_action_delay</code> or <code>total_actions</code> , instead, we see a new group (Orange) entering at a very late stage block and setting far below-average gas prices as seen in <code>average_gas_behavior</code>. If I was to try and map this to the clusters in 118, I believe the &quot;speed-up&quot; group has now become the &quot;greedy&quot; group (Orange) that is entering late and bidding a low gas. The Green cluster probably represents users with more experience than the Orange cluster, but who are still transitioning between Orange and Blue in terms of their behavior. The &quot;set-and-forget&quot; group maps pretty well to the &quot;early-grab&quot; group (Green and Blue) since they all exhibit pretty good patience and an adequate safety net on gas bids.</p><p><strong>I call the Orange group &quot;greedy&quot; not just because of their behavior, but also because of their rate of failed transactions.</strong></p><p>For project 118, fail rates are of the &quot;speed-up&quot; versus &quot;set-and-forget&quot; groups are within 10-15%.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4c3848fc4e8a3790d3856135d07e246ece43d3fdba8ac2c411c13e3edebb88bd.png" alt="percent_lost takes (cancel + dropped + failed) / number_submitted" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">percent_lost takes (cancel + dropped + failed) / number_submitted</figcaption></figure><p>For project 140, the fail rate of the &quot;greedy&quot; cluster is around 69% versus the &quot;early-grab&quot; group at around 5-15%.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fca0c26a8549ab6d97f9d14f993ccfc223cdc5848e8436f1c332ac2c25e81227.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><strong>Overall, my read of this is that the group&apos;s bad habits and emotions were amplified - it feels to me like we made a tradeoff in anxiety → greed. This may have made the auction less stressful, but ultimately led to more users being upset (due to failed mints).</strong></p><p><em>I&apos;m sure there&apos;s a more granular analysis that can be done to segment the auctions further based on factory/curated/playground or by artists themselves too. This will only get more interesting and complex as the community continues to grow, and emotions play a larger factor in both a single auction and on if they return for future auctions.</em></p><p><em>This study of multiple auctions helped us validate our assumptions, understand the proportions of user groups, and see how users&apos; good or bad behaviors shift over time (and other parameters). Now we need to plug it into the rest of the product cycle process.</em></p><h2 id="h-where-we-go-from-here" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Where We Go From Here:</h2><p>The reason that I chose just Artblocks auctions for this and not a mix of platforms is because I wanted to look for a place where the variability in terms of interface and project type is mostly controlled. This should have given us fairly consistent users and behavior types.</p><p>This is just the start of a UX research cycle, so ideally we could continue in the following steps:</p><ol><li><p>Use an unsupervised machine learning algorithm to identify the user groups (clusters) and see how many people are making &quot;mistakes&quot; when entering an auction. <em>This is the step we covered today.</em></p></li><li><p>Create a new user interface, such as a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/andrewhong5297/status/1423020670825504768">histogram view on the bidding screen</a>, or showing historical data on when most people usually enter/crowd the auction and at what prices. Anything to give both current and historical context to the user, especially those from the speed cluster.</p></li><li><p>With each auction, run the mempool/wallet data through the created algorithm to see if the user groups have shifted and if specific users have &quot;learned&quot; to participate in the auction differently (i.e. did they move between user groups). <em>I think that the most value can be found in this step if done well. Using ENS or other identifiers to help supplement this grouping would be exponentially helpful too</em></p></li><li><p>Based on the results, continue to iterate on the user interface and design. You could also run more informed A/B testing since you could even figure out what screens to show by making an educated guess based on the users&apos; last cluster (or use label propagation for new users).</p></li></ol><p><strong>The Dutch auction-style change is also an example of step #2, and we were able to see a clear shift in user behaviors.</strong> While typically this sort of research and testing is focused on increasing engagement or conversions, here we are optimizing for the user&apos;s ability to learn and improve instead. This may become even more robust if this was iterated in a multiplatform context, so that we can study how someone is learning at an ecosystem level (maybe even supplement with Rabbithole data and user profiles). Since my Artblocks user research is all based on publicly sourced data, it can be replicated and supplemented by any other auction/sale platform. <strong>Crypto could be the first industry that would have a synchronized and transparent set of user groups and UX research, to be applied in products and academia.</strong> Nansen wallet labeling is already a step towards this, but it&apos;s different when teams from different products build this up from various facets and approaches.</p><p>What I would eventually envision is using data to build on the following user personas (with subgroups/levels within them):</p><ul><li><p>I want to buy a Fidenza, so I can either buy one through a private sale, bid on one in an auction myself, bid on one in a prtyDAO bid auction, or buy a fraction of one with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://fractional.art/">fractional.art</a></p></li><li><p>I like Fidenzas in general, so I&apos;ll just buy the NFTX Fidenza index token or an NFT basket of Artblocks Curated on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://fractional.art/">fractional.art</a></p></li><li><p>I&apos;m a collector already, so I want to swap or bid on a Fidenza using a curated set of NFTs and ERC20s I already hold (using genie-xyz swap).</p></li><li><p>I like the rush of acquiring through initial mint versus secondary market, and heavily participate in auctions like Artblocks live mints.</p></li></ul><p>I hope you found this project interesting and/or helpful, I had a ton of fun with it. Thanks to the folks at Blocknative for setting me up, and the community at Artblocks for answering my many auction questions. As always, feel free to reach out with any questions or ideas you may have!</p><p>You can find the GitHub repo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/andrewhong5297/artblock_auctions_analysis">with all the data and script here</a>. The script may be a bit hard to read since I’m still refactoring and cleaning it up. The script and some of the analysis here may get updated as I analyze the last few auctions of August for new patterns.</p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[$WRITE Airdrop Proposal: Incentivizing a More Diverse Creator Crowd on Mirror]]></title>
            <link>https://paragraph.com/@ilemi/write-airdrop-proposal-incentivizing-a-more-diverse-creator-crowd-on-mirror</link>
            <guid>AwgF7y7tf3TIVdj2mzno</guid>
            <pubDate>Wed, 18 Aug 2021 16:12:23 GMT</pubDate>
            <description><![CDATA[A (very) short history on token airdrops:Airdrops have come a long way in the last year, most notably starting from Uniswap&apos;s 400 UNI token airdrop in September of 2020. From there, we&apos;ve grown into airdrops that are calculated based on the frequency and volume of interactions with different facets of a protocol. Below is one such example: banteg @bantg You've been photographed. Expect a gift. 243 7:32 AM • Jul 15, 2021 We&apos;ve also seen NFT drops recently that rely on more stand...]]></description>
            <content:encoded><![CDATA[<h2 id="h-a-very-short-history-on-token-airdrops" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">A (very) short history on token airdrops:</h2><p>Airdrops have come a long way in the last year, most notably starting from Uniswap&apos;s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://uniswap.org/blog/uni/">400 UNI token airdrop</a> in September of 2020. From there, we&apos;ve grown into airdrops that are calculated based on the frequency and volume of interactions with different facets of a protocol. Below is one such example:</p><div data-type="twitter" tweetId="1415650580299669512" tweetData="{&quot;__typename&quot;:&quot;Tweet&quot;,&quot;lang&quot;:&quot;en&quot;,&quot;favorite_count&quot;:243,&quot;possibly_sensitive&quot;:false,&quot;created_at&quot;:&quot;2021-07-15T12:32:54.000Z&quot;,&quot;display_text_range&quot;:[0,43],&quot;entities&quot;:{&quot;hashtags&quot;:[],&quot;urls&quot;:[],&quot;user_mentions&quot;:[],&quot;symbols&quot;:[],&quot;media&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/7uwXs3ZAwh&quot;,&quot;expanded_url&quot;:&quot;https://x.com/bantg/status/1415650580299669512/photo/1&quot;,&quot;indices&quot;:[43,66],&quot;url&quot;:&quot;https://t.co/7uwXs3ZAwh&quot;}]},&quot;id_str&quot;:&quot;1415650580299669512&quot;,&quot;text&quot;:&quot;📸\nYou&apos;ve been photographed. Expect a gift. https://t.co/7uwXs3ZAwh&quot;,&quot;user&quot;:{&quot;id_str&quot;:&quot;108172903&quot;,&quot;name&quot;:&quot;banteg&quot;,&quot;screen_name&quot;:&quot;bantg&quot;,&quot;is_blue_verified&quot;:true,&quot;profile_image_shape&quot;:&quot;Circle&quot;,&quot;verified&quot;:false,&quot;profile_image_url_https&quot;:&quot;https://storage.googleapis.com/papyrus_images/b8dd6209b3440ed521f7cae27af4d90baa20c25bd850425261301a264ffa1a7a.jpg&quot;},&quot;edit_control&quot;:{&quot;edit_tweet_ids&quot;:[&quot;1415650580299669512&quot;],&quot;editable_until_msecs&quot;:&quot;1626354174516&quot;,&quot;is_edit_eligible&quot;:true,&quot;edits_remaining&quot;:&quot;5&quot;},&quot;mediaDetails&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/7uwXs3ZAwh&quot;,&quot;expanded_url&quot;:&quot;https://x.com/bantg/status/1415650580299669512/photo/1&quot;,&quot;ext_media_availability&quot;:{&quot;status&quot;:&quot;Available&quot;},&quot;indices&quot;:[43,66],&quot;media_url_https&quot;:&quot;https://pbs.twimg.com/media/E6VmeLhWUAUKDX4.jpg&quot;,&quot;original_info&quot;:{&quot;height&quot;:2400,&quot;width&quot;:2400,&quot;focus_rects&quot;:[{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:2400,&quot;h&quot;:1344},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:2400,&quot;h&quot;:2400},{&quot;x&quot;:295,&quot;y&quot;:0,&quot;w&quot;:2105,&quot;h&quot;:2400},{&quot;x&quot;:1200,&quot;y&quot;:0,&quot;w&quot;:1200,&quot;h&quot;:2400},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:2400,&quot;h&quot;:2400}]},&quot;sizes&quot;:{&quot;large&quot;:{&quot;h&quot;:2048,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:2048},&quot;medium&quot;:{&quot;h&quot;:1200,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:1200},&quot;small&quot;:{&quot;h&quot;:680,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:680},&quot;thumb&quot;:{&quot;h&quot;:150,&quot;resize&quot;:&quot;crop&quot;,&quot;w&quot;:150}},&quot;type&quot;:&quot;photo&quot;,&quot;url&quot;:&quot;https://t.co/7uwXs3ZAwh&quot;}],&quot;photos&quot;:[{&quot;backgroundColor&quot;:{&quot;red&quot;:204,&quot;green&quot;:214,&quot;blue&quot;:221},&quot;cropCandidates&quot;:[{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:2400,&quot;h&quot;:1344},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:2400,&quot;h&quot;:2400},{&quot;x&quot;:295,&quot;y&quot;:0,&quot;w&quot;:2105,&quot;h&quot;:2400},{&quot;x&quot;:1200,&quot;y&quot;:0,&quot;w&quot;:1200,&quot;h&quot;:2400},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:2400,&quot;h&quot;:2400}],&quot;expandedUrl&quot;:&quot;https://x.com/bantg/status/1415650580299669512/photo/1&quot;,&quot;url&quot;:&quot;https://storage.googleapis.com/papyrus_images/25490fc34e0f523b8ddbd123afe597c1882854d996943bbdd6e61307804fddff.jpg&quot;,&quot;width&quot;:2400,&quot;height&quot;:2400}],&quot;conversation_count&quot;:22,&quot;news_action_type&quot;:&quot;conversation&quot;,&quot;isEdited&quot;:false,&quot;isStaleEdit&quot;:false}"> 
  <div class="twitter-embed embed">
    <div class="twitter-header">
        <div style="display:flex">
          <a target="_blank" href="https://twitter.com/bantg">
              <img alt="User Avatar" class="twitter-avatar" src="https://storage.googleapis.com/papyrus_images/b8dd6209b3440ed521f7cae27af4d90baa20c25bd850425261301a264ffa1a7a.jpg" />
            </a>
            <div style="margin-left:4px;margin-right:auto;line-height:1.2;">
              <a target="_blank" href="https://twitter.com/bantg" class="twitter-displayname">banteg</a>
              <p><a target="_blank" href="https://twitter.com/bantg" class="twitter-username">@bantg</a></p>
    
            </div>
            <a href="https://twitter.com/bantg/status/1415650580299669512" target="_blank">
              <img alt="Twitter Logo" class="twitter-logo" src="https://paragraph.com/editor/twitter/logo.png" />
            </a>
          </div>
        </div>
      
    <div class="twitter-body">
      <img class="twitter-emoji" draggable="false" alt="📸" src="https://abs-0.twimg.com/emoji/v2/72x72/1f4f8.png"/><br />You've been photographed. Expect a gift. 
      <div class="twitter-media"><img class="twitter-image" src="https://storage.googleapis.com/papyrus_images/25490fc34e0f523b8ddbd123afe597c1882854d996943bbdd6e61307804fddff.jpg" /></div>
      
       
    </div>
    
     <div class="twitter-footer">
          <a target="_blank" href="https://twitter.com/bantg/status/1415650580299669512" style="margin-right:16px; display:flex;">
            <img alt="Like Icon" class="twitter-heart" src="https://paragraph.com/editor/twitter/heart.png">
            243
          </a>
          <a target="_blank" href="https://twitter.com/bantg/status/1415650580299669512"><p>7:32 AM • Jul 15, 2021</p></a>
        </div>
    
  </div> 
  </div><p>We&apos;ve also seen NFT drops recently that rely on more standardized <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://galaxy.eco/">tools built</a> for quickly setting rules/requirements and rewards/distribution. None of these methodologies are bad, but I do believe there&apos;s still <em>a lot</em> of room for improvement. This could come from the distribution model, drop frequency, or even the token rules themselves. In this proposal, I&apos;ll be focusing on a new distribution model, one that combines data from user interactions in the Mirror $WRITE race, on Twitter, and in Mirror-related Ethereum transactions.</p><h2 id="h-rewards-incentives-and-governance" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Rewards, Incentives, and Governance:</h2><p>The Mirror $WRITE race is a vote-based competition that occurs once a week, where the top ten writers get 1 $WRITE token. This gives them access to the platform as well as 1000 votes for the future rounds of the race. The structure is not dissimilar from most Sybil-resistant approaches where a validated party votes in a new party, however, the propagation of rounds is a lot slower as it only happens once a week. This means it takes a lot longer to really diversify away from the friends/communities of the genesis writers of the $WRITE race. For new participants who aren&apos;t very close to that initial circle, it becomes harder and harder to win as the top 10 vote floor continues to rise:</p><div data-type="twitter" tweetId="1415055142928490500" tweetData="{&quot;__typename&quot;:&quot;Tweet&quot;,&quot;lang&quot;:&quot;en&quot;,&quot;favorite_count&quot;:17,&quot;possibly_sensitive&quot;:false,&quot;created_at&quot;:&quot;2021-07-13T21:06:51.000Z&quot;,&quot;display_text_range&quot;:[0,276],&quot;entities&quot;:{&quot;hashtags&quot;:[],&quot;urls&quot;:[],&quot;user_mentions&quot;:[],&quot;symbols&quot;:[],&quot;media&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/ZyVzFWH4iw&quot;,&quot;expanded_url&quot;:&quot;https://x.com/andrewhong5297/status/1415055142928490500/photo/1&quot;,&quot;indices&quot;:[277,300],&quot;url&quot;:&quot;https://t.co/ZyVzFWH4iw&quot;}]},&quot;id_str&quot;:&quot;1415055142928490500&quot;,&quot;text&quot;:&quot;Each week 10 new writers gain access to the platform, meaning a potential 10,000 more votes to spread around. It&apos;s currently round 20, so we should have 200,000 available votes from winning writers alone. Here&apos;s the distribution of how many votes you needed to get to top ten: https://t.co/ZyVzFWH4iw&quot;,&quot;user&quot;:{&quot;id_str&quot;:&quot;801246156340740096&quot;,&quot;name&quot;:&quot;ilemi&quot;,&quot;screen_name&quot;:&quot;andrewhong5297&quot;,&quot;is_blue_verified&quot;:true,&quot;profile_image_shape&quot;:&quot;Circle&quot;,&quot;verified&quot;:false,&quot;profile_image_url_https&quot;:&quot;https://storage.googleapis.com/papyrus_images/f903871b38b5a4c8fb81a65b362af213e8c3ab3e83ead7e3da32e5f80fa4d7a9.jpg&quot;},&quot;edit_control&quot;:{&quot;edit_tweet_ids&quot;:[&quot;1415055142928490500&quot;],&quot;editable_until_msecs&quot;:&quot;1626212211184&quot;,&quot;is_edit_eligible&quot;:true,&quot;edits_remaining&quot;:&quot;5&quot;},&quot;mediaDetails&quot;:[{&quot;display_url&quot;:&quot;pic.x.com/ZyVzFWH4iw&quot;,&quot;expanded_url&quot;:&quot;https://x.com/andrewhong5297/status/1415055142928490500/photo/1&quot;,&quot;ext_media_availability&quot;:{&quot;status&quot;:&quot;Available&quot;},&quot;indices&quot;:[277,300],&quot;media_url_https&quot;:&quot;https://pbs.twimg.com/media/E6NJE7dXsAU8hsd.png&quot;,&quot;original_info&quot;:{&quot;height&quot;:388,&quot;width&quot;:564,&quot;focus_rects&quot;:[{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:316},{&quot;x&quot;:176,&quot;y&quot;:0,&quot;w&quot;:388,&quot;h&quot;:388},{&quot;x&quot;:224,&quot;y&quot;:0,&quot;w&quot;:340,&quot;h&quot;:388},{&quot;x&quot;:370,&quot;y&quot;:0,&quot;w&quot;:194,&quot;h&quot;:388},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:388}]},&quot;sizes&quot;:{&quot;large&quot;:{&quot;h&quot;:388,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:564},&quot;medium&quot;:{&quot;h&quot;:388,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:564},&quot;small&quot;:{&quot;h&quot;:388,&quot;resize&quot;:&quot;fit&quot;,&quot;w&quot;:564},&quot;thumb&quot;:{&quot;h&quot;:150,&quot;resize&quot;:&quot;crop&quot;,&quot;w&quot;:150}},&quot;type&quot;:&quot;photo&quot;,&quot;url&quot;:&quot;https://t.co/ZyVzFWH4iw&quot;}],&quot;photos&quot;:[{&quot;backgroundColor&quot;:{&quot;red&quot;:204,&quot;green&quot;:214,&quot;blue&quot;:221},&quot;cropCandidates&quot;:[{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:316},{&quot;x&quot;:176,&quot;y&quot;:0,&quot;w&quot;:388,&quot;h&quot;:388},{&quot;x&quot;:224,&quot;y&quot;:0,&quot;w&quot;:340,&quot;h&quot;:388},{&quot;x&quot;:370,&quot;y&quot;:0,&quot;w&quot;:194,&quot;h&quot;:388},{&quot;x&quot;:0,&quot;y&quot;:0,&quot;w&quot;:564,&quot;h&quot;:388}],&quot;expandedUrl&quot;:&quot;https://x.com/andrewhong5297/status/1415055142928490500/photo/1&quot;,&quot;url&quot;:&quot;https://storage.googleapis.com/papyrus_images/9f372eff36624d3c7294ca98d2d6bacce64f87ef7a75b6048a445e642850d6f4.png&quot;,&quot;width&quot;:564,&quot;height&quot;:388}],&quot;conversation_count&quot;:1,&quot;news_action_type&quot;:&quot;conversation&quot;,&quot;parent&quot;:{&quot;lang&quot;:&quot;en&quot;,&quot;reply_count&quot;:10,&quot;retweet_count&quot;:8,&quot;favorite_count&quot;:92,&quot;created_at&quot;:&quot;2021-07-13T21:05:16.000Z&quot;,&quot;display_text_range&quot;:[0,196],&quot;entities&quot;:{&quot;hashtags&quot;:[],&quot;urls&quot;:[],&quot;user_mentions&quot;:[{&quot;id_str&quot;:&quot;1314619820399353857&quot;,&quot;indices&quot;:[40,50],&quot;name&quot;:&quot;Mirror&quot;,&quot;screen_name&quot;:&quot;viamirror&quot;}],&quot;symbols&quot;:[{&quot;indices&quot;:[177,183],&quot;text&quot;:&quot;WRITE&quot;}]},&quot;id_str&quot;:&quot;1415054747778920456&quot;,&quot;text&quot;:&quot;📊 I&apos;ve started my dive into data behind @viamirror, one of the only web3/web2 social graphs that exist today. Articles are coming soon, but for today I have a few charts on the $WRITE race. -&amp;gt;&quot;,&quot;user&quot;:{&quot;id_str&quot;:&quot;801246156340740096&quot;,&quot;name&quot;:&quot;ilemi&quot;,&quot;screen_name&quot;:&quot;andrewhong5297&quot;,&quot;is_blue_verified&quot;:true,&quot;profile_image_shape&quot;:&quot;Circle&quot;,&quot;verified&quot;:false,&quot;profile_image_url_https&quot;:&quot;https://pbs.twimg.com/profile_images/1724513825293017088/-QsTay3l_normal.jpg&quot;},&quot;edit_control&quot;:{&quot;edit_tweet_ids&quot;:[&quot;1415054747778920456&quot;],&quot;editable_until_msecs&quot;:&quot;1626212116973&quot;,&quot;is_edit_eligible&quot;:true,&quot;edits_remaining&quot;:&quot;5&quot;},&quot;isEdited&quot;:false,&quot;isStaleEdit&quot;:false},&quot;isEdited&quot;:false,&quot;isStaleEdit&quot;:false}"> 
  <div class="twitter-embed embed">
    <div class="twitter-header">
        <div style="display:flex">
          <a target="_blank" href="https://twitter.com/andrewhong5297">
              <img alt="User Avatar" class="twitter-avatar" src="https://storage.googleapis.com/papyrus_images/f903871b38b5a4c8fb81a65b362af213e8c3ab3e83ead7e3da32e5f80fa4d7a9.jpg" />
            </a>
            <div style="margin-left:4px;margin-right:auto;line-height:1.2;">
              <a target="_blank" href="https://twitter.com/andrewhong5297" class="twitter-displayname">ilemi</a>
              <p><a target="_blank" href="https://twitter.com/andrewhong5297" class="twitter-username">@andrewhong5297</a></p>
    
            </div>
            <a href="https://twitter.com/andrewhong5297/status/1415055142928490500" target="_blank">
              <img alt="Twitter Logo" class="twitter-logo" src="https://paragraph.com/editor/twitter/logo.png" />
            </a>
          </div>
        </div>
      
    <div class="twitter-body">
      Each week 10 new writers gain access to the platform, meaning a potential 10,000 more votes to spread around. It's currently round 20, so we should have 200,000 available votes from winning writers alone. Here's the distribution of how many votes you needed to get to top ten: 
      <div class="twitter-media"><img class="twitter-image" src="https://storage.googleapis.com/papyrus_images/9f372eff36624d3c7294ca98d2d6bacce64f87ef7a75b6048a445e642850d6f4.png" /></div>
      
       
    </div>
    
     <div class="twitter-footer">
          <a target="_blank" href="https://twitter.com/andrewhong5297/status/1415055142928490500" style="margin-right:16px; display:flex;">
            <img alt="Like Icon" class="twitter-heart" src="https://paragraph.com/editor/twitter/heart.png">
            17
          </a>
          <a target="_blank" href="https://twitter.com/andrewhong5297/status/1415055142928490500"><p>4:06 PM • Jul 13, 2021</p></a>
        </div>
    
  </div> 
  </div><p>While increasing the # of winners and base vote allocation or gamifying the prompt system could incrementally improve the race, an airdrop of $WRITE tokens would offer a much faster method of reducing the influence of the starter group and increase the diversity of writers (winners) on the platform.</p><p>A key first decision here is that <strong>airdropped tokens should <em>not</em> affect the current vote allocation</strong> for each participant in the $WRITE race. But, they can still be redeemed for publications**, at 1 $WRITE token per publication.</p><p>My first thoughts when structuring this airdrop model were around &quot;what should an airdrop really be targeting?&quot; The three pillars that came to mind were:</p><ol><li><p><strong>Rewards:</strong> How can we fairly compensate early users for their support and risks that were taken? They chose to publish on Mirror rather than their existing publishing platform, carrying both new funnel and smart contract risks.</p></li><li><p><strong>Incentives:</strong> Knowing that this model will set a precedent for rewards distribution criteria, how will that affect voter/creator/contributor behaviors going forward?</p></li><li><p><strong>Governance:</strong> How can the balance of power be shifted in a way that diversifies the writer community much faster?</p></li></ol><p>From there, I set three goals for the token formula:</p><ol><li><p><strong>Rewards:</strong> Creators should be rewarded for their usage of web3 platform features, and contributors should be rewarded for the value (ETH) they&apos;ve provided to creator projects</p></li><li><p><strong>Incentives:</strong> We should also incentivize contributors to support a larger array of creators, rather than just the same two or three creators (or a single community).</p></li><li><p><strong>Governance:</strong> We should try to amplify anyone who bridges different communities by giving them more tokens.</p></li></ol><p>We know that for Mirror to thrive long-term, there needs to be diversity in creators with an equally diverse set of contributors. However, with over 7000 users it can be hard to choose who gets what allocation off of usage alone. This is where the social graphs enter the picture, as we can use that data to identify who might be best from a community perspective to allocate greater or fewer airdrop tokens to.</p><h2 id="h-token-reward-formula" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Token Reward Formula:</h2><p><em>For all of the following, $W$ stands for a weight between 0-1 and $T$ stands for $WRITE token.</em></p><ol><li><p>First, let&apos;s take care of the community diversification weighting based on centrality:</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f0d0a844844cecbfd7191ab5e67de36ec37a12f1bf605a47f28bfcf0f7854771.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><ul><li><p>Betweenness centrality is a measure that highlights the nodes that bridge the most communities. This serves to incentivize everyone to support and collaborate with more diverse communities in the future. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/aYOJc8pihb9wxI___QR9qmM5mQ4caUyQhHJIlevspjw"><strong>See this post for details on this metric and the methodology</strong></a>. We multiply it by 50 to give it more weight.</p></li><li><p>While the linked post above does not account for the difference in edge/relationship data type, so a mention and a 1 ETH contribution would have the same non-scaled weight), for this airdrop, we converted the multi-edge graph into a weighted directional graph. This means normalizing each edge by total mentions/contributions/votes a certain user has given, and then weighting mentions, contributions, and votes by 15x, 40x, 40x respectively. Another important change from the original post is the use of a directional graph.</p></li></ul><ol start="2"><li><p>We still want to make sure creators and contributors are getting fairly rewarded. Let&apos;s define the <em>T_baseReward</em> formula as:</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/45f6d449c9bb82f90761c46ca8103a23af9ec296b78ca83824dc91052d4d2c15.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><ul><li><p><em>V_votesAllocated</em> represents the current allocation of votes someone has in the $WRITE race. This is divided by 1000 to represent the $WRITE token balance. This is weighted by <em>W_voted</em> which represents the total votes used out of votes allocated each week (cumulatively).</p></li><li><p><em>B_hasCreated</em> represents a Boolean (1 or 0 value) for if someone has created at least one entry or block (edition, split, crowdfund, auction).</p></li><li><p><em>V^n_contributed</em> is the value of ETH contributed to creators (across <em>n</em> different block types). This is weighted by the unique # of creators someone has contributed to, max_min scaled into <em>W_contributed</em>. This means if the maximum number of unique creators someone has contributed to is 10, and I&apos;ve also contributed to 10 creators, then I would have a <em>W_contributed</em> of 1. Depending on the distribution of contributors, if I&apos;ve only contributed to 1 creator, I would have a <em>W_contributed</em> of something like 0.0833. Thus, we are rewarding those who both contribute to creators and support many creators, in an effort to incentivize that behavior.</p></li><li><p>The constants of 0.65 and 0.15 were chosen based on how many total tokens we wanted to distribute.</p></li></ul><ol start="3"><li><p>Putting it all together, we get our total $WRITE token reward formula:</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c7e9505f6ed7012739892dbd1e877e2b5541be57109588070256d7deb48d3763.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><h3 id="h-airdrop-results" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Airdrop Results:</h3><p><em>The results of the airdrop can be found in the following CSV file.</em></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1456ca0e-8847-49a1-9580-8d598525668d/mirror_finalAirdrop_cleaned_w.csv">mirror_finalAirdrop_cleaned_w.csv</a></p><p><em>The data dictionary for this file can be found below:</em></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/Mirror-WRITE-Airdrop-Data-Dictionary-51f753cab17148b3a086978336f2f353">Mirror $WRITE Airdrop Data Dictionary</a></p><h2 id="h-what-a-reputation-based-airdrop-enables-for-the-community" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What a Reputation-based Airdrop Enables for the Community:</h2><p>I believe this airdrop has iterated upon everything we built in web2 and web3, mainly due to its combined use of multiple social graphs alongside tokenized ownership. As I&apos;ve <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/aYOJc8pihb9wxI___QR9qmM5mQ4caUyQhHJIlevspjw">covered before</a>, betweenness centrality is a measure that helps us target a more resilient and diverse network. Tokens are a great way to reward those who have fulfilled that behavior historically, and also as an incentive mechanism to further that diversity and resilience (support) in the future.</p><p>This proposal indirectly tackles the issue of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gov.rarible.com/t/problems-in-the-ownership-economy/16070">long-term ownership of tokens</a>, where many receivers (other than core investors and the product team) sell the tokens soon after the drop. My hope is that if the tokens are distributed to an aligned subset of the community, we won&apos;t see this issue appear as strongly. I think the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/OlympusDAO/status/1416489213185380358">Ohmies</a> are a great example of this done well.</p><p>While this airdrop is at a protocol level, there&apos;s no reason why we couldn&apos;t go more micro in our approach and provide creators and DAOs betweenness scores for their specific social graph of contributors, voters, and Twitter interactors. They could leverage that data to then airdrop their own tokens as well. Ultimately, I think that what has been done here can be further expanded and productized to help all of us gain better visibility into and reward/incentivize each step of the community flywheel created by the team at 0xSTATION:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1a3117e61078ff25dfa28baa80e30d6b3bb9927af6945458cd20b4c39d64a605.png" alt="https://station.mirror.xyz/xlPSC6PYsazGxjo-pqyaV8M4ujtWapxhCmVQfBjmN9o" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://station.mirror.xyz/xlPSC6PYsazGxjo-pqyaV8M4ujtWapxhCmVQfBjmN9o</figcaption></figure><h2 id="h-sources-and-methods" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Sources and Methods:</h2><ul><li><p>All data (besides identity mappings) were publicly sourced. Please see the data dictionary for details on sources.</p></li><li><p>Data analysis and visualization were performed in Python, using a mix of Pandas, Numpy, Scikit-learn, Networkx, Matplotlib, Seaborn, Plotly, Cdlib, Gephi, and Neo4j. The Neo4j Dashboard, Bloom, and Graph Data Science (GDS) packages were used as well for ancillary analysis. Desmos was used for early exploration and tuning of the reward formula.</p></li></ul>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[Creating a Community-Specific Reputation Score for Mirror Users]]></title>
            <link>https://paragraph.com/@ilemi/creating-a-community-specific-reputation-score-for-mirror-users</link>
            <guid>8hM7mFbqZ0shwT7P4oCw</guid>
            <pubDate>Thu, 29 Jul 2021 15:54:32 GMT</pubDate>
            <description><![CDATA[In my previous post on digital identity, I mentioned that "the tokenization of these graph shards could take many forms and will likely be layered upon by proof tokens." I believe that sharded graph identity approach requires coming up with a community-specific reputation score that measures how influential a certain person has been in expanding a specific network. While some reputation scores may be more set in terms of having to have done X or Y actions, this score captures a users reputati...]]></description>
            <content:encoded><![CDATA[<p>In my <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ath.mirror.xyz/mDu_nGsWpjvF-KaPLADwxeAMfze3UJOtTAQi2CwPwWc">previous post on digital identity</a>, I mentioned that &quot;the tokenization of these graph shards could take many forms and will likely be layered upon by proof tokens.&quot; I believe that sharded graph identity approach requires coming up with a community-specific reputation score that measures how influential a certain person has been in expanding a specific network. While some reputation scores may be more set in terms of having to have done X or Y actions, this score captures a users reputation in the context of other users in a more fluid manner - <strong>acting like a signal rather than a badge</strong>.</p><p>Typically in Web2, users are &quot;rewarded&quot; by an algorithm which will highlight them based on the engagement and attention they bring to the platform. Thus, their reputation score is just the number of likes or followers they have - regardless of who those vanity metrics come from. In Web3, we typically reward with tokens representing the value of the protocol or product. These tokens also carry a lot of power in the form of voting and other privileges. As such, a score that <strong>signals not only influence but also how supportive or aligned a user is</strong> with the rest of the community will become increasingly important over time.</p><p>For this post, we will be focusing on creating a reputation score for Mirror users (voters, writers, contributors) based on where each user sits on an interaction-based social graph across Ethereum, Twitter, and Mirror data. I chose Mirror for three reasons:</p><ol><li><p>I&apos;m already very familiar with their community and product</p></li><li><p>They have verifiable consolidation of identity on their platform (Ethereum &lt;&gt; Twitter), allowing me to layer social graphs together.</p></li><li><p>Their product and governance are heavily user-to-user interaction focused, something most products on Ethereum don&apos;t currently have (we mostly interact with pools or marketplace protocols).</p></li></ol><p>Social graphs themselves are not new, but selectively layering them will open up quite a few new doors of usability and meaningfulness. There are two main reasons for this:</p><ol><li><p><strong>Enabling new applications:</strong> We can use this graph data to create a context-dependent community-specific reputation score, which is then applicable in many situations.</p></li><li><p><strong>What the data represents:</strong> The creation of a representational network built off of scarcity creates a social graph that proxies how users support one another.</p></li></ol><p><strong>Enabling new applications:</strong> The way that we understand the layering affects what we do with the data. The way I see it, Ethereum is a base layer social graph that everything else is built upon. Platforms like Mirror and Twitter are <em>contexts</em> that sit on top of this base layer and shift how we see the connection of users across the space.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3e881416f33d882012026aa63476f4f2513721c491d6712d7923b2e9310cc7cc.jpg" alt="I don&apos;t have the design capability, but imagine this in 3D where each box is a slice across a sphere at various angles. " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">I don&apos;t have the design capability, but imagine this in 3D where each box is a slice across a sphere at various angles.</figcaption></figure><p>Because I wanted to analyze only users of Mirror, I took just a subset of available Ethereum and Twitter data. Those who have a high community-specific reputation score could get a larger token airdrop, be delegated for roles (or more votes) in treasury management, or get preferential access to new protocol features. There are also many more such contexts like Mirror built on top of Web2 + Web3 platforms, such as NFT communities (Cryptopunks, BAYC, Blitmaps) and gaming communities (Axie Infinity, Darkforest).</p><p>As DAOs start working together more and the metaverse becomes more interconnected, we&apos;ll see more communities (and contexts) overlap. I imagine that studying how people and communities interact <em>within and across different contexts of the social graph</em> could produce mixed-community reputation scores which could be applied in quite a few different situations. For example, this score could be used for multi-token or collaborative NFT airdrops, as well as choosing leaders for partnerships and programs like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rabbithole.gg/pathfinder">rabbithole&apos;s pathfinder initiative</a>.</p><p><strong>What the data represents:</strong> The kinds of data collected and used affect the social graph as well. Using data from $WRITE votes, funding contributions (across editions, splits, crowdfunds, and auctions), and Twitter mentions, I want to represent three buckets of scarcity (respectively): belief, capital, and attention.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a5e395123625824fd62a84fe3bdcd763f6e9e2a76a09fbb03c8d26dbaa541635.jpg" alt="Yes, technically this should be visualized as a self-referencing loop but that can come across as confusing" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Yes, technically this should be visualized as a self-referencing loop but that can come across as confusing</figcaption></figure><p>I believe that analyzing how interactions connect different people across these three buckets <em>gives us a proxy for how much they support each other</em>. I also believe that <em>networks of support give us a more accurate representation of communities within social graphs</em>. These two assumptions gave me confidence in using a concept called &quot;betweenness centrality&quot; as a primitive for a reputation score.</p><p>The selection of data representation and contexts was key to the form the social graph ultimately took. If I wanted to proxy just willingness to contribute, then I would probably create a completely create node schemas based on different kinds of products/categories of creators rather than a pure user-to-user graph. This would likely shift the shape of the social graph completely.</p><h2 id="h-using-graph-data-science-to-create-a-community-reputation-score-betweenness-centrality" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Using Graph Data Science to Create a Community Reputation Score: Betweenness Centrality</h2><p>Let&apos;s try to target and quantify the strong connection points of the social graph of race participants, writers, and contributors. I&apos;ve chosen to use a concept called &quot;betweenness centrality&quot; to represent the score of each node. Betweenness centrality is calculated <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf">using an algorithm that calculates the shortest path between all nodes for all nodes</a>).</p><p>Community clusters in a social graph usually look something like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c46a9cce43ce961d9caee691a3bfa4051587e282bbd40a5711f2ad7377d52f95.png" alt="Example social graph with community detection, where nodes represent people and lines represent different types of interactions" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Example social graph with community detection, where nodes represent people and lines represent different types of interactions</figcaption></figure><p>For Mirror, the base social graph of who has voted for who 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/0e8231ab880146b83df11790fea129080f5ab45714ad7540b6256611435baee9.png" alt="Gold dots are winners, purple dots are still competing in the race. Above there are 2130 nodes pictured, where 2041 of the nodes have put in at least one vote." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Gold dots are winners, purple dots are still competing in the race. Above there are 2130 nodes pictured, where 2041 of the nodes have put in at least one vote.</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c4d378eaa2c2a8711798c94b2811238a8132a6735de6a4d59302c01dabc24b77.png" alt="Here is a zoom-in on the nucleus, color-coded by each community using the [Leiden Community Detection](https://cdlib.readthedocs.io/en/latest/reference/cd_algorithms/algs/cdlib.algorithms.leiden.html?highlight=leiden#cdlib.algorithms.leiden) method. From this and the plot above, we can see there are quite a few communities but almost all the winners sit in the very middle." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Here is a zoom-in on the nucleus, color-coded by each community using the [Leiden Community Detection](https://cdlib.readthedocs.io/en/latest/reference/cd_algorithms/algs/cdlib.algorithms.leiden.html?highlight=leiden#cdlib.algorithms.leiden) method. From this and the plot above, we can see there are quite a few communities but almost all the winners sit in the very middle.</figcaption></figure><p>However, this doesn&apos;t have an outside-of-race social context yet. Let&apos;s layer in Ethereum transaction-level data - this is limited to Mirror-related transactions between participants, such as <strong>sending a split, funding a crowdfund, and buying an edition or reserve auction.</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a9d5541710408e71f170fadeaa0abdffec38470ba7a8329927dc1ec448f1e58b.png" alt="Pink indicates Ethereum tx, note that there are some nodes that are just an Ethereum address and don&apos;t have associated Twitter data as they aren&apos;t registered in the race." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Pink indicates Ethereum tx, note that there are some nodes that are just an Ethereum address and don&apos;t have associated Twitter data as they aren&apos;t registered in the race.</figcaption></figure><p>Now we&apos;ll add Twitter data too, which will link nodes based on <strong>who has mentioned another participant</strong> in their last 2000 tweets.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/32995c6fc44967e96ec18227717a9cd290eef83c0a7ecfd5bc8ef20a9fa80eb3.png" alt="Blue now represents Twitter mentions between nodes
" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Blue now represents Twitter mentions between nodes</figcaption></figure><p>Showing the interactions (edges) in a cleaner fashion, the mix of interactions across the social graph 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/42baff80adc4c2b6a1f08d919becb71c9988515df61078b7555d54ab5dd24a41.png" alt="Counting the number of users who have interacted with each other in each facet." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Counting the number of users who have interacted with each other in each facet.</figcaption></figure><p>Now getting back to the original point, the expectation is that some of these nodes between large clusters would get a higher weighting than others since they&apos;ve connected the paths across the most other nodes.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a3d8f7b6b23355eb348d11e335f1e7b86bc0c047b53aa046a5b915a4c587f882.png" alt="The top 300 betweenness users have been highlighted in red, we can see they start to spread fairly far out from the center of the graph. " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">The top 300 betweenness users have been highlighted in red, we can see they start to spread fairly far out from the center of the graph.</figcaption></figure><p>This is called &quot;betweenness&quot; and is a factor I believe to be very important when trying to proactively grow a community. The base idea here is that the higher the &quot;betweenness&quot; factor a person has, the more likely they will lead to creating connections and branches that build up a more diverse community. There have been a few research papers that highlight the beneficial effect that nodes with high betweenness have on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dl.acm.org/doi/10.1145/2365952.2366010">diffusion of a community</a> as well as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arxiv.org/pdf/0711.3710.pdf">building the resilience of a network</a>.</p><p>Some of you might be wondering why I chose betweenness centrality over something like closeness or degree centrality. Those latter two metrics highlight pure influence, and I don&apos;t think reputation in a community should be based on just those who already have that level of influence. The <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.google.com/books/edition/Graph_Algorithms/z4WZDwAAQBAJ?hl=en&amp;gbpv=0">Graph Algorithms</a> textbook by Neo4j puts the concept behind betweenness very well:</p><blockquote><p>&quot;Sometimes the most important cog in the system is not the one with the most overt power or the highest status. Sometimes it’s the middlemen that connect groups or the brokers who have the most control over resources or the flow of information. Betweenness Centrality is a way of detecting the amount of influence a node has over the flow of information or resources in a graph. It is typically used to find nodes that serve as a bridge from one part of a graph to another.&quot;</p></blockquote><p><strong><em>A lot of Web2 has been about concentrated influence and echo chambers, I believe Web3 should try to enable and incentivize creating bridges as much as possible instead.</em></strong></p><p>For anyone who wants to see the scores, check out the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.google.com/spreadsheets/d/1XiX8b7KkvtfBE2KLJWv-mCPtphrQxjt1-g4wKCa4JwE/edit?usp=sharing">sheet here</a>. Note that these values have not been weighted based on data/edge type, so some users may have higher betweenness due to Twitter interactions rather than Mirror/Ethereum interactions.</p><h2 id="h-why-is-this-methodology-important-to-the-score" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Why is this Methodology Important to the Score?</h2><p>We&apos;ve already discussed some of the applications of this score, but the solution I used may still appear unnecessarily complex or overengineered. I think this methodology is required to provide composability while also measuring reputation in a way that is much tougher to game.</p><p><strong>Composability:</strong> As mentioned before, this graph is built up layer-by-layer. The data elements are all publicly available to collect, the model follows a search algorithm and is flexible to whatever nodes or edges (users or interactions) are chosen, and once the pipeline is built once it can be reused or forked for any set of tweaks. Hopefully in the future, all the available data components just sit in a user interface and this model becomes drag and drop. From there I imagine you could export scores or connect directly to something like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://disperse.app">disperse.app</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://galaxy.eco">galaxy drops</a>.</p><p><strong>Durability:</strong> The problem with many scores and measures is that once they have been publicly used once, then people can start to figure out how to game the system. This is especially true for anything that is just <code>user &lt;&gt; protocol</code> interaction based. Creating a model that is <code>user &lt;&gt; user &lt;&gt; user</code> dependent is harder to game because the users in the current community won&apos;t necessarily reciprocate interactions with a bad actor. Actions are also compounding, so having just one interaction (or one type of interaction) will not be good enough to get a higher score). Even if they do find some way to game it, then congratulations you now have another active participant who is contributing to the community.</p><p><em>These two elements allow for an overall stronger reputation score mechanism, which I believe justifies the efforts it takes to get there.</em></p><h2 id="h-in-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">In Conclusion:</h2><p>I would like to continue iterating this research and possibly use this kind of score for specific use cases from protocols and communities (please reach out if interested). If you&apos;ve made it this far and want to contribute to this analysis with ideas or technical expertise, I do invite you to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/jEm2UgBpXu">join ImagDAO</a> for further work on social graph data and decentralized identity).</p><p>The next steps include more data collection, setting up a Neo4j dashboard for others to play with, and of course applying more data science algorithms. Machine learning and community detection will likely take on a bigger role in the future as we try to predict how the social graph will grow or try to target specific sub-communities.</p><p>I mentioned before that this analysis was only possible because of the verifiable consolidation of identity by Mirror&apos;s platform (Ethereum &lt;&gt; Twitter). Continuation of this work heavily depends on an identity consolidation API as well, so anyone working in this context please connect with me as well (looking at you Ceramic and Gitcoin 👀).</p><p><em>The data and scripts may be shared publicly later once I refactor and figure out how to protect the privacy of users in this social graph.</em></p><p><em>Special thanks to Ben Schecter for all his help and ideas in reviewing this post</em></p><p><strong>If you want to support more of this research, consider bidding on the auction for &quot;Decentralized Community&quot; or contributing to the split below:</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7">Token #4194</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x370d93E74E0f5Aa84caeC70A36c75e489EEaf1cF">Social Graph Searchers</a></p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[The Composability of Identity across Web2 and Web3]]></title>
            <link>https://paragraph.com/@ilemi/the-composability-of-identity-across-web2-and-web3</link>
            <guid>D2bVktvBR1peKxbwku4S</guid>
            <pubDate>Sun, 30 May 2021 23:03:31 GMT</pubDate>
            <description><![CDATA[A decade or two ago, your digital identity didn&apos;t mean very much. It was represented more by your email address than any social media account you had. Fast forward to today, and we&apos;ve seen an increased focus on how we appear in online media by everyone: yourself, your friends, and your employers. Most of our day-to-day interactions exist in digital accounts on someone&apos;s database. Yet all-in-all, your digital worth is measured by the engagement (and advertising revenue) garnered...]]></description>
            <content:encoded><![CDATA[<p>A decade or two ago, your digital identity didn&apos;t mean very much. It was represented more by your email address than any social media account you had. Fast forward to today, and we&apos;ve seen an increased focus on how we appear in online media by everyone: yourself, your friends, and your employers. Most of our day-to-day interactions exist in digital accounts on someone&apos;s database.</p><p>Yet all-in-all, your digital worth is measured by the engagement (and advertising revenue) garnered. Sometimes you get a share of that revenue, but for 99% of us, the value of our digital identity is locked within the platform. This doesn&apos;t just apply to Facebook, Twitter, or Reddit - the &quot;platform&quot; can be our workplace as well.</p><p>Let&apos;s say you&apos;ve worked at a company for a few years, and you&apos;ve decided to move on. When you leave the company, your reputation still stands with individuals you&apos;ve worked with and in the many programs/emails you&apos;ve created, but otherwise, the company&apos;s reputation is your reputation. This dynamic has slowly changed with the rise of the internet - hence the rise of the personal brand. However, your personal brand is still built off of your own word (which may or may not have much value when first starting out).</p><p>Our digital identity exists in fragments, it isn&apos;t flexible past the platform it was built on, and it has little reusability other than cross-platform authentication. We don&apos;t own our digital identity, and it&apos;s not composable at all. Now, what if you could <strong>own all of the pieces of your digital identity permanently</strong>, while also <strong>controlling who you reveal that data to</strong> and <strong>how it&apos;s represented</strong>? This would enable us to tell more compelling stories and have a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/hackernoon/richard-stallman-future-of-software-innovation-4e591fa93d7f">user-controlled value function</a> for identity. I think we&apos;re (finally) not so far off from a future where all of that is possible.</p><p>But the phrase &quot;digital identity&quot; is really complex and abstract. Let&apos;s start by sorting it into a treemap of <code>identity type -&gt; platform type -&gt; transaction type -&gt; action type</code>.</p><h2 id="h-hierarchy-of-digital-identity" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Hierarchy of Digital Identity</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3e6bd8767cbae8bec64b46e713537f6af9bb04c06d77f432a3c84d40e642b99a.jpg" alt="I know, it&apos;s a thicc chart. Desktop viewing is best for easier zooming." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">I know, it&apos;s a thicc chart. Desktop viewing is best for easier zooming.</figcaption></figure><p>For identity types, I&apos;ve split it into physical and digital identity (physical is hidden for this article). The next layer is platform types, which I&apos;ve just split into Web2 and Web3 for now. In the future, it may not be so simple to separate which platform different types of transactions are coming from. Now for the meat and potatoes of this breakdown, transaction and action types:</p><p><strong>Social Transactions</strong>: These are transactions where you have a set individual or group of individuals you know you want to interact with.    - <em>Individual</em>: This is just like Venmo when you pay or interact with someone for any number of reasons    - <em>Community</em>: These are actions that go towards some group cause, and can be anything from funding a treasury to governing actions for spending from that treasury.    - <em>Gaming</em>: This is another way of saying actions where the result/end party of the action isn&apos;t always known. In many games, this is common, like going on raids or adding to/interacting with some city on your journey.</p><p><strong>Protocol Transactions</strong>: These are transactions where you interact with a product for its specific benefits or utility.   - <em>Selling/Acquiring</em>: These are marketplace actions, where the protocol is used to conduct a peer-to-peer interaction.   - <em>Staking</em>: This is an action where you are staking your belief in a protocol, acting as a core member of the product community. The actual use of the stake may vary, but the signaling is the same.   - <em>Use</em>: I&apos;m defining &quot;use&quot; here as the primary use case action of the protocol. Sometimes that may be &quot;selling/acquiring&quot; or &quot;staking.&quot;</p><p><strong>Conversations</strong>: These are transactions where you are trying to work with (or against) others to directly push towards some goal or understanding (in a friendly and sustainable way). In the context of this article, these conversations are focused on the growth and governance of communities/products/protocols.    - <em>Proposals</em>: These are like Ethereum Improvement Proposals, but can be much more general too.    - <em>Moderation</em>: Some examples are Reddit mods and Twitch chat mods, where they enforce rules set by proposals.    - <em>Feedback</em>: This is usually in direct response to proposal or moderation actions. A lot of this is providing a larger context and bridging the conversation between old and new users.</p><p><strong>Contributions</strong>: These are transactions where you either create something or engage (without conversation) with something someone created.    - <em>Consumption</em>: Actions here include liking or saving an article, or running <code>npm install</code> on someone&apos;s <code>node js</code> package.    - <em>Creation</em>: This includes creating new ideas, products, integrations, and much more.    - <em>Sharing</em>: These actions contribute directly to network effects, and typically act as bridges across platforms and communities.</p><p>Our web of actions ultimately forms our digital identity. I know that even this is still pretty abstract, so let&apos;s look at how this could be realistically represented and used.</p><h2 id="h-representing-digital-identity-in-practice" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Representing Digital Identity in Practice</h2><p>Here&apos;s the structure I&apos;ve been working with on what digital identity on a more technical level:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0e2cc57a78ad9999fac88ee7dba69ad5672c9681bc486ef11d6dc17572b644db.jpg" 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>The first layer is comprised of transaction types (the four we talked about) and social graphs. I didn&apos;t include social graphs as part of the identity breakdown since the graph&apos;s nodes are each their own digital identity, connected by lines that represent transactions. I&apos;ve labeled this whole layer as &quot;not composable,&quot; meaning I can&apos;t detach them from an identifier or really move them around from platform to platform to form a single identity. While transaction data is immutable, it is typically exportable and can be represented in tokens. Social graphs are more difficult to manage in a portable way, first and foremost because current platforms limit the ability to export that data. This has been <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://stratechery.com/2021/the-webs-missing-interoperability/">a heated topic of discussion</a> for years now, so there&apos;s a large lack of transparency on what they actually look like and how to break them down. However, new products and approaches allow you to build up and represent the nodes closest to you in the social graph - which can then also be stored into tokens. That representation as tokens brings us to the second layer of the chart.</p><p>The second layer (and onwards) highlights categories and products that allow us to represent that transaction data and/or social graph as <strong>tokens</strong>. Since tokens have the qualities of existence, flexibility, and reusability - then by the transitive property - our digital identity now does as well. I can move around these tokens at will to different accounts and in different combinations. If we add on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-2255">permission/connection rules</a> wallets already have to the tokens&apos; data, we&apos;re coming very close to the picture I painted at the start.</p><p>Let&apos;s talk about what&apos;s behind the tokens of this composable digital identity layer =&gt;</p><p>Tokens built off of transaction data will likely rely on different models and algorithms that may start centralized and then transition to community-governed. These models will take different combinations of transaction and action types depending on what they want to represent. SourceCred allows custom-set rules for measuring <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://sourcecred.io/docs/beta/cred/#calculating-cred">&quot;contributions&quot;</a>. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.spectral.finance/macro-score/on-chain-credit-score">Spectral.finance</a> creates machine learning credit score models that may take on a Numerai style many-model architecture in the future. I&apos;d expect <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.notion.so/RabbitHole-Manifesto-75477a7e03634336bba77c4a7b43ee3b">Rabbithole.gg</a> to have some token(s) representing levels of different skills in the future, where the levels are calculated with different models. How we tokenize web2 account transaction data probably won&apos;t be that different in structure <code>data =&gt; model =&gt; token</code>. They may rely on existing web2 aggregators like orbit.love and their <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/orbit-love/orbit-model">model for calculating reputation by community</a>.</p><p>The fungible versus non-fungible identity token approach here reflects what kind of identity economies will be generated. Fungible tokens act as a standard and stable reputation coin that holds regardless of the type of community or contribution. These may help facilitate creative cross-community collaboration and creative talent acquisition, leading to new treasury management strategies and considerations. Non-fungible tokens are identity bonds that can be staked or lent out, which growing in value over time as an individual&apos;s actions continue to evolve. Identity forges (a protocol where you and I place our creditworthiness NFT to create a new representative token) will increase the utility and complexity of this token. Multiply this across all proof tokens and we have the beginnings of an &quot;identity marketplace.&quot;</p><p>Earlier I said that social graph tokens would likely be represented by your closest nodes instead of the full graph. This comes from the two popular approaches I&apos;ve seen today:</p><ol><li><p>Sybil Resistant: The theory here is that if I am verified by enough other &quot;people&quot; who are real, then I am real. BrightID&apos;s health score reflects this, and it seems to be working well.</p></li><li><p>Tiered Entry: Let&apos;s start with 100 people who we know are real and trusted, and then bring in more people based on the selection/voting of those 100 people</p></li></ol><p>With both of these approaches, your social graph is the people who verified or voted for you. Whether or not these decentralized identities (DIDs) aggregate under addresses or the other way around largely depends on how we interface with the digital world - I believe it will be the former for the same reasons we don&apos;t &quot;login&quot; to pages with our ENS. The tokenization of these graph shards could take many forms and will likely be layered upon by proof tokens.</p><p>All of these identity tokens represent the earliest primitives, and I&apos;m sure they will be built upon with additional complexity as our mental and technical understanding of &quot;trust&quot; and &quot;digital identity&quot; evolve. With that as the expectation, our digital identity becomes more like a portfolio, requiring a new set of tools. We&apos;ve seen community SaaS tools grow over the last few years that help product teams increase engagement with their community of users across platforms, but what I&apos;m pushing for here is an <strong>identity management tool</strong> for the users themselves.</p><h2 id="h-building-an-identity-management-tool" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Building an Identity Management tool</h2><p>While we have asset management tools like Zerion and Zapper, there is no &quot;identity management tool&quot; yet. This isn&apos;t too surprising as proof tokens are largely still under development for the Ethereum transaction data side, and most protocols still link web2 accounts independently (like mirror.xyz does when you sign up for the $WRITE race). For now, I view the product stack as follows:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cee6bb498c60f19dde4a6a6cb067a2f9ee2605ae3aebc0c1ddce6f156c7a3f19.jpg" 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>The data aggregation layer should be managed by other protocols, where each protocol will have decentralized governance of standards and usage. An identity management tool would play with everything in blue, starting as a specialized SDK between all our identity tokens interactions/metadata for wallets to use. While there are many features required for managing identity, I want to start with the actions of verification and permissioning.</p><p>Let&apos;s focus on connecting unique web2 identifiers (i.e., Github and Twitter accounts) to Ethereum address(es). There is a growing list of tools (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://idx.xyz/">Ceramic IDX</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://veramo.io/docs/veramo_agent/introduction/#:~:text=A%20Veramo%20Agent%20is%20an,in%20the%20verifiable%20data%20space.">Serto/Veramo Agents</a>) for representing identifiers and action data in standard ways (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://lists.identity.foundation/g/sds-wg/wiki">DIF</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.w3.org/TR/did-core/">W3</a>). We can build a verification process users have to pass once and then issue a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.serto.id/docs/main-concepts/vcs/">verifiable credential</a> using existing tools onto a decentralized database. Then we build the plugin that fits into a wallet to allow users to manage data sharing with apps. I recently built a proof of concept for this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3df76220689651768ee331e43ff1dbb87c2b9cfcf69065b88fbf5de9ef43b407.jpg" 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><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=D4FoO7Ph5lI"><em>tech demo</em></a></p><p><em>You also may be wondering what a &quot;snap&quot; is - this is like a plugin/API built directly into the Metamask wallet. I believe that an identity management tool should be controlled by the user in the most decentralized and private way possible, so building it into a wallet makes the most sense.</em></p><p>Other added benefits of this approach are:</p><ol><li><p>Developers can stop reinventing the wheel and save on AWS overhead/privacy concerns, requiring just one provider request to the wallet instead (no API key or sign-up process required).</p></li><li><p>Users can stop going through the <code>input account -&gt; sign -&gt; post sig -&gt; refresh</code> flow once every few weeks when a new social dapp launches.</p></li><li><p>Users can start to manage who has access to their identity branches/data since it isn&apos;t on a centralized/controlled database.</p></li></ol><p>This third point is critical, as it opens up a whole new world of applications in terms of verifiable storytelling and data ownership/economies. I think that&apos;s the ultimate goal - anyone should be able to curate an identity for the story they want to tell, and if they don&apos;t have the pieces then they can build (through transactions) or borrow (through a marketplace) up to it.</p><p>If you like the vision and want to see this built out more, then pick up some $IMAG to bootstrap the project (I&apos;ll also create a group for further discussion about this with supporters - maybe make this a DAO if there&apos;s enough interest):</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x85625B4983E6A54eDA7E237f1a64e0CFB4408c6D">Identity Curators</a></p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
        <item>
            <title><![CDATA[Build {on} bridges, not [behind] walls]]></title>
            <link>https://paragraph.com/@ilemi/build-on-bridges-not-behind-walls</link>
            <guid>xHwz4dMziXgIsC4m45ID</guid>
            <pubDate>Thu, 27 May 2021 00:29:58 GMT</pubDate>
            <description><![CDATA[Ever since sharding and the internet of blockchains ideas were first introduced, maintaining composability has been a hot topic of discussion. Let&apos;s try to better understand the role bridges play in keeping our ecosystem composable. While I&apos;ve written about composability of dapps and wallets before, I don&apos;t believe I&apos;ve explicitly defined the word "composable." Generally, I think composability is comprised of existence, flexibility, and reusability. As a pre-condition, eve...]]></description>
            <content:encoded><![CDATA[<p>Ever since sharding and the internet of blockchains ideas were first introduced, maintaining composability has been a hot topic of discussion. Let&apos;s try to better understand the role bridges play in keeping our ecosystem composable.</p><p>While I&apos;ve written about composability of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/crypto-and-web-3-0-are-the-future-of-product-and-work-3d19e3733181">dapps</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/1the-importance-of-composable-wallets-for-users-and-developers-accb2aadff49">wallets</a> before, I don&apos;t believe I&apos;ve explicitly defined the word &quot;composable.&quot; Generally, I think composability is comprised of <strong>existence, flexibility, and reusability</strong>. As a pre-condition, everything should be accessible in a permissionless manner (i.e. sufficiently decentralized).</p><h2 id="h-existence" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Existence</h2><p>I believe that right now, most people think of bridges as &quot;how can I get token A transferred from blockchain X to blockchain Y,&quot; or slightly fancier as &quot;how can I swap token A on blockchain X for token B on blockchain Y.&quot;</p><p>In other words, right now the focus is on <strong>asset existence</strong> - meaning the same asset should exist on every chain. For example, USDC should exist on both Ethereum and Polygon and remain fungible between chains (almost as if they were the same ERC20 contract). Another example would be getting Bitcoin from its chain to Ethereum through the Ren wrapper as renBTC.</p><p>A second facet is continuous versus ubiquitous existence. Continuous is the earlier example where my tokens are either on chain A or chain B. However, some tokens may need to exist on multiple chains at the same time, hence, ubiquitous. This can apply to something like a proof token (NFT). Let&apos;s say I have an NFT representing my credit score which I can use to borrow with special terms inside some defi dapp. I wouldn&apos;t want to transfer this NFT across chains, since I&apos;m likely borrowing from multiple chains at the same time. Hence, the NFT needs to exist on both chain A and chain B at the same time - and remain in sync on mints, transfers, and URI updates. This can be extended to DAOs as well, though this one is harder to think about since DAOs don&apos;t have a set contract standard.</p><p>A more technical way of framing asset existence is as the data on a blockchain. Usually, we either access data stored in a contract or we mutate the state by interacting with the contract. As far as I know, we don&apos;t have a good way of accessing or mutating data between chains, besides what is under research like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.celo.org/celo-codebase/protocol/optics">optics</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/eth2/beacon-chain/">sharding</a>. This means that currently, smart contracts (the logic and assets) are portable from chain to chain but are non-interactive between them. Instead of the vertical legos we&apos;re used to, we really only have horizontal integration right now. Each chain is built up as a walled city, with resources traded around between them all.</p><h2 id="h-flexibility-and-reusability" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Flexibility and Reusability</h2><p>I think that the scope of asset transfer for understanding bridges is a little narrow. The truth is, we&apos;ve actually all been using bridges for years now! Let&apos;s redefine a bridge to be &quot;the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=m5lQIa-lSKI">transport, authentication, and ordering</a> of information between two or more parties.&quot;</p><p>This is very similar to how the internet works today, where data is split and transferred in packets between a web of nodes before reaching their desired destination (IP) and being put together in a specific order to represent the original data. Our extra layers of complexity with bridges involving blockchains come from security and verification:</p><ul><li><p>As chain B, can you trust the message being sent across the bridge is true, like when using wrappers like renBTC?</p></li><li><p>Conversely as chain A, can you trust that the message you sent through was committed into a transaction (i.e. calling a smart contract on chain B)? I won&apos;t go deep into this today but you can learn more about the technical difficulties <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eprint.iacr.org/2019/1128">here</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=b0mC-ZqN8Oo">here</a>.</p></li></ul><p>Now, let&apos;s think about what common party-to-party bridges exist in the our ecosystem:</p><ul><li><p>database &lt;&gt; database (bridged by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/collection">ACID methodologies</a> and microservices)</p></li><li><p>database &lt;&gt; blockchain (oracle networks that bridge data to a blockchain)</p></li><li><p>blockchain &lt;&gt; database (event reader networks that bridge blockchain to a database)</p></li><li><p>blockchain &lt;&gt; blockchain (the bridges we&apos;ve been talking about for the internet of blockchains fit here)</p></li><li><p>dapp &lt;&gt; dapp (everything in between is one large, flexible bridge)</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/00fe1b573fb2d4979e51039a181e74dd6bf8093940fa27602b46eabb53c9d66f.jpg" 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>I&apos;ve observed that bridges are first built for a specific purpose of supporting data existence from point A to point B, but then become more and more flexible as <strong>they can be built upon by anyone).</strong></p><p>Generally with any bridge there are three roles:</p><ul><li><p>Node Runner (manage the bridge infrastructure)</p></li><li><p>Creator (developers who create a marketplace of possible interactions/queries to load onto nodes)</p></li><li><p>User/Query Runner (consumers of data, who can use anything from the marketplace built by creators to port data from point A to point B through node runners)</p></li></ul><p>Once these three roles have been set up nicely, you obtain the properties of flexibility and reusability. Let&apos;s look at some concrete examples:</p><ul><li><p><strong>Chainlink</strong>: On Chainlink, you have a party that is specifically responsible for running a node that takes in requests from an on-chain oracle contract and returns the value from the endpoint queried. Creators are developers who can create <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.chain.link/docs/external-adapters/">external adapters</a> that allow for API keys and complex logic (i.e. the data returned is a multi-key JSON object, and I can use an adapter to concatenate that into a bytes32 object to easily parse in solidity).</p></li><li><p><strong>theGraph</strong>: This service has the three roles <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/network#overview">most clearly defined</a>, with indexers (node runners that read emitted events from on-chain), curators (creators of the subgraphs/API endpoints), and consumers (the ones running each query).</p></li><li><p><strong>Numerai</strong>: While their user use case may not be as flexible (given they are not purposed to output data on-chain past staking purposes), they allow creators to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.numer.ai/tournament/compute">upload machine learning models</a> onto hosted infrastructure. Given the prevalence of ML/AI in our world, I imagine that one day someone will provide a similar service/structure for running models with inputs/outputs on-chain.</p></li></ul><p>Now for some bridges that I think will reach the same structure:</p><ul><li><p><strong>Teller</strong>: While right now <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://teller.gitbook.io/teller-docs/teller-nodes/overview">their node network</a> supports only the transfer of your bank account data on chain, it is possible that they become a network that allows any fintech data provider to onboard and create a data service. This is similar to chainlink, but their infrastructure has better privacy management/implications.</p></li><li><p><strong>Mina</strong>: Speaking of privacy, Mina is actually a super interesting project because they enable use cases like Teller with their technology. Their tooling allows for a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://minaprotocol.com/tech">zk/privacy overlay end-to-end</a>, which in my mind feels very similar to how we have gone from TCP/IP to VPN in the traditional internet world. I&apos;m assuming they&apos;ll be like any node network where these privacy use cases can be built on top of it and used by anyone on another blockchain.</p></li></ul><ul><li><p><strong>Cosmos</strong>: With CosmWasm/IBC/Tendermint/Ethermint, you can actually start building logic into bridges that are similar to smart contracts (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.cosmos.network/sifchain-announces-peggy-cosmos-ethereum-cross-chain-bridge-eeb46a8f91db">like DEXs</a>). Some examples that have come out of their SDK are proof of stake style chains like Thorchain.</p></li><li><p><strong>Connext</strong>: With state channels/ILP, you get a level of user flexibility that is hard to manage with IBC. Their <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.connext.network/custom-transfers">custom transfer definitions</a> and routers may in the future allow for special use cases for DAOs, NFTs, and other self-managed multi-chain needs.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/92fb57468958386624549de8df9765dd49f4ba50c2d9e8245c359fd01c560571.jpg" alt="Together, our ecosystem looks something like this" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Together, our ecosystem looks something like this</figcaption></figure><p>Building freely upon bridges gives us <strong>flexibility</strong>, and the shared infrastructure and split roles gives us <strong>reusability</strong>. Many of our bridges already have these two properties, and the bridges between blockchains are getting there as well. One day these bridges will enable full (veritcal/horizontal) existence as well, giving us composability across the ecosystem.</p><h2 id="h-a-token-from-the-haert" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">A Token from the Haert</h2><p>We&apos;re all out here building bridges right now, trying out best to move in sync. Walls are being torn down, and the groundwork is being laid for the many future generations to build upon. We must <strong>exist</strong> together, with <strong>flexibility</strong> of mind, and a <strong>shared</strong> heart. There will be no walls in the metaverse. I wanted to represent this ethos in an algorithmically generated art piece from Ethereum data:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7">Token #3347</a></p><p>The identicons are generated from 100 unique Ethereum addresses. Through 100 rounds, each &quot;block&quot; moves towards the center following the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethresear.ch/t/deep-dive-into-current-pow-difficulty-adjustment-algorithm-and-a-possible-alternative/5267">Ethereum PoW Poisson distribution</a>. The &quot;heartbeat&quot; is generated by the amplitudes of the sine transform of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/chart/tx">Ethereum transaction history</a>.</p>]]></content:encoded>
            <author>ilemi@newsletter.paragraph.com (Andrew Hong)</author>
        </item>
    </channel>
</rss>