Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Add typedocs for the Token module (#8897)
Browse files Browse the repository at this point in the history
* Add typedocs for command hooks

* Add typedocs for schema

* Export relevant data

* Update module description

* Add typedocs for cc-transfer

* Fix error

* Add typedocs for schemas

* Link to LIP

* Fix link

* Use camelcase

* Apply suggestions from code review

Co-authored-by: chris529 <christopher.braithwaite@lightcurve.io>

* Apply suggestions from code review

Co-authored-by: has5aan <50018215+has5aan@users.noreply.github.com>

* Export context

* Add typedocs folder to gitignore

* Export ImmutableCrossChainMessageContext

---------

Co-authored-by: chris529 <christopher.braithwaite@lightcurve.io>
Co-authored-by: has5aan <50018215+has5aan@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 31, 2023
1 parent 9e5242e commit 2d04e23
Show file tree
Hide file tree
Showing 16 changed files with 298 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ tmp
build/
dist/
build/
docs/typedoc/
dist-node/
dist-browser/
browsertest.build/
Expand Down
11 changes: 11 additions & 0 deletions framework/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,17 @@ export {
TokenMethod,
TokenModule,
TransferCommand,
TransferCrossChainCommand,
CrossChainTransferCommand,
TokenInteroperableMethod,
TokenEndpoint,
TransferParams,
CCTransferParams,
genesisTokenStoreSchema as tokenGenesisStoreSchema,
CROSS_CHAIN_COMMAND_NAME_TRANSFER,
LOCAL_ID_LENGTH,
TOKEN_ID_LENGTH,
MAX_DATA_LENGTH,
} from './modules/token';
export { NFTModule, NFTMethod } from './modules/nft';
export {
Expand Down Expand Up @@ -137,6 +146,8 @@ export {
BaseCCMethod,
BaseInteroperableModule,
CrossChainMessageContext,
CCCommandExecuteContext,
ImmutableCrossChainMessageContext,
getMainchainID,
RecoverContext,
} from './modules/interoperability';
Expand Down
24 changes: 24 additions & 0 deletions framework/src/modules/base_command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import { Schema, emptySchema } from '@liskhq/lisk-codec';
import { CommandVerifyContext, CommandExecuteContext, VerificationResult } from '../state_machine';
import { NamedRegistry } from './named_registry';

/**
* The `BaseCommand` represents Lisk commands by providing a generic interface, from which each command extends from.
*/
export abstract class BaseCommand<T = unknown> {
public schema: Schema = emptySchema;

Expand All @@ -28,7 +31,28 @@ export abstract class BaseCommand<T = unknown> {
// eslint-disable-next-line no-useless-constructor
public constructor(protected stores: NamedRegistry, protected events: NamedRegistry) {}

/**
* The hook `Command.verify()` is called to perform all necessary verifications.
* If the verification of the command was successful, for the next step the command can be {@link execute | executed}.
* Similar to the {@link BaseModule.verifyTransaction} hook, `Command.verify()` will be called also in the {@link @liskhq/lisk-transaction-pool!TransactionPool}, and its purpose is to guarantee that the verification defined within this hook is adhered to when the transactions are incorporated into a block.
*
* In this hook, the state *cannot* be mutated and events cannot be emitted.
*
* @param context The context available in every Command.verify() hook.
*/
public verify?(context: CommandVerifyContext<T>): Promise<VerificationResult>;

/**
* Applies the state changes of a command through the state machine.
* The hook `Command.execute()` is triggered by a transaction identified by the module name and the command name.
*
* Additionally, an event will be emitted that provides the information on whether a command is executed successfully or failed.
*
* In this hook, the *state can be mutated* and *events* can be emitted.
*
* If the {@link verify | command verification} succeeded, but the hook execution *fails*, the transaction that triggered this command is still valid, however the *state changes applied in this hook are reverted.*
*
* @param context The context available in every `Command.execute()` hook.
*/
public abstract execute(context: CommandExecuteContext<T>): Promise<void>;
}
3 changes: 3 additions & 0 deletions framework/src/modules/base_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export interface ModuleMetadata {

export type ModuleMetadataJSON = ModuleMetadata & { name: string };

/**
* The `BaseModule` represents Lisk modules by providing a generic interface, from which each module extends from.
*/
export abstract class BaseModule {
public commands: BaseCommand[] = [];
public events: NamedRegistry = new NamedRegistry();
Expand Down
26 changes: 26 additions & 0 deletions framework/src/modules/interoperability/base_cc_command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,42 @@ import { Schema, emptySchema } from '@liskhq/lisk-codec';
import { NamedRegistry } from '../named_registry';
import { CCCommandExecuteContext, ImmutableCrossChainMessageContext } from './types';

/**
* The `BaseCCCommand` represents Lisk cross-chain commands by providing a generic interface, from which each cross-chain command extends from.
*/
export abstract class BaseCCCommand<T = unknown> {
public schema: Schema = emptySchema;

/**
* Returns the name of the cross-chain command.
*/
public get name(): string {
const name = this.constructor.name.replace('CCCommand', '');
return name.charAt(0).toLowerCase() + name.substring(1);
}

// eslint-disable-next-line no-useless-constructor
public constructor(protected stores: NamedRegistry, protected events: NamedRegistry) {}
/**
* The hook `CCCommand.verify()` is called to perform all necessary verifications.
*
* In this hook, the state *cannot* be mutated and events cannot be emitted.
*
* If the verification of the command was successful, for the next step the cc-command can be {@link execute | executed}.
*
* @param context The context available in every Command.verify() hook.
*/
public verify?(ctx: ImmutableCrossChainMessageContext): Promise<void>;

/**
* Applies the state changes of a command through the state machine.
* The hook `CCCommand.execute()` is triggered by a transaction identified by the module name and the command name.
*
* Additionally, an event will be emitted that provides the information on whether a command is executed successfully or failed.
*
* In this hook, the *state can be mutated* and *events* can be emitted.
*
* @param context The context available in every `CCCommand.execute()` hook.
*/
public abstract execute(ctx: CCCommandExecuteContext<T>): Promise<void>;
}
7 changes: 7 additions & 0 deletions framework/src/modules/interoperability/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ export const MIN_MODULE_NAME_LENGTH = 1;
export const MAX_MODULE_NAME_LENGTH = 32;
export const MIN_CROSS_CHAIN_COMMAND_NAME_LENGTH = 1;
export const MAX_CROSS_CHAIN_COMMAND_NAME_LENGTH = 32;
/**
* Chain identifiers are 4-byte values that follow a specific format:
* - The network-specific prefix: The first byte is used to identify the mainchain and its corresponding network of blockchains to which the chain wishes to establish a connection.
* It is included explicitly to ensure that a chain does not use the same chain identifier in the test network as in the mainnet.
* - The chain-specific suffix: The other 3 bytes identify the chain within the network.
* Must be unique within the network.
*/
export const CHAIN_ID_LENGTH = 4;
export const CHAIN_ID_STRING_LENGTH = 2 * CHAIN_ID_LENGTH;
export const SUBSTORE_PREFIX_LENGTH = 2;
Expand Down
2 changes: 2 additions & 0 deletions framework/src/modules/interoperability/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export {
LastCertificate,
LastCertificateJSON,
CrossChainMessageContext,
CCCommandExecuteContext,
ImmutableCrossChainMessageContext,
RecoverContext,
} from './types';
// Common
Expand Down
6 changes: 6 additions & 0 deletions framework/src/modules/interoperability/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ export interface CCUpdateParams {
inboxUpdate: InboxUpdate;
}

/**
* TODO
*/
export interface ImmutableCrossChainMessageContext {
getMethodContext: () => ImmutableMethodContext;
getStore: ImmutableStoreCallback;
Expand All @@ -94,6 +97,9 @@ export interface ImmutableCrossChainMessageContext {
ccm: CCMsg;
}

/**
* TODO
*/
export interface CrossChainMessageContext extends ImmutableCrossChainMessageContext {
getMethodContext: () => MethodContext;
getStore: StoreCallback;
Expand Down
36 changes: 36 additions & 0 deletions framework/src/modules/token/cc_commands/cc_transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,48 @@ import { EscrowStore } from '../stores/escrow';
import { InternalMethod } from '../internal_method';
import { MAX_RESERVED_ERROR_STATUS } from '../../interoperability/constants';

/**
* The `transferCrossChain` cross-chain command of the {@link TokenModule}
*
* - name: `transferCrossChain`
* - module: {@link TokenModule | `token`}
*/
export class CrossChainTransferCommand extends BaseCCCommand {
public schema = crossChainTransferMessageParams;

private _tokenMethod!: TokenMethod;
private _internalMethod!: InternalMethod;

/**
* Returns the command name: {@link CROSS_CHAIN_COMMAND_NAME_TRANSFER}
*/
public get name(): string {
return CROSS_CHAIN_COMMAND_NAME_TRANSFER;
}

/**
* The `init()` hook of a command is called by the Lisk Framework when the node starts.
*
* In this context, you have the opportunity to validate and cache the module config or perform initializations that are intended to occur only once.
*
* @see [Command initialization](https://lisk.com/documentation/beta/understand-blockchain/sdk/modules-commands.html#command-initialization)
*
* @param args Contains the module methods and internal module methods.
*/
public init(args: { tokenMethod: TokenMethod; internalMethod: InternalMethod }): void {
this._tokenMethod = args.tokenMethod;
this._internalMethod = args.internalMethod;
}

/**
* Checks if the token is native on either the sending or the receiving chain.
*
* If the token is native to the receiving chain, it additionally verifies whether the escrow account holds a sufficient balance to facilitate the transfer of the designated tokens.
*
* For more info about the `verify()` method, please refer to the {@link BaseCommand}
*
* @param context
*/
public async verify(ctx: CrossChainMessageContext): Promise<void> {
const { ccm } = ctx;
const methodContext = ctx.getMethodContext();
Expand Down Expand Up @@ -73,6 +100,15 @@ export class CrossChainTransferCommand extends BaseCCCommand {
}
}

/**
* Transfers the specified amount of tokens to the recipient account.
*
* If the token being transferred is native to the receiving chain, it also subtracts the same amount of tokens from the respective escrow account.
*
* For more info about the `execute()` method, please refer to the {@link BaseCommand}.
*
* @param context
*/
public async execute(ctx: CrossChainMessageContext): Promise<void> {
const { ccm } = ctx;
const methodContext = ctx.getMethodContext();
Expand Down
36 changes: 35 additions & 1 deletion framework/src/modules/token/commands/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,50 @@ import { TokenID } from '../types';
import { InternalMethod } from '../internal_method';
import { InsufficientBalanceError } from '../../../errors';

interface Params {
/** Interface for the parameters of the Token Transfer Command */
export interface Params {
/** ID of the tokens being transferred. `TokenID` must be 8 bytes (16 characters). The first 4 bytes correspond to the `chainID`. */
tokenID: TokenID;
/** Amount of tokens to be transferred in Beddows. */
amount: bigint;
/** Address of the recipient. */
recipientAddress: Buffer;
/** Optional message / data field. */
data: string;
}

/**
* The `transfer` command of the {@link TokenModule} transfers tokens from one account to another.
*
* - name: `transfer`
* - module: {@link TokenModule | `token`}
*/
export class TransferCommand extends BaseCommand {
public schema = transferParamsSchema;
private _method!: TokenMethod;
private _internalMethod!: InternalMethod;

/**
* The `init()` hook of a command is called by the Lisk Framework when the node starts.
*
* In this context, you have the opportunity to validate and cache the module config or perform initializations that are intended to occur only once.
*
* @see [Command initialization](https://lisk.com/documentation/beta/understand-blockchain/sdk/modules-commands.html#command-initialization)
*
* @param args Contains the module methods and internal module methods.
*/
public init(args: { method: TokenMethod; internalMethod: InternalMethod }) {
this._method = args.method;
this._internalMethod = args.internalMethod;
}

/**
* Checks if the sender has enough balance to send the specified amount of tokens.
*
* For more info about the `verify()` method, please refer to the {@link BaseCommand}
*
* @param context
*/
public async verify(context: CommandVerifyContext<Params>): Promise<VerificationResult> {
const { params } = context;

Expand All @@ -64,6 +91,13 @@ export class TransferCommand extends BaseCommand {
};
}

/**
* Transfers the specified amount of tokens from the sender to the recipient account.
*
* For more info about the `execute()` method, please refer to the {@link BaseCommand}.
*
* @param context
*/
public async execute(context: CommandExecuteContext<Params>): Promise<void> {
const { params } = context;

Expand Down
36 changes: 35 additions & 1 deletion framework/src/modules/token/commands/transfer_cross_chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { TransferCrossChainEvent } from '../events/transfer_cross_chain';
import { InternalMethod } from '../internal_method';
import { InsufficientBalanceError } from '../../../errors';

interface Params {
export interface Params {
tokenID: Buffer;
amount: bigint;
receivingChainID: Buffer;
Expand All @@ -47,13 +47,28 @@ interface Params {
messageFeeTokenID: Buffer;
}

/**
* The `transfer` command of the {@link TokenModule} transfers tokens from one account to another account on a different chain.
*
* - name: `transferCrossChain`
* - module: {@link TokenModule | `token`}
*/
export class TransferCrossChainCommand extends BaseCommand {
public schema = crossChainTransferParamsSchema;
private _moduleName!: string;
private _method!: TokenMethod;
private _interoperabilityMethod!: InteroperabilityMethod;
private _internalMethod!: InternalMethod;

/**
* The `init()` hook of a command is called by the Lisk Framework when the node starts.
*
* In this context, you have the opportunity to validate and cache the module config or perform initializations that are intended to occur only once.
*
* @see [Command initialization](https://lisk.com/documentation/beta/understand-blockchain/sdk/modules-commands.html#command-initialization)
*
* @param args Contains the module methods and internal module methods.
*/
public init(args: {
moduleName: string;
method: TokenMethod;
Expand All @@ -66,6 +81,16 @@ export class TransferCrossChainCommand extends BaseCommand {
this._internalMethod = args.internalMethod;
}

/**
* Verifies if:
* - the token being sent is native to either the sending or the receiving chain.
* - the correct token ID is used to pay the CCM fee.
* - if the sender has enough balance to send the specified amount of tokens.
*
* For more info about the `verify()` method, please refer to the {@link BaseCommand}
*
* @param context
*/
// eslint-disable-next-line @typescript-eslint/require-await
public async verify(context: CommandVerifyContext<Params>): Promise<VerificationResult> {
const { params } = context;
Expand Down Expand Up @@ -127,6 +152,15 @@ export class TransferCrossChainCommand extends BaseCommand {
};
}

/**
* Creates and sends a CCM that transfers the specified amount of tokens from the sender to the recipient account on another chain.
*
* If the token being sent is native to the sending chain, it also adds the amount of tokens being sent to the escrow account for the respective tokens.
*
* For more info about the `execute()` method, please refer to the {@link BaseCommand}.
*
* @param context
*/
public async execute(context: CommandExecuteContext<Params>): Promise<void> {
const {
params,
Expand Down
8 changes: 8 additions & 0 deletions framework/src/modules/token/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ export const MIN_RETURN_FEE_PER_BYTE_BEDDOWS = BigInt(1000);

export const CHAIN_ID_LENGTH = 4;
export const HASH_LENGTH = 32;
/** The local token ID is a ID that is unique within a specific blockchain for a particular kind of token.
* It is exactly 4bytes (=8 characters) long. */
export const LOCAL_ID_LENGTH = 4;
/**
* `TokenID`s must be exactly 8 bytes (16 characters) long.
*
* The first 4 bytes correspond to the `chainID`, see {@link CHAIN_ID_LENGTH }.
* The last 4 bytes to the local ID, see {@link LOCAL_ID_LENGTH }.
* */
export const TOKEN_ID_LENGTH = CHAIN_ID_LENGTH + LOCAL_ID_LENGTH;
export const LOCAL_ID_LSK = Buffer.alloc(LOCAL_ID_LENGTH, 0);
export const USER_ACCOUNT_INITIALIZATION_FEE = BigInt(5000000);
Expand Down
Loading

0 comments on commit 2d04e23

Please sign in to comment.