Skip to main content

Triggering Events

Smart contracts do not live in a vacuum. Even though they run in a very limited sandbox, from a larger perspective there will have to be a way for users to interact with them. Since smart contracts are essentially event-driven, and requests run asynchronously from the user's perspective, there is a need for triggering events by the smart contracts themselves. Of course, it would be possible for users to periodically call a view function to retrieve the latest state of the smart contract, but this burdens the nodes unnecessarily. A better way is to have the smart contracts trigger events that the user can subscribe to and that convey changes to its state.

To support events the ISCP sandbox provides a very rudimentary interface. The function call context exposes this interface through its event() function, which is passed a completely arbitrary text string. It is up to the smart contract creator to format this text string and it's up to the user to interpret this text string correctly. This is error-prone, inconsistent, and means that a lot of code needs to be written both on the smart contract side that generates these events, and on the client side that handles these events. And with any change to the formatting of these events both ends need to be modified to stay in sync.

This is why the schema tool allows you to define your own structured events. The schema tool will generate a structure that will become part of all func call contexts. Events can only be triggered from within a func. They will become part of the state of the smart contract because every event is logged in the core eventlog contract. Therefore, they cannot be triggered from a view.

For each event defined in the events section of the schema definition file, this events structure will contain a member function that takes the defined types of parameters and will automatically encode the event as a consistently formatted string and pass it to the ISCP context's event() function. The string consists of the name of the event, a timestamp, and string representations of each field, all separated by vertical bars.

Here is the events section that can be found in the demo fairroulette smart contract:

events:
bet:
address: Address // address of better
amount: Int64 // amount of iotas to bet
number: Int64 // number to bet on
payout:
address: Address // address of winner
amount: Int64 // amount of iotas won
round:
number: Int64 // current betting round number
start:
stop:
winner:
number: Int64 // the winning number

The schema tool will generate events.xx which contains the following code for the FairRouletteEvents struct:

package fairroulette

import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib"

type FairRouletteEvents struct{}

func (e FairRouletteEvents) Bet(address wasmlib.ScAddress, amount int64, number int64) {
wasmlib.NewEventEncoder("fairroulette.bet").
Address(address).
Int64(amount).
Int64(number).
Emit()
}

func (e FairRouletteEvents) Payout(address wasmlib.ScAddress, amount int64) {
wasmlib.NewEventEncoder("fairroulette.payout").
Address(address).
Int64(amount).
Emit()
}

func (e FairRouletteEvents) Round(number int64) {
wasmlib.NewEventEncoder("fairroulette.round").
Int64(number).
Emit()
}

func (e FairRouletteEvents) Start() {
wasmlib.NewEventEncoder("fairroulette.start").
Emit()
}

func (e FairRouletteEvents) Stop() {
wasmlib.NewEventEncoder("fairroulette.stop").
Emit()
}

func (e FairRouletteEvents) Winner(number int64) {
wasmlib.NewEventEncoder("fairroulette.winner").
Int64(number).
Emit()
}

Notice how the generated functions use the WasmLib EventEncoder to encode the parameters into a single string before emitting it. Here is the way in which fairroulette emits the bet event in its smart contract code:

    f.Events.Bet(bet.Better.Address(), bet.Amount, bet.Number)

The smart contract client code can listen in to the event stream and respond to the events it deems noteworthy. The schema tool will shortly also be generating the client side code that properly parses these events and passes a type-safe structure to the client code.

In the next section we will explore how the schema tool helps to simplify function definitions.