|
4 | 4 |
|
5 | 5 | from hiero_sdk_python.account.account_id import AccountId |
6 | 6 | from hiero_sdk_python.Duration import Duration |
| 7 | +from hiero_sdk_python.hbar import Hbar |
| 8 | +from hiero_sdk_python.query.token_info_query import TokenInfoQuery |
7 | 9 | from hiero_sdk_python.response_code import ResponseCode |
8 | 10 | from hiero_sdk_python.timestamp import Timestamp |
9 | 11 | from hiero_sdk_python.tokens.custom_fee import CustomFee |
|
19 | 21 | from hiero_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction |
20 | 22 | from hiero_sdk_python.tokens.token_create_transaction import TokenCreateTransaction |
21 | 23 | from hiero_sdk_python.tokens.token_delete_transaction import TokenDeleteTransaction |
| 24 | +from hiero_sdk_python.tokens.token_freeze_status import TokenFreezeStatus |
22 | 25 | from hiero_sdk_python.tokens.token_freeze_transaction import TokenFreezeTransaction |
23 | 26 | from hiero_sdk_python.tokens.token_id import TokenId |
| 27 | +from hiero_sdk_python.tokens.token_info import TokenInfo |
| 28 | +from hiero_sdk_python.tokens.token_kyc_status import TokenKycStatus |
24 | 29 | from hiero_sdk_python.tokens.token_mint_transaction import TokenMintTransaction |
| 30 | +from hiero_sdk_python.tokens.token_pause_status import TokenPauseStatus |
25 | 31 | from hiero_sdk_python.tokens.token_pause_transaction import TokenPauseTransaction |
26 | 32 | from hiero_sdk_python.tokens.token_type import TokenType |
27 | 33 | from hiero_sdk_python.transaction.transaction_receipt import TransactionReceipt |
|
34 | 40 | CreateTokenParams, |
35 | 41 | DeleteTokenParams, |
36 | 42 | FreezeTokenParams, |
| 43 | + GetTokenInfoParams, |
37 | 44 | MintTokenParams, |
38 | 45 | PauseTokenParams, |
39 | 46 | ) |
|
42 | 49 | AssociateTokenResponse, |
43 | 50 | ClaimTokenResponse, |
44 | 51 | CreateTokenResponse, |
| 52 | + CustomFeeResponse, |
45 | 53 | DeleteTokenResponse, |
46 | 54 | FreezeTokenResponse, |
| 55 | + GetTokenInfoResponse, |
47 | 56 | MintTokenResponse, |
48 | 57 | PauseTokenResponse, |
49 | 58 | ) |
@@ -478,3 +487,157 @@ def claim_token(params: ClaimTokenParams) -> ClaimTokenResponse: |
478 | 487 | receipt: TransactionReceipt = response.get_receipt(client, validate_status=True) |
479 | 488 |
|
480 | 489 | return ClaimTokenResponse(status=ResponseCode(receipt.status).name) |
| 490 | + |
| 491 | + |
| 492 | +def _serialize_key(key) -> str | None: |
| 493 | + """Serialize a key to its DER-encoded hex string representation.""" |
| 494 | + if key is None: |
| 495 | + return "" |
| 496 | + return key.to_string_der() |
| 497 | + |
| 498 | + |
| 499 | +def _serialize_custom_fee(fee: CustomFee) -> CustomFeeResponse: |
| 500 | + """Serialize a CustomFee to a CustomFeeResponse.""" |
| 501 | + response = CustomFeeResponse() |
| 502 | + |
| 503 | + if fee.fee_collector_account_id is not None: |
| 504 | + aid = fee.fee_collector_account_id |
| 505 | + response.feeCollectorAccountId = { |
| 506 | + "realm": str(aid.realm), |
| 507 | + "shard": str(aid.shard), |
| 508 | + "num": str(aid.num), |
| 509 | + } |
| 510 | + response.feeCollectorsExempt = fee.all_collectors_are_exempt |
| 511 | + |
| 512 | + if isinstance(fee, CustomFixedFee): |
| 513 | + fixed_fee_dict: dict = {"amount": str(fee.amount)} |
| 514 | + if fee.denominating_token_id is not None: |
| 515 | + fixed_fee_dict["denominatingTokenId"] = str(fee.denominating_token_id) |
| 516 | + response.fixedFee = fixed_fee_dict |
| 517 | + elif isinstance(fee, CustomFractionalFee): |
| 518 | + response.fractionalFee = { |
| 519 | + "numerator": str(fee.numerator), |
| 520 | + "denominator": str(fee.denominator), |
| 521 | + "minimumAmount": str(fee.min_amount), |
| 522 | + "maximumAmount": str(fee.max_amount), |
| 523 | + "assessmentMethod": "inclusive" if fee.assessment_method == FeeAssessmentMethod.INCLUSIVE else "exclusive", |
| 524 | + } |
| 525 | + elif isinstance(fee, CustomRoyaltyFee): |
| 526 | + royalty_fee_dict: dict = { |
| 527 | + "numerator": str(fee.numerator), |
| 528 | + "denominator": str(fee.denominator), |
| 529 | + } |
| 530 | + if fee.fallback_fee is not None: |
| 531 | + fallback: dict = {"amount": str(fee.fallback_fee.amount)} |
| 532 | + if fee.fallback_fee.denominating_token_id is not None: |
| 533 | + fallback["denominatingTokenId"] = str(fee.fallback_fee.denominating_token_id) |
| 534 | + royalty_fee_dict["fallbackFee"] = fallback |
| 535 | + response.royaltyFee = royalty_fee_dict |
| 536 | + |
| 537 | + return response |
| 538 | + |
| 539 | + |
| 540 | +def _map_pause_status(pause_status: TokenPauseStatus) -> bool | None: |
| 541 | + """Map TokenPauseStatus enum to TCK boolean representation.""" |
| 542 | + if pause_status == TokenPauseStatus.PAUSED: |
| 543 | + return True |
| 544 | + if pause_status == TokenPauseStatus.UNPAUSED: |
| 545 | + return False |
| 546 | + return None |
| 547 | + |
| 548 | + |
| 549 | +def _map_token_type(token_type: TokenType | None) -> str | None: |
| 550 | + """Map TokenType enum to TCK string representation.""" |
| 551 | + if token_type is None: |
| 552 | + return None |
| 553 | + mapping = { |
| 554 | + TokenType.FUNGIBLE_COMMON: "FUNGIBLE_COMMON", |
| 555 | + TokenType.NON_FUNGIBLE_UNIQUE: "NON_FUNGIBLE_UNIQUE", |
| 556 | + } |
| 557 | + return mapping.get(token_type) |
| 558 | + |
| 559 | + |
| 560 | +def _map_supply_type(supply_type: SupplyType | None) -> str | None: |
| 561 | + """Map SupplyType enum to TCK string representation.""" |
| 562 | + if supply_type is None: |
| 563 | + return None |
| 564 | + mapping = { |
| 565 | + SupplyType.INFINITE: "INFINITE", |
| 566 | + SupplyType.FINITE: "FINITE", |
| 567 | + } |
| 568 | + return mapping.get(supply_type) |
| 569 | + |
| 570 | + |
| 571 | +def _map_freeze_status(freeze_status: TokenFreezeStatus) -> bool | None: |
| 572 | + """Map TokenFreezeStatus enum to TCK boolean representation.""" |
| 573 | + if freeze_status == TokenFreezeStatus.FROZEN: |
| 574 | + return True |
| 575 | + if freeze_status == TokenFreezeStatus.UNFROZEN: |
| 576 | + return False |
| 577 | + return None |
| 578 | + |
| 579 | + |
| 580 | +def _map_kyc_status(kyc_status: TokenKycStatus) -> bool | None: |
| 581 | + """Map TokenKycStatus enum to TCK boolean representation.""" |
| 582 | + if kyc_status == TokenKycStatus.GRANTED: |
| 583 | + return True |
| 584 | + if kyc_status == TokenKycStatus.REVOKED: |
| 585 | + return False |
| 586 | + return None |
| 587 | + |
| 588 | + |
| 589 | +def _build_token_info_response(info: TokenInfo) -> GetTokenInfoResponse: |
| 590 | + """Build a GetTokenInfoResponse from a TokenInfo object.""" |
| 591 | + # Serialize custom fees |
| 592 | + custom_fees = [_serialize_custom_fee(fee) for fee in info.custom_fees] if info.custom_fees else [] |
| 593 | + |
| 594 | + return GetTokenInfoResponse( |
| 595 | + tokenId=str(info.token_id) if info.token_id else None, |
| 596 | + name=info.name or "", |
| 597 | + symbol=info.symbol or "", |
| 598 | + decimals=info.decimals, |
| 599 | + totalSupply=str(info.total_supply) if info.total_supply is not None else "0", |
| 600 | + treasuryAccountId=str(info.treasury) if info.treasury else None, |
| 601 | + adminKey=_serialize_key(info.admin_key), |
| 602 | + kycKey=_serialize_key(info.kyc_key), |
| 603 | + freezeKey=_serialize_key(info.freeze_key), |
| 604 | + pauseKey=_serialize_key(info.pause_key), |
| 605 | + wipeKey=_serialize_key(info.wipe_key), |
| 606 | + supplyKey=_serialize_key(info.supply_key), |
| 607 | + feeScheduleKey=_serialize_key(info.fee_schedule_key), |
| 608 | + metadataKey=_serialize_key(info.metadata_key), |
| 609 | + defaultFreezeStatus=_map_freeze_status(info.default_freeze_status), |
| 610 | + defaultKycStatus=_map_kyc_status(info.default_kyc_status), |
| 611 | + pauseStatus=_map_pause_status(info.pause_status), |
| 612 | + isDeleted=info.is_deleted, |
| 613 | + autoRenewAccountId=str(info.auto_renew_account) if info.auto_renew_account else None, |
| 614 | + autoRenewPeriod=str(info.auto_renew_period.seconds) if info.auto_renew_period else None, |
| 615 | + expirationTime=str(info.expiry.seconds) if info.expiry else None, |
| 616 | + tokenMemo=info.memo if info.memo is not None else "", |
| 617 | + customFees=custom_fees, |
| 618 | + tokenType=_map_token_type(info.token_type), |
| 619 | + supplyType=_map_supply_type(info.supply_type), |
| 620 | + maxSupply=str(info.max_supply) if info.max_supply is not None else "0", |
| 621 | + metadata=info.metadata.hex() if info.metadata else "", |
| 622 | + ledgerId=info.ledger_id.hex() if info.ledger_id else "", |
| 623 | + ) |
| 624 | + |
| 625 | + |
| 626 | +@rpc_method("getTokenInfo") |
| 627 | +def get_token_info(params: GetTokenInfoParams) -> GetTokenInfoResponse: |
| 628 | + """Query token info using TCK getTokenInfo parameters.""" |
| 629 | + client = get_client(params.sessionId) |
| 630 | + |
| 631 | + query = TokenInfoQuery().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT) |
| 632 | + |
| 633 | + if params.tokenId is not None: |
| 634 | + query.set_token_id(TokenId.from_string(params.tokenId)) |
| 635 | + |
| 636 | + if params.queryPayment is not None: |
| 637 | + query.set_query_payment(Hbar.from_tinybars(int(params.queryPayment))) |
| 638 | + |
| 639 | + if params.maxQueryPayment is not None: |
| 640 | + query.set_max_query_payment(Hbar.from_tinybars(int(params.maxQueryPayment))) |
| 641 | + |
| 642 | + info = query.execute(client) |
| 643 | + return _build_token_info_response(info) |
0 commit comments