From ad2be1d5494bd44b748b854338e957733b473f04 Mon Sep 17 00:00:00 2001 From: matevszm Date: Tue, 10 Mar 2026 10:37:44 +0100 Subject: [PATCH] feat(1540): Replace outdated key schemas with keySchema Signed-off-by: matevszm --- .../token/create-nft.integration.test.ts | 2 - .../token/mint-nft.integration.test.ts | 2 - .../token/transfer-nft.integration.test.ts | 6 --- src/core/services/token/token-service.ts | 7 ++- src/core/types/token.types.ts | 2 +- src/core/utils/resolve-payer.ts | 4 +- .../account/__tests__/unit/import.test.ts | 8 +--- .../account/commands/import/handler.ts | 45 ++++++++----------- src/plugins/account/commands/import/input.ts | 6 +-- .../network/commands/set-operator/input.ts | 8 +--- .../token/__tests__/unit/create-nft.test.ts | 14 +++++- .../token/__tests__/unit/create.test.ts | 2 +- .../__tests__/unit/createFromFile.test.ts | 2 +- .../__tests__/unit/createNftFromFile.test.ts | 4 +- src/plugins/token/commands/associate/input.ts | 4 +- .../token/commands/create-ft/handler.ts | 20 +++++---- src/plugins/token/commands/create-ft/input.ts | 6 +-- src/plugins/token/commands/create-ft/types.ts | 3 +- .../token/commands/create-nft/handler.ts | 25 ++++++----- .../token/commands/create-nft/input.ts | 8 ++-- .../token/commands/create-nft/output.ts | 3 +- .../token/commands/create-nft/types.ts | 10 +++-- src/plugins/token/commands/mint-ft/input.ts | 4 +- src/plugins/token/commands/mint-nft/input.ts | 4 +- .../token/commands/transfer-ft/input.ts | 4 +- .../token/commands/transfer-nft/input.ts | 4 +- src/plugins/token/schema.ts | 12 +++-- .../token/utils/token-data-builders.ts | 2 +- src/plugins/topic/commands/create/input.ts | 3 +- .../topic/commands/submit-message/input.ts | 4 +- 30 files changed, 108 insertions(+), 120 deletions(-) diff --git a/src/__tests__/integration/token/create-nft.integration.test.ts b/src/__tests__/integration/token/create-nft.integration.test.ts index 4c73bece0..7118796bf 100644 --- a/src/__tests__/integration/token/create-nft.integration.test.ts +++ b/src/__tests__/integration/token/create-nft.integration.test.ts @@ -85,8 +85,6 @@ describe('Create NFT Integration Tests', () => { expect(createNftOutput.name).toBe('Test NFT'); expect(createNftOutput.alias).toBe('test-nft'); expect(createNftOutput.treasuryId).toBe(viewAccountOutput.accountId); - expect(createNftOutput.adminAccountId).toBe(viewAccountOutput.accountId); - expect(createNftOutput.supplyAccountId).toBe(viewAccountOutput.accountId); expect(createNftOutput.symbol).toBe('NFT'); expect(createNftOutput.supplyType).toBe(SupplyType.FINITE); }); diff --git a/src/__tests__/integration/token/mint-nft.integration.test.ts b/src/__tests__/integration/token/mint-nft.integration.test.ts index 9bb9a947f..609f8a428 100644 --- a/src/__tests__/integration/token/mint-nft.integration.test.ts +++ b/src/__tests__/integration/token/mint-nft.integration.test.ts @@ -90,8 +90,6 @@ describe('Mint NFT Integration Tests', () => { expect(createNftOutput.name).toBe('Test NFT Collection'); expect(createNftOutput.alias).toBe('test-nft-collection'); expect(createNftOutput.treasuryId).toBe(viewAccountOutput.accountId); - expect(createNftOutput.adminAccountId).toBe(viewAccountOutput.accountId); - expect(createNftOutput.supplyAccountId).toBe(viewAccountOutput.accountId); expect(createNftOutput.symbol).toBe('TNFT'); expect(createNftOutput.supplyType).toBe(SupplyType.FINITE); diff --git a/src/__tests__/integration/token/transfer-nft.integration.test.ts b/src/__tests__/integration/token/transfer-nft.integration.test.ts index c9ab16ffb..ceb5ec3f8 100644 --- a/src/__tests__/integration/token/transfer-nft.integration.test.ts +++ b/src/__tests__/integration/token/transfer-nft.integration.test.ts @@ -106,12 +106,6 @@ describe('Transfer NFT Integration Tests', () => { expect(createNftOutput.treasuryId).toBe( createSourceAccountOutput.accountId, ); - expect(createNftOutput.adminAccountId).toBe( - createSourceAccountOutput.accountId, - ); - expect(createNftOutput.supplyAccountId).toBe( - createSourceAccountOutput.accountId, - ); expect(createNftOutput.symbol).toBe('TNFTC'); expect(createNftOutput.supplyType).toBe(SupplyType.FINITE); diff --git a/src/core/services/token/token-service.ts b/src/core/services/token/token-service.ts index 7e07ddb5f..9debbc4eb 100644 --- a/src/core/services/token/token-service.ts +++ b/src/core/services/token/token-service.ts @@ -112,8 +112,11 @@ export class TokenServiceImpl implements TokenService { .setTokenType(TokenTypeMap[tokenType]) .setInitialSupply(initialSupplyRaw) .setSupplyType(tokenSupplyType) - .setTreasuryAccountId(AccountId.fromString(treasuryId)) - .setAdminKey(adminPublicKey); + .setTreasuryAccountId(AccountId.fromString(treasuryId)); + + if (adminPublicKey) { + tokenCreateTx.setAdminKey(adminPublicKey); + } // Set max supply for finite supply tokens if (supplyType === SupplyType.FINITE && maxSupplyRaw !== undefined) { diff --git a/src/core/types/token.types.ts b/src/core/types/token.types.ts index 91c82de0b..f900e7747 100644 --- a/src/core/types/token.types.ts +++ b/src/core/types/token.types.ts @@ -63,7 +63,7 @@ export interface TokenCreateParams { tokenType: HederaTokenType; supplyType: SupplyType; maxSupplyRaw?: bigint; // Required for FINITE supply type - adminPublicKey: PublicKey; + adminPublicKey?: PublicKey; supplyPublicKey?: PublicKey; wipePublicKey?: PublicKey; kycPublicKey?: PublicKey; diff --git a/src/core/utils/resolve-payer.ts b/src/core/utils/resolve-payer.ts index e227d0b26..c5d8195be 100644 --- a/src/core/utils/resolve-payer.ts +++ b/src/core/utils/resolve-payer.ts @@ -1,7 +1,7 @@ import type { CoreApi } from '@/core'; import type { KeyManagerName } from '@/core/services/kms/kms-types.interface'; -import { PrivateKeySchema } from '@/core'; +import { KeySchema } from '@/core'; /** * Resolves payer from string (alias or account-id:private-key format) @@ -17,7 +17,7 @@ export async function resolvePayer( ): Promise { const keyManager = coreApi.config.getOption('default_key_manager') || 'local'; - const parsedPayer = PrivateKeySchema.parse(payerString); + const parsedPayer = KeySchema.parse(payerString); const resolvedPayer = await coreApi.keyResolver.resolveAccountCredentials( parsedPayer, keyManager, diff --git a/src/plugins/account/__tests__/unit/import.test.ts b/src/plugins/account/__tests__/unit/import.test.ts index d23c1844e..74640feac 100644 --- a/src/plugins/account/__tests__/unit/import.test.ts +++ b/src/plugins/account/__tests__/unit/import.test.ts @@ -63,12 +63,6 @@ describe('account plugin - import command (ADR-003)', () => { const result = await importAccount(args); - expect(kms.importAndValidatePrivateKey).toHaveBeenCalledWith( - KeyAlgorithm.ECDSA, - 'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890', - '0230a1f42abc4794541e4a4389ec7e822666b8a7693c4cc3dedd2746b32f9c015b', - 'local', - ); expect(mirrorMock.getAccount).toHaveBeenCalledWith('0.0.9999'); expect(alias.register).toHaveBeenCalledWith( expect.objectContaining({ @@ -76,7 +70,7 @@ describe('account plugin - import command (ADR-003)', () => { type: AliasType.Account, network: 'testnet', entityId: '0.0.9999', - publicKey: 'pub-key-test', + publicKey: expect.any(String), keyRefId: 'kr_test123', }), ); diff --git a/src/plugins/account/commands/import/handler.ts b/src/plugins/account/commands/import/handler.ts index 4f8ef4b9f..caea2b89f 100644 --- a/src/plugins/account/commands/import/handler.ts +++ b/src/plugins/account/commands/import/handler.ts @@ -4,7 +4,7 @@ import type { KeyManagerName } from '@/core/services/kms/kms-types.interface'; import type { AccountData } from '@/plugins/account/schema'; import type { ImportAccountOutput } from './output'; -import { StateError, ValidationError } from '@/core/errors'; +import { StateError } from '@/core/errors'; import { AliasType } from '@/core/services/alias/alias-service.interface'; import { composeKey } from '@/core/utils/key-composer'; import { buildAccountEvmAddress } from '@/plugins/account/utils/account-address'; @@ -20,43 +20,36 @@ export class ImportAccountCommand implements Command { const validArgs = ImportAccountInputSchema.parse(args.args); - const key = validArgs.key; const alias = validArgs.name; const keyManagerArg = validArgs.keyManager; - const accountId = key.accountId; const network = api.network.getCurrentNetwork(); - const accountKey = composeKey(network, accountId); - - if (accountState.hasAccount(accountKey)) { - throw new StateError('Account with this ID is already saved in state'); - } const keyManager = - keyManagerArg || + keyManagerArg ?? api.config.getOption('default_key_manager'); - api.alias.availableOrThrow(alias, network); - - const accountInfo = await api.mirror.getAccount(key.accountId); - - const { keyRefId, publicKey } = api.kms.importAndValidatePrivateKey( - accountInfo.keyAlgorithm, - key.privateKey, - accountInfo.accountPublicKey, + const resolved = await api.keyResolver.resolveAccountCredentials( + validArgs.key, keyManager, + ['account:import'], ); - logger.info(`Importing account: ${accountKey} (${accountId})`); + const accountId = resolved.accountId; + const accountKey = composeKey(network, accountId); if (accountState.hasAccount(accountKey)) { - throw new ValidationError( - `Account with identifier '${accountKey}' already exists`, - ); + throw new StateError('Account with this ID is already saved in state'); } + api.alias.availableOrThrow(alias, network); + + const accountInfo = await api.mirror.getAccount(accountId); + + logger.info(`Importing account: ${accountKey} (${accountId})`); + const evmAddress = buildAccountEvmAddress({ accountId, - publicKey, + publicKey: resolved.publicKey, keyType: accountInfo.keyAlgorithm, existingEvmAddress: accountInfo.evmAddress, }); @@ -68,8 +61,8 @@ export class ImportAccountCommand implements Command { network: api.network.getCurrentNetwork(), entityId: accountId, evmAddress, - publicKey, - keyRefId, + publicKey: resolved.publicKey, + keyRefId: resolved.keyRefId, createdAt: new Date().toISOString(), }); } @@ -78,9 +71,9 @@ export class ImportAccountCommand implements Command { name: alias, accountId, type: accountInfo.keyAlgorithm, - publicKey: publicKey, + publicKey: resolved.publicKey, evmAddress, - keyRefId, + keyRefId: resolved.keyRefId, network: api.network.getCurrentNetwork(), }; diff --git a/src/plugins/account/commands/import/input.ts b/src/plugins/account/commands/import/input.ts index 80a0ee7d3..fb322de2a 100644 --- a/src/plugins/account/commands/import/input.ts +++ b/src/plugins/account/commands/import/input.ts @@ -1,9 +1,9 @@ import { z } from 'zod'; import { - AccountIdWithPrivateKeySchema, AccountNameSchema, KeyManagerTypeSchema, + KeySchema, } from '@/core/schemas'; /** @@ -11,8 +11,8 @@ import { * Validates arguments for importing an existing account */ export const ImportAccountInputSchema = z.object({ - key: AccountIdWithPrivateKeySchema.describe( - 'Account ID with private key in format accountId:privateKey', + key: KeySchema.describe( + 'Account credentials. Can be accountId:privateKey pair, key reference or account alias.', ), name: AccountNameSchema.optional().describe('Optional account name/alias'), keyManager: KeyManagerTypeSchema.optional().describe( diff --git a/src/plugins/network/commands/set-operator/input.ts b/src/plugins/network/commands/set-operator/input.ts index 672004644..062988b56 100644 --- a/src/plugins/network/commands/set-operator/input.ts +++ b/src/plugins/network/commands/set-operator/input.ts @@ -1,17 +1,13 @@ import { z } from 'zod'; -import { - KeyManagerTypeSchema, - NetworkSchema, - PrivateKeyWithAccountIdSchema, -} from '@/core/schemas'; +import { KeyManagerTypeSchema, KeySchema, NetworkSchema } from '@/core/schemas'; /** * Input schema for network set-operator command * Validates arguments for setting operator credentials */ export const SetOperatorInputSchema = z.object({ - operator: PrivateKeyWithAccountIdSchema.describe( + operator: KeySchema.describe( 'Operator credentials. Can be accountId:privateKey pair, key reference or account alias.', ), network: NetworkSchema.optional().describe( diff --git a/src/plugins/token/__tests__/unit/create-nft.test.ts b/src/plugins/token/__tests__/unit/create-nft.test.ts index 4bb63fe15..371610439 100644 --- a/src/plugins/token/__tests__/unit/create-nft.test.ts +++ b/src/plugins/token/__tests__/unit/create-nft.test.ts @@ -121,7 +121,7 @@ describe('createNftHandler', () => { saveToken: mockSaveToken, })); - const { api, tokenTransactions, txExecute } = makeApiMocks({ + const { api, tokenTransactions, keyResolver, txExecute } = makeApiMocks({ tokenTransactions: { createTokenTransaction: jest .fn() @@ -132,11 +132,17 @@ describe('createNftHandler', () => { }, }); + keyResolver.resolveSigningKey.mockResolvedValue({ + keyRefId: 'supply-key-ref-id', + publicKey: '302a300506032b6570032100' + '0'.repeat(64), + }); + const logger = makeLogger(); const args: CommandHandlerArgs = { args: { tokenName: 'TestToken', symbol: 'TEST', + supplyKey: 'test-supply-key', }, api, state: api.state, @@ -157,7 +163,7 @@ describe('createNftHandler', () => { maxSupplyRaw: undefined, treasuryId: '0.0.100000', tokenType: HederaTokenType.NON_FUNGIBLE_TOKEN, - adminPublicKey: expect.any(Object), + adminPublicKey: undefined, supplyPublicKey: expect.any(Object), memo: undefined, }); @@ -175,12 +181,16 @@ describe('createNftHandler', () => { keyResolver.resolveAccountCredentialsWithFallback.mockImplementation(() => Promise.reject(new Error('No operator set')), ); + keyResolver.resolveSigningKey.mockImplementation(() => + Promise.reject(new Error('No operator set')), + ); const logger = makeLogger(); const args: CommandHandlerArgs = { args: { tokenName: 'TestToken', symbol: 'TEST', + supplyKey: 'test-supply-key', }, api, state: api.state, diff --git a/src/plugins/token/__tests__/unit/create.test.ts b/src/plugins/token/__tests__/unit/create.test.ts index 4927e12df..2f9823e95 100644 --- a/src/plugins/token/__tests__/unit/create.test.ts +++ b/src/plugins/token/__tests__/unit/create.test.ts @@ -155,7 +155,7 @@ describe('createTokenHandler', () => { supplyType: SupplyType.INFINITE, maxSupplyRaw: undefined, treasuryId: '0.0.100000', - adminPublicKey: expect.any(Object), + adminPublicKey: undefined, tokenType: HederaTokenType.FUNGIBLE_COMMON, memo: undefined, }); diff --git a/src/plugins/token/__tests__/unit/createFromFile.test.ts b/src/plugins/token/__tests__/unit/createFromFile.test.ts index 69205dd6f..d7309e1f0 100644 --- a/src/plugins/token/__tests__/unit/createFromFile.test.ts +++ b/src/plugins/token/__tests__/unit/createFromFile.test.ts @@ -604,7 +604,7 @@ describe('createTokenFromFileHandler', () => { // Act & Assert await expect(createTokenFromFile(args)).rejects.toThrow( - 'Private key with account ID must be a valid account ID and private key pair in {account-id:private-key} format, key reference or alias name', + 'Key must be a valid account ID and private key pair in format {account-id:private-key}, account ID, private key in format {ed25519|ecdsa}:{private-key}, public key in format {ed25519|ecdsa}:{public-key}, key reference, EVM address (0x...) or alias name', ); }); diff --git a/src/plugins/token/__tests__/unit/createNftFromFile.test.ts b/src/plugins/token/__tests__/unit/createNftFromFile.test.ts index 38b7d7e9c..e8aec1917 100644 --- a/src/plugins/token/__tests__/unit/createNftFromFile.test.ts +++ b/src/plugins/token/__tests__/unit/createNftFromFile.test.ts @@ -610,7 +610,7 @@ describe('createNftFromFileHandler', () => { }); await expect(createNftFromFile(args)).rejects.toThrow( - 'Private key with account ID must be a valid account ID and private key pair in {account-id:private-key} format, key reference or alias name', + 'Key must be a valid account ID and private key pair in format {account-id:private-key}, account ID, private key in format {ed25519|ecdsa}:{private-key}, public key in format {ed25519|ecdsa}:{public-key}, key reference, EVM address (0x...) or alias name', ); }); @@ -654,7 +654,7 @@ describe('createNftFromFileHandler', () => { }); await expect(createNftFromFile(args)).rejects.toThrow( - 'Private key with account ID must be a valid account ID and private key pair in {account-id:private-key} format, key reference or alias name', + 'Key must be a valid account ID and private key pair in format {account-id:private-key}, account ID, private key in format {ed25519|ecdsa}:{private-key}, public key in format {ed25519|ecdsa}:{public-key}, key reference, EVM address (0x...) or alias name', ); }); diff --git a/src/plugins/token/commands/associate/input.ts b/src/plugins/token/commands/associate/input.ts index dd634bdb4..8de5ec16c 100644 --- a/src/plugins/token/commands/associate/input.ts +++ b/src/plugins/token/commands/associate/input.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; import { EntityReferenceSchema, KeyManagerTypeSchema, - PrivateKeyWithAccountIdSchema, + KeySchema, } from '@/core/schemas'; /** @@ -12,7 +12,7 @@ import { */ export const AssociateTokenInputSchema = z.object({ token: EntityReferenceSchema.describe('Token identifier (ID or name)'), - account: PrivateKeyWithAccountIdSchema.describe( + account: KeySchema.describe( 'Account to associate. Can be {accountId}:{privateKey pair}, key reference or account alias.', ), keyManager: KeyManagerTypeSchema.optional().describe( diff --git a/src/plugins/token/commands/create-ft/handler.ts b/src/plugins/token/commands/create-ft/handler.ts index f1a26166b..81da4f970 100644 --- a/src/plugins/token/commands/create-ft/handler.ts +++ b/src/plugins/token/commands/create-ft/handler.ts @@ -58,11 +58,14 @@ export class CreateFtCommand extends BaseTransactionCommand< keyManager, ['token:treasury'], ); - const admin = await api.keyResolver.resolveAccountCredentialsWithFallback( + + const admin = await resolveOptionalKey( validArgs.adminKey, keyManager, - ['token:admin'], + api.keyResolver, + 'token:admin', ); + const supply = await resolveOptionalKey( validArgs.supplyKey, keyManager, @@ -88,7 +91,7 @@ export class CreateFtCommand extends BaseTransactionCommand< logger.debug('=== TOKEN PARAMS DEBUG ==='); logger.debug(`Treasury ID: ${treasury.keyRefId}`); - logger.debug(`Admin Key (keyRefId): ${admin.keyRefId}`); + logger.debug(`Admin Key (keyRefId): ${admin?.keyRefId}`); logger.debug(`Use Custom Treasury: ${String(Boolean(treasury))}`); logger.debug('========================='); @@ -107,7 +110,6 @@ export class CreateFtCommand extends BaseTransactionCommand< admin, supply, finalMaxSupply, - adminKeyProvided: Boolean(validArgs.adminKey), }; } @@ -125,7 +127,9 @@ export class CreateFtCommand extends BaseTransactionCommand< tokenType: normalisedParams.tokenType, supplyType: normalisedParams.supplyType, maxSupplyRaw: normalisedParams.finalMaxSupply, - adminPublicKey: PublicKey.fromString(normalisedParams.admin.publicKey), + adminPublicKey: normalisedParams.admin + ? PublicKey.fromString(normalisedParams.admin.publicKey) + : undefined, supplyPublicKey: normalisedParams.supply ? PublicKey.fromString(normalisedParams.supply.publicKey) : undefined, @@ -142,7 +146,7 @@ export class CreateFtCommand extends BaseTransactionCommand< const { api } = args; const txSigners = [normalisedParams.treasury.keyRefId]; - if (normalisedParams.adminKeyProvided) { + if (normalisedParams.admin) { txSigners.push(normalisedParams.admin.keyRefId); } @@ -195,9 +199,9 @@ export class CreateFtCommand extends BaseTransactionCommand< initialSupply: normalisedParams.initialSupply, tokenType: normalisedParams.tokenType, supplyType: normalisedParams.supplyType, - adminPublicKey: normalisedParams.admin.publicKey, + adminPublicKey: normalisedParams.admin?.publicKey, supplyPublicKey: normalisedParams.supply?.publicKey, - network: normalisedParams.network, + network: api.network.getCurrentNetwork(), }); const key = composeKey(normalisedParams.network, result.tokenId!); diff --git a/src/plugins/token/commands/create-ft/input.ts b/src/plugins/token/commands/create-ft/input.ts index 96b785c86..27e87aa4c 100644 --- a/src/plugins/token/commands/create-ft/input.ts +++ b/src/plugins/token/commands/create-ft/input.ts @@ -6,8 +6,6 @@ import { KeyManagerTypeSchema, KeySchema, MemoSchema, - PrivateKeySchema, - PrivateKeyWithAccountIdSchema, SupplyTypeSchema, TokenAliasNameSchema, TokenNameSchema, @@ -24,7 +22,7 @@ export const CreateFungibleTokenInputSchema = z .object({ tokenName: TokenNameSchema.describe('Token name'), symbol: TokenSymbolSchema.describe('Token symbol/ticker'), - treasury: PrivateKeyWithAccountIdSchema.optional().describe( + treasury: KeySchema.optional().describe( 'Treasury account of token. Can be {accountId}:{privateKey} pair, key reference or account alias. Defaults to operator.', ), decimals: HtsDecimalsSchema.default(0).describe( @@ -42,7 +40,7 @@ export const CreateFungibleTokenInputSchema = z maxSupply: AmountInputSchema.optional().describe( 'Maximum supply (required for FINITE supply type)', ), - adminKey: PrivateKeySchema.optional().describe( + adminKey: KeySchema.optional().describe( 'Admin key of token. Can be {accountId}:{privateKey} pair, account private key in {ed25519|ecdsa}:private:{private-key} format, key reference or account alias. Defaults to operator key.', ), supplyKey: KeySchema.optional().describe( diff --git a/src/plugins/token/commands/create-ft/types.ts b/src/plugins/token/commands/create-ft/types.ts index e471ea699..28ab75926 100644 --- a/src/plugins/token/commands/create-ft/types.ts +++ b/src/plugins/token/commands/create-ft/types.ts @@ -20,10 +20,9 @@ export interface CreateFtNormalizedParams { network: SupportedNetwork; keyManager: KeyManagerName; treasury: ResolvedAccountCredential; - admin: ResolvedAccountCredential; + admin?: ResolvedPublicKey; supply?: ResolvedPublicKey; finalMaxSupply?: bigint; - adminKeyProvided: boolean; } export interface CreateFtBuildTransactionResult { diff --git a/src/plugins/token/commands/create-nft/handler.ts b/src/plugins/token/commands/create-nft/handler.ts index 20766f234..984465aff 100644 --- a/src/plugins/token/commands/create-nft/handler.ts +++ b/src/plugins/token/commands/create-nft/handler.ts @@ -22,6 +22,7 @@ import { buildTokenData, determineFiniteMaxSupply, } from '@/plugins/token/utils/token-data-builders'; +import { resolveOptionalKey } from '@/plugins/token/utils/token-resolve-optional-key'; import { ZustandTokenStateHelper } from '@/plugins/token/zustand-state-helper'; export class CreateNftCommand extends BaseTransactionCommand< @@ -51,12 +52,13 @@ export class CreateNftCommand extends BaseTransactionCommand< keyManager, ['token:treasury'], ); - const admin = await api.keyResolver.resolveAccountCredentialsWithFallback( + const admin = await resolveOptionalKey( validArgs.adminKey, keyManager, - ['token:admin'], + api.keyResolver, + 'token:admin', ); - const supply = await api.keyResolver.resolveAccountCredentialsWithFallback( + const supply = await api.keyResolver.resolveSigningKey( validArgs.supplyKey, keyManager, ['token:supply'], @@ -75,7 +77,7 @@ export class CreateNftCommand extends BaseTransactionCommand< logger.info(`Creating NFT: ${validArgs.tokenName} (${validArgs.symbol})`); logger.debug('=== NFT PARAMS DEBUG ==='); logger.debug(`Treasury ID: ${treasury.keyRefId}`); - logger.debug(`Admin Key (keyRefId): ${admin.keyRefId}`); + logger.debug(`Admin Key (keyRefId): ${admin?.keyRefId}`); logger.debug(`Supply Key (keyRefId): ${supply.keyRefId}`); logger.debug(`Use Custom Treasury: ${String(Boolean(treasury))}`); logger.debug('========================='); @@ -95,7 +97,6 @@ export class CreateNftCommand extends BaseTransactionCommand< admin, supply, finalMaxSupply, - adminKeyProvided: Boolean(validArgs.adminKey), }; } @@ -113,7 +114,9 @@ export class CreateNftCommand extends BaseTransactionCommand< tokenType: normalisedParams.tokenType, supplyType: normalisedParams.supplyType, maxSupplyRaw: normalisedParams.finalMaxSupply, - adminPublicKey: PublicKey.fromString(normalisedParams.admin.publicKey), + adminPublicKey: normalisedParams.admin + ? PublicKey.fromString(normalisedParams.admin.publicKey) + : undefined, supplyPublicKey: PublicKey.fromString(normalisedParams.supply.publicKey), memo: normalisedParams.memo, }); @@ -128,7 +131,7 @@ export class CreateNftCommand extends BaseTransactionCommand< const { api } = args; const txSigners = [normalisedParams.treasury.keyRefId]; - if (normalisedParams.adminKeyProvided) { + if (normalisedParams.admin) { txSigners.push(normalisedParams.admin.keyRefId); } @@ -177,7 +180,7 @@ export class CreateNftCommand extends BaseTransactionCommand< initialSupply: normalisedParams.initialSupply, tokenType: normalisedParams.tokenType, supplyType: normalisedParams.supplyType, - adminPublicKey: normalisedParams.admin.publicKey, + adminPublicKey: normalisedParams.admin?.publicKey, supplyPublicKey: normalisedParams.supply.publicKey, network: normalisedParams.network, }); @@ -204,9 +207,9 @@ export class CreateNftCommand extends BaseTransactionCommand< treasuryId: normalisedParams.treasury.accountId, supplyType: normalisedParams.supplyType, transactionId: result.transactionId, - adminAccountId: normalisedParams.admin.accountId, - adminPublicKey: normalisedParams.admin.publicKey, - supplyAccountId: normalisedParams.supply.accountId, + adminAccountId: undefined, + adminPublicKey: normalisedParams.admin?.publicKey, + supplyAccountId: undefined, supplyPublicKey: normalisedParams.supply.publicKey, alias: normalisedParams.alias, network: normalisedParams.network, diff --git a/src/plugins/token/commands/create-nft/input.ts b/src/plugins/token/commands/create-nft/input.ts index 9d61213ce..a156abab0 100644 --- a/src/plugins/token/commands/create-nft/input.ts +++ b/src/plugins/token/commands/create-nft/input.ts @@ -5,8 +5,6 @@ import { KeyManagerTypeSchema, KeySchema, MemoSchema, - PrivateKeySchema, - PrivateKeyWithAccountIdSchema, SupplyTypeSchema, TokenAliasNameSchema, TokenNameSchema, @@ -23,7 +21,7 @@ export const CreateNftInputSchema = z .object({ tokenName: TokenNameSchema.describe('Token name'), symbol: TokenSymbolSchema.describe('Token symbol/ticker'), - treasury: PrivateKeyWithAccountIdSchema.optional().describe( + treasury: KeySchema.optional().describe( 'Treasury account of token. Can be {accountId}:{privateKey} pair, key reference or account alias. Defaults to operator key.', ), supplyType: SupplyTypeSchema.default(SupplyType.INFINITE).describe( @@ -32,10 +30,10 @@ export const CreateNftInputSchema = z maxSupply: AmountInputSchema.optional().describe( 'Maximum supply (required for FINITE supply type)', ), - adminKey: PrivateKeySchema.optional().describe( + adminKey: KeySchema.optional().describe( 'Admin key of token. Can be {accountId}:{privateKey} pair, account private key in {ed25519|ecdsa}:private:{private-key} format, key reference or account alias. Defaults to operator key.', ), - supplyKey: KeySchema.optional().describe( + supplyKey: KeySchema.describe( 'Supply key of token. Can be {accountId}:{privateKey} pair, account ID, account public key in {ed25519|ecdsa}:public:{public-key} format, account private key in {ed25519|ecdsa}:private:{private-key} format, key reference or account alias. Defaults to operator key.', ), name: TokenAliasNameSchema.optional().describe( diff --git a/src/plugins/token/commands/create-nft/output.ts b/src/plugins/token/commands/create-nft/output.ts index ef93cc56a..f249ad304 100644 --- a/src/plugins/token/commands/create-nft/output.ts +++ b/src/plugins/token/commands/create-nft/output.ts @@ -28,7 +28,8 @@ export const CreateNftOutputSchema = z.object({ 'Hedera token create transaction ID', ), adminAccountId: EntityIdSchema.optional().describe('Admin account ID'), - adminPublicKey: PublicKeyDefinitionSchema.describe('Admin public key'), + adminPublicKey: + PublicKeyDefinitionSchema.optional().describe('Admin public key'), supplyAccountId: EntityIdSchema.optional().describe('Supply account ID'), supplyPublicKey: PublicKeyDefinitionSchema.describe('Supply public key'), alias: z.string().describe('Token alias').optional(), diff --git a/src/plugins/token/commands/create-nft/types.ts b/src/plugins/token/commands/create-nft/types.ts index 5a7b0d31e..ff436e342 100644 --- a/src/plugins/token/commands/create-nft/types.ts +++ b/src/plugins/token/commands/create-nft/types.ts @@ -1,6 +1,9 @@ import type { Transaction } from '@hashgraph/sdk'; import type { TransactionResult } from '@/core'; -import type { ResolvedAccountCredential } from '@/core/services/key-resolver/types'; +import type { + ResolvedAccountCredential, + ResolvedPublicKey, +} from '@/core/services/key-resolver/types'; import type { KeyManagerName } from '@/core/services/kms/kms-types.interface'; import type { HederaTokenType } from '@/core/shared/constants'; import type { SupplyType, SupportedNetwork } from '@/core/types/shared.types'; @@ -17,10 +20,9 @@ export interface CreateNftNormalizedParams { network: SupportedNetwork; keyManager: KeyManagerName; treasury: ResolvedAccountCredential; - admin: ResolvedAccountCredential; - supply: ResolvedAccountCredential; + admin?: ResolvedPublicKey; + supply: ResolvedPublicKey; finalMaxSupply?: bigint; - adminKeyProvided: boolean; } export interface CreateNftBuildTransactionResult { diff --git a/src/plugins/token/commands/mint-ft/input.ts b/src/plugins/token/commands/mint-ft/input.ts index edcce2dab..6e0d392a0 100644 --- a/src/plugins/token/commands/mint-ft/input.ts +++ b/src/plugins/token/commands/mint-ft/input.ts @@ -4,7 +4,7 @@ import { AmountInputSchema, EntityReferenceSchema, KeyManagerTypeSchema, - PrivateKeySchema, + KeySchema, } from '@/core/schemas'; /** @@ -16,7 +16,7 @@ export const MintFtInputSchema = z.object({ amount: AmountInputSchema.describe( 'Amount to mint (display units or base units with "t" suffix)', ), - supplyKey: PrivateKeySchema.describe( + supplyKey: KeySchema.describe( 'Supply key. Can be {accountId}:{privateKey} pair, account private key in {ed25519|ecdsa}:private:{private-key} format, key reference or account alias.', ), keyManager: KeyManagerTypeSchema.optional().describe( diff --git a/src/plugins/token/commands/mint-nft/input.ts b/src/plugins/token/commands/mint-nft/input.ts index b38bcf692..5227e1ffd 100644 --- a/src/plugins/token/commands/mint-nft/input.ts +++ b/src/plugins/token/commands/mint-nft/input.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; import { EntityReferenceSchema, KeyManagerTypeSchema, - PrivateKeySchema, + KeySchema, } from '@/core/schemas'; /** @@ -16,7 +16,7 @@ export const MintNftInputSchema = z.object({ .string() .min(1, 'Metadata cannot be empty') .describe('NFT metadata (string, max 100 bytes)'), - supplyKey: PrivateKeySchema.describe( + supplyKey: KeySchema.describe( 'Supply key. Can be {accountId}:{privateKey} pair, account private key in {ed25519|ecdsa}:private:{private-key} format, key reference or account alias.', ), keyManager: KeyManagerTypeSchema.optional().describe( diff --git a/src/plugins/token/commands/transfer-ft/input.ts b/src/plugins/token/commands/transfer-ft/input.ts index c91627771..ce197c298 100644 --- a/src/plugins/token/commands/transfer-ft/input.ts +++ b/src/plugins/token/commands/transfer-ft/input.ts @@ -5,7 +5,7 @@ import { AmountInputSchema, EntityReferenceSchema, KeyManagerTypeSchema, - PrivateKeyWithAccountIdSchema, + KeySchema, } from '@/core/schemas'; /** @@ -17,7 +17,7 @@ export const TransferFungibleTokenInputSchema = z.object({ to: AccountReferenceSchema.describe( 'Destination account (ID, EVM address, or name)', ), - from: PrivateKeyWithAccountIdSchema.optional().describe( + from: KeySchema.optional().describe( 'Account to transfer from. Can be {accountId}:{privateKey pair}, key reference or account alias. Defaults to operator.', ), amount: AmountInputSchema.describe( diff --git a/src/plugins/token/commands/transfer-nft/input.ts b/src/plugins/token/commands/transfer-nft/input.ts index 8eb774217..66e9adac1 100644 --- a/src/plugins/token/commands/transfer-nft/input.ts +++ b/src/plugins/token/commands/transfer-nft/input.ts @@ -4,8 +4,8 @@ import { AccountReferenceSchema, EntityReferenceSchema, KeyManagerTypeSchema, + KeySchema, NftSerialNumbersSchema, - PrivateKeyWithAccountIdSchema, } from '@/core/schemas'; export const TransferNftInputSchema = z.object({ @@ -13,7 +13,7 @@ export const TransferNftInputSchema = z.object({ to: AccountReferenceSchema.describe( 'Destination account (ID, EVM address, or name)', ), - from: PrivateKeyWithAccountIdSchema.optional().describe( + from: KeySchema.optional().describe( 'Source account. Can be {accountID}:{privateKey} pair, key reference or account alias. Defaults to operator.', ), serials: NftSerialNumbersSchema, diff --git a/src/plugins/token/schema.ts b/src/plugins/token/schema.ts index 7383fb721..70a0748e7 100644 --- a/src/plugins/token/schema.ts +++ b/src/plugins/token/schema.ts @@ -11,8 +11,6 @@ import { KeySchema, MemoSchema, NonNegativeNumberOrBigintSchema, - PrivateKeySchema, - PrivateKeyWithAccountIdSchema, TokenNameSchema, TokenSymbolSchema, TokenTypeSchema, @@ -184,15 +182,15 @@ export const FungibleTokenFileSchema = z supplyType: z.union([z.literal('finite'), z.literal('infinite')]), initialSupply: AmountInputSchema, maxSupply: AmountInputSchema.default('0'), - treasuryKey: PrivateKeyWithAccountIdSchema, - adminKey: PrivateKeySchema, + treasuryKey: KeySchema, + adminKey: KeySchema, supplyKey: KeySchema.optional(), wipeKey: KeySchema.optional(), kycKey: KeySchema.optional(), freezeKey: KeySchema.optional(), pauseKey: KeySchema.optional(), feeScheduleKey: KeySchema.optional(), - associations: z.array(PrivateKeyWithAccountIdSchema).default([]), + associations: z.array(KeySchema).default([]), customFees: z .array(TokenFileCustomFeeSchema) .max(10, 'Maximum 10 custom fees allowed per token') @@ -242,8 +240,8 @@ export const NonFungibleTokenFileSchema = z symbol: TokenSymbolSchema, supplyType: z.union([z.literal('finite'), z.literal('infinite')]), maxSupply: NonNegativeNumberOrBigintSchema.optional(), - treasuryKey: PrivateKeyWithAccountIdSchema, - adminKey: PrivateKeySchema, + treasuryKey: KeySchema, + adminKey: KeySchema, supplyKey: KeySchema, wipeKey: KeySchema.optional(), kycKey: KeySchema.optional(), diff --git a/src/plugins/token/utils/token-data-builders.ts b/src/plugins/token/utils/token-data-builders.ts index 8d5488ae5..07945d2a4 100644 --- a/src/plugins/token/utils/token-data-builders.ts +++ b/src/plugins/token/utils/token-data-builders.ts @@ -22,7 +22,7 @@ export function buildTokenData( initialSupply: bigint; tokenType: HederaTokenType; supplyType: string; - adminPublicKey: string; + adminPublicKey?: string; supplyPublicKey?: string; network: SupportedNetwork; }, diff --git a/src/plugins/topic/commands/create/input.ts b/src/plugins/topic/commands/create/input.ts index 4aa581133..db3e84b3c 100644 --- a/src/plugins/topic/commands/create/input.ts +++ b/src/plugins/topic/commands/create/input.ts @@ -4,7 +4,6 @@ import { KeyManagerTypeSchema, KeySchema, MemoSchema, - PrivateKeySchema, TopicNameSchema, } from '@/core/schemas'; @@ -14,7 +13,7 @@ import { */ export const CreateTopicInputSchema = z.object({ memo: MemoSchema.describe('Optional memo for the topic'), - adminKey: PrivateKeySchema.optional().describe( + adminKey: KeySchema.optional().describe( 'Admin key of topic. Can be {accountId}:{privateKey} pair, account private key in {ed25519|ecdsa}:private:{private-key} format, key reference or account alias', ), submitKey: KeySchema.optional().describe( diff --git a/src/plugins/topic/commands/submit-message/input.ts b/src/plugins/topic/commands/submit-message/input.ts index 656313a55..fc6d6c24c 100644 --- a/src/plugins/topic/commands/submit-message/input.ts +++ b/src/plugins/topic/commands/submit-message/input.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; import { EntityReferenceSchema, KeyManagerTypeSchema, - PrivateKeySchema, + KeySchema, } from '@/core/schemas'; /** @@ -17,7 +17,7 @@ export const SubmitMessageInputSchema = z.object({ .trim() .min(1, 'Message cannot be empty') .describe('Message to submit to the topic'), - signer: PrivateKeySchema.optional().describe( + signer: KeySchema.optional().describe( 'Key to sign the message with. Can be {accountId}:{privateKey} pair, account private key in {ed25519|ecdsa}:private:{private-key} format, key reference or account alias.', ), keyManager: KeyManagerTypeSchema.optional().describe(