SUI
Create project
You can create a new project with the following command:
npx @sentio/cli@latest create <your project name> --chain-type sui
Setup contract address
Use sentio add
to add contracts and fetch ABIs.
npx @sentio/cli@latest add --chain sui_mainnet [--name <your contract name>] <your contract address>
Or directly modify the sentio.yaml
file:
project: your-project-name
contracts:
- name: <contract name> # (optional)
address: <contract address> # sui contract address
chain: sui_mainnet # Chain id, sui_mainnet or sui_testnet
Contract name is optional but will make file generated more readable.
Type Generation
Run
yarn sentio gen
Will generate all types bindings for the added contracts.
Navigate to the project directory, where you should find the following files:
βββ package.json
βββ sentio.yaml
βββ abis/sui
β βββ 0x305fdc899f4d5d13a1e03ea784eed9bc5bdcb3e3550a32466ff34518aa4627a3.json [or <contract name>.json]
βββ src
β βββ types/sui
β. β βββ 0x305fdc899f4d5d13a1e03ea784eed9bc5bdcb3e3550a32466ff34518aa4627a3.ts [or <contract name>.ts]
β. β βββ index.ts
β βββ processor.test.ts
β βββ processor.ts
βββ tsconfig.json
Processor
Start your processor by importing the generated code and binding the processor to the contract address.
Event processor
You should find onEventXXX
methods to capture events emitted by any transactions.
import { bluemove_launchpad } from "./types/sui/0x305fdc899f4d5d13a1e03ea784eed9bc5bdcb3e3550a32466ff34518aa4627a3.js";
bluemove_launchpad.bind({
startCheckpoint: 1500000n
})
.onEventMintNFTEvent(async (event, ctx) => {
ctx.eventLogger.emit("MintEvent", {
distinctId: event.data_decoded.creator,
name: event.data_decoded.name,
object_id: event.data_decoded.object_id,
project: "bluemove"
})
})
You can access the event content by event
, and SUI transaction by ctx.transaction
. Not all fields in ctx.transaction
are fetched by default to increase performance. To get more fields like objectChanges
, add fetch config. All options can be found at MoveFetchConfig
.onEventMintNFTEvent(async (event, ctx) => {
...
},
{ resourceChanges: true }
})
Object processor
If you want to watch a single object's content changes, you can use SuiObjectProcessor
, for example:
SuiObjectProcessor.bind({
objectId: '0xa14f85860d6ce99154ecbb13570ba5fba1d8dc16b290de13f036b016fd19a29c',
startCheckpoint: 10000
})
.onTimeInterval(async (self, objects, ctx) => {
const fields = await ctx.coder.getDynamicFields(
objects,
BUILTIN_TYPES.U64_TYPE,
single_collateral.PortfolioVault.type()
)
ctx.meter.Gauge('fields_count').record(fields.length)
},
60*24, // watching time interval
60*24*30, // backfill time interval
undefined,
{ owned: true } // whether to fetch objects owned by the object
)
.onCheckpointInterval(...)
It will fetch the object content and optionally all objects belong to it (such as dynamic objects) every certain period of time in history.
To enable fetch owned objects, the last argument of MoveAccountFetchConfig
should be used , most used field is owned
, represent if objects owned by the object need to be fetched into objects
argument of the handler.
If more info for object is needed, use ctx.objectVersion
to work with SUI Typescript SDK to do that.
You may also want to carefully tune the two time intervals for better indexing performance
- Watching time interval: How often the handler is triggered by default
- Backfill time interval: How often the handler is triggered during processor backfill. You may want to set this to a larger number, especially if the object has a very long history
Address processor
Similar to object processor, you can use SuiAddressProcessor
to fetch all objects belonging to an address every certain period of time or checkpoints.
Object type processor
If you want to handle all objects that has the same type instead of single object, use SuiObjectTypeProcessor.onTimeInterval
, e.g.
import { staking_pool } from '@sentio/sdk/sui/builtin/0x3'
SuiObjectTypeProcessor.bind({
objectType: staking_pool.StakedSui.type()
})
.onTimeInterval(
(self, objects, ctx) => {
ctx.meter.Gauge('voting_power').record(self.data_decoded.principal, { pool: self.data_decoded.pool_id })
},
60,
60 * 24 * 30,
{ owned: false} // optional, default false for all fields
)
If you want to handle all object changes for certain object type, use SuiObjectTypeProcessor.onObjectChange
, e.g.
SuiObjectTypeProcessor.bind({
objectType: staking_pool.StakedSui.type()
})
.onObjectChange((changes, ctx) => {
ctx.meter.Counter('updates').add(changes.length)
})
Templating object processor
Sometimes you want to dynamically bind object processors. For example, you might want to register object handlers for all pools created by a contract (we prefer using SuiObjectTypeProcessor
for better performance, but sometimes you only care about a subset of those objects).
In this case, you can create a SuiObjectProcessorTemplate
and call bind
/unbind
in other triggers, for example:
import { validator_set } from '@sentio/sdk/sui/builtin/0x3'
const template = new SuiObjectProcessorTemplate().onTimeInterval(() => {
// logic to record staking pool
})
// begin watch a staking pool
validator_set.bind({ network: SuiNetwork.TEST_NET }).onEventValidatorJoinEvent((evt, ctx) => {
template.bind({ objectId: evt.data_decoded.staking_pool_id }, ctx)
})
// end watch the staking pool
validator_set.bind({ network: SuiNetwork.TEST_NET }).onEventValidatorLeaveEvent((evt, ctx) => {
template.unbind({ objectId: evt.data_decoded.staking_pool_id }, ctx)
})
Updated 13 days ago