Writing a subgraph to get the friend.tech real-time trading data

Introduction

The decentralized social network friend.tech has gathered substantial attention within the Web3 space lately. It enables the trading of users' tokenized stocks and is constructed on Coinbase's L2 network Base. With a surge in queries concerning the accessibility of this application's data, and considering the forthcoming release of the Base protocol in Chainstack Subgraphs hosting, we have prepared this tutorial. It aims to assist traders and analysts in launching their own subgraph, granting access to internal transactions, and if desired, facilitating the development of trading bots or financial analytics.

Getting started

First, install the Graph CLI with either npm or yarn:

npm install -g @graphprotocol/graph-cli
yarn global add @graphprotocol/graph-cli

After successful installation, initialize your subgraph project:

graph init --studio friendtech-by-chainstack

You will be prompted the questions that should be answered as follows:

✔ Protocol · ethereum
✔ Subgraph slug · friendtech-by-chainstack
✔ Directory to create the subgraph in · friendtech-by-chainstack
✔ Ethereum network · base
✔ Contract address · 0xCF205808Ed36593aa40a44F10c7f7C2F67d4A4d4
✔ Fetching ABI from Etherscan

Here we’ve chosen the protocol type, the subgraph name, the chain name, and the address of the related smart contract. The ABI has been automatically fetched from the BaseScan.

After you get a message that the start block couldn’t be found on the block explorer you can write the block number which is before the first transaction of this application. We can find this transaction block following the link in the section More info in the BaseScan called ContractCreator: 0xdd9176ea3e7559d6b68b537ef555d3e89403f742 at txn [0xa7eba644182d78c4568364](https://basescan.org/tx/0xa7eba644182d78c4568364e00b0320a9fde9c1fe779cdbec6941fb7443d14c01):

✖ Failed to fetch Start Block: Failed to fetch contract creation transaction
✔ Start Block · 2430439

Then choose the name of a smart contract (you can use any) and approve automatic code generation for the events indexing.:

✔ Contract Name · FriendtechSharesV1
✔ Index contract events as entities (Y/n) · true

In the end you need to refuse adding more contracts:

  Generate subgraph
  Write subgraph to directory
✔ Create subgraph scaffold
✔ Initialize networks config
✔ Initialize subgraph repository
✔ Install dependencies with yarn
✔ Generate ABI and schema types with yarn codegen
Add another contract? (y/n):

Launching the subgraph

Let’s check what we have generated in the friendtech-by-chainstack directory. Specifically, we're going to focus on the following files:

  • subgraph.yaml
  • schema.graphql
  • src/friendtech-shares-v-1.ts

In the subgraph.yaml file, you can find the following code:

specVersion: 0.0.5
schema:
  file: ./schema.graphql
dataSources:
  - kind: ethereum
    name: FriendtechSharesV1
    network: base
    source:
      address: "0xCF205808Ed36593aa40a44F10c7f7C2F67d4A4d4"
      abi: FriendtechSharesV1
      startBlock: 2430439
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.7
      language: wasm/assemblyscript
      entities:
        - OwnershipTransferred
        - Trade
      abis:
        - name: FriendtechSharesV1
          file: ./abis/FriendtechSharesV1.json
      eventHandlers:
        - event: OwnershipTransferred(indexed address,indexed address)
          handler: handleOwnershipTransferred
        - event: Trade(address,address,bool,uint256,uint256,uint256,uint256,uint256)
          handler: handleTrade
      file: ./src/friendtech-shares-v-1.ts

You can see that all the parameters that we put in the command line have been used here. But along with them, there are entities that will be created in the database to store the smart contract events data and eventHandlers that also can be used in the subgraph code and the paths to the other source code files.

If we open the file called schema.graphql , we see the actual structure of the tables with data:

type OwnershipTransferred @entity(immutable: true) {
  id: Bytes!
  previousOwner: Bytes! # address
  newOwner: Bytes! # address
  blockNumber: BigInt!
  blockTimestamp: BigInt!
  transactionHash: Bytes!
}

type Trade @entity(immutable: true) {
  id: Bytes!
  trader: Bytes! # address
  subject: Bytes! # address
  isBuy: Boolean! # bool
  shareAmount: BigInt! # uint256
  ethAmount: BigInt! # uint256
  protocolEthAmount: BigInt! # uint256
  subjectEthAmount: BigInt! # uint256
  supply: BigInt! # uint256
  blockNumber: BigInt!
  blockTimestamp: BigInt!
  transactionHash: Bytes!
}

And the Trade table is what we need. It contains the following entries:

  • trader — the address of the trader
  • subject — the address of the influencer
  • isBuy — the direction of sale
  • shareAmount — the number of shares in the trade
  • ethAmount — the price of the share in the deal
  • subjectEthAmount — the fee that is received by the influencer
  • protocolEthAmount field is the fee that is received by the protocol
  • supply — the current total number of issued tokens
  • blockNumber, blockTimestamp, and transactionHash are the block data that is not related to the protocol but useful for data analysis

The last file with the source code is src/friendtech-shares-v-1.ts which contains the straightforward AssemblyScript code transferring the smart contract events data into the tables with the described structure.

import {
  OwnershipTransferred as OwnershipTransferredEvent,
  Trade as TradeEvent
} from "../generated/FriendtechSharesV1/FriendtechSharesV1"
import { OwnershipTransferred, Trade } from "../generated/schema"

export function handleOwnershipTransferred(
  event: OwnershipTransferredEvent
): void {
  let entity = new OwnershipTransferred(
    event.transaction.hash.concatI32(event.logIndex.toI32())
  )
  entity.previousOwner = event.params.previousOwner
  entity.newOwner = event.params.newOwner

  entity.blockNumber = event.block.number
  entity.blockTimestamp = event.block.timestamp
  entity.transactionHash = event.transaction.hash

  entity.save()
}

export function handleTrade(event: TradeEvent): void {
  let entity = new Trade(
    event.transaction.hash.concatI32(event.logIndex.toI32())
  )
  entity.trader = event.params.trader
  entity.subject = event.params.subject
  entity.isBuy = event.params.isBuy
  entity.shareAmount = event.params.shareAmount
  entity.ethAmount = event.params.ethAmount
  entity.protocolEthAmount = event.params.protocolEthAmount
  entity.subjectEthAmount = event.params.subjectEthAmount
  entity.supply = event.params.supply

  entity.blockNumber = event.block.number
  entity.blockTimestamp = event.block.timestamp
  entity.transactionHash = event.transaction.hash

  entity.save()
}

Again, the handleTrade function is what we are interested in. We see that each event emitting leads to the new entity created with the fields that exactly correspond to the table structure without any changes. But if you need any additional operations you can add them in the function.

Finally, to start using the subgraph, run the command:

graph codegen && graph build

Then generate the binaries and deploy the subgraph into the hosting using the command from the UI (the detailed process is described here):

graph deploy --node https://api.graph-eu.p2pify.com/3c6e0b8a9c15214b8258b9a98ca1531d/deploy --ipfs https://api.graph-eu.p2pify.com/3c6e0b8a9c15524b8238b9a98ca1531d/ipfs friendtech-by-chainstack

After successful deployment, you can run queries via the UI interface (the link can be found in the platform UI) and get, for example, all deals with your account:

Querying all account's deals in friend.tech

And that is how you use subgraphs to index all the share trades of friend.tech platform.

Conclusion

Chainstack Subgraphs is a powerful tool that allows Web3 developers to index and query data from decentralized networks like Ethereum. They allow developers to easily access and use the data stored on these networks in their decentralized applications without building and maintaining their own infrastructure for data indexing and querying. This can save developers significant time and resources and make BUIDL-efficient DApps easier.

The aim of this article was to showcase the scale of these subgraphs by using them to easily fetch, process, and organize data that is as scattered as social DApp trades.

See also:

About the author

Kirill Balakhonov

🥑 Product Lead @ Chainstack
🛠️ BUIDLs on Ethereum and Graph protocol
💻 Majored in Data Science and Product Management
Kirill Balakhonov | GitHub Kirill Balakhonov | Twitter Kirill Balakhonov | LinkedIN