Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(devx): Update event docs #4465

Merged
merged 6 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 109 additions & 48 deletions docs/content/developer/iota-101/using-events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,20 @@ An event object in IOTA consists of the following attributes:
- `bcs`: Binary canonical serialization value.
- `timestampMs`: Unix epoch timestamp in milliseconds.

## Exploring Available Events
### Exploring Available Events

To subscribe to on-chain events, you first need to identify which events are available. While you can easily track events emitted by your own code, discovering events from external packages can be more challenging. The IOTA RPC provides the [`queryEvents`](/iota-api-ref#iotax_queryevents) method, which allows you to query on-chain packages and obtain a list of events you can subscribe to.
To [subscribe to on-chain events](#subscribing-to-events), you first need to identify which events are available. While you can easily track events emitted by your own code, discovering events from external packages can be more challenging. The IOTA RPC provides the [`queryEvents`](/iota-api-ref#iotax_queryevents) method, which allows you to query on-chain packages and obtain a list of events you can subscribe to.

## Applying Event Filters
### Applying Event Filters

When targeting specific events for querying or subscribing, you can use filters to refine your results. Although the filtering options for querying and subscribing are similar, there are notable differences to be aware of.
When targeting specific events for [querying](#querying-events) or [subscribing](#subscribing-to-events), you can use [filters](#filtering-events) to refine your results. Although the filtering options for querying and subscribing are similar, there are notable differences to be aware of.

## Emitting Events in Move

To emit events from your Move modules, you need to use the [`iota::event`](../../references/framework/iota-framework/event.mdx) module.
Emitting events allows external applications to subscribe and respond to specific on-chain activities.


lucas-tortora marked this conversation as resolved.
Show resolved Hide resolved
First, import the `event` module in your Move code:

```move
Expand All @@ -49,65 +50,117 @@ use iota::event;

Then, within your function, you can emit an event using the [`emit`](../../references/framework/iota-framework/event.mdx#function-emit) function. For example:

```move
/// Take coin from `DonutShop` and transfer it to tx sender.
/// Requires authorization with `ShopOwnerCap`.
public fun collect_profits( _: &ShopOwnerCap, shop: &mut DonutShop, ctx: &mut TxContext ) {
let amount = balance::value(&shop.balance);
let profits = coin::take(&mut shop.balance, amount, ctx);
// simply create new type instance and emit it.
event::emit(ProfitsCollected { amount });
transfer::public_transfer(profits, tx_context::sender(ctx));
}
```move file=<rootDir>/examples/trading/contracts/escrow/sources/lock.move#L42-L63
```

## Subscribing to Events
## Querying Events

<Tabs>

To react to events emitted by Move modules, you need to subscribe to them.
IOTA full nodes support event subscriptions via JSON-RPC notifications over WebSocket. You can interact with the [RPC directly][iotax_subscribeEvent](/iota-api-ref#iotax_subscribeevent), [iotax_subscribeTransaction](/iota-api-ref#iotax_subscribetransaction) or use an SDK like the [IOTA TypeScript SDK](../../references/ts-sdk/typescript/index.mdx).
<TabItem value="RPC" label="IOTA RPC">
The IOTA RPC provides a [`queryEvents`](/iota-api-ref#iotax_queryevents) method to query on-chain packages and return available events. As an example, the following `curl` command queries the Deepbook package on Mainnet for a specific type of event:

```sh
curl -X POST https://api.testnet.iota.cafe:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "iotax_queryEvents",
"params": [
{
"MoveModule": {
"package": "0x0000000000000000000000000000000000000000000000000000000000000002",
"module": "display",
"type": "0x0000…0002::display::Display<0xba68…286b::testnet_nft::TestnetNFT>"
}
},
null,
3,
false
]
}'
```

The following excerpt from one of the examples uses the TypeScript SDK to create an asynchronous subscription to the filter identified in the filter.
The TypeScript SDK provides a wrapper for the `iotax_queryEvents` method:
[`client.queryEvents`](../../references/ts-sdk/api/client/classes/IotaClient#queryevents).

```move
let unsubscribe = await provider.subscribeEvent({
filter: { <PACKAGE_ID> },
onMessage: (event) => {
console.log("subscribeEvent", JSON.stringify(event, null, 2))
</TabItem>
<TabItem value="rs" label="Rust">

You can use the following as an example on how to query for events using the `query_events` function. You should update
the `PACKAGE_ID_CONST` with a package of your choice.

```rust
use iota_sdk::{rpc_types::EventFilter, types::Identifier, IotaClientBuilder};

const PACKAGE_ID_CONST: &str = "";

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let iota_testnet = IotaClientBuilder::default()
.build("https://api.testnet.iota.cafe:443")
.await?;

let events = iota_testnet
.event_api()
.query_events(
EventFilter::MoveModule {
package: PACKAGE_ID_CONST.parse()?,
module: Identifier::new("dev_trophy")?,
},
None,
None,
false,
)
.await?;

for event in events.data {
println!("Event: {:?}", event.parsed_json);
}
});

Ok(())
}
```
</TabItem>
<TabItem value="graphql" label="GraphQL">

Move smart contracts can call other smart contracts that emit events. For example, `0x107a::nft` calls the `0x2::display::new_with_fields` smart contract and emits a `0x2::display::DisplayCreated` event. Note that using package and transaction module to query for `0x2::display` misses the following event even though it is actually an event the `0x2` package emits. The current workaround for this issue is to know all the `packageId`s you care about and search those in the `queryEvent` call.
You can use GraphQL to query events instead of JSON RPC. The following example queries are in the
[`iota-graphql-rpc` crate](https://github.com/iotaledger/iota/tree/develop/crates/iota-graphql-rpc/examples/event_connection) in the IOTA repo.

```json
{
"id": {
"txDigest": "DrZmtQDDCUKooLzFCi29VhUB4w6AT8phCsT9d62BAf8g",
"eventSeq": "0"
},
"packageId": "0x000000000000000000000000000000000000000000000000000000000000107a",
"transactionModule": "nft",
"sender": "0x0000000000000000000000000000000000000000000000000000000000000000",
"type": "0x2::display::DisplayCreated<0x107a::nft::Nft>",
"parsedJson": {
"id": "0xa12d72c159d57d4c7f540b2b9e985327628d856b20c1d6cdfd3028a2a605abfe"
},
"bcs": "CFbAeqXAwwkyTxUD36FtzTGEcMGrVj4zgcTR1G7AaRjb",
"timestampMs": "1521456213521"
}
#### Event Connection

```graphql file=<rootDir>/crates/iota-graphql-rpc/examples/event_connection/event_connection.graphql
```

#### Filter Events By Sender

```graphql file=<rootDir>/crates/iota-graphql-rpc/examples/event_connection/filter_by_sender.graphql
```

## Examples
#### Filter Events By Emitting Package and Type

### Subscribe to Event
```graphql file=<rootDir>/crates/iota-graphql-rpc/examples/event_connection/filter_by_sender.graphql
```

:::tip

The [TypeScript SDK](../../references/ts-sdk/api/graphql/classes/IotaGraphQLClient) provides functionality to
interact with the IOTA GraphQL service.

:::

</TabItem>
</Tabs>


## Subscribing to Events

This example leverages the IOTA TypeScript SDK to subscribe to events the package with ID `<PACKAGE_ID>` emits. Each time the event fires, the code displays the response to the console.

<Tabs>
<TabItem value="rs" label="Rust">

### Rust

See [Rust SDK](../../references/rust-sdk.mdx).

```rust
Expand All @@ -132,8 +185,6 @@ async fn main() -> Result<()> {
</TabItem>
<TabItem value="ts" label="TypeScript">

### TypeScript

To create the event subscription, you can use a basic Node.js app. You need the [IOTA TypeScript SDK](../../references/ts-sdk/typescript/index.mdx), so install the module using `npm install @iota/iota-sdk` at the root of your project. In your TypeScript code, import `JsonRpcProvider` and a connection from the library.

```ts
Expand Down Expand Up @@ -199,9 +250,19 @@ subscribeEvent {
</TabItem>
</Tabs>

## Monitoring Events

Firing events is not very useful in a vacuum. You also need the ability to respond to those events.
There are two methods from which to choose when you need to monitor on-chain events:
- Incorporate a [custom indexer](../advanced/custom-indexer.mdx) to take advantage of IOTA's micro-data ingestion framework.
- Poll the IOTA network on a schedule to query events.

Using a custom indexer provides a near-real time monitoring of events, so is most useful when your project requires immediate reaction to the firing of events. Polling the network is most useful when the events you're monitoring don't fire often or the need to act on those events are not immediate. The following section provides a polling example.


## Filtering Events

You can filter events when querying or subscribing to receive only the events you are interested in.
You can filter events when [querying](#querying-events) or [subscribing](#subscribing-to-events) to receive only the events you are interested in.

:::info

Expand Down
4 changes: 2 additions & 2 deletions docs/content/sidebars/developer.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ const developer = [
label: 'Typescript SDK',
href: '/references/ts-sdk/typescript',
},
'developer/iota-101/using-events',
],
},
{
Expand All @@ -70,6 +69,8 @@ const developer = [
'developer/iota-101/move-overview/init',
'developer/iota-101/move-overview/visibility',
'developer/iota-101/move-overview/entry-functions',
'developer/iota-101/using-events',
'developer/iota-101/access-time',
{
type: 'category',
label: 'Structs and Abilities',
Expand Down Expand Up @@ -107,7 +108,6 @@ const developer = [
'developer/iota-101/move-overview/patterns/id-pointer',
],
},
'developer/iota-101/access-time',
'developer/iota-101/move-overview/conventions',
],
},
Expand Down
Loading