Why do we need the validateAsset function?

The validateAsset() function is designed to perform static checks. This means it cannot access any data from the state store that has been loaded inside the custom transaction.

Therefore, we can only perform checks against the type and format of the data.
To give an example (Invoice Transaction Lisk Invoice):

validateAsset() {
  const errors = [];
  if (!this.asset.client || typeof this.asset.client !== 'string') {
    errors.push(
      new TransactionError(
        'Invalid "asset.client" defined on transaction',
        this.id,
        '.asset.client',
        this.asset.client,
        'A string value',
      )
    );
  }
  if (!this.asset.requestedAmount || typeof this.asset.requestedAmount !== 'string') {
    errors.push(
      new TransactionError(
        'Invalid "asset.requestedAmount" defined on transaction',
        this.id,
        '.asset.requestedAmount',
        this.asset.requestedAmount,
        'A string value',
      )
    );
  }
  if (!this.asset.description || typeof this.asset.description !== 'string') {
    errors.push(
      new TransactionError(
        'Invalid "asset.description" defined on transaction',
        this.id,
        '.asset.description',
        this.asset.description,
        'A string value',
      )
    );
  }
  return errors;
}

Another good example can be found in Lisk Transport for registering a new packet.