Giter Club home page Giter Club logo

click's Introduction

Click

Support of Moonsama-based NFTs in the KodaDot

How does it work

We basically index three types of events:

  • Transfer - events emitted by the ERC-721 contract when a token is transferred.
  • TransferSingle - events emitted by the ERC-1155 contract when a single token id is transferred.
  • TransferBatch - events emitted by the ERC-1155 contract when a batch of token ids are transferred.
// Snippet that shows how to handle events
processor.addEvmLogHandler(Contracts.Moonsama, transferFilter, mappings.mainFrame);
processor.addEvmLogHandler(Contracts.Moonx, singleTransferFilter, mappings.singleMainFrame);
processor.addEvmLogHandler(Contracts.Moonx, multiTransferFilter, mappings.mutliMainFrame);

What's the Contracts.Moonsama ? That's an excellent question. In the processable.ts, we have an enum that defines the contract addresses.

enum Contracts {
  Moonsama = '0xb654611f84a8dc429ba3cb4fda9fad236c505a1a', // ERC-721
  Moonx = '0x1974eeaf317ecf792ff307f25a3521c35eecde86', // ERC-1155
}

What are the transferFilter and singleTransferFilter ?

We simply tell the indexer that we want to listen to this specific event (topic) from the particular contract. As shown in the snippet below, we have a filter that listens to the Transfer event.

export const transferFilter: EvmLogHandlerOptions = {
  filter: [erc721.events["Transfer(address,address,uint256)"].topic],
}

The last parameter of the addEvmLogHandler is a function that will be called when the event is emitted. The algorithm is as follows:

export async function mainFrame(ctx: Context): Promise<void> {
  const transfer = decode721Transfer(ctx) // decode the event to [from, to, tokenId]
  
    switch (whatIsThisTransfer(transfer)) { // check what kind of transfer it is (mint, transfer, send)
    case Interaction.MINTNFT:
      transferDebug(Interaction.MINTNFT, transfer)
      await handleTokenCreate(ctx)
      break
    case Interaction.SEND:
      transferDebug(Interaction.SEND, transfer)
      await handleTokenTransfer(ctx)
      break
    case Interaction.CONSUME:
      transferDebug(Interaction.CONSUME, transfer)
      await handleTokenBurn(ctx)
      break
    default:
      logger.warn(`Unknown transfer: ${JSON.stringify(transfer, null, 2)}`)
  }
}

For example, we have a function that handles the Transfer event.

  • First, we need to get base transaction data and data about the transferred token.
  • This is done by calling the unwrap(context, getTransferTokenEvent) function.
  • Then we need to check if the token exists in the database.
  • In the last step, we need to update the currentOwner and save the token to the database.
  • Moreover, for historical purposes, we also created an event where the NFT was transferred.
export async function handleTokenTransfer(context: Context): Promise<void> {
  const event = unwrap(context, getTransferTokenEvent)
  const id = createTokenId(event.collectionId, event.sn)
  const entity = ensure<NE>(await get(context.store, NE, id))
  plsBe(real, entity)

  entity.currentOwner = event.to
  
  await context.store.save(entity)
  await createEvent(entity, Interaction.SEND, event, event.to || '', context.store, currentOwner)
}

Fast Forward

just up
just codegen
just build
just reset
just explore

Start processor

just process

Run GraphQL queries

just serve

Prerequisites

  • NodeJS 16.x
  • npm
  • docker

Bootstrap

# 1. Install dependencies
npm ci

# 2. Compile typescript files
npm run build

# 3. Start target Postgres database
docker compose up -d

# 4. Apply database migrations from db/migrations
npx sqd db create
npx sqd db migrate

# 5. Now start the processor
node -r dotenv/config lib/processor.js

# 6. The above command will block the terminal
#    being busy with fetching the chain data, 
#    transforming and storing it in the target database.
#
#    To start the graphql server open the separate terminal
#    and run
npx squid-graphql-server

Import ABI contract and set up interfaces to decode events

In order to be able to process EVM logs, it is necessary to import the respective ABI definition. In the case of this project, this has been done via the src/abis/ERC721.json file.

Furthermore, it is necessary to decode logs and this is shown in src/abis/erc721.ts. The events dictionary define there maps the event name at the center of this project to the function used to decode it.

Project structure

Hydra tools expect a certain directory layout:

  • src/generated - model/server definitions created by codegen. Do not alter the contents of this directory manually.
  • src/server-extension - module with custom type-graphql based resolvers
  • src/types - data type definitions for chain events and extrinsics created by typegen.
  • src/mappings - mapping module.
  • lib - compiled js files. The structure of this directory must reflect src.
  • .env - hydra tools are heavily driven by environment variables defined here or supplied by a shell.

Viki's Randomnotes

  1. Squid EVM typegen
npx squid-evm-typegen --abi ./src/abi/ERC1155.json --output ./src/abi/erc1155.ts

click's People

Contributors

vikiival avatar yangwao avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

click's Issues

Video pitch for Polkadot North America

Name

KodaDot: Moonsama Integration

As Kodadot, we've started implementation with various NFT standards in Dotsama ecosystem, with Moonsama it was a challenging opportunity for us to incorporate EVM standards into our NFT marketplace on MoonRiver

novelty/originality

As novelty across the ecosystem, we are leading NFT analytics in the Dotsama ecosystem for various NFT standards out there like RMRK or the upcoming Basilisk. We are here to provide deep dive into Moonsama NFT, as extracting on-chain data is our expert domain. To drive usage of our analytics platform for end-user experience, we have natively made a table where users can see top holders by address, amount of items for particular address holds and inspect their profile directly. This was all made thanks to the amazing architecture SubSquid has and speed-up our implementation as we previously used them for RMRK.

technical complexity

Right now the current solution is powered by a SubSquid indexer which is in the Kodadot repository under the name Click and anyone feels free to inspect our work as we love to work in an open-source environment.
We used the state-of-art EVM indexer by SubSquid. Using their tech stack, we could properly and correctly index NFTs based on the ERC-721 standard. Moreover, thanks to several smart hacks, we could integrate ERC-1155 NFTs without breaking the whole KodaDot architecture.

First, not all smart contracts used the standard ERC-721 ABI, namely the BLVCK smart contract, written in solidity 0.4.24, used different calls.

Second, the library ethers.js used internally unhandled WebSocket that crashed after a couple of minutes. Therefore, the SubSquid indexer suffered the downtimes.

Third, the support of ERC-1155 - KodaDot UI was firstly optimized for the non-fungible tokens. Adding support for semi-fungible tokens, we added a ton of entropy. Thanks to the

The challenge we ran into was indexing Moonsama contracts as there was a lack of information for some marketplace contracts to fetch current and historical floor prices as we haven't found full source code in Moonsama-dev repository.

daily/mass usability

We believe that NFTs are the best channel for crypto adoption for massive audiences and if it's connected within Minecraft servers or other simple games it should not miss an easy marketplace interface to drive their assets mobility, whether it is buying or selling or learning insights about marketplace trading dynamics, traits snipers and enable people to accumulate NFTs by their taste and preference, with KodaDot we are here to help them to extract on-chain insights in various collections.

impact of project

What's best on top of, this is referential implementation which is open source and we have the intention to expand this with other on-chain insights on a long-term basis and invite others to contribute to this and keep this as a public good of the Dotsama ecosystem. We believe this cross-chain NFT marketplace implementation will help fulfil the nature of Polkadot Layer 0 in future and enable teleportation assets across other parachains through KodaDot

what we haven't finished

Future work is to get into touch with Moonsama developers and implement into KodaDot historical volumes, current and historical floor price and rarity as we had to tackle other issues on our side during development and we managed to fight through a few EVM hurdles.

Antick is stuck

processor 2022-10-07T09:34:39.073Z INFO > @kodadot1/[email protected] processor:start
processor 2022-10-07T09:34:39.073Z INFO > node lib/processor.js
processor 2022-10-07T09:34:40.883Z INFO sqd:processor last processed block was 1918707
processor 2022-10-07T09:34:40.884Z INFO sqd:processor processing blocks from 1918708
processor 2022-10-07T09:34:40.960Z INFO sqd:processor prometheus metrics are served at port 3000
processor 2022-10-07T09:34:41.588Z INFO mainFrame 0x1bd9e17d306cf76cc07b70234427220f0ec2c2f2771233900314f03b21a55f1f
processor 2022-10-07T09:34:41.596Z INFO ⬤  debug     [[MINTNFT]]: [0x0000000000000000000000000000000000000000, 0xcAc7Ca0BfAF5f1DAB1E56BEacC822aD6472888D9, 2282, 1]
processor 2022-10-07T09:34:41.596Z INFO ☐  pending   [NFT++]: 1919599
processor 2022-10-07T09:34:41.600Z CRITICAL sqd:processor Error: invalid contract address or ENS name (argument="addressOrName", value=undefined, code=INVALID_ARGUMENT, version=contracts/5.7.0)
    at Logger.makeError (/squid/node_modules/@ethersproject/logger/lib/index.js:238:21)
    at Logger.throwError (/squid/node_modules/@ethersproject/logger/lib/index.js:247:20)
    at Logger.throwArgumentError (/squid/node_modules/@ethersproject/logger/lib/index.js:250:21)
    at Contract.BaseContract (/squid/node_modules/@ethersproject/contracts/lib/index.js:669:20)
    at new Contract (/squid/node_modules/@ethersproject/contracts/lib/index.js:1053:42)
    at Contract.BaseContract.attach (/squid/node_modules/@ethersproject/contracts/lib/index.js:830:16)
    at contractify (/squid/lib/contract.js:61:44)
    at tokenUriOf (/squid/lib/contract.js:43:99)
    at getCreateTokenEvent (/squid/lib/mappings/utils/getters.js:16:48)
    at unwrap (/squid/lib/mappings/utils/extract.js:18:23)

Get signer of the transaction

This issue blocks #22

The problem:

if you try to make this query here

query MyQuery {
  batch(
    limit: 10
    fromBlock: 569006
    toBlock: 569006
    ethereumTransactions: {
      contract: "*"
      data: { call: { origin: true, _all: true } }
    }
    evmLogs: { contract: "*" }
  ) {
    header {
      height
    }
    extrinsics
  }
}

You will see that signature field on extrinsics array is null.

It means that we can get who was the caller of the tx

Workaround:

here is an example of serializing and parsing substrate eth transaction data with ethers
https://github.com/belopash/squid/blob/ccc1ebb0308d041ea07d7376f369a36b6430ada3/test/astar-erc20/src/processor.ts#L24

Optimize logs

I have a feeling that I/O is a bottleneck for the indexer.

So:

  • find better logging library ?
  • Do less logs
  • minimize logs info

Use mapping table for metadata

Instead of querying data from the ethers.js
Screenshot 2022-07-05 at 12 37 28

We can have some sort of mapping <contractAddr, metaFunction>

[Contract.Moonsama]: (id) => `ipfs://Something/${id}`

Rarity explorer

How it should look like

From the technical perspective we need to edit model so attributes will become @entity instead of current JSON implementation.

With a current JSON impl it's not so simple task and not very effective to do that.

Screen_Recording_2022-07-19_at_13.14.33.mov

Strange EVM logs

MY click died because:

processor 2022-07-11T09:57:10.832Z INFO ⬤  debug     [[SEND]]: {
processor 2022-07-11T09:57:10.833Z INFO   "from": "0xC0E0e7122c163a8c70c9858E8674C51Fb7117e88",
processor 2022-07-11T09:57:10.833Z INFO   "to": "0x59C481548CE7BA13f3288df9f4FCf44a10A589A0",
processor 2022-07-11T09:57:10.833Z INFO   "tokenId": {
processor 2022-07-11T09:57:10.833Z INFO     "type": "BigNumber",
processor 2022-07-11T09:57:10.833Z INFO     "hex": "0x1f0e"
processor 2022-07-11T09:57:10.833Z INFO   }
processor 2022-07-11T09:57:10.833Z INFO }
processor 2022-07-11T09:57:10.833Z INFO ☐  pending   [SEND]: 2165977
processor 2022-07-11T09:57:10.835Z INFO ⬤  debug     send: {
processor 2022-07-11T09:57:10.835Z INFO   "caller": "0xC0E0e7122c163a8c70c9858E8674C51Fb7117e88",
processor 2022-07-11T09:57:10.835Z INFO   "blockNumber": "2165977",
processor 2022-07-11T09:57:10.835Z INFO   "timestamp": "2022-07-08T18:21:54.461Z",
processor 2022-07-11T09:57:10.835Z INFO   "collectionId": "0xe4edcaaea73684b310fc206405ee80abcec73ee0",
processor 2022-07-11T09:57:10.835Z INFO   "sn": "7950",
processor 2022-07-11T09:57:10.835Z INFO   "to": "0x59C481548CE7BA13f3288df9f4FCf44a10A589A0"
processor 2022-07-11T09:57:10.835Z INFO }
processor 2022-07-11T09:57:10.865Z ERROR ReferenceError: [PROBLEM] Entity  needs to be real
    at needTo (/squid/lib/mappings/utils/consolidator.js:42:15)
    at plsBe (/squid/lib/mappings/utils/consolidator.js:32:12)
    at handleTokenTransfer (/squid/lib/mappings/index.js:132:30)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async technoBunker (/squid/lib/mappings/index.js:198:13)
    at async /squid/node_modules/@subsquid/substrate-processor/lib/processor.js:289:29
    at async /squid/node_modules/@subsquid/substrate-processor/lib/db.js:69:13

That means:

Problem:

Screenshot 2022-07-11 at 12 20 31

Investigation:

Integrate more EVM collections

MoonRiver

The Damned Pirates Society @TheDPSproject

collection based: moonriver
contact address: https://moonriver.moonscan.io/token/0xb6e9e605aa159017173caa6181c522db455f6661
collection type: ERC721
Verified contract on URL Moonscan.io:
https://moonriver.moonscan.io/token/0xb6e9e605aa159017173caa6181c522db455f6661

NeonCrisis @NeonCrisisNFT

collection based: moonriver
contact address: 0xFD86D63748a6390E4a80739e776463088811774D
collection type: ERC721
Verified contract on URL Moonscan.io:
https://moonriver.moonscan.io/address/0x2d4a19b306a496be628469de820f0367a13178e5

MoonBeam

Moonbeam Punks™ @moonbeam_punk

collection based: moonbeam
contact address: 0xFD86D63748a6390E4a80739e776463088811774D
collection type: ERC721
Verified contract on URL Moonscan.io:
https://moonscan.io/token/0xfd86d63748a6390e4a80739e776463088811774d

Canary Network Agency @canaryagency

collection based: moonbeam
contact address: 0xFD86D63748a6390E4a80739e776463088811774D
collection type: ERC721
Verified contract on URL Moonscan.io:
https://moonscan.io/token/0x139e9ba28d64da245ddb4cf9943aa34f6d5abfc5

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.