Skip to content
Dataverse Connector

Getting started with Dataverse SDK

A quick guide to get you started with the dataverse runtime connector SDK.

After reading this guide, you will be able to connect with the dataverse browser extension, create, load, update and monetize a file.

⚠️

Before we start, please make sure you have created your dataverse-app and defined the data models you want to use in your app using the create-dataverse-app framework.

Prerequisites

Install Dataverse wallet

Dataverse Wallet is a Chrome browser extension. We need to make sure it's installed and it's updated to the latest version before we proceed with the development.

Download on chrome store (opens in a new tab)

quickstart-1 You may sign in with MetaMask, WalletConnect, Coinbase Wallet or Particle Social Account and create a new identity.

Install JS SDK

pnpm install @dataverse/dataverse-connector

Step 1: Initialize the connector

// After installation, you can import the SDK and initialize the dataverse connector.
/** Import Dataverse Connector SDK */
import { DataverseConnector } from '@dataverse/dataverse-connector';
 
/** Initialize the dataverse connector class object */
const dataverseConnector = new DataverseConnector();

If you are using the SDK in a Vite project, you may need to add the following to your vite.config.ts file:

export default defineConfig({
  ...
  define: {
    'process.env': {},
  },
  ...
});

Step 2: Connect with user wallet

import React, { useState } from 'react';
 
/** Import Dataverse Connector SDK and types */
import {
  DataverseConnector,
  WALLET
} from "@dataverse/dataverse-connector";
 
/**
 * Initialize the Dataverse Connector
 */
const dataverseConnector: DataverseConnector = new DataverseConnector();
 
const App: React.FC = () => {
  const [wallet, setWallet] = useState<WALLET>();
 
  const connectWallet = async () => {
    try {
      const res = await dataverseConnector.connectWallet();
      setWallet(res.wallet);
      return(res.address);
    } catch (error) {
      console.error(error);
    }
  };
 
  return (
    <button onClick={connectWallet}>
      Connect Wallet
    </button>
  );
};
 
export default App;

The connectWallet function receives an optional parameter wallet to specify which wallet to use.

enum WALLET {
  METAMASK = "MetaMask",
  WALLETCONNECT = "WalletConnect",
  COINBASE = "Coinbase",
  PARTICLE = "Particle"
}

if not specified (pass in no parameters), the function will open an option page for users to choose which wallet to use.

Step 3: Create capability

import { RESOURCE } from '@dataverse/dataverse-connector';
 
const app = 'YOUR_APP_NAME';
 
const createCapability = async () => {
  const pkh = await dataverseConnector.runOS({
    method: SYSTEM_CALL.createCapability,
    params: {
      appId,
      resource: RESOURCE.CERAMIC,
      wallet,
    },
  });
  return pkh;
};

This will open a popup window to ask for user permission to connect with the application. We use Sign-in-with-Ethereum signatures to authenticate the user approvement. The popup shall be like this:

It returns: pkh: string - a pkh 'DID' you may use to interact with the data resources later.

Step 4: Create a file

File is the smallest unit of data in our system. Unlike IPFS CID which 1. cannot be changed after upload 2. are discrete and not related, files can be updated after creation and linked between each other. Each file belongs to a data model. For example, if you have created a data model called post as a data structure for posts in a social app

type post @createModel(accountRelation: LIST, description: "post") {
  author: DID! @documentAccount # DID of the user who created this post
  version: CommitID! @documentVersion
  appVersion: String! @string(maxLength: 100)
  text: String @string(maxLength: 300000000) # text content of the post
  images: [String] @list(maxLength: 10000000) @string(maxLength: 2000000) # images of the post
  videos: [String] @list(maxLength: 10000000) @string(maxLength: 2000000) # videos of the post
  options: String @string(maxLength: 300000000)
  createdAt: DateTime! # time when the post is created
  updatedAt: DateTime! # time when the post is updated
}

createIndexFile under this post model is how you create posts.

const encrypted = JSON.stringify({
  text: false,
  images: false,
  videos: false,
});
 
const res = await dataverseConnector.runOS({
  method: SYSTEM_CALL.createIndexFile,
  params: {
    modelId,
    fileName: "post1",
    fileContent: {
      modelVersion: "0.0.1",
      text: "hello",
      images: [
        "https://bafkreib76wz6wewtkfmp5rhm3ep6tf4xjixvzzyh64nbyge5yhjno24yl4.ipfs.w3s.link",
      ],
      videos: [],
      createdAt: new Date().toISOString();,
      updatedAt: new Date().toISOString();,
      encrypted,
    },
  },
});

return example

{
  "pkh": "did:pkh:eip155:1:0xb4D93398f6F3FB5EE4436D1aE93b32d65693a799",
  "appId": "a3f0ac63-ff7d-4085-aade-c04888b71088",
  "modelId": "kjzl6hvfrbw6catek36h3pep09k9gymfnla9k6ojlgrmwjogvjqg8q3zpybl1yu",
  "fileContent": {
    "content": {
      "text": "hello",
      "images": [
        "https://bafkreib76wz6wewtkfmp5rhm3ep6tf4xjixvzzyh64nbyge5yhjno24yl4.ipfs.w3s.link"
      ],
      "videos": [],
      "createdAt": "2023-11-02T08:04:53.380Z",
      "encrypted": "{\"text\":false,\"images\":false,\"videos\":false}",
      "updatedAt": "2023-11-02T08:04:53.380Z",
      "modelVersion": "0.0.1"
    },
    "file": {
      "fsVersion": "0.11",
      "contentId": "kjzl6kcym7w8y8wx1zuujmssq4wj6o6paynupzmidz7izcsiqwgpnt1uyo9lg2a",
      "contentType": {
        "resource": "CERAMIC",
        "resourceId": "kjzl6hvfrbw6catek36h3pep09k9gymfnla9k6ojlgrmwjogvjqg8q3zpybl1yu"
      },
      "fileName": "create a file",
      "fileType": 0,
      "createdAt": "2023-11-02T08:04:56.699Z",
      "updatedAt": "2023-11-02T08:04:56.699Z",
      "fileId": "kjzl6kcym7w8ya3kyamskljmo181t6z3vz6px0w90c76ea3m28g994t58341ijt"
    }
  }
}

To create a file under a specific model, you need to specify the model id and ensure your app has the capability to write data under this model. if not, please use createCapability to create a capability for the model first.

Step 5: Load a file

You can load an indexFile's content by its id.

await dataverseConnector.runOS({
  method: SYSTEM_CALL.loadFile,
  params: indexFileId,
});

You can also load multiple indexFiles under a model using loadFilesBy.

await dataverseConnector.runOS({
  method: SYSTEM_CALL.loadFilesBy,
  params: {
    modelId,
    pkh,
  },
});

The pkh field is optional. If not specified, it will return all streams under the model. Otherwise, it will return streams under the model that are created by the user.

Step 6: Update a file

const date = new Date().toISOString();
 
const encrypted = JSON.stringify({
  text: true,
  images: true,
  videos: false,
});
 
const res = await dataverseConnector.runOS({
  method: SYSTEM_CALL.updateIndexFile,
  params: {
    fileId,
    fileName: 'new-post1',
    fileContent: {
      appVersion: '0.1.0',
      text: 'hello',
      images: [
        'https://bafkreib76wz6wewtkfmp5rhm3ep6tf4xjixvzzyh64nbyge5yhjno24yl4.ipfs.w3s.link',
      ],
      videos: [],
      createdAt: date,
      updatedAt: date,
      encrypted,
    },
  },
});

updateIndexFile shares the same parameters as createIndexFile, except the fileId is required. and the return value is in the same format as createIndexFile.

Step 7: Monetize a file

import { Currency } from "@dataverse/dataverse-connector";
 
const res = await dataverseConnector.runOS({
  method: SYSTEM_CALL.monetizeFile,
  params: {
    ...(indexFileId ? { indexFileId } : { streamId }),
    datatokenVars: {
      profileId,
      collectLimit: 100,
      amount: 0.0001,
      currency: Currency.WMATIC,
    },
    decryptionConditions: [
      ...
    ]
  },
});

To put it simply, data monetization is to deploy a collection of NFTs on the blockchain and use the NFT as access credentials to the data. We deployed multi version of smart contracts for this process of converting off-chain data to on-chain NFTs. By default, leave the profileId as null, and the transaction will go through dataverse default profileless smart contracts. We're also compatible with Lens Protocol (opens in a new tab) in case you want to use their smart contracts and let your lens handle own your data. Pass in your lens profile id to profileId to use Lens Protocol here.

decryptionConditions specifies a set of conditions to limit access to the data. For example

[
  {
    conditionType: 'evmBasic',
    contractAddress: '',
    standardContractType: '',
    chain: 'filecoin',
    method: '',
    parameters: [':userAddress'],
    returnValueTest: {
      comparator: '=',
      value: '0x3c6216caE32FF6691C55cb691766220Fd3f55555',
    },
  },
];

This condition specifies that the data can only be accessed by the wallet address 0x3c6216caE32FF6691C55cb691766220Fd3f55555 on filecoin chain.

Step 8: Purchase a file

await dataverseConnector.runOS({
  method: SYSTEM_CALL.collectFile,
  params: indexFileId,
});

This will send a transaction to mint an NFT to the user's wallet address. The NFT is the access credential to the data.

💡

monetizeFile and collectFile functions are on Mumbai testnet for now.

After purchase completed, you can load the file content using unlockFile function.

await dataverseConnector.runOS({
  method: SYSTEM_CALL.unlockFile,
  params: indexFileId,
});