Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/plugins/batch/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const batchPluginManifest: PluginManifest = {
registeredHooks: [
'account-create-batch-state',
'topic-create-batch-state',
'token-create-ft-batch-state',
],
options: [
{
Expand Down
114 changes: 114 additions & 0 deletions src/plugins/token/hooks/batch-create-ft/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type { CommandHandlerArgs, CoreApi, Logger } from '@/core';
import type {
HookResult,
PreOutputPreparationParams,
} from '@/core/hooks/types';
import type {
BatchDataItem,
BatchExecuteTransactionResult,
TransactionResult,
} from '@/core/types/shared.types';

import { StateError } from '@/core';
import { AbstractHook } from '@/core/hooks/abstract-hook';
import { AliasType } from '@/core/services/alias/alias-service.interface';
import { composeKey } from '@/core/utils/key-composer';
import { TOKEN_CREATE_FT_COMMAND_NAME } from '@/plugins/token/commands/create-ft';
import { buildTokenData } from '@/plugins/token/utils/token-data-builders';
import { ZustandTokenStateHelper } from '@/plugins/token/zustand-state-helper';

import { CreateFtNormalizedParamsSchema } from './types';

export class TokenCreateFtBatchStateHook extends AbstractHook {
override async preOutputPreparationHook(
args: CommandHandlerArgs,
params: PreOutputPreparationParams<
unknown,
unknown,
unknown,
BatchExecuteTransactionResult
>,
): Promise<HookResult> {
const { api, logger } = args;
const batchData = params.executeTransactionResult.updatedBatchData;
await Promise.all(
[...batchData.transactions]
.filter((item) => item.command === TOKEN_CREATE_FT_COMMAND_NAME)
.map((batchDataItem) => this.saveCreateFt(api, logger, batchDataItem)),
);
return Promise.resolve({
breakFlow: false,
result: {
message: 'success',
},
});
}

private async saveCreateFt(
api: CoreApi,
logger: Logger,
batchDataItem: BatchDataItem,
): Promise<void> {
const parseResult = CreateFtNormalizedParamsSchema.safeParse(
batchDataItem.normalizedParams,
);
if (!parseResult.success) {
logger.warn(
`There was a problem with parsing data schema. The saving will not be done`,
);
return;
}
const normalisedParams = parseResult.data;
const innerTransactionId = batchDataItem.transactionId;
if (!innerTransactionId) {
logger.warn(
`No transaction ID found for batch transaction ${batchDataItem.order}`,
);
return;
}

const innerTransactionResult: TransactionResult =
await api.receipt.getReceipt({
transactionId: innerTransactionId,
});

if (!innerTransactionResult.tokenId) {
throw new StateError(
'Transaction completed but did not return a token ID',
{ context: { transactionId: innerTransactionResult.transactionId } },
);
}

const tokenData = buildTokenData(innerTransactionResult, {
name: normalisedParams.name,
symbol: normalisedParams.symbol,
treasuryId: normalisedParams.treasury.accountId,
decimals: normalisedParams.decimals,
initialSupply: normalisedParams.initialSupply,
tokenType: normalisedParams.tokenType,
supplyType: normalisedParams.supplyType,
adminPublicKey: normalisedParams.admin.publicKey,
supplyPublicKey: normalisedParams.supply?.publicKey,
network: normalisedParams.network,
});

const key = composeKey(
normalisedParams.network,
innerTransactionResult.tokenId,
);
const tokenState = new ZustandTokenStateHelper(api.state, logger);
tokenState.saveToken(key, tokenData);
logger.info(' Token data saved to state');

if (normalisedParams.alias) {
api.alias.register({
alias: normalisedParams.alias,
type: AliasType.Token,
network: normalisedParams.network,
entityId: innerTransactionResult.tokenId,
createdAt: innerTransactionResult.consensusTimestamp,
});
logger.info(` Name registered: ${normalisedParams.alias}`);
}
}
}
1 change: 1 addition & 0 deletions src/plugins/token/hooks/batch-create-ft/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { TokenCreateFtBatchStateHook } from './handler';
39 changes: 39 additions & 0 deletions src/plugins/token/hooks/batch-create-ft/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { z } from 'zod';

import {
NetworkSchema,
SupplyTypeSchema,
TinybarSchema,
} from '@/core/schemas/common-schemas';
import { keyManagerNameSchema } from '@/core/services/kms/kms-types.interface';
import { HederaTokenType } from '@/core/shared/constants';

const ResolvedAccountCredentialSchema = z.object({
keyRefId: z.string(),
accountId: z.string(),
publicKey: z.string(),
});

const ResolvedPublicKeySchema = z.object({
keyRefId: z.string(),
publicKey: z.string(),
});

export const CreateFtNormalizedParamsSchema = z.object({
name: z.string(),
symbol: z.string(),
decimals: z.number(),
initialSupply: TinybarSchema,
supplyType: SupplyTypeSchema,
alias: z.string().optional(),
memo: z.string().optional(),
tokenType: z.enum([
HederaTokenType.NON_FUNGIBLE_TOKEN,
HederaTokenType.FUNGIBLE_COMMON,
]),
network: NetworkSchema,
keyManager: keyManagerNameSchema,
treasury: ResolvedAccountCredentialSchema,
admin: ResolvedAccountCredentialSchema,
supply: ResolvedPublicKeySchema.optional(),
});
8 changes: 8 additions & 0 deletions src/plugins/token/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,20 @@ import {
tokenView,
TokenViewOutputSchema,
} from './commands/view';
import { TokenCreateFtBatchStateHook } from './hooks/batch-create-ft';

export const tokenPluginManifest: PluginManifest = {
name: 'token',
version: '1.0.0',
displayName: 'Token Plugin',
description: 'Plugin for managing Hedera fungible and non-fungible tokens',
hooks: [
{
name: 'token-create-ft-batch-state',
hook: new TokenCreateFtBatchStateHook(),
options: [],
},
],
commands: [
{
name: 'mint-ft',
Expand Down
Loading