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.
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
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.
@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.
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)
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)
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
Go SDK Methods for Chaincode Events
Event Generation in Blockchain App Builder Chaincode
If theevents
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.