<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: ali kim</title>
    <description>The latest articles on Forem by ali kim (@alinobrasil).</description>
    <link>https://forem.com/alinobrasil</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F919293%2F6d4a8cbc-6c6e-4ba0-9802-4230aa8714a4.png</url>
      <title>Forem: ali kim</title>
      <link>https://forem.com/alinobrasil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alinobrasil"/>
    <language>en</language>
    <item>
      <title>EIP 712: A simple example using Ethers.js &amp; Hardhat</title>
      <dc:creator>ali kim</dc:creator>
      <pubDate>Fri, 12 Apr 2024 16:48:15 +0000</pubDate>
      <link>https://forem.com/alinobrasil/eip-712-a-simple-example-using-ethersjs-hardhat-2hn5</link>
      <guid>https://forem.com/alinobrasil/eip-712-a-simple-example-using-ethersjs-hardhat-2hn5</guid>
      <description>&lt;p&gt;Several months ago, I was trying to use EIP712 to create verifiable signatures using structured data. It’s a standard way of signing structured data, so theoretically it should be super simple: Sign a message and then decode to verify it, right? &lt;/p&gt;

&lt;p&gt;In practice, I had a tough time getting this to work. I looked at various documentation and code examples, but I noticed they all had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;different implementations of signing and verifying (decoding) signature&lt;/li&gt;
&lt;li&gt;different implementations by ethers version&lt;/li&gt;
&lt;li&gt;different decode implementations&lt;/li&gt;
&lt;li&gt;overcomplicated demos&lt;/li&gt;
&lt;li&gt;No end to end example of using ethers.js (only web3.js)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all these little issues combined, I just couldn’t do a simple sign &amp;amp; verify using EIP712. I ended up wasting so much time.&lt;/p&gt;

&lt;p&gt;Here’s a sample repo to help anyone having trouble using EIP-712.  If you can’t do a simple sign &amp;amp; verify within 15 minutes, just use my code: &lt;a href="https://github.com/alinobrasil/eip712_product_registry"&gt;https://github.com/alinobrasil/eip712_product_registry&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By utilizing EIP712, you will have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enhanced Security: EIP712 helps prevent certain types of replay attacks and phishing attacks, thereby enhancing the security of transactions and interactions within the Ethereum ecosystem.&lt;/li&gt;
&lt;li&gt;Improved User Experience: EIP712 provides a better user experience by enabling wallets and dApps to display transaction information in a structured, human-readable format, reducing the likelihood of user errors and increasing overall usability.&lt;/li&gt;
&lt;li&gt;Interoperability: EIP712 facilitates interoperability between different wallets and dApps by defining a standard for how transaction data is structured and signed, thereby promoting seamless interaction and integration across the Ethereum network.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>eip712</category>
      <category>ethereum</category>
      <category>webdev</category>
      <category>ethers</category>
    </item>
    <item>
      <title>How to use The Graph to query Event data</title>
      <dc:creator>ali kim</dc:creator>
      <pubDate>Thu, 02 Nov 2023 17:28:12 +0000</pubDate>
      <link>https://forem.com/alinobrasil/how-to-use-the-graph-to-query-event-data-4df0</link>
      <guid>https://forem.com/alinobrasil/how-to-use-the-graph-to-query-event-data-4df0</guid>
      <description>&lt;p&gt;As a data guy, I find The Graph super awesome for developing any dapp. But I had a slightly hard time getting my subgraph to work. So here's a little guide for anyone who may find the same struggles. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contents:
&lt;/h2&gt;

&lt;p&gt;Why The Graph&lt;/p&gt;

&lt;p&gt;How to use the Graph&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Getting set up&lt;/li&gt;
&lt;li&gt;Build your subgraph&lt;/li&gt;
&lt;li&gt;Define event handlers&lt;/li&gt;
&lt;li&gt;Finishing Touches&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Extras&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a more complex example&lt;/li&gt;
&lt;li&gt;how to deal with using proxy contracts&lt;/li&gt;
&lt;li&gt;how to deal with slow Studio performance&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why The Graph
&lt;/h2&gt;

&lt;p&gt;The Graph is GREAT for developing the frontend of a decentralized app (dapp). Here's my take on why it's so awesome and how you can quickly get up and running with it.&lt;/p&gt;

&lt;p&gt;When your dapp needs to display some information on the state or history of something going on in your smart contract, using events instead of state variables will help save gas and overall performance. Things like tracking transaction history of an ERC20 token, borrowing/lending activity or actions like voting. You only need to read this info. &lt;/p&gt;

&lt;p&gt;So if you design your frontend to read from logs, you can potentially let your smart contract use less storage variables. Your frontend can query from some external source with the data all prepared in a clean format. &lt;/p&gt;

&lt;p&gt;The problem is that you need some infrastructure to collect all the  relevant events, clean them up a bit and then host them somewhere for you. The Graph solves these problems in one go. Your project of indexed events is referred to as a Subgraph.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use The Graph
&lt;/h2&gt;

&lt;p&gt;At a high level you'll need 3 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up a subgraph using their web interface and cli tool&lt;/li&gt;
&lt;li&gt;Design a schema for how to store your data&lt;/li&gt;
&lt;li&gt;Set up the logic to fit the event data into your schema&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Part 1: Getting set up
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to thegraph's studio: thegraph.com/studio. You'll need to connect your metamask wallet to log in. &lt;/li&gt;
&lt;li&gt;Click the button "Create a Subgraph"
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqxt36u86zbcnwj66l0v.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;li&gt;Set things up
The next screen shows you the commands you need to get set up&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8hnns5ue41d7hi3op65c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8hnns5ue41d7hi3op65c.png" alt="Setting up subgraph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll be prompted to enter a bunch of info. Here's an example from thegraph's site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0302oof966gr2amkubjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0302oof966gr2amkubjf.png" alt="setting things up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you enter a contract address, it will be able to fetch the ABI from etherscan if the contract has been verified. So if it's your own smart contract, take the steps to verify/publish your contract. Then this &lt;code&gt;graph init&lt;/code&gt; step will obtain the abi automatically.&lt;/p&gt;

&lt;p&gt;It's easiest to just go with the default config by pressing enter all the way. &lt;/p&gt;

&lt;h3&gt;
  
  
  Part 2: Design a schema
&lt;/h3&gt;

&lt;p&gt;Go into your subgraph folder. In my case, it'd be test123. Open your code editor in this folder.&lt;/p&gt;

&lt;p&gt;The default schema generated by &lt;code&gt;graph init&lt;/code&gt; is called &lt;code&gt;schema.graphql&lt;/code&gt;. It creates an entity (data table) for each smart contract event but most often that will not be the schema you want to use.&lt;/p&gt;

&lt;p&gt;How do you go about this?&lt;/p&gt;

&lt;p&gt;Let's say your smart contract emits 2 events:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event GravatarAccepted(
  address indexed owner,
  bytes32 indexed id, 
  string displayName,
  string imageUrl
);


event GravatarDeclined(
  address indexed owner,
  bytes32 indexed id,
  string displayName,
  string imageUrl  
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instead of creating an entity for each event, you should try to think of the simplest way you can store this info in a way that makes sense to  your front-end app. &lt;/p&gt;

&lt;p&gt;We shouldn't need duplicate info for owner, id, displayName and imageUrl. You'd likely need just one additional field indicating whether a Gravatar was accepted or declined. So you can end up with this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlti59bl8z5yjeh0eol8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlti59bl8z5yjeh0eol8.png" alt="Schema example - gravatar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an over-simplified example. Later I'll show you a slightly more complex example that got me an award from The Graph (1st place in Best Use of Subgraph at ETH Global New York 2023). &lt;/p&gt;

&lt;h3&gt;
  
  
  Event handlers: Mapping events to your schema
&lt;/h3&gt;

&lt;p&gt;This is the bulk of the work. &lt;/p&gt;

&lt;p&gt;You'll see a &lt;code&gt;ts&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; folder named after your contract. It auto-generates a bunch of files to be able to import contract &amp;amp; event related event objects.&lt;/p&gt;

&lt;p&gt;You just need to focus on the handler functions that specify what to do with each event. &lt;/p&gt;

&lt;p&gt;In the Gravatar example above, I had 2 events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GravatarAccepted&lt;/li&gt;
&lt;li&gt;GravatarDeclined&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then my &lt;code&gt;ts&lt;/code&gt; file would have handler functions called&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;handleGravatarAccepted&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handleGravatarDeclined&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The default ones only show you how to create a new record in your entity. &lt;/p&gt;

&lt;p&gt;But that's not what we want to do for &lt;code&gt;GravatarAccepted&lt;/code&gt; and &lt;code&gt;GravatarDeclined&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;For these events, we should only need to indicate whether the gravatar was accepted or not. Consider the schema defined earlier:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flty5h8nicjupbh3of82f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flty5h8nicjupbh3of82f.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We should only need to update the "accepted" field. &lt;/p&gt;

&lt;p&gt;Let's assume the contract has an event 'GravatarCreated' indicating the details (owner, displayName, imageUrl). This can simply use the default function where it creates for the our entity every time this event is created.&lt;/p&gt;

&lt;p&gt;Then our handler functions for &lt;code&gt;GravatarAccepted&lt;/code&gt; and &lt;code&gt;GravatarDeclined&lt;/code&gt; should only need to locate the existing record by id and update the value for the field 'accepted'. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function handleGravatarAccepted(event: GravatarAccepted): void {

  const gravatarId = event.params.id.toString()

  const gravatar = Gravatar.load(gravatarId) //locate entry with matching Id

  if (gravatar) {
    gravatar.accepted = true // set to true for GravatarAccepted event
    gravatar.save()
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For &lt;code&gt;GravatarDeclined&lt;/code&gt;, the handler function would be identical except I'd just change the value to false. &lt;/p&gt;

&lt;p&gt;That's all!&lt;/p&gt;

&lt;h3&gt;
  
  
  Finishing touches
&lt;/h3&gt;

&lt;p&gt;One last thing before attempting to deploy your subgraph: make sure your &lt;code&gt;subgraph.yaml&lt;/code&gt; file specifies the correct handler functions. The initially auto-generated settings are likely wrong.&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;datasources&lt;/code&gt; you'll see &lt;code&gt;eventHandlers&lt;/code&gt;. We should keep only the ones we need: GravatarAccepted &amp;amp; GravatarDeclined. Based on our assumption that we have another event for initially creating the records, we may have GravatarCreated. So in the end it should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pnq5gal53hpmqlz8te7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pnq5gal53hpmqlz8te7.png" alt="yaml file - event handlers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alright. Time to deploy. Just follow the cli instructions you see in The Graph's studio page and you should be good to go:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsad9kpauffpztzqofrxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsad9kpauffpztzqofrxb.png" alt="instructions from Studio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon successful deployment, you'll see a query url that you can use from a frontend app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb6jjf7yrwz2vp8ikjsu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb6jjf7yrwz2vp8ikjsu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use the playground to put together a query you want:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqteo44sn8cr4ijr0onff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqteo44sn8cr4ijr0onff.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then from the frontend, you just need to make a request to the url using a graphql query. &lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const graphqlQuery = &lt;code&gt;&lt;br&gt;
{&lt;br&gt;
  gravatar(last: 5) {&lt;br&gt;
    id&lt;br&gt;
    owner&lt;br&gt;
    displayName&lt;br&gt;
    imageUrl&lt;br&gt;
    accepted&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;;

&lt;p&gt;const graphQLRequest = {&lt;br&gt;
  method: 'post',&lt;br&gt;
  url: '&lt;a href="https://api.studio.thegraph.com/query/12345/test123/0.0.26" rel="noopener noreferrer"&gt;https://api.studio.thegraph.com/query/12345/test123/0.0.26&lt;/a&gt;',&lt;br&gt;
  data: {&lt;br&gt;
    query: graphqlQuery,&lt;br&gt;
  },&lt;br&gt;
};&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Extras:&lt;br&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A more complex example
&lt;/h3&gt;

&lt;p&gt;In this post I've been using the Gravatar example seen on The Graph's documentation. Here's a slightly more complex example from &lt;a href="https://github.com/alinobrasil/leverage-labs/tree/thegraph/thegraph" rel="noopener noreferrer"&gt;my hackathon project&lt;/a&gt; at ETH Global New York. It won #1 Best Use of Subgraph. &lt;/p&gt;

&lt;p&gt;It indexes some key info from Blend, which is Blur's lending contract for NFT-backed loans. (Blur is the largest NFT trading dex)&lt;/p&gt;

&lt;p&gt;The events from Blend's smart contract are rather messy because they did some hacky things to optimize for gas. The result is some very unintuitive events. I simplified them into 2 entities that reflect the true context of NFT-backed lending.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/alinobrasil/leverage-labs/blob/thegraph/thegraph/schema.graphql" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hbffwusbof1nuiqrxpk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My schema has a 1-to-many relationship between Liens and Loans. Each lien contains a collateralized NFT and can have its associated loan renewed/updated many times with new terms. This schema makes it much easier to work with for building an app that analyzes historical data. &lt;/p&gt;

&lt;p&gt;I have many different events that map to these 2 entities. One of the events get re-used in many different situations so I have some complex logic for that event:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/alinobrasil/leverage-labs/blob/thegraph/thegraph/src/blend.ts" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztpnh6nvbe6mm422oc24.png" alt="Event handler code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What if your smart contract is a proxy contract, and the implementation code is in another contract?
&lt;/h2&gt;

&lt;p&gt;When setting up your project with &lt;code&gt;graph init&lt;/code&gt;, it'll get the abi of the contract. If it's a proxy contract, it'll get the abi of the proxy, NOT the implementation.&lt;/p&gt;

&lt;p&gt;To deal with this, you should specify the address of the implementation contract containing the actual logic of the smart contract, including the events you're trying to index.&lt;/p&gt;

&lt;p&gt;For my hackathon project, this was the target contract: &lt;a href="https://etherscan.io/address/0x29469395eaf6f95920e59f858042f0e28d98a20b#readProxyContract" rel="noopener noreferrer"&gt;0x29469395eaf6f95920e59f858042f0e28d98a20b&lt;/a&gt;. On etherscan, I obtained the address of the implementation contract and used it when initializing my subgraph project (&lt;code&gt;graph init&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtttzeyzkezdr285lo0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtttzeyzkezdr285lo0w.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But when deploying the subgraph, you still need to point to the proxy contract, so just before deploying, you should specify the proxy contract in &lt;code&gt;subgraph.yaml&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgausq6s4vghp4dfb12go.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgausq6s4vghp4dfb12go.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Slow indexing on Studio
&lt;/h2&gt;

&lt;p&gt;While The Graph's Studio is mostly great, it is possible for you to run into performance issues. In my case, it took countless hours to index my target smart contract. &lt;/p&gt;

&lt;p&gt;To deal with this, I specified a startBlock that's very recent, just so I could obtain some data to test with during the hackathon, though incomplete. &lt;/p&gt;

&lt;p&gt;Some time later, the slow Studio issue was resolved. But in the heat of the moment that's what I did.&lt;/p&gt;

</description>
      <category>thegraph</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Getting started with Web3 Frontend Development: A Quick &amp; Dirty Guide</title>
      <dc:creator>ali kim</dc:creator>
      <pubDate>Wed, 12 Jul 2023 21:04:50 +0000</pubDate>
      <link>https://forem.com/alinobrasil/getting-started-with-web3-frontend-development-a-quick-dirty-guide-1aek</link>
      <guid>https://forem.com/alinobrasil/getting-started-with-web3-frontend-development-a-quick-dirty-guide-1aek</guid>
      <description>&lt;p&gt;Developing for web3 might sound crazy, but frontend devs are very well positioned to get in on the action. There are so many 6 figure frontend dev jobs and it’s so little work to transition into web3.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Introduction to decentralized app (dApp) Development
&lt;/h2&gt;

&lt;p&gt;Much of dapp development is really on the front-end. You don’t even need to know much about smart contract development to get going. You only need to be familiar with the libraries and infrastructure necessary to prepare your app for blockchain access.&lt;/p&gt;

&lt;p&gt;Imagine building a decentralized financial application utilizing DeFi protocols. As a front-end dev, your mission is to identify which contracts you need to access. This process doesn't require writing any code for the smart contracts themselves.&lt;/p&gt;

&lt;p&gt;You can just think of smart contracts as apps hosted on the blockchain and you want to access their functions via APIs. Instead of a URL, you receive a smart contract address. And instead of using tools like Axios to call APIs, you use something called Ethers.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilizing Ethers.js for Smart Contract Interaction
&lt;/h2&gt;

&lt;p&gt;Ethers.js enables interaction with a smart contract. After instantiating an object representing the smart contract, you can access its functions seamlessly. An example is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;walletContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, a smart contract wallet contains a function called &lt;code&gt;getBalance&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To reach this point where you can access functions on a smart contract with one line of JavaScript code, you utilize &lt;code&gt;ethers.Contract&lt;/code&gt; to instantiate the smart contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;walletContract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;deployedWalletAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;WalletArtifact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;signer&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, you're importing 'ethers' and passing in three elements into &lt;code&gt;ethers.Contract&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The address of the already deployed contract on the blockchain&lt;/li&gt;
&lt;li&gt;The Application Binary Interface (ABI), which is a JSON file that outlines interaction with the smart contract (e.g., function names, parameter types)&lt;/li&gt;
&lt;li&gt;A signer - an ethers object that contains the URL of the RPC endpoint, which sends your requests to a blockchain node&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Acquiring the Address and the ABI
&lt;/h3&gt;

&lt;p&gt;If you're collaborating with a team, the address and ABI will likely be provided. &lt;/p&gt;

&lt;p&gt;When working independently, the contract address can be found on the documentation site of whoever wrote the smart contracts, along with a detailed explanation of the available functions. &lt;/p&gt;

&lt;p&gt;You can also obtain the ABI from a block explorer website using the smart contract address. For instance, if you look up the address &lt;strong&gt;0xe0d7427a900828d553A6579C842d76926a73433e&lt;/strong&gt; on &lt;strong&gt;&lt;a href="http://polygonscan.com/"&gt;polygonscan.com&lt;/a&gt;&lt;/strong&gt;, you'll find the contract code on the &lt;a href="https://polygonscan.com/address/0xe0d7427a900828d553A6579C842d76926a73433e#code"&gt;"Contract" page&lt;/a&gt;. Scroll down, and you'll find the "Contract ABI", which can be copied and saved as a JSON or JS file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the Signer
&lt;/h3&gt;

&lt;p&gt;To set up the signer, use the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSigner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signer is necessary for accessing write functions in the smart contract. &lt;/p&gt;

&lt;p&gt;If you only need read functions from a smart contract, you can use the provider instead of the signer. Setting up the provider involves using Metamask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Web3Provider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ethersproject/providers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Web3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// MetaMask is not available, handle accordingly&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Install metamask from the Chrome webstore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code allows users to interact with smart contracts through their Metamask wallet. Once these steps are complete, you can treat any smart contract function as a module or an API. If write operations are required, use the signer when creating an instance of the smart contract in your frontend code. For read-only functions, use the provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Remarks
&lt;/h2&gt;

&lt;p&gt;While Ethereum is the most prominent blockchain, numerous others like Binance chain, Polygon, Arbitrum are either aimed at scaling Ethereum or function independently. However, from a frontend developer's perspective, this doesn't matter as these are all Ethereum Virtual Machine (EVM) compatible. So, if your code works for Ethereum, it'll function for these chains as well.&lt;/p&gt;

&lt;p&gt;Using Ethers.js is the rawest, most traditional way. There are libraries that make some aspects of front end web3 development easier. &lt;a href="http://wagmi.sh"&gt;Wagmi&lt;/a&gt; is a great example. It contains all sorts of react hooks to do things like check balance of an ERC20 token, see account details and even one for performing a write operation in a smart contract called useContractWrite. But getting that set up still requires you to provide an address and ABI. &lt;/p&gt;

&lt;p&gt;Even though you can get started quickly, it's still beneficial to study smart contracts at your own pace. A deeper understanding will aid in designing better apps, as there are some aspects of Web3 development that are not so intuitive. For example, many ERC20 token operations require 2 transactions even though they seem like simple operations. As a front-end dev, it’ll take very little time to get up to speed.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>frontend</category>
      <category>ethereum</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How Freelancers on Decentralized Marketplaces will Pioneer the On-Chain Credit Revolution</title>
      <dc:creator>ali kim</dc:creator>
      <pubDate>Sat, 01 Jul 2023 21:04:02 +0000</pubDate>
      <link>https://forem.com/alinobrasil/how-freelancers-on-decentralized-marketplaces-will-pioneer-the-on-chain-credit-revolution-4o6d</link>
      <guid>https://forem.com/alinobrasil/how-freelancers-on-decentralized-marketplaces-will-pioneer-the-on-chain-credit-revolution-4o6d</guid>
      <description>&lt;p&gt;In an ever-evolving financial landscape, people using decentralized freelance marketplaces are playing a groundbreaking role in shaping the future of on-chain credit. Thanks to the transparent and accessible nature of blockchain technology, freelancers could be among the first individuals to borrow money on-chain without collateral. Here's why this group of people will pave way for on-chain borrowing gaining traction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Employment History is King
&lt;/h2&gt;

&lt;p&gt;When it comes to borrowing money, your employment info is your secret weapon. It's the main thing lenders check to see if you're good for the money. For freelancers using decentralized platforms, their work history – every gig, every payment, every review – is up there on the blockchain for all to see. It's an open book of proof that they are able to pay back.&lt;/p&gt;

&lt;p&gt;Now think about the old-school way of checking employment history. It's an inefficient process involving contacting bosses, cross-checking pay slips all just to verify that you have a real job. With the blockchain, lenders can skip those steps and get straight to the point. They can directly check a freelancer's work history on the blockchain, making things quicker and easier for everyone involved.&lt;/p&gt;

&lt;p&gt;To take things one step further, freelance platforms could even tokenize future earnings for established accounts. A reputable freelancer could use this to access an uncollateralized loan and it’d be in their interest to pay it back considering they’d be tarnishing their hard earned credibility if they fail to repay. &lt;/p&gt;

&lt;h2&gt;
  
  
  Shaking Up the Credit Scene
&lt;/h2&gt;

&lt;p&gt;Traditional credit systems suck. They’re controlled by a handful of major institutions. Their systems are slow. They’re notoriously bad at keeping your data safe and it only takes a few personal details for someone to impersonate you.  In the end, you even need pay money just to see your own credit score.&lt;/p&gt;

&lt;p&gt;On-chain credit brings about a paradigm shift. In a decentralized, blockchain-based system, every action can contribute to your creditworthiness. This includes not just traditional factors like loan repayment history. Active freelance work builds strong signals for credit, but also participation in Decentralized Autonomous Organizations (DAOs) and even engagement in blockchain-based games can all count.&lt;/p&gt;

&lt;p&gt;Each of these actions, tied to your blockchain identity, contributes to building your credit. It's a way of actively accumulating creditworthiness without needing anyone's permission or relying on a centralized authority.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Should Care
&lt;/h2&gt;

&lt;p&gt;For many people around the world, this can open up access to fair interest rates. In Brazil, mortgage rates are over 10%. Credit cards can legally charge 600% APY when you’re late on credit card payments. Having access to global interest rates can solve so many problems for so many people.&lt;/p&gt;

&lt;p&gt;Even in the developed world, on-chain credit could make borrowing money more transparent and fair, reducing the chances of sketchy practices and helping more people get in on the financial action. Plus, it could make the process of checking out someone's credit history quicker and cheaper.&lt;/p&gt;

&lt;p&gt;It also puts you in the driver's seat, giving you the power to build and keep an eye on your own credit. You won't have to pay to access your own credit score.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;When freelance marketplaces gain traction, we might see the whole Decentralized Finance (DeFi) ecosystem pick up huge momentum. When freelancers start gaining access to uncollateralized on-chain credit, it'll quickly open doors for others too.&lt;/p&gt;

&lt;p&gt;But like any groundbreaking technology, this shift will come with its own challenges, such as ensuring privacy, combating fraud, and maintaining regulatory compliance. However, there are plenty of great solutions out there already. For example. ZK proofs can verify specific claims about identity or work experience without revealing identity. It’s just a matter of building the infrastructure to create an environment where people want to work in a decentralized marketplace.&lt;/p&gt;

&lt;h1&gt;
  
  
  V-Lance: ETH Global Waterloo 2023 Hackathon project
&lt;/h1&gt;

&lt;p&gt;My team at ETH Global Waterloo built a proof of concept on-chain professional passport. A problem with freelance platforms is that it's hard to verify anything people say. So our solution provided on-chain proof to backup claims about project &amp;amp; work experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ethglobal.com/showcase/v-lance-3j8qe"&gt;https://ethglobal.com/showcase/v-lance-3j8qe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmh3lzsaxw9sancth0ya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmh3lzsaxw9sancth0ya.png" alt="Image description" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We built on top of TalentLayer, which is a freelance marketplace builder. We used Sismo’s zkproofs to truly verify whether someone has contributed to some pre-defined list of repositories. This allows a person to prove that they contributed without revealing their identity. This would be practical for people working with a pseudonymous identity. &lt;/p&gt;

&lt;p&gt;We stored the result of the proofs on our own smart contract and used The Graph to query the data from our front-end. &lt;/p&gt;

&lt;p&gt;Most people publicize their identities. For them we planned to use Ethereum Attestation Service as a means to let people have their friends and colleagues endorse them on claims about where they worked and what projects they worked on. Being a 36-hour hackathon, we ran out of time before we implemented a front-end for making attestations. But this is something we may add as we continue this project. &lt;/p&gt;

&lt;p&gt;And we used NounsDAO’s artwork to add some style on top of TalentLayer’s default UI. &lt;/p&gt;

&lt;p&gt;A web3 powered freelance marketplace could potentially bring better talent &amp;amp; client verifications than what’s seen in web2. It also enables cross-platform interoperability: Access jobs/clients on other freelance platforms. There’s no doubt about whether web3 tech can create a better product.&lt;/p&gt;

&lt;p&gt;I feel the main challenge is in winning over traffic. Web3 freelance needs to be able to compete with Web2.&lt;/p&gt;

&lt;p&gt;With many advancements in usability like account abstraction, there will be little friction for people to start pouring into web3 platforms.&lt;/p&gt;

</description>
      <category>defi</category>
      <category>web3</category>
      <category>freelance</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Get started now with ComposeDB: A user-owned decentralized database on Ceramic Network</title>
      <dc:creator>ali kim</dc:creator>
      <pubDate>Mon, 20 Mar 2023 19:17:32 +0000</pubDate>
      <link>https://forem.com/alinobrasil/get-started-now-with-composedb-a-user-owned-decentralized-database-on-ceramic-network-22fc</link>
      <guid>https://forem.com/alinobrasil/get-started-now-with-composedb-a-user-owned-decentralized-database-on-ceramic-network-22fc</guid>
      <description>&lt;p&gt;Here you'll find a step by step guide to get your ComposeDB setup working asap. &lt;/p&gt;

&lt;p&gt;Quick primer: ComposeDB is a decentralized database on Ceramic Network. End-users truly own their data because they're the only ones that can write/edit their own records.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ceramicstudio/ethdenver-workshop"&gt;This workshop repo by Ceramic&lt;/a&gt; packs a lot of stuff in it. It works, but if you use it as a template like I did to build your own project, you may end up running into various issues... like I did. &lt;/p&gt;

&lt;p&gt;Here are my own notes that helped me use this repo to consistently get the required components set up and ultimately win a bounty award at ETH Denver 2023. &lt;/p&gt;

&lt;p&gt;I've broken this down to a few sections:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding ComposeDB&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;About the workshop repo &amp;amp; Issues I kept running into&lt;/li&gt;
&lt;li&gt;Essential Terminology&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How to get backend running:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run ceramic node&lt;/li&gt;
&lt;li&gt;Setting up your data structure&lt;/li&gt;
&lt;li&gt;Spinning up your Graphiql server&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Understanding ComposeDB
&lt;/h1&gt;

&lt;p&gt;The workshop repo spins up a Decentralized Twitter app. It allows end-users to be in control of their Tweets. Elon Musk wouldn't be able to delete your profile or tweets. &lt;/p&gt;

&lt;p&gt;You can see it running if you run "npm run dev". However, you'll see that it does a lot of things: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run ceramic node, &lt;/li&gt;
&lt;li&gt;prepare composite files, &lt;/li&gt;
&lt;li&gt;prepare the composite files that the decentralized twitter app needs. &lt;/li&gt;
&lt;li&gt;spin up graphiql server (to enable graphql queries)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When they all run together in a single terminal window as multiple child processes, they crash easily and prevent your node from running properly after that. &lt;/p&gt;

&lt;h2&gt;
  
  
  Issues I kept running into
&lt;/h2&gt;

&lt;p&gt;Here are some issues I kept running into and the solutions I got from several people at Ceramic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;unexplainable ceramic node errors &lt;br&gt;
==&amp;gt; delete the .ceramic folder in root directory or reboot computer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.goipfs - someone else has locked the file. &lt;br&gt;
==&amp;gt; delete the .lock file in the folder ~/.goipfs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;composedb.config.json file issues &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workshop repo's config file had statestore.local-directory  pointing to someone's local directory. ==&amp;gt; Change it to project root directory: "local-directory": ".ceramic/statestore/"&lt;/li&gt;
&lt;li&gt;network.name: use "testnet-clay". If that gives you issues, you can try "inmemory" and it will do everything locally.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;composite issues or model not getting indexed: &lt;br&gt;&lt;br&gt;
==&amp;gt; Most likely missed a step in setting up composite file. Run the commands 1 by 1 slowly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ended up doing these things multiple times but once I started following my final step-by-step notes further below, I never had a problem getting set up again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential Terminology
&lt;/h2&gt;

&lt;p&gt;Things really only started to make sense after understanding the terminology better.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A model is essentially the schema of a data table. You define field names and types (eg. Name: String, ID: string). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A composite turns that model into JSON format, which can then be used to deploy the model to the Ceramic network.&lt;br&gt;
If you have multiple models, their composite JSON files can be merged into a single file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Users create "instances" of your model known as documents. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both models and documents are streams on the ceramic network. You can access any model/document using their stream IDs. &lt;/p&gt;

&lt;h1&gt;
  
  
  Get backend running
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Run ceramic node
&lt;/h2&gt;



&lt;p&gt;&lt;code&gt;npm run ceramic&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Run this on its own so that you can easily terminate later if you need to. The workshop repo's &lt;em&gt;npm run dev&lt;/em&gt; runs everything in the backend and the frontend together, so it runs into errors easily. By separating the ceramic node, composite setup, graphiql server and frontend, you'll run into way less issues. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up data structure the first time
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installing composedb
&lt;/h3&gt;

&lt;p&gt;If you have it installed using npm, then uninstall it first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm uninstall @composed/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You MUST install using pnpm. How to install pnpm depends on your OS: &lt;a href="https://pnpm.io/installation"&gt;https://pnpm.io/installation&lt;/a&gt;. For linux it is...&lt;br&gt;
wget -qO- &lt;a href="https://get.pnpm.io/install.sh"&gt;https://get.pnpm.io/install.sh&lt;/a&gt; | ENV="$HOME/.bashrc" SHELL="$(which bash)" bash - &lt;/p&gt;

&lt;p&gt;And you must install composedb globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm add -g @composedb/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;npm and yarn and npx all didn't work for me. Use pnpm. It can save you hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compiling composite files
&lt;/h3&gt;

&lt;p&gt;These steps are needed to feed deploy your model into the ceramic network and to generate files necessary for the graphql server and for your frontend app.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define model (schema) in a graphql file. Name of schema, field names and data types etc. 
Follow the format shown in docs here or in the workshop repo. &lt;/li&gt;
&lt;li&gt;set privatekey environment variable
export DPK=yourprivatekey
echo $DPK&lt;/li&gt;
&lt;li&gt;create a composite for your model
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composedb composite:create composites/termsheet.graphql --output=composite.json --ceramic-url=http://localhost:7007 --did-private-key=$DPK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you open that output file you'll see a model ID in there identifying the model you just created. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you have multiple composite files, you merge composites into one file.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;composedb composite:merge composite1.json composite2.json --output=merged-composite.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy the single composite file. This will add all models to the model catalog
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composedb composite:deploy output/composite.json --ceramic-url=http://localhost:7007 --did-private-key=$DPK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Compile composite &lt;/li&gt;
&lt;li&gt;to enable data interactions via composeDB client, output as JSON
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composedb composite:compile output/composite.json runtime-composite.json

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;to enable import from javascript, output as  JS
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composedb composite:compile output/composite.json runtime-composite.js

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your frontend app will need this runtime-composite.js file.&lt;/p&gt;

&lt;p&gt;check if it was deployed properly:&lt;br&gt;
npx composedb composite :from-model &lt;/p&gt;

&lt;p&gt;You should be able to see your modelID somewhere in there. You can add it to your composedb config file to make sure it gets indexed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spin up graphql server that can interact with your model / composite:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composedb graphql:server --ceramic-url=http://localhost:7007 --graphiql runtime-composite.json --did-private-key=$DPK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all. You can now just focus on building your webapp. You just need a simple setup to use Ceramic and all data queries utilize graphql. &lt;a href="https://github.com/alinobrasil/ceramic2/blob/master/pages/explore.tsx"&gt;Here's an example &lt;/a&gt;of how composeClient is used to execute graphql queries. &lt;/p&gt;

&lt;h1&gt;
  
  
  Ending remarks
&lt;/h1&gt;

&lt;p&gt;Here are some questions I had earlier on about Ceramic &amp;amp; ComposeDB:&lt;/p&gt;

&lt;p&gt;How does data live on Ceramic nodes?&lt;br&gt;
==&amp;gt; Your data would need to be indexed by at least one node for the data to persist, so it's kind of like pinning files in ipfs. Fun fact: the data itself is stored in IPFS. ComposeDB abstracts everything away to work as a DB. In the end, anyone can spin up a node and it doesn't cost a ton of money the way various EVM chain validators do. &lt;/p&gt;

&lt;p&gt;How do users own the data if they need to connect to a node to read/write data?&lt;br&gt;
==&amp;gt; On the frontend, when you authenticate with authenticateCeramic, you are cryptographically signing a message with your ethereum wallet. Nodes can only write to your data on your behalf using that message. &lt;/p&gt;

&lt;p&gt;How can I get historical data on the test network?&lt;br&gt;
==&amp;gt; You'd need to enable historical data in the composedb config file. But to do that, you also need to change how the node keeps indexed data. Under indexing.db you'll see that it's using a sqlite server, but activating historical data would require you to setup a postgres sql server.&lt;/p&gt;

&lt;p&gt;I think ComposeDB opens up a lot of choices for decentralized apps. It allows high speed with good enough decentralization. Over time I'm sure the backend can be packaged to be easier to manage. By then, people would be able to easily run their own nodes on their own laptops to truly own their data without relying on RPC nodes. &lt;/p&gt;

</description>
      <category>ceramicnetwork</category>
      <category>web3</category>
      <category>ethdenver</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
