onflow / fcl-js

FCL (Flow Client Library) - The best tool for building JavaScript (browser & NodeJS) applications on Flow 🌊
https://onflow.org
Apache License 2.0
323 stars 117 forks source link

Live scraper #493

Closed Ng2k closed 3 years ago

Ng2k commented 3 years ago

THE GOAL

I'm trying to build a live market scraper of nbatopshot

THE PROBLEM

First of all I wanna say that I'm new to this technology and to cadence language, so 99% will be an error in the cadence code.

I've already got an API who can retrieve all the events "MomentListed" (a particular event minted when someone puts a token on the market) and right now I have the token's Id, seller's address and the price (from the event).

I have a cadence script in order to retrieve all the token metadata (such as setName, playName etc...) from the seller address and the token Id, but I get an error while sending the script.

The code:

const express = require('express');
const router = express.Router();
const flow = require('@onflow/sdk');
const types = require('@onflow/types');
const fcl = require('@onflow/fcl');
const { json } = require('express');
const fetch = require("node-fetch");

const config = require("../utils/config.json");
const script = require("../utils/script");

router.use(json());

fcl.config().put("accessNode.api", config.apiAccessNode)

/* GET home page. */
router.get('/', function(req, res, next) {
  //I'm call the API in order t get all the events data
  fetch("http://localhost:8080")
    .then(res => res.json())
    .then(events => {
      events.forEach(({ Id, Seller }) => {

        flow.build([
          flow.script`${script}`,
          flow.args([flow.arg(Id, types.UInt64), flow.arg(Seller, types.String)])
        ])
          .then(scriptBuilted => {
            return flow.resolve(scriptBuilted, [
              flow.resolveArguments,
              flow.resolveParams,
            ])
          })
          .then(scriptResolved => {
            return flow.send(scriptResolved, { node: config.apiAccessNode })
          })
          .then(scriptResponse => {
            return flow.decode(scriptResponse)
          })
          .then(console.log)
          .catch(console.error)
        })

    })
      .catch(console.error)
});

module.exports = router;

The cadence script is:

import TopShot from 0x0b2a3299cc857e29
import Market from 0xc1e4f4f4c4257510
pub struct SaleMoment {
  pub var id: UInt64
  pub var playId: UInt32
  pub var play: {String: String}
  pub var setId: UInt32
  pub var setName: String
  pub var serialNumber: UInt32
  pub var price: UFix64
  init(moment: &TopShot.NFT, price: UFix64) {
    self.id = moment.id
    self.playId = moment.data.playID
    self.play = TopShot.getPlayMetaData(playID: self.playId)!
    self.setId = moment.data.setID
    self.setName = TopShot.getSetName(setID: self.setId)!
    self.serialNumber = moment.data.serialNumber
    self.price = price
  }
}
pub fun main(owner:Address, momentID:UInt64): SaleMoment {
  let acct = getAccount(owner)
  let collectionRef = acct.getCapability(/public/topshotSaleCollection)!.borrow<&{Market.SalePublic}>() ?? panic("Could not borrow capability from public collection")
  return SaleMoment(moment: collectionRef.borrowMoment(id: momentID)!,price: collectionRef.getPrice(tokenID: momentID)!)
}

config file:

{
  "apiAccessNode": "https://access-mainnet-beta.onflow.org",
  "appContractProfile": "0xc1e4f4f4c4257510",
  "eventType": "MomentListed"
}

THE ERROR

the error I have is:

* rpc error: code = Internal desc = failed to execute the script on the execution node execution-160241f88cbfaa0f361cf64adb0a1c9fc19dec1daf4b96550cd67b7a9fb26cd9@execution-002.mainnet4.nodes.onflow.org:3569=1000: rpc error: code = Internal desc = failed to execute script: failed to execute script at block (706ad1c305c20726d1a1848110c8e3275ffea9c82dd9dd4ac7c6386764ee5678): Execution failed:
invalid argument at index 0

I really don't know where is the problem, and also I can't understand the error message. Thanks for the time.

Ng2k commented 3 years ago

I've built a solution.

It's a web scraper (first version so it's not perfect), it analyze the last 50 blocks and display all the MomentListed (excluding the ones already sold).