Skip to content

Commit f2dd8df

Browse files
committed
chore: claim e2e integration test
Signed-off-by: exploreriii <[email protected]>
1 parent 83d6c03 commit f2dd8df

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import pytest
2+
from hiero_sdk_python.response_code import ResponseCode
3+
from hiero_sdk_python.crypto.private_key import PrivateKey
4+
from hiero_sdk_python.account.account_update_transaction import AccountUpdateTransaction
5+
from hiero_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction
6+
from hiero_sdk_python.tokens.token_airdrop_transaction import TokenAirdropTransaction
7+
from hiero_sdk_python.tokens.token_transfer import TokenTransfer
8+
from hiero_sdk_python.tokens.token_airdrop_pending_id import PendingAirdropId
9+
from hiero_sdk_python.tokens.token_airdrop_claim import TokenClaimAirdropTransaction
10+
from hiero_sdk_python.account.account_id import AccountId
11+
from hiero_sdk_python.tokens.token_id import TokenId
12+
from hiero_sdk_python.query.transaction_record_query import TransactionRecordQuery
13+
from tests.integration.utils_for_test import env, create_fungible_token, create_nft_token
14+
15+
pytestmark = pytest.mark.integration
16+
17+
# ======================
18+
# --- Inline Helpers ---
19+
# ======================
20+
21+
def set_receiver_signature_required(env, account_id: AccountId, account_key: PrivateKey, required: bool):
22+
receipt = (
23+
AccountUpdateTransaction()
24+
.set_account_id(account_id)
25+
.set_receiver_signature_required(required)
26+
.freeze_with(env.client)
27+
.sign(account_key)
28+
.execute(env.client)
29+
)
30+
assert receipt.status == ResponseCode.SUCCESS, f"Account update failed: {receipt.status}"
31+
32+
def associate_token(env, account_id: AccountId, account_key: PrivateKey, token_id: TokenId):
33+
receipt = (
34+
TokenAssociateTransaction()
35+
.set_account_id(account_id)
36+
.add_token_id(token_id)
37+
.freeze_with(env.client)
38+
.sign(account_key)
39+
.execute(env.client)
40+
)
41+
assert receipt.status == ResponseCode.SUCCESS, f"Association failed: {receipt.status}"
42+
43+
def submit_airdrop(env, receiver_id: AccountId, token_id: TokenId, amount=1):
44+
tx = TokenAirdropTransaction(
45+
token_transfers=[
46+
TokenTransfer(token_id, env.operator_id, -amount),
47+
TokenTransfer(token_id, receiver_id, amount),
48+
]
49+
).freeze_with(env.client).sign(env.operator_key).execute(env.client)
50+
assert tx.status == ResponseCode.SUCCESS, f"Airdrop failed: {tx.status}"
51+
52+
record = TransactionRecordQuery(tx.transaction_id).execute(env.client)
53+
assert record is not None
54+
return record
55+
56+
def has_immediate_credit(record, token_id: TokenId, account_id: AccountId, amount=1):
57+
token_map = record.token_transfers.get(token_id, {})
58+
return token_map.get(account_id, 0) == amount
59+
60+
def has_new_pending(record):
61+
return bool(record.new_pending_airdrops)
62+
63+
def extract_pending_ids(record):
64+
ids = []
65+
for item in record.new_pending_airdrops:
66+
# If it's already a PendingAirdropId object, just append
67+
if isinstance(item, PendingAirdropId):
68+
ids.append(item)
69+
else:
70+
# Attempt to extract the protobuf field
71+
pid_proto = getattr(item, "pending_airdrop_id", None)
72+
if pid_proto is None and hasattr(item, "_to_proto"):
73+
pid_proto = item._to_proto().pending_airdrop_id
74+
75+
if pid_proto is None:
76+
raise AssertionError(f"Cannot extract pending_airdrop_id from {type(item)}")
77+
78+
ids.append(PendingAirdropId._from_proto(pid_proto))
79+
return ids
80+
81+
def claim_pending(env, pending_ids, receiver_key):
82+
tx = TokenClaimAirdropTransaction().add_pending_airdrop_ids(pending_ids)
83+
tx.freeze_with(env.client).sign(receiver_key)
84+
return tx.execute(env.client)
85+
86+
# ======================
87+
# --- Integration Tests ---
88+
# ======================
89+
90+
def test_immediate_airdrop_if_associated_and_no_sig_required(env):
91+
receiver = env.create_account(initial_hbar=2.0)
92+
token_id = create_fungible_token(env)
93+
94+
set_receiver_signature_required(env, receiver.id, receiver.key, False)
95+
associate_token(env, receiver.id, receiver.key, token_id)
96+
97+
record = submit_airdrop(env, receiver.id, token_id)
98+
assert not has_new_pending(record)
99+
assert has_immediate_credit(record, token_id, receiver.id)
100+
101+
def test_pending_airdrop_if_unassociated_and_no_sig_required(env):
102+
receiver = env.create_account(initial_hbar=2.0)
103+
token_id = create_fungible_token(env)
104+
105+
set_receiver_signature_required(env, receiver.id, receiver.key, False)
106+
record = submit_airdrop(env, receiver.id, token_id)
107+
assert has_new_pending(record)
108+
assert not has_immediate_credit(record, token_id, receiver.id)
109+
110+
def test_pending_airdrop_if_sig_required_even_if_associated(env):
111+
receiver = env.create_account(initial_hbar=2.0)
112+
token_id = create_fungible_token(env)
113+
114+
set_receiver_signature_required(env, receiver.id, receiver.key, True)
115+
associate_token(env, receiver.id, receiver.key, token_id)
116+
record = submit_airdrop(env, receiver.id, token_id)
117+
assert has_new_pending(record)
118+
assert not has_immediate_credit(record, token_id, receiver.id)
119+
120+
def test_claim_fungible_pending(env):
121+
receiver = env.create_account(initial_hbar=2.0)
122+
token_id = create_fungible_token(env)
123+
124+
record = submit_airdrop(env, receiver.id, token_id)
125+
ids = extract_pending_ids(record)
126+
receipt = claim_pending(env, ids, receiver.key)
127+
assert ResponseCode(receipt.status) == ResponseCode.SUCCESS
128+
129+
claim_record = TransactionRecordQuery(receipt.transaction_id).execute(env.client)
130+
assert has_immediate_credit(claim_record, token_id, receiver.id)
131+
132+
def test_claim_multiple_pendings(env):
133+
receiver = env.create_account(initial_hbar=2.0)
134+
token_id = create_fungible_token(env)
135+
136+
rec1 = submit_airdrop(env, receiver.id, token_id)
137+
rec2 = submit_airdrop(env, receiver.id, token_id)
138+
139+
ids = extract_pending_ids(rec1) + extract_pending_ids(rec2)
140+
seen = set()
141+
unique_ids = []
142+
for pid in ids:
143+
key = (pid.token_id, pid.nft_id)
144+
if key not in seen:
145+
seen.add(key)
146+
unique_ids.append(pid)
147+
148+
receipt = claim_pending(env, unique_ids, receiver.key)
149+
assert ResponseCode(receipt.status) == ResponseCode.SUCCESS
150+
151+
152+
def test_claim_fails_without_signature(env):
153+
receiver = env.create_account(initial_hbar=2.0)
154+
token_id = create_fungible_token(env)
155+
156+
record = submit_airdrop(env, receiver.id, token_id)
157+
ids = extract_pending_ids(record)
158+
159+
tx = TokenClaimAirdropTransaction().add_pending_airdrop_ids(ids).freeze_with(env.client)
160+
# Execute without signing
161+
receipt = tx.execute(env.client)
162+
163+
# The status should indicate failure
164+
assert receipt.status != ResponseCode.SUCCESS
165+
166+
167+
def test_cannot_claim_duplicate_ids(env):
168+
receiver = env.create_account(initial_hbar=2.0)
169+
token_id = create_fungible_token(env)
170+
171+
record = submit_airdrop(env, receiver.id, token_id)
172+
pid = extract_pending_ids(record)[0]
173+
174+
tx = TokenClaimAirdropTransaction()
175+
with pytest.raises(ValueError):
176+
tx.add_pending_airdrop_ids([pid, pid])
177+
178+
def test_cannot_claim_same_pending_twice(env):
179+
receiver = env.create_account(initial_hbar=2.0)
180+
token_id = create_fungible_token(env)
181+
182+
record = submit_airdrop(env, receiver.id, token_id)
183+
ids = extract_pending_ids(record)
184+
185+
# First claim should succeed
186+
first = claim_pending(env, ids, receiver.key)
187+
assert ResponseCode(first.status) == ResponseCode.SUCCESS
188+
189+
# Second claim should fail (already claimed)
190+
second = claim_pending(env, ids, receiver.key)
191+
assert ResponseCode(second.status) != ResponseCode.SUCCESS
192+
193+
def test_claim_max_ids(env):
194+
receiver = env.create_account(initial_hbar=2.0)
195+
196+
tokens = [create_fungible_token(env) for _ in range(TokenClaimAirdropTransaction.MAX_IDS)]
197+
198+
pending_ids = []
199+
for token_id in tokens:
200+
record = submit_airdrop(env, receiver.id, token_id)
201+
pending_ids.extend(extract_pending_ids(record))
202+
203+
assert len(pending_ids) == TokenClaimAirdropTransaction.MAX_IDS
204+
205+
receipt = claim_pending(env, pending_ids, receiver.key)
206+
assert ResponseCode(receipt.status) == ResponseCode.SUCCESS

0 commit comments

Comments
 (0)