Chaincode Events

The enhanced version of Blockchain App Builder can generate chaincode events for token operations.

Chaincode events are specific notifications that are emitted when transactions run. Events include transaction information that can be used to notify external systems about specific conditions or changes in the blockchain ledger state. You can use chaincode events to enable real-time integration and interaction with applications that are not on the blockchain, and to facilitate event-driven workflows and monitoring across the blockchain environment. Chaincode events have two components, the event name and the payload.

Chaincode events are supported for all Blockchain App Builder specification files. If you enable chaincode events, all controller functions in your scaffolded project will emit events, except for getter methods. For example, in a token scenario, chaincode events will be emitted when tokens are minted, transferred, burned, or locked

You use the Boolean events parameter in the specification file to enable chaincode events, as shown in the following example.

assets:
    - name: FiatMoneyTOK # Asset name
      type: token  # Asset type
      events: true  # Generate events for create, update and delete APIs

If you enable events, the controller functions in your scaffolded chaincode project will include event creation methods, as shown in the following examples.

TypeScript:

@Validator(yup.string(), yup.string(), yup.string())
public async createAccount(org_id: string, user_id: string, token_type: string) {
  await this.Ctx.Auth.checkAuthorization("ACCOUNT.createAccount", "TOKEN", { org_id });
  await this.Ctx.Model.createEvent(EVENT_NAME.CREATE_ACCOUNT, { org_id, user_id, token_type });
  return await this.Ctx.Account.createAccount(org_id, user_id, token_type);
}

Go:

func (t *Controller) CreateAccount(org_id string, user_id string, token_type string, daily_limits ...account.AccountDailyLimits) (interface{}, error) {
    auth, err := t.Ctx.Auth.CheckAuthorization("Account.CreateAccount", "TOKEN", map[string]string{"org_id": org_id})
    if err != nil && !auth {
        return nil, fmt.Errorf("error in authorizing the caller  %s", err.Error())
    }
    err = t.Ctx.Model.CreateEvent(constants.CreateAccountEventName, map[string]interface{}{"org_id": org_id, "user_id": user_id, "token_type": token_type})
    if err != nil {
        return nil, err
    }
    return t.Ctx.Account.CreateAccount(org_id, user_id, token_type, daily_limits...)
}

Chaincode events use the following default values for the name and payload components. You can modify the default values as needed.

EventName
The name of the controller function.
Payload
A JSON object that contains all of the input parameters of the controller function.
A new events parameter was also added to the token details in the extended Token Taxonomy Framework and ERC-1155 standards. If the events parameter in the specification file is set to true, the events parameter in the generated token is set to true. If the events parameter in the specification file is set to false or not defined, the events parameter in the generated token is set to false. The following examples show a token with the new events parameter for both TypeScript and Go.
{
    "metadata": {
        "paintingName": "monalisa",
        "description": "monalisa painting",
        "image": "image link",
        "painterName": "Leonardo da Vinci"
    },
    "assetType": "otoken",
    "events": true,
    "quantity": 1,
    "tokenId": "artnft",
    "tokenName": "artcollection",
    "tokenDesc": "artcollection nft",
    "tokenStandard": "erc1155+",
    "tokenType": "nonfungible",
    "tokenUnit": "whole",
    "behaviors": [
        "indivisible",
        "singleton",
        "mintable",
        "transferable",
        "burnable",
        "roles"
    ],
    "roles": {
        "minter_role_name": "minter",
        "burner_role_name": "burner"
    },
    "mintable": {
        "max_mint_quantity": 500
    },
    "owner": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "createdBy": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "creationDate": "2022-12-29T04:08:35.000Z",
    "isBurned": false,
    "tokenUri": "tu",
    "price": 10000,
    "onSaleFlag": false
}
{
    "AssetType": "otoken",
    "Behavior": [
        "indivisible",
        "singleton",
        "mintable",
        "transferable",
        "burnable",
        "roles"
    ],
    "CreatedBy": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "CreationDate": "2022-12-29T09:57:03+05:30",
    "Events": true,
    "IsBurned": false,
    "Mintable": {
        "Max_mint_quantity": 500
    },
    "OnSaleFlag": false,
    "Owner": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "Price": 100,
    "Quantity": 1,
    "Roles": {
        "burner_role_name": "burner",
        "minter_role_name": "minter"
    },
    "TokenDesc": "token description",
    "TokenId": "monalisa",
    "TokenMetadata": {
        "Description": "Mona Lisa Painting",
        "Image": "monalisa.jpeg",
        "PainterName": "Leonardo_da_Vinci",
        "PaintingName": "Mona_Lisa"
    },
    "TokenName": "artcollection",
    "TokenStandard": "erc1155+",
    "TokenType": "nonfungible",
    "TokenUnit": "whole",
    "TokenUri": "https://bafybeid6pmpp62bongoip5iy2skosvyxh3gr7r2e35x3ctvawjco6ddmsq\\\\ .ipfs.infura-ipfs.io/?filename=MonaLisa.jpeg"
}

Generating Events

The stub.setEvent method enables the chaincode to create and emit an event when a transaction runs. The following code shows the TypeScript version of the method.
async setEvent(eventName: string, payload: Buffer): Promise<void>

In this example, eventName is the name to assign to the event, and payload is data associated with the event. The payload can contain any information that you want to send with the event, typically serialized in JSON format.

Chaincode Events for Batch Methods

The enhanced ERC-1155 standard supports batch methods. Batch methods operate on multiple tokens that are passed as parameters. For batch methods, chaincode events are emitted for only the tokens where the events parameter is set to true in the specification file.

For each transaction completed in the batch method, a corresponding chaincode event is generated. The payload of each chaincode event contains the transaction details. For example, if you use the BatchTransfer method to transfer quantities of five different tokens, five corresponding chaincode events are emitted. The payload of each event contains the token details and the quantity transferred, along with common parameters that are applicable to all batch transfers.

The following example shows events code using the enhanced ERC-1155 standard.
@Validator(yup.string(), yup.string(), yup.string(), yup.string(), yup.array().of(yup.string()), yup.array().of(yup.number()))
  public async batchTransferFrom(
    fromOrgId: string,
    fromUserId: string,
    toOrgId: string,
    toUserId: string,
    tokenIds: string[],
    quantity: number[]
  ) {
    const fromAccountId = this.Ctx.ERC1155Account.generateAccountId(fromOrgId, fromUserId, ACCOUNT_TYPE.USER_ACCOUNT);
    const toAccountId = this.Ctx.ERC1155Account.generateAccountId(toOrgId, toUserId, ACCOUNT_TYPE.USER_ACCOUNT);
    let tokenAssets = [];
    for (let i = 0; i < tokenIds.length; i++) {
      const tokenAsset = await this.Ctx.ERC1155Token.get(tokenIds[i]);
      tokenAssets.push(tokenAsset);
    }
    await this.Ctx.Model.createEventForBatch(EVENT_NAME.BATCH_TRANSFER_FROM, { fromOrgId, fromUserId, toOrgId, toUserId }, quantity, tokenAssets);
    return await this.Ctx.ERC1155Token.batchTransferFrom(fromAccountId, toAccountId, tokenIds, quantity);
  }

Chaincode Events for Multiple Assets

The enhanced Token Taxonomy Framework and ERC-1155 standards support defining more than one token asset in a specification file. The chaincode event behavior is different depending on whether a method is token-specific (such as creating or updating a token) or common (such as minting or burning).

For token-specific methods, chaincode events are generated for only the tokens where the events parameter is set to true in the specification file.

For common methods, chaincode events are generated in the scaffolded project if any token has the events parameter set to true in the specification file. The actual chaincode event behavior is based on the number of token ID parameters passed to the method.

  • If a single token ID is passed as a parameter, chaincode events are generated only if the events parameter in the corresponding token details is set to true.
  • If multiple token IDs are passed as parameters, chaincode events are generated only if the events parameter in any one of the token details is set to true.
  • If no token ID is passed as a parameter, chaincode events are always generated.
The following list shows common methods that must be passed two tokens. This list applies to the extended Token Taxonomy Framework standard.
  • addConversionRate(from_token_id: string, to_token_id: string, token_conversion_rate: number)
  • updateConversionRate(from_token_id: string, to_token_id: string, token_conversion_rate: number)
  • tokenConversion(from_token_id: string, to_token_id: string, to_org_id: string, to_user_id: string,token_quantity: number)
  • exchangeToken(fromTokenId: string, fromOrgId: string, fromUserId: string, fromTokenQuantity: number, toTokenId: string, toOrgId: string,toUserId: string,toTokenQuantity: number)
The following list shows common methods that do not take tokens as arguments The following list applies to the extended Token Taxonomy Framework standard.
  • addTokenAdmin(org_id: string, user_id: string)
  • removeTokenAdmin(org_id: string, user_id: string)
  • addOrgAdmin(org_id: string, user_id: string)
  • removeOrgAdmin(org_id: string, user_id: string)
  • createAccount(org_id: string, user_id: string, token_type: string)
  • deleteHistoricalTransactions(time_to_expiration: Date)
  • initializeExchangePoolUser(org_id: string, user_id: string)
This list shows common methods that do not take tokens as arguments for the extended ERC-1155 standard.
  • addTokenAdmin(orgId: string, userId: string)
  • removeTokenAdmin(orgId: string, userId: string)
  • createAccount(orgId: string, userId: string, ftAccount: boolean, nftAccount: boolean)
  • createUserAccount(orgId: string, userId: string)
  • createTokenAccount(orgId: string, userId: string, tokenType: TokenType)
  • addTokenSysRole(orgId: string, userId: string, role: string)
  • removeTokenSysRole(orgId: string, userId: string, role: string)
  • transferTokenSysRole(fromOrgId: string, fromUserId: string, toOrgId: string, toUserId: string, role: string)
  • deleteHistoricalTransactions(time_to_expiration: Date)

TypeScript SDK Methods for Chaincode Events

createEvent
This method generates events based on a specified event name and payload.
public async createEvent(eventName: any, eventPayload: any, assets?: any)
Parameters:
  • eventName: string – The event name to use when generating events.
  • eventPayload: map[string]interface{} – The event payload to use when generating events.
  • assets – Optionally, the token asset can be passed as a parameter to the method.
createEventForBatch
This method generates events for batch operations such as the mintBatch or burnBatch methods.
public async createEventForBatch(eventName: any, eventPayload: any, quantities: number[], assets: any)
Parameters:
  • eventName: string – The event name to use when generating events.
  • eventPayload: map[string]interface{} – The event payload to use when generating events.
  • quantities: number[] – A list of amounts, corresponding to each token ID, that represent the number of tokens to use in the batch method transactions.
  • assets – Optionally, the token asset can be passed as a parameter to the method.

Go SDK Methods for Chaincode Events

CreateEvent
This method generates events based on a specified event name and payload.
func (m *Model) CreateEvent(eventName string, eventPayload map[string]interface{}, assets ...interface{})
Parameters:
  • eventName: string – The event name to use when generating events.
  • eventPayload: map[string]interface{} – The event payload to use when generating events.
  • assets – Optionally, the token asset can be passed as a parameter to the method.
CreateEventForBatch
This method generates events for batch operations such as the mintBatch or burnBatch methods.
func (m *Model) CreateEventForBatch(eventName string, eventPayload map[string]interface{}, quantities []float64, assets []interface{})
Parameters:
  • eventName: string – The event name to use when generating events.
  • eventPayload: map[string]interface{} – The event payload to use when generating events.
  • quantities: []float64 – A list of amounts, corresponding to each token ID, that represent the number of tokens to use in the batch method transactions.
  • assets – Optionally, the token asset can be passed as a parameter to the method.

Event Generation in Blockchain App Builder Chaincode

If the events parameter in the specification file is set to true, chaincode events code is generated for all controller APIs except for those designated as getter APIs. The following examples show controller APIs with chaincode events enabled for both TypeScript and Go.
@Validator(yup.string(), yup.string(), yup.string())
public async createAccount(org_id: string, user_id: string, token_type: string) {
  await this.Ctx.Auth.checkAuthorization("ACCOUNT.createAccount", "TOKEN", { org_id });
  await this.Ctx.Model.createEvent(EVENT_NAME.CREATE_ACCOUNT, { org_id, user_id, token_type });
  return await this.Ctx.Account.createAccount(org_id, user_id, token_type);
}
func (t *Controller) CreateAccount(org_id string, user_id string, token_type string, daily_limits ...account.AccountDailyLimits) (interface{}, error) {
    auth, err := t.Ctx.Auth.CheckAuthorization("Account.CreateAccount", "TOKEN", map[string]string{"org_id": org_id})
    if err != nil && !auth {
        return nil, fmt.Errorf("error in authorizing the caller  %s", err.Error())
    }
    err = t.Ctx.Model.CreateEvent(constants.CreateAccountEventName, map[string]interface{}{"org_id": org_id, "user_id": user_id, "token_type": token_type})
    if err != nil {
        return nil, err
    }
    return t.Ctx.Account.CreateAccount(org_id, user_id, token_type, daily_limits...)
}
Chaincode events are generated with the following default values. You can modify these values as needed.
  • EventName: The name of the controller function.
  • Payload: A JSON object that contains all of the input parameters of the controller function.