Skip to content

Commit 4b48870

Browse files
committed
feat: Add transferCrypto method to TCK
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
1 parent 9571a78 commit 4b48870

4 files changed

Lines changed: 180 additions & 0 deletions

File tree

tck/handlers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
key,
99
sdk, # setup, reset
1010
topic,
11+
transfer,
1112
)
1213
from .registry import (
1314
get_all_handlers,

tck/handlers/transfer.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
from __future__ import annotations
2+
3+
from hiero_sdk_python import (
4+
AccountId,
5+
Hbar,
6+
NftId,
7+
TokenId,
8+
TransferTransaction,
9+
)
10+
from hiero_sdk_python.response_code import ResponseCode
11+
from tck.handlers.registry import rpc_method
12+
from tck.param.transfer import TransferCryptoParams
13+
from tck.response.transfer import TransferCryptoResponse
14+
from tck.util.client_utils import get_client
15+
16+
17+
def _build_transfer_transaction(params: TransferCryptoParams) -> TransferTransaction:
18+
tx = TransferTransaction()
19+
20+
tx.set_grpc_deadline(params.grpcDeadline)
21+
22+
if not params.transfers:
23+
return tx
24+
25+
for entry in params.transfers:
26+
## HBAR Transfer
27+
if entry.hbar is not None:
28+
hbar = entry.hbar
29+
account = AccountId.from_string(hbar.evmAddress if hbar.evmAddress else hbar.accountId)
30+
amount = Hbar.from_string(int(hbar.amount))
31+
32+
if entry.approved:
33+
tx.add_approved_hbar_transfer(account, amount)
34+
else:
35+
tx.add_hbar_transfer(account, amount)
36+
37+
## Token Transfer
38+
elif entry.token is not None:
39+
token = entry.tokem
40+
41+
token_id = TokenId.from_string(token.tokenId)
42+
account = AccountId.from_string(token.accountId)
43+
44+
if token.decimals is not None:
45+
decimals = int(token.decimals)
46+
47+
if entry.approved:
48+
tx.add_approved_token_transfer_with_decimals(token_id, account, int(token.amount), decimals)
49+
else:
50+
tx.add_token_transfer_with_decimals(token_id, account, int(token.amount), decimals)
51+
else:
52+
if entry.approved:
53+
tx.add_approved_token_transfer(token_id, account, int(token.amount))
54+
else:
55+
tx.add_token_transfer(token_id, account, int(token.amount))
56+
57+
## NFT Transfer
58+
elif entry.nft is not None:
59+
nft = entry.nft
60+
61+
nft_id = NftId(TokenId.from_string(nft.tokenId), int(nft.serialNumber))
62+
63+
sender = AccountId.from_string(nft.senderAccountId)
64+
receiver = AccountId.from_string(nft.receiverAccountId)
65+
66+
if entry.approved:
67+
tx.add_approved_nft_transfer(nft_id, sender, receiver)
68+
else:
69+
tx.add_nft_transfer(nft_id, sender, receiver)
70+
71+
return tx
72+
73+
74+
@rpc_method("transferCrypto")
75+
def transfer_crypto(params: TransferCryptoParams) -> TransferCryptoResponse:
76+
client = get_client(params.sessionId)
77+
78+
tx = _build_transfer_transaction(params)
79+
80+
if hasattr(params, "commonTransactionParams") and params.commonTransactionParams:
81+
tx.apply_common_params(params.commonTransactionParams)
82+
83+
receipt = tx.execute(client, wait_for_receipt=False).get_receipt(
84+
client,
85+
validate_status=True,
86+
)
87+
88+
return TransferCryptoResponse(status=ResponseCode(receipt.status).name)

tck/param/transfer.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from __future__ import annotations
2+
3+
from dataclasses import dataclass
4+
5+
from tck.param.base import BaseTransactionParams
6+
from tck.util.param_utils import parse_session_id, to_bool
7+
8+
9+
@dataclass
10+
class HbarTransferParams:
11+
accountId: str | None = None
12+
evmAddress: str | None = None
13+
amount: str | None = None
14+
15+
@classmethod
16+
def parse_json_params(cls, params: dict[str, object]) -> HbarTransferParams:
17+
return cls(accountId=params.get("accountId"), evmAddress=params.get("evmAddress"), amount=params.get("amount"))
18+
19+
20+
@dataclass
21+
class TokenTransferParams:
22+
tokenId: str | None = None
23+
accountId: str | None = None
24+
amount: str | None = None
25+
decimals: str | None = None
26+
27+
@classmethod
28+
def parse_json_params(cls, params: dict[str, object]) -> TokenTransferParams:
29+
return cls(
30+
tokenId=params.get("tokenId"),
31+
accountId=params.get("accountId"),
32+
amount=params.get("amount"),
33+
decimals=params.get("decimals"),
34+
)
35+
36+
37+
@dataclass
38+
class NftTransferParams:
39+
tokenId: str | None = None
40+
serialNumber: str | None = None
41+
senderAccountId: str | None = None
42+
receiverAccountId: str | None = None
43+
44+
@classmethod
45+
def parse_json_params(cls, params: dict[str, object]) -> NftTransferParams:
46+
return cls(
47+
tokenId=params.get("tokenId"),
48+
serialNumber=params.get("serialNumber"),
49+
senderAccountId=params.get("senderAccountId"),
50+
receiverAccountId=params.get("receiverAccountId"),
51+
)
52+
53+
54+
@dataclass
55+
class TransferParams:
56+
hbar: HbarTransferParams | None = None
57+
token: TokenTransferParams | None = None
58+
nft: NftTransferParams | None = None
59+
approved: bool | None = None
60+
61+
@classmethod
62+
def parse_json_params(cls, params: dict[str, object]) -> TransferParams:
63+
return cls(
64+
hbar=HbarTransferParams.parse_json_params(params["hbar"]) if params.get("hbar") is not None else None,
65+
token=TokenTransferParams.parse_json_params(params["token"]) if params.get("token") is not None else None,
66+
nft=NftTransferParams.parse_json_params(params["nft"]) if params.get("nft") is not None else None,
67+
approved=to_bool(params.get("approved")) if "approved" in params else None,
68+
)
69+
70+
71+
@dataclass
72+
class TransferCryptoParams(BaseTransactionParams):
73+
transfers: list[TransferParams] | None = None
74+
75+
@classmethod
76+
def parse_json_params(cls, params: dict) -> TransferCryptoParams:
77+
transfers_raw = params.get("transfers")
78+
79+
return cls(
80+
sessionId=parse_session_id(params),
81+
commonTransactionParams=params.get("commonTransactionParams"),
82+
transfers=[TransferParams.parse_json_params(t) for t in transfers_raw] if transfers_raw else None,
83+
)

tck/response/transfer.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from __future__ import annotations
2+
3+
from dataclasses import dataclass
4+
5+
6+
@dataclass
7+
class TransferCryptoResponse:
8+
status: str | None = None

0 commit comments

Comments
 (0)