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
11 changes: 11 additions & 0 deletions src/core/schemas/common-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -930,3 +930,14 @@ export const HexEncodedDataSchema = z
'Data must be a hex encoded string starting in format "0x12abfe456123"',
)
.describe('HEX encoded data format');

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

export const ResolvedPublicKeySchema = z.object({
keyRefId: z.string(),
publicKey: z.string(),
});
1 change: 1 addition & 0 deletions src/plugins/batch/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const batchPluginManifest: PluginManifest = {
'account-create-batch-state',
'topic-create-batch-state',
'token-create-ft-batch-state',
'token-create-ft-from-file-batch-state',
],
options: [
{
Expand Down
133 changes: 133 additions & 0 deletions src/plugins/token/hooks/batch-create-ft-from-file/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import type { CommandHandlerArgs, CoreApi, Logger } from '@/core';
import type {
HookResult,
PreOutputPreparationParams,
} from '@/core/hooks/types';
import type { Credential } from '@/core/services/kms/kms-types.interface';
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_FROM_FILE_COMMAND_NAME } from '@/plugins/token/commands/create-ft-from-file';
import { processTokenAssociations } from '@/plugins/token/utils/token-associations';
import { buildTokenDataFromFile } from '@/plugins/token/utils/token-data-builders';
import { ZustandTokenStateHelper } from '@/plugins/token/zustand-state-helper';

import { CreateFtFromFileNormalizedParamsSchema } from './types';

export class TokenCreateFtFromFileBatchStateHook extends AbstractHook {
override async preOutputPreparationHook(
args: CommandHandlerArgs,
params: PreOutputPreparationParams<
unknown,
unknown,
unknown,
BatchExecuteTransactionResult
>,
): Promise<HookResult> {
const { api, logger } = args;
const batchData = params.executeTransactionResult.updatedBatchData;
if (!batchData.success) {
return Promise.resolve({
breakFlow: false,
result: {
message: 'Batch transaction status failure',
},
});
}
for (const batchDataItem of [...batchData.transactions].filter(
(item) => item.command === TOKEN_CREATE_FT_FROM_FILE_COMMAND_NAME,
)) {
await this.saveToken(api, logger, batchDataItem);
}
return Promise.resolve({
breakFlow: false,
result: {
message: 'success',
},
});
}

private async saveToken(
api: CoreApi,
logger: Logger,
batchDataItem: BatchDataItem,
): Promise<void> {
const parseResult = CreateFtFromFileNormalizedParamsSchema.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 = buildTokenDataFromFile(
innerTransactionResult,
normalisedParams.tokenDefinition,
normalisedParams.treasury.accountId,
normalisedParams.adminKey.publicKey,
normalisedParams.network,
{
supplyPublicKey: normalisedParams.supplyKey?.publicKey,
wipePublicKey: normalisedParams.wipeKey?.publicKey,
kycPublicKey: normalisedParams.kycKey?.publicKey,
freezePublicKey: normalisedParams.freezeKey?.publicKey,
pausePublicKey: normalisedParams.pauseKey?.publicKey,
feeSchedulePublicKey: normalisedParams.feeScheduleKey?.publicKey,
},
);

tokenData.associations = await processTokenAssociations(
innerTransactionResult.tokenId,
normalisedParams.tokenDefinition.associations as Credential[],
api,
logger,
normalisedParams.keyManager,
);

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');

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

import {
HtsDecimalsSchema,
KeySchema,
MemoSchema,
NetworkSchema,
PrivateKeySchema,
PrivateKeyWithAccountIdSchema,
ResolvedAccountCredentialSchema,
ResolvedPublicKeySchema,
TinybarSchema,
TokenNameSchema,
TokenSymbolSchema,
TokenTypeSchema,
} from '@/core/schemas/common-schemas';
import { keyManagerNameSchema } from '@/core/services/kms/kms-types.interface';
import { TokenFileCustomFeeSchema } from '@/plugins/token/schema';

export const FungibleTokenFileSchema = z.object({
name: TokenNameSchema,
symbol: TokenSymbolSchema,
decimals: HtsDecimalsSchema,
supplyType: z.union([z.literal('finite'), z.literal('infinite')]),
initialSupply: TinybarSchema,
maxSupply: TinybarSchema,
treasuryKey: PrivateKeyWithAccountIdSchema,
adminKey: PrivateKeySchema,
supplyKey: KeySchema.optional(),
wipeKey: KeySchema.optional(),
kycKey: KeySchema.optional(),
freezeKey: KeySchema.optional(),
pauseKey: KeySchema.optional(),
feeScheduleKey: KeySchema.optional(),
associations: z.array(PrivateKeyWithAccountIdSchema).default([]),
customFees: z
.array(TokenFileCustomFeeSchema)
.max(10, 'Maximum 10 custom fees allowed per token')
.default([]),
memo: MemoSchema.default(''),
tokenType: TokenTypeSchema,
});

export const CreateFtFromFileNormalizedParamsSchema = z.object({
keyManager: keyManagerNameSchema,
tokenDefinition: FungibleTokenFileSchema,
network: NetworkSchema,
treasury: ResolvedAccountCredentialSchema,
adminKey: ResolvedPublicKeySchema,
supplyKey: ResolvedPublicKeySchema.optional(),
wipeKey: ResolvedPublicKeySchema.optional(),
kycKey: ResolvedPublicKeySchema.optional(),
freezeKey: ResolvedPublicKeySchema.optional(),
pauseKey: ResolvedPublicKeySchema.optional(),
feeScheduleKey: ResolvedPublicKeySchema.optional(),
});
13 changes: 2 additions & 11 deletions src/plugins/token/hooks/batch-create-ft/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,14 @@ import { z } from 'zod';

import {
NetworkSchema,
ResolvedAccountCredentialSchema,
ResolvedPublicKeySchema,
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(),
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/token/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import {
TokenViewOutputSchema,
} from './commands/view';
import { TokenCreateFtBatchStateHook } from './hooks/batch-create-ft';
import { TokenCreateFtFromFileBatchStateHook } from './hooks/batch-create-ft-from-file';

export const tokenPluginManifest: PluginManifest = {
name: 'token',
Expand All @@ -85,6 +86,11 @@ export const tokenPluginManifest: PluginManifest = {
hook: new TokenCreateFtBatchStateHook(),
options: [],
},
{
name: 'token-create-ft-from-file-batch-state',
hook: new TokenCreateFtFromFileBatchStateHook(),
options: [],
},
],
commands: [
{
Expand Down
Loading