Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
7 changes: 5 additions & 2 deletions src/core/services/token/token-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/types/token.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/core/utils/resolve-payer.ts
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -17,7 +17,7 @@ export async function resolvePayer(
): Promise<void> {
const keyManager =
coreApi.config.getOption<KeyManagerName>('default_key_manager') || 'local';
const parsedPayer = PrivateKeySchema.parse(payerString);
const parsedPayer = KeySchema.parse(payerString);
const resolvedPayer = await coreApi.keyResolver.resolveAccountCredentials(
parsedPayer,
keyManager,
Expand Down
8 changes: 1 addition & 7 deletions src/plugins/account/__tests__/unit/import.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,14 @@ 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({
alias: 'imported',
type: AliasType.Account,
network: 'testnet',
entityId: '0.0.9999',
publicKey: 'pub-key-test',
publicKey: expect.any(String),
keyRefId: 'kr_test123',
}),
);
Expand Down
45 changes: 19 additions & 26 deletions src/plugins/account/commands/import/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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<KeyManagerName>('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,
});
Expand All @@ -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(),
});
}
Expand All @@ -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(),
};

Expand Down
6 changes: 3 additions & 3 deletions src/plugins/account/commands/import/input.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { z } from 'zod';

import {
AccountIdWithPrivateKeySchema,
AccountNameSchema,
KeyManagerTypeSchema,
KeySchema,
} from '@/core/schemas';

/**
* Input schema for account import command
* 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(
Expand Down
8 changes: 2 additions & 6 deletions src/plugins/network/commands/set-operator/input.ts
Original file line number Diff line number Diff line change
@@ -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(
Expand Down
14 changes: 12 additions & 2 deletions src/plugins/token/__tests__/unit/create-nft.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('createNftHandler', () => {
saveToken: mockSaveToken,
}));

const { api, tokenTransactions, txExecute } = makeApiMocks({
const { api, tokenTransactions, keyResolver, txExecute } = makeApiMocks({
tokenTransactions: {
createTokenTransaction: jest
.fn()
Expand All @@ -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,
Expand All @@ -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,
});
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/token/__tests__/unit/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/token/__tests__/unit/createFromFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
);
});

Expand Down
4 changes: 2 additions & 2 deletions src/plugins/token/__tests__/unit/createNftFromFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
);
});

Expand Down Expand Up @@ -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',
);
});

Expand Down
4 changes: 2 additions & 2 deletions src/plugins/token/commands/associate/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { z } from 'zod';
import {
EntityReferenceSchema,
KeyManagerTypeSchema,
PrivateKeyWithAccountIdSchema,
KeySchema,
} from '@/core/schemas';

/**
Expand All @@ -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.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change description so that we can use any format of the key

),
keyManager: KeyManagerTypeSchema.optional().describe(
Expand Down
20 changes: 12 additions & 8 deletions src/plugins/token/commands/create-ft/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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('=========================');

Expand All @@ -107,7 +110,6 @@ export class CreateFtCommand extends BaseTransactionCommand<
admin,
supply,
finalMaxSupply,
adminKeyProvided: Boolean(validArgs.adminKey),
};
}

Expand All @@ -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,
Expand All @@ -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);
}

Expand Down Expand Up @@ -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!);
Expand Down
Loading
Loading