Skip to content
Version 0.0.1 (Testnet)

Datai SDK API Reference

Command Line Interface (CLI)

Datai CLI is a collection of helpers and tools to help you build, test and deploy projections. It consists of a few key parts.

create-datai-app

Executed with npx create-datai-app, this command will create a new Datai project in the current directory. Generally one datai project is enough for all your projection development needs. A Datai App is a scaffolding/contaienr for all your projections.

This command will create a project in the current directory with the following structure:

  • Directory.devcontainer
  • DirectoryAPI
  • Directorygraph-node
  • Directoryprojections
    • Directoryassembly
      • Directorylibs
      • Directoryprotocols
      • Directorytemplates
    • Directorytypescript

.devcontainer

Configuration of the VS Code Dev Containers for the project.

API

Protocol buffer definitions for the Datai API used by the host application to communicate with the subgraph and the watcher.

graph-node

Configuration for the local Graph Node that will be used to deploy the subgraph and the watcher.

projections

Projections are the main part of the Datai project. They are divided into two main parts: assembly and typescript.

assembly

Main part of the projection. It contains all the protocol definitions, templates and libraries used to build the projection.

libs

Contains libraries that can be used across multiple protocols and templates.

protocols

Contains yaml filtes that define protocol data sources and graph templates.

templates

Contains projection implementations that use protocol definitions from the folder above. Templates have a substructure of network folders. This is important becuase the build scripts will be looking for projections based on the specified network.

  • Directorytemplates
    • Directorymainnet
    • Directoryarbitrum
typescript

Contains scripts written in TypeScript that will be used to compile, build and deploy the projection.

build

Executed with yarn this script will compile projection’s subgraph and watcher code into a format that can be deployed to graph-node

terminal
yarn build TEMPLATE PROTOCOL MODULE NETWORK

It’s important to remember how you name your projection files and templates. They directly tie back to the folder structure. For example:

yarn build uniswap2_liquidity uniswap2 liquidity_pool mainnet

This will take the projection configuration from projections/assembly/protocols/uniswap2.liquidity_pool/mainnet/uniswap2_liquidity.yaml as well as the template files from projections/assembly/templates/mainnet/uniswap2_liquidity and compile them into a format that can be deployed to graph-node.

Let’s break it down into parts:

projections/assembly/protocols/<PROTOCOL>.<MODULE>/<NETWORK>/<TEMPLATE>.yaml

projections/assembly/templates/<NETWORK>/<TEMPLATE>

Partial builds

If you want to build only the subgraph or the watcher, you can use the following arguments.

Build just the subgraph
terminal
yarn build TEMPLATE PROTOCOL MODULE NETWORK graph
Build just the watcher
terminal
yarn build TEMPLATE PROTOCOL MODULE NETWORK watcher

deploy

Executed with yarn this script will deploy the compiled projection to graph-node. The argument reference is the same as the build script.

terminal
yarn deploy TEMPLATE PROTOCOL MODULE NETWORK

The result will be a deployed subgraph and watcher on the specified network. Pay attention to the name of your subgraph and watcher that you’ve been given by the network. It follows this pattern:

<PROTOCOL>__<MODULE>___NETWORK

For example

uniswap2__liquidity_pool___mainnet

Partial deploys

If you want to deploy only the subgraph or the watcher, you can use the following arguments.

Deploy just the subgraph
terminal
yarn deploy TEMPLATE PROTOCOL MODULE NETWORK graph
Deploy just the watcher
terminal
yarn deploy TEMPLATE PROTOCOL MODULE NETWORK watcher

Schema

Common Entities

schema.graphql
type User @entity(immutable: true) {
id: ID!
positions: [UserPosition!]! @derivedFrom(field: "user")
}
enum UpdateType {
SCHEDULE
EVENT
}
type UpdateTrigger @entity {
id: ID!
updateType: UpdateType!
nonce: Bytes!
}
type PositionUpdateTrigger @entity {
id: ID!
user: User!
updateTrigger: UpdateTrigger!
}
interface UserPosition {
id: ID!
user: User!
}

type User @entity(immutable: true)

The User entity represents a user of the protocol. It is marked as immutable because the user’s ID should not change. The user entity has a one-to-many relationship with UserPosition entities.

This entity is used to locate a user in the Datai Network when called by a gateway.

enum UpdateType

Update type tells the watcher on what condition a position should be updated in the network.

SCHEDULE

@Miquel I need your help here

EVENT

@Miquel I need your help here

type UpdateTrigger @entity

@Miquel I need your help here

type PositionUpdateTrigger @entity

@Miquel I need your help here

interface UserPosition

@Miquel I need your help here

Protocol Specific Entities

Generally each protocol will have its own set of entities that are specific to the protocol. You may want to store LP pair data, token metadata or protocol specific identifiers of positions.

Subgraph

Subgraph is responsible for crawling the network block by block and saving a trigger every time a user enters a position in a protocol. It then registers the position for the watcher to observe and compute the position balances.

SDK Function Reference

There are a few key functions you’ll be using to successfully create a projection.

ensureUpdateTrigger(positionId: ID!): Boolean

This function is used in event mappings to ensure that an UpdateTrigger exists for a given UserPosition. Use it to abort the execution of registering a user position if the trigger already exists.

mapping.ts
...
if (ensureUpdateTrigger(positionId)) return;
// If no trigger exists, proceed to registering a user position.
...

registerUser(userId: ID!): User

Accepts a user ID and returns the User entity. If the user does not exist, it will create a new user entity.

Watcher

SDK Function Reference

export function GetActivePositions(): void

Every watcher needs to export a function called GetActivePositions. This function is called by the host application to compute the active positions of a user.

activePositions.inputPosition<T>()

A function that injects a position id into the watcher from a registered trigger in the subgraph.

<T>

Type of a specific position entity that the watcher will be computing. For example Uniswap2UserPosition. A UserPosition entity must contain an id. The id should be composed of <WALLET>-<POSITION_ID>.

class ActivePositionsResult()

A class that is used to store and mutate the computed active positions of a user.

tokenBalance(tokenBalances: Array<TokenBalancePd>, index: i32): TokenBalance

A function that returns a token balance of a specific token at a given index.

findBalance(tokenBalances: Array<TokenBalancePd>, tokenAddress: Address, tokenId: BigInt | null = null): BigInt | null

A function that returns the balance of a specific token in the token balances array.

setBalance(tokenBalances: Array<TokenBalancePb>, balance: BigInt, tokenAddress: Address, tokenId: BigInt | null = null): void

A function that sets the balance of a specific token in the token balances array.

supplyBalance(tokenAddress: Address, tokenId: BigInt | null = null): BigInt | null

A function that returns the supply balance of a specific token.

setSupplyBalance(tokenAddress: Address, balance: BigInt, tokenId: BigInt | null): void

A function that sets the supply balance of a specific token.

borrowBalance(tokenAddress: Address, tokenId: BigInt | null = null): BigInt | null

A function that returns the borrow balance of a specific token.

setBorrowBalance(tokenAddress: Address, balance: BigInt, tokenId: BigInt | null): void

A function that sets the borrow balance of a specific token.

rewardBalance(tokenAddress: Address, tokenId: BigInt | null = null): BigInt | null

A function that returns the reward balance of a specific token.

setRewardBalance(tokenAddress: Address, balance: BigInt, tokenId: BigInt | null): void

A function that sets the reward balance of a specific token.

set poolAddress(address: Address)

A function that sets the pool address of the active position.

get poolAddress(): Address

A function that returns the pool address of the active position.

set unlockTime(seconds: i64)

A function that sets the unlock time of the active position. Useful for time-locked positions like staked or vested.

get unlockTime(): i64

A function that returns the unlock time of the active position.

setPositionTokenBalance(tokenAddress: Address, balance: BigInt, tokenId: BigInt | null = null): void

A function that sets the token balance of the active position. This is different to setBalance as it indicates the balance of the token that represents the position. For example a rebasible token one could find in Aave or Compound protocols. Similarly this could be an LP token in Uniswap or Sushiswap.