Scaffolded TypeScript Chaincode Project

Blockchain App Builder takes the input from your specification file and generates a fully-functional scaffolded chaincode project. The project contains automatically generated classes and functions, CRUD methods, SDK methods, automatic validation of arguments, marshalling/un-marshalling and transparent persistence capability (ORM).

If the chaincode project uses the TypeScript language, the scaffolded project contains three main files:
  • main.ts
  • <chaincodeName>.model.ts
  • <chaincodeName>.controller.ts
All the necessary libraries are installed and packaged. The tsconfig.json file contains the necessary configuration to compile and build the TypeScript project.

The <chaincodeName>.model.ts file in the model subdirectory contains multiple asset definitions and the <chaincodeName>.controller.ts file in the controller subdirectory contains the assets behavior and CRUD methods.

The various decorators in model.ts and controller.ts provide support for features like automatic validation of arguments, marshalling/unmarshalling of arguments, transparent persistence capability (ORM) and calling rich queries.

Models

Every model class extends the OchainModel class, which has an additional read-only property called assetType. This property can be used to fetch only assets of this type. Any changes to this property are ignored during the creation and updating of the asset. The property value by default is <modelName>.

The OchainModel class enforces decorator behaviors on properties of the class.
@Id('supplierId')
export class Supplier extends OchainModel<Supplier> {
    public readonly assetType = 'supplier';
    @Mandatory()
    @Validate(yup.string()) 
    public supplierId: string;

Decorators

Class decorators
@Id(identifier)
This decorator identifies the property which uniquely defines the underlying asset. This property is used as a key of the record, which represents this asset in the chaincode's state. This decorator is automatically applied when a new TypeScript project is scaffolded. The 'identifier' argument of the decorator takes the value from specification file.
@Id('supplierId')
export class Supplier extends OchainModel{
...
}
Property decorators
Multiple property decorators can be used. The decorators are resolved in top to bottom order.
@Mandatory()
This marks the following property as mandatory so it cannot be skipped while saving to the ledger. If skipped it throws an error.
@Mandatory()
public supplierID: string;
@Default(param)
This property can have a default value. The default value in the argument (param) is used when the property is skipped while saving to the ledger.
@Default('open for business')
@Validate(yup.string())
public remarks: string;
@Validate(param)
The following property is validated against the schema presented in the parameter. The argument param takes a yup schema and many schema methods can be chained together. Many complex validations can be added. Refer to https://www.npmjs.com/package/yup for more details.
@Validate(yup.number().min(3))
public productsShipped: number;
@ReadOnly(param)
This property decorator marks the underlying property as having a read-only value. The value in the argument, for example param, is used when the property is saved in the ledger. Once the value is set it cannot be edited or removed.
@ReadOnly('digicur')
public token_name: string;
@Embedded(PropertyClass)
This property decorator marks the underlying property as an embeddable asset. It takes the embeddable class as a parameter. This class should extend the EmbeddedModel class. This is validated by the decorator.
In this example, Employee has a property called address of type Address, which is to be embedded with the Employee asset. This is denoted by the @Embedded() decorator.
export class Employee extends OchainModel<Employee> {

   public readonly assetType = 'employee';

   @Mandatory()
   @Validate(yup.string())
   public emplyeeID: string;

   @Mandatory()
   @Validate(yup.string().max(30))
   public firstName: string;

   @Mandatory()
   @Validate(yup.string().max(30))
   public lastName: string;

   @Validate(yup.number().positive().min(18))
   public age: number;

   @Embedded(Address)
   public address: Address;
}
export class Address extends EmbeddedModel<Address> {

   @Validate(yup.string())
   public street: string;

   @Validate(yup.string())
   public city: string;

   @Validate(yup.string())
   public state: string;

   @Validate(yup.string())
   public country: string;
}
When a new instance of the Address class is created, all the properties of the Address class are automatically validated by the @Validate() decorator. Note that the Address class does not have the assetType property or @Id() class decorator. This asset and its properties are not saved in the ledger separately but are saved along with the Employee asset. Embedded assets are user defined classes that function as value types. The instance of this class can only be stored in the ledger as a part of the containing object (OchainModel assets). All the above decorators are applied automatically based on the input file while scaffolding the project.
@Derived(STRATEGY, ALGORITHM, FORMAT)
This decorator is used for defining the attribute derived from other properties. This decorator has two mandatory parameters:
  • STRATEGY: takes values of CONCAT or HASH. Requires an additional parameter ALGORITHM if HASH is selected. The default algorithm is sha256; md5 is also supported.
  • FORMAT: takes an array of specification strings and values to be used by the strategy.
@Id('supplierID')
export class Supplier extends OchainModel<Supplier> {

   public readonly assetType = 'supplier';

   @Mandatory()
   @Derived(STRATEGY.HASH.'sha256',['IND%1IND%2','license','name'])
   @Validate(yup.string())
   public supplierID: string;

   @Validate(yup.string().min(2).max(4))
   public license: string;

   @Validate(yup.string().min(2).max(4))
   public name: string;
Method decorators
@Validator(…params)
This decorator is applied on methods of the main controller class. This decorator is important for parsing the arguments, validating against all the property decorators and returning a model/type object. Controller methods must have this decorator to be invokable. It takes multiple user-created models or yup schemas as parameters.
The order of the parameters must be exactly the same as the order of the arguments in the method.
In the following example, the Supplier model reference is passed in the parameter that corresponds to the asset type in the method argument. At run time, the decorator parses and converts the method argument to a JSON object, validates against the Supplier validators, and after successful validation converts the JSON object to a Supplier object and assigns it to the asset variable. Then the underlying method is finally called.
@Validator(Supplier)
public async createSupplier(asset: Supplier) {
    return await this.Ctx.Model.save(asset);
}
In the following example, multiple asset references are passed; they correspond to the object types of the method arguments. Notice the order of the parameters.
@Validator(Supplier, Manufacturer)
public async createProducts(supplier: Supplier, manufacturer: Manufacturer) {
}
Apart from asset references, yup schema objects can also be passed if the arguments are of basic-types. In the following example, supplierId and rawMaterialSupply are of type string and number respectively, so the yup schema of similar type and correct order is passed to the decorator. Notice the chaining of yup schema methods.
@Validator(yup.string(), yup.number().positive())
public async fetchRawMaterial(supplierID: string, rawMaterialSupply: number) {
	const supplier = await this.Ctx.Model.get(supplierID, Supplier);
	supplier.rawMaterialAvailable = supplier.rawMaterialAvailable + rawMaterialSupply;
	return await this.Ctx.Model.update(supplier);
}

ORM

Transparent Persistence Capability or simplified ORM is captured in the Model class of the Context (Ctx) object. If your model calls any of the following SDK methods, access them by using this.Ctx.Model.

SDK methods that implement ORM are the following methods:
  • save – this calls the Hyperledger Fabric putState method
  • get – this calls the Hyperledger Fabric getState method
  • update – this calls the Hyperledger Fabric putState method
  • delete – this calls the Hyperledger Fabric deleteState method
  • history – this calls the Hyperledger Fabric getHistoryForKey method
  • getByRange – this calls the Hyperledger Fabric getStateByRange method
  • getByRangeWithPagination – this calls the Hyperledger Fabric getStateByRangeWithPagination method
For more information, see: SDK Methods.

SDK Methods

Note:

Beginning with version 21.3.2, the way to access the ORM methods has changed. Run the ochain --version command to determine the version of Blockchain App Builder.

In previous releases, the ORM methods were inherited from the OchainModel class. In version 21.3.2 and later, the methods are defined on the Model class of Context (Ctx) object. To call these methods, access them by using this.Ctx.Model.<method_name>.

The following example shows a method call in previous releases:

@Validator(Supplier)
public async createSupplier(asset: Supplier){
    return await asset.save();
}

The following example shows a method call from the version 21.3.2 and later:

@Validator(Supplier)
public async createSupplier(asset: Supplier) {
      return await this.Ctx.Model.save(asset);
}

After you upgrade to version 21.3.2, make this change in all chaincode projects that you created with an earlier version of Blockchain App Builder. If you use the sync command to synchronize changes between the specification file and your source code, the changes are automatically brought to your controller for the ready-to-use methods. You still need to manually resolve any conflicts.

save
The save method adds the caller asset details to the ledger.
This method calls the Hyperledger Fabric putState internally. All marshalling/unmarshalling is handled internally. The save method is part of the Model class, which you access by using the Ctx object.
Ctx.Model.save(asset: <Instance of Asset Class> , extraMetadata?: any) : Promise <any>
Parameters:
  • extraMetadata : any (optional) – To save metadata apart from the asset into the ledger.
Returns:
  • Promise<any> - Returns a promise on completion
Example:
@Validator(Supplier)
public async createSupplier(asset: Supplier) {
	return await this.Ctx.Model.save(asset);
}
get
The get method is a method of OchainModel class which is inherited by the concrete model classes of {chaincodeName}.model.ts. The get method is part of the Model class, which you access by using the Ctx object.
If you would like to return any asset by the given id, use the generic controller method getAssetById.
Ctx.Model.get(id: string, modelName: <Model Asset Class Name>) : Promise<asset>
Parameters:
  • id : string – Key used to save data into the ledger.
  • modelName: <Model Asset Class Name> – (Optional) Model asset class to return.
Returns:
  • Promise: <Asset> - If the modelName parameter is not provided and data exists in ledger, then Promise<object> is returned. If the id parameter does not exist in ledger, an error message is returned. If the modelName parameter is provided, then an object of type <Asset> is returned. Even though any asset with given id is returned from the ledger, this method will take care of casting into the caller Asset type. If the asset returned from the ledger is not of the Asset type, then it throws an error. This check is done by the read-only assetType property in the Model class.
Example:
@Validator(yup.string())
public async getSupplierById(id: string) {
	const asset = await this.Ctx.Model.get(id, Supplier);
	return asset;
}
In the example, asset is of the type Supplier.
update
The update method updates the caller asset details in the ledger. This method returns a promise.
This method calls the Hyperledger Fabric putState internally. All the marshalling/unmarshalling is handled internally. The update method is part of the Model class, which you can access by using the Ctx object.
Ctx.Model.update(asset: <Instance of Asset Class> , extraMetadata?: any) : Promise <any>
Parameters:
  • extraMetadata : any (optional) – To save metadata apart from the asset into the ledger.
Returns:
  • Promise<any> - Returns a promise on completion
Example:
@Validator(Supplier)
public async updateSupplier(asset: Supplier) {
	return await this.Ctx.Model.update(asset);
}
delete
This deletes the asset from the ledger given by id if it exists. This method calls the Hyperledger Fabric deleteState method internally. The delete method is part of the Model class, which you can access by using the Ctx object.
Ctx.Model.delete(id: string): Promise <any>
Parameters:
  • id : string – Key used to save data into the ledger.
Returns:
  • Promise <any> - Returns a promise on completion.
Example:
@Validator(yup.string())
public async deleteSupplier(id: string) {
	const result = await this.Ctx.Model.delete(id);
	return result;
}
history
The history method is part of the Model class, which you can access by using the Ctx object. This method returns the asset history given by id from the ledger, if it exists.
This method calls the Hyperledger Fabric getHistoryForKey method internally.
Ctx.Model.history(id: string): Promise <any>
Parameters:
  • id : string – Key used to save data into the ledger.
Returns:
  • Promise <any[]> - Returns any [] on completion.
Example
@Validator(yup.string())
public async getSupplierHistoryById(id: string) {
	const result = await this.Ctx.Model.history(id);
	return result;
}
Example of the returned asset history for getSupplierHistoryById:
[
    {
        "trxId": "8ef4eae6389e9d592a475c47d7d9fe6253618ca3ae0bcf77b5de57be6d6c3829",
        "timeStamp": 1602568005,
        "isDelete": false,
        "value": {
            "assetType": "supplier",
            "supplierId": "s01",
            "rawMaterialAvailable": 10,
            "license": "abcdabcdabcd",
            "expiryDate": "2020-05-28T18:30:00.000Z",
            "active": true
        }
    },
    {
        "trxId": "92c772ce41ab75aec2c05d17d7ca9238ce85c33795308296eabfd41ad34e1499",
        "timeStamp": 1602568147,
        "isDelete": false,
        "value": {
            "assetType": "supplier",
            "supplierId": "s01",
            "rawMaterialAvailable": 15,
            "license": "valid license",
            "expiryDate": "2020-05-28T18:30:00.000Z",
            "active": true
        }
    }
]
getByRange
The getByRange method is a static method of OchainModel class which is inherited by the concrete Model classes of {chaincodeName}.model.ts.
This returns a list of asset between the range startId and endId. This method calls the Hyperledger Fabric getStateByRange method internally.
If the modelName parameter is not provided, the method returns Promise<Object [ ] >. If the modelName parameter is provided, then the method handles casting into the caller Model type. In the following example, the result array is of the type Supplier. If the asset returned from the ledger is not of the Model type, then it will not be included in the list. This check is done by the read-only assetType property in the Model class.
To return all the assets between the range startId and endId, use the generic controller method getAssetsByRange.
Ctx.Model.getByRange(startId: string, endId: string, modelName: <Asset Model Class Name> ): Promise <any>
Parameters:
  • startId : string – Starting key of the range. Included in the range.
  • endId : string – Ending key of the range. Excluded of the range.
  • modelName: <Model Asset Class Name> – (Optional) Model asset class to return.
Returns:
  • Promise< Asset[ ] > - Returns array of <Asset> on completion.
Example:
@Validator(yup.string(), yup.string())
public async getSupplierByRange(startId: string, endId: string) {
	const result = await this.Ctx.Model.getByRange(startId, endId, Supplier);
	return result;
}
getByRangeWithPagination
The getByRangeWithPagination method is a static method of OchainModel class which is inherited by the concrete Model classes of {chaincodeName}.model.ts.
This returns a list of asset between the range startId and endId. This method calls the Hyperledger Fabric getStateByRangeWithPagination method internally.
If the modelName parameter is not provided, the method returns Promise<Object [ ] >. If the modelName parameter is provided, then the method handles casting into the caller Model type. In the following example, the result array is of the type Supplier. If the asset returned from the ledger is not of the Model type, then it will not be included in the list. This check is done by the read-only assetType property in the Model class.
To return all the assets between the range startId and endId, filtered by page size and bookmarks, use the generic controller method getAssetsByRange.
public async getByRangeWithPagination<T extends OchainModel<T>>(startId: string, endId: string, pageSize: number, bookmark?: string, instance?: new (data: any, skipMandatoryCheck: boolean, skipReadOnlyCheck: boolean) => T): Promise<T[]>
Parameters:
  • startId : string – Starting key of the range. Included in the range.
  • endId : string – Ending key of the range. Excluded from the range.
  • pageSize : number - The page size of the query.
  • bookmark : string - The bookmark of the query. Output starts from this bookmark.
  • modelName: <Model Asset Class Name> – (Optional) Model asset class to return.
Returns:
  • Promise< Asset[ ] > - Returns array of <Asset> on completion.
getId
When the asset has a derived key as Id, you can use this method to get a derived ID. This method will return an error if the derived key contains %t (timestamp).
Parameters:
  • object – Object should contain all the properties on which the derived key is dependent.
Returns:
  • Returns the derived key as a string.
Example:
@Validator(yup.string(), yup.string())
  
public async customGetterForSupplier(license: string, name: string){
    let object = {
      license : license,
      name: name
    }
    const id = await this.Ctx.Model.getID(object);
    return this.Ctx.Model.get(id);
}

For token SDK methods, see the topics under Tokenization Support Using Blockchain App Builder.

Controller

Main controller class extends OchainController. There is only one main controller.

export class TSProjectController extends OchainController{

You can create any number of classes, functions, or files, but only those methods that are defined within the main controller class are invokable from outside, the rest of them are hidden.

Automatically Generated Methods

As described in Input Specification File, you can specify which CRUD methods you want generated in the specification file. For example, if you selected to generate all methods, the result would be similar to:

@Validator(Supplier)
public async createSupplier(asset: Supplier) {
	return await this.Ctx.Model.save(asset);
}

@Validator(yup.string())
public async getSupplierById(id: string) {
	const asset = await this.Ctx.Model.get(id, Supplier);
	return asset;
}

@Validator(Supplier)
public async updateSupplier(asset: Supplier) {
	return await this.Ctx.Model.update(asset);
}

@Validator(yup.string())
public async deleteSupplier(id: string) {
	const result = await this.Ctx.Model.delete(id);
	return result;
}

@Validator(yup.string())
public async getSupplierHistoryById(id: string) {
	const result = await this.Ctx.Model.history(id);
	return result;
}

@Validator(yup.string(), yup.string())
public async getSupplierByRange(startId: string, endId: string) {
	const result = await this.Ctx.Model.getByRange(startId, endId, Supplier);
	return result;
}

Controller Method Details

Apart from the above model CRUD and non-CRUD methods, Blockchain App Builder provides out-of-the box support for other Hyperledger Fabric methods from our controller. These methods are:
  • getAssetById
  • getAssetsByRange
  • getAssetHistoryById
  • query
  • queryWithPagination
  • generateCompositeKey
  • getByCompositeKey
  • getTransactionId
  • getTransactionTimestamp
  • getChannelID
  • getCreator
  • getSignedProposal
  • getArgs
  • getStringArgs
  • getMspID
  • getNetworkStub

Note:

These methods are available with the this context in any class that extends the OChainController class.
For example:
public async getModelById(id: string) {   
    const asset = await this.getAssetById(id); 
    return asset;
}
@Validator(yup.string(), yup.string())
public async getModelsByRange(startId: string, endId: string) { 
    const asset = await this.getAssetsByRange(startId, endId); 
    return asset;
}
public async getModelHistoryById(id: string) {
    const result = await this.getAssetHistoryById(id); 
    return result;
}
getAssetById
The getAssetById method returns asset based on id provided. This is a generic method and be used to get asset of any type.
this.getAssetById(id: string): Promise<byte[]>
Parameters:
  • id : string – Key used to save data into the ledger.
Returns:
  • Promise <byte [ ]> - Returns promise on completion. You have to convert byte[] into an object.
getAssetsByRange
The getAssetsByRange method returns all assets present from startId (inclusive) to endId (exclusive) irrespective of asset types. This is a generic method and can be used to get assets of any type.
this.getAssetsByRange(startId: string, endId: string):
Promise<shim.Iterators.StateQueryIterator>
Parameters:
  • startId : string – Starting key of the range. Included in the range.
  • endId : string – Ending key of the range. Excluded of the range.
Returns:
  • Promise< shim.Iterators.StateQueryIterator> - Returns an iterator on completion. You have to iterate over it.
getAssetHistoryById
The getAssetHistoryById method returns history iterator of an asset for id provided.
this.getAssetHistoryById(id: string):
Promise<shim.Iterators.HistoryQueryIterator>
Parameters:
  • id : string – Key used to save data into the ledger.
Returns:
  • Promise<shim.Iterators.HistoryQueryIterator> - Returns a history query iterator. You have to iterate over it.
query
The query method will run a Rich SQL/Couch DB query over the ledger. This method is only supported for remote deployment on Oracle Blockchain Platform. This is a generic method for executing SQL queries on the ledger.
this.query(queryStr: string):
Promise<shim.Iterators.StateQueryIterator>
Parameters:
  • queryStr : string - Rich SQL/Couch DB query.
Returns:
  • Promise<shim.Iterators.StateQueryIterator> - Returns a state query iterator. You have to iterate over it.
queryWithPagination
This method runs a Rich SQL/Couch DB query over the ledger, filtered by page size and bookmarks. This method is only supported for remote deployment on Oracle Blockchain Platform. This is a generic method for executing SQL queries on the ledger.
public async queryWithPagination(query: string, pageSize: number, bookmark?: string)
Parameters:
  • query : string - Rich SQL/Couch DB query.
  • pageSize : number - The page size of the query.
  • bookmark : string - The bookmark of the query. Output starts from this bookmark.
Returns:
  • Promise<shim.Iterators.StateQueryIterator> - Returns a state query iterator. You have to iterate over it.
generateCompositeKey
This method generates and returns the composite key based on the indexName and the attributes given in the arguments.
this.generateCompositeKey(indexName: string, attributes:
string[]): string
Parameters:
  • indexName : string - Object Type of the key used to save data into the ledger.
  • attributes: string[ ] - Attributes based on which composite key will be formed.
Returns:
  • string - Returns a composite key.
getByCompositeKey
This method returns the asset that matches the key and the column given in the attribute parameter while creating composite key. indexOfId parameter indicates the index of the key returned in the array of stub method SplitCompositeKey. Internally this method calls Hyperledger Fabric’s getStateByPartialCompositeKey, splitCompositeKey and getState.
this.getByCompositeKey(key: string, columns: string[],
indexOfId: number): Promise<any []>
Parameters:
  • key: string – Key used to save data into ledger.
  • columns: string[ ] - Attributes based on key is generated.
  • indexOfId: number - Index of attribute to be retrieved from Key.
Returns:
  • Promise< any [ ] - Returns any [] on completion.
getTransactionId
Returns the transaction ID for the current chaincode invocation request. The transaction ID uniquely identifies the transaction within the scope of the channel.
this.getTransactionId(): string
Parameters:
  • none
Returns:
  • string - Returns the transaction ID for the current chaincode invocation request.
getTransactionTimestamp
Returns the timestamp when the transaction was created. This is taken from the transaction ChannelHeader, therefore it will indicate the client's timestamp, and will have the same value across all endorsers.
this.getTransactionTimestamp(): Timestamp
Parameters:
  • id : string – Key used to save data into the ledger.
Returns:
  • Timestamp - Returns the timestamp when the transaction was created.
getChannelID
Returns the channel ID for the proposal for chaincode to process.
this.getChannelID(): string
Parameters:
  • none
Returns:
  • string - Returns the channel ID.
getCreator
Returns the identity object of the chaincode invocation's submitter.
this.getCreator(): shim.SerializedIdentity
Parameters:
  • none
Returns:
  • shim.SerializedIdentity - Returns identity object.
getSignedProposal
Returns a fully decoded object of the signed transaction proposal.
this.getSignedProposal():
shim.ChaincodeProposal.SignedProposal
Parameters:
  • none
Returns:
  • shim.ChaincodeProposal.SignedProposal - Returns decoded object of the signed transaction proposal.
getArgs
Returns the arguments as array of strings from the chaincode invocation request.
this.getArgs(): string[]
Parameters:
  • none
Returns:
  • string [ ] - Returns arguments as array of strings from the chaincode invocation.
getStringArgs
Returns the arguments as array of strings from the chaincode invocation request.
this.getStringArgs(): string[]
Parameters:
  • none
Returns:
  • string [ ] - Returns arguments as array of strings from the chaincode invocation.
getMspID
Returns the MSP ID of the invoking identity.
this.getMspID(): string
Parameters:
  • none
Returns:
  • string - Returns the MSP ID of the invoking identity.
getNetworkStub
The user can get access to the shim stub by calling getNetworkStub method. This will help user to write its own implementation of working directly with the assets.
this.getNetworkStub(): shim.ChaincodeStub
Parameters:
  • none
Returns:
  • shim.ChaincodeStub - Returns chaincode network stub.
invokeCrossChaincode
You can use this method in a chaincode to call a function in another chaincode. Both chaincodes must be installed on the same peer.
this.invokeCrossChaincode(chaincodeName: string, methodName: string, args: string[], channelName: string): Promise<any>
Parameters:
  • chaincodeName – The name of the chaincode to call.
  • methodName - The name of the method to call in the chaincode.
  • arg - The argument of the calling method.
  • channelName - The channel where the chaincode to call is located.
Returns:
  • Promise<any> - Returns a JSON object that contains three fields:
    • isValid - true if the call is valid.
    • payload - The output returned by the cross-chaincode call, as a JSON object.
    • message - The message returned by the cross-chaincode call, in UTF-8 format.
invokeChaincode
You can use this method in a chaincode to call a function in another chaincode. Both chaincodes must be installed on the same peer.
this.invokeChaincode(chaincodeName: string, methodName: string, args: string[], channelName: string): Promise<any>
Parameters:
  • chaincodeName – The name of the chaincode to call.
  • methodName - The name of the method to call in the chaincode.
  • arg - The argument of the calling method.
  • channelName - The channel where the chaincode to call is located.
Returns:
  • Promise<any> - Returns a JSON object that contains three fields:
    • isValid - true if the call is valid.
    • payload - The output returned by the cross-chaincode call, as a JSON object.
    • message - The message returned by the cross-chaincode call, in UTF-8 format.

Custom Methods

The following custom methods were generated from our example specification file.

The executeQuery shows how SQL rich queries can be called. The validators against the arguments are added automatically by Blockchain App Builder based on the type of the argument specified in the specification file.


/**
*
*	BDB sql rich queries can be executed in OBP CS/EE.
*	This method can be invoked only when connected to remote OBP CS/EE network.
*
*/
@Validator(yup.string()}
public async executeQuery(query: string) {
    const result = await OchainController.query(query); 
    return result;
}
@Validator(yup.string(), yup.number()}
public async fetchRawMaterial(supplierId: string, rawMaterialSupply: number) {
}
@Validator(yup.string(), yup.string(), yup.number())
public async getRawMaterialFromSupplier(manufacturerId: string, supplierId: string, rawMaterialSupply: number) {
}
@Validator(yup.string(), yup.number(), yup.number())
public async createProducts(manufacturerId: string, rawMaterialConsumed: number, productsCreated: number) {
}
public async sendProductsToDistribution() { 
}

Init Method

A custom init method is provided in the controller with an empty definition. If you use Blockchain App Builder to deploy or upgrade, the init method is called automatically. If you deploy or upgrade from the Oracle Blockchain Platform console on the Hyperledger Fabric v1.4.7 platform, the init method is also called automatically. If you deploy or upgrade from the Oracle Blockchain Platform console on the Hyperledger Fabric v2.x platform, you must call the init method manually. You can use a third-party tool such as Postman to call the init method manually.

export class TestTsProjectController extends OchainController {
    public async init(params: any) { 
        return;
}

If you would like to initialize any application state at this point, you can use this method to do that.