Skip to content

Commit bcd946c

Browse files
authored
feat(1651): Token delete command extend (#1723)
Signed-off-by: matevszm <mateusz.marcinkowski@blockydevs.com>
1 parent be17c4f commit bcd946c

File tree

21 files changed

+1084
-155
lines changed

21 files changed

+1084
-155
lines changed

docs/output-schemas-guide.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,37 @@ Lists all tokens from all networks stored in state.
552552
}
553553
```
554554

555+
#### `token delete`
556+
557+
**Output** (network delete):
558+
559+
```json
560+
{
561+
"transactionId": "0.0.123@1700000000.123456789",
562+
"deletedToken": {
563+
"name": "MyToken",
564+
"tokenId": "0.0.67890"
565+
},
566+
"network": "testnet",
567+
"removedAliases": ["my-token (testnet)"]
568+
}
569+
```
570+
571+
**Output** (`--state-only`):
572+
573+
```json
574+
{
575+
"deletedToken": {
576+
"name": "MyToken",
577+
"tokenId": "0.0.67890"
578+
},
579+
"network": "testnet",
580+
"removedAliases": ["my-token (testnet)"]
581+
}
582+
```
583+
584+
`transactionId` is absent for `--state-only`. `removedAliases` is omitted when no aliases exist.
585+
555586
#### `token allowance-nft`
556587

557588
**Output** (specific serials):

src/__tests__/integration/token/import-token.integration.test.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describe('Import Token Integration Tests', () => {
3737
initialSupply: '10',
3838
supplyType: SupplyType.INFINITE,
3939
name: `token-import-${Date.now()}`,
40+
adminKey: `${process.env.OPERATOR_ID}:${process.env.OPERATOR_KEY}`,
4041
};
4142
const createTokenResult = await tokenCreateFt({
4243
args: createTokenArgs,
@@ -57,11 +58,18 @@ describe('Import Token Integration Tests', () => {
5758
});
5859

5960
afterEach(async () => {
60-
const deleteTokenArgs: Record<string, unknown> = {
61-
token: tokenId,
62-
};
6361
await tokenDelete({
64-
args: deleteTokenArgs,
62+
args: { token: tokenId, stateOnly: true },
63+
api: coreApi,
64+
state: coreApi.state,
65+
logger: coreApi.logger,
66+
config: coreApi.config,
67+
});
68+
});
69+
70+
afterAll(async () => {
71+
await tokenDelete({
72+
args: { token: tokenId },
6573
api: coreApi,
6674
state: coreApi.state,
6775
logger: coreApi.logger,

src/core/services/token/__tests__/unit/mocks.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ export const createMockTokenAssociateTransaction = () => ({
3737
setTokenIds: jest.fn().mockReturnThis(),
3838
});
3939

40+
export const createMockTokenDeleteTransaction = () => ({
41+
setTokenId: jest.fn().mockReturnThis(),
42+
});
43+
4044
export const createMockCustomFixedFee = () => ({
4145
setHbarAmount: jest.fn().mockReturnThis(),
4246
setAmount: jest.fn().mockReturnThis(),

src/core/services/token/__tests__/unit/token-service.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
createMockCustomFractionalFee,
2727
createMockTokenAssociateTransaction,
2828
createMockTokenCreateTransaction,
29+
createMockTokenDeleteTransaction,
2930
createMockTransferTransaction,
3031
} from './mocks';
3132

@@ -49,6 +50,7 @@ const TRANSFER_AMOUNT = 100n;
4950
const mockTransferTransaction = createMockTransferTransaction();
5051
const mockTokenCreateTransaction = createMockTokenCreateTransaction();
5152
const mockTokenAssociateTransaction = createMockTokenAssociateTransaction();
53+
const mockTokenDeleteTransaction = createMockTokenDeleteTransaction();
5254
const mockCustomFixedFee = createMockCustomFixedFee();
5355
const mockCustomFractionalFee = createMockCustomFractionalFee();
5456

@@ -68,6 +70,7 @@ jest.mock('@hashgraph/sdk', () => ({
6870
TransferTransaction: jest.fn(() => mockTransferTransaction),
6971
TokenCreateTransaction: jest.fn(() => mockTokenCreateTransaction),
7072
TokenAssociateTransaction: jest.fn(() => mockTokenAssociateTransaction),
73+
TokenDeleteTransaction: jest.fn(() => mockTokenDeleteTransaction),
7174
CustomFixedFee: jest.fn(() => mockCustomFixedFee),
7275
CustomFractionalFee: jest.fn(() => mockCustomFractionalFee),
7376
FeeAssessmentMethod: {
@@ -741,4 +744,26 @@ describe('TokenServiceImpl', () => {
741744
expect(AccountId.fromString).toHaveBeenCalledWith('0.0.8888');
742745
});
743746
});
747+
748+
describe('createDeleteTransaction', () => {
749+
it('should create delete transaction with correct tokenId', () => {
750+
const params = { tokenId: TOKEN_ID };
751+
752+
const result = tokenService.createDeleteTransaction(params);
753+
754+
expect(TokenId.fromString).toHaveBeenCalledWith(TOKEN_ID);
755+
expect(mockTokenDeleteTransaction.setTokenId).toHaveBeenCalledWith(
756+
mockTokenIdInstance,
757+
);
758+
expect(result).toBe(mockTokenDeleteTransaction);
759+
});
760+
761+
it('should log debug messages during delete transaction creation', () => {
762+
tokenService.createDeleteTransaction({ tokenId: TOKEN_ID });
763+
764+
expect(logger.debug).toHaveBeenCalledWith(
765+
`[TOKEN SERVICE] Creating delete transaction for token ${TOKEN_ID}`,
766+
);
767+
});
768+
});
744769
});

src/core/services/token/token-service.interface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
AccountAllowanceApproveTransaction,
77
TokenAssociateTransaction,
88
TokenCreateTransaction,
9+
TokenDeleteTransaction,
910
TokenMintTransaction,
1011
TransferTransaction,
1112
} from '@hashgraph/sdk';
@@ -15,6 +16,7 @@ import type {
1516
TokenAllowanceFtParams,
1617
TokenAssociationParams,
1718
TokenCreateParams,
19+
TokenDeleteParams,
1820
TokenMintParams,
1921
TokenTransferParams,
2022
} from '@/core/types/token.types';
@@ -59,4 +61,6 @@ export interface TokenService {
5961
createFungibleTokenAllowanceTransaction(
6062
params: TokenAllowanceFtParams,
6163
): AccountAllowanceApproveTransaction;
64+
65+
createDeleteTransaction(params: TokenDeleteParams): TokenDeleteTransaction;
6266
}

src/core/services/token/token-service.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {
1111
TokenAllowanceFtParams,
1212
TokenAssociationParams,
1313
TokenCreateParams,
14+
TokenDeleteParams,
1415
TokenMintParams,
1516
TokenTransferParams,
1617
} from '@/core/types/token.types';
@@ -26,6 +27,7 @@ import {
2627
NftId,
2728
TokenAssociateTransaction,
2829
TokenCreateTransaction,
30+
TokenDeleteTransaction,
2931
TokenId,
3032
TokenMintTransaction,
3133
TokenSupplyType,
@@ -342,6 +344,15 @@ export class TokenServiceImpl implements TokenService {
342344
return tx;
343345
}
344346

347+
createDeleteTransaction(params: TokenDeleteParams): TokenDeleteTransaction {
348+
this.logger.debug(
349+
`[TOKEN SERVICE] Creating delete transaction for token ${params.tokenId}`,
350+
);
351+
return new TokenDeleteTransaction().setTokenId(
352+
TokenId.fromString(params.tokenId),
353+
);
354+
}
355+
345356
/**
346357
* Process custom fees and convert them to Hedera CustomFee objects
347358
*/

src/core/types/token.types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ export interface NftTransferParams {
107107
serialNumbers: number[];
108108
}
109109

110+
export interface TokenDeleteParams {
111+
tokenId: string;
112+
}
113+
110114
/**
111115
* Parameters for approving NFT allowance for specific serial numbers
112116
*/

src/plugins/batch/manifest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export const batchPluginManifest: PluginManifest = {
104104
'token-create-nft-batch-state',
105105
'token-create-nft-from-file-batch-state',
106106
'token-associate-batch-state',
107+
'token-delete-batch-state',
107108
],
108109
options: [
109110
{

src/plugins/token/README.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ src/plugins/token/
6767
│ │ ├── types.ts # Internal types
6868
│ │ └── index.ts # Command exports
6969
│ ├── delete/
70-
│ │ ├── handler.ts # Token delete handler (local state only)
70+
│ │ ├── handler.ts # Token delete handler (network or local state)
7171
│ │ ├── input.ts # Input schema
7272
│ │ ├── output.ts # Output schema and template
7373
│ │ └── index.ts # Command exports
@@ -520,21 +520,30 @@ hcli token allowance-ft \
520520

521521
### Token Delete
522522

523-
Delete a token from local state. This only removes the token from the local address book, not from the Hedera network.
523+
Delete a token from the Hedera network and remove it from local state. The token must have an admin key to be deleted from the network.
524524

525525
```bash
526-
# Delete by token alias
526+
# Delete by token alias (network delete)
527527
hcli token delete --token mytoken-alias
528528

529-
# Delete by token ID
529+
# Delete by token ID (network delete)
530530
hcli token delete --token 0.0.123456
531+
532+
# Provide admin key explicitly
533+
hcli token delete --token 0.0.123456 --admin-key <key-ref>
534+
535+
# Remove from local state only (no network transaction)
536+
hcli token delete --token mytoken-alias --state-only
531537
```
532538

533539
**Parameters:**
534540

535541
- `--token` / `-T`: Token identifier: either a token alias or token-id - **Required**
542+
- `--admin-key`: Admin key reference for signing (auto-resolved from key manager if omitted) - **Optional**
543+
- `--key-manager`: Key manager type, defaults to config setting - **Optional**
544+
- `--state-only`: Remove token from local state only, without a network transaction - **Optional**
536545

537-
Any aliases associated with the token on the current network will also be removed.
546+
`--state-only` and `--admin-key` are mutually exclusive. Any aliases associated with the token on the current network will also be removed.
538547

539548
### Token List
540549

0 commit comments

Comments
 (0)