mirror of
https://github.com/bohd4nx/FragmentAPI.git
synced 2026-07-25 06:14:29 +00:00
Refactor for GRAM (ex TON) integration
- Updated imports and references from TON to GRAM across multiple modules. - Renamed functions and variables to reflect the change from TON to GRAM. - Adjusted validation checks for top-up and recharge amounts to use GRAM limits. - Modified error messages and exceptions to indicate GRAM instead of TON. - Updated tests to ensure they reflect the new GRAM terminology and functionality. - Introduced new constants for GRAM-related configurations.
This commit is contained in:
@@ -9,7 +9,7 @@ from tonutils.clients import TonapiClient
|
||||
from tonutils.contracts.jetton import get_wallet_address_get_method, get_wallet_data_get_method
|
||||
from tonutils.exceptions import ProviderResponseError
|
||||
|
||||
from pyfragment.core.constants import MIN_TON_BALANCE, MIN_USDT_BALANCE, USDT_TON_MASTER_ADDRESS
|
||||
from pyfragment.core.constants import MIN_GRAM_BALANCE, MIN_USDT_BALANCE, USDT_GRAM_MASTER_ADDRESS
|
||||
from pyfragment.exceptions import WalletError
|
||||
from pyfragment.models.enums import WALLET_CLASSES
|
||||
from pyfragment.models.wallet import WalletInfo
|
||||
@@ -22,11 +22,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def get_usdt_balance(ton: Any, wallet_address: str) -> float:
|
||||
"""Return the USDT balance for a Fragment-linked TON wallet."""
|
||||
"""Return the USDT balance for a Fragment-linked GRAM (ex TON) wallet."""
|
||||
try:
|
||||
jetton_wallet_address = await get_wallet_address_get_method(
|
||||
client=ton,
|
||||
address=USDT_TON_MASTER_ADDRESS,
|
||||
address=USDT_GRAM_MASTER_ADDRESS,
|
||||
owner_address=wallet_address,
|
||||
)
|
||||
wallet_data = await get_wallet_data_get_method(client=ton, address=jetton_wallet_address)
|
||||
@@ -43,40 +43,40 @@ async def get_usdt_balance(ton: Any, wallet_address: str) -> float:
|
||||
raise WalletError(WalletError.USDT_BALANCE_CHECK_FAILED.format(exc=exc)) from exc
|
||||
|
||||
|
||||
async def check_ton_payment_balance(
|
||||
balance_ton: float,
|
||||
amount_ton: float,
|
||||
async def check_gram_payment_balance(
|
||||
balance_gram: float,
|
||||
amount_gram: float,
|
||||
required_payment_amount: float | None,
|
||||
) -> None:
|
||||
"""Validate that the TON wallet can cover a TON-denominated payment."""
|
||||
tx_price_ton = amount_ton
|
||||
"""Validate that the GRAM (ex TON) wallet can cover a GRAM (ex TON)-denominated payment."""
|
||||
tx_price_gram = amount_gram
|
||||
if required_payment_amount is not None and required_payment_amount > 0:
|
||||
tx_price_ton = max(tx_price_ton, required_payment_amount)
|
||||
tx_price_gram = max(tx_price_gram, required_payment_amount)
|
||||
|
||||
required_ton = max(tx_price_ton, MIN_TON_BALANCE)
|
||||
if balance_ton < required_ton:
|
||||
required_gram = max(tx_price_gram, MIN_GRAM_BALANCE)
|
||||
if balance_gram < required_gram:
|
||||
logger.error(
|
||||
"Failed TON balance check: balance=%s TON, required=%s TON",
|
||||
round(balance_ton, 6),
|
||||
round(required_ton, 6),
|
||||
"Failed GRAM (ex TON) balance check: balance=%s GRAM (ex TON), required=%s GRAM (ex TON)",
|
||||
round(balance_gram, 6),
|
||||
round(required_gram, 6),
|
||||
)
|
||||
raise WalletError(WalletError.LOW_TON_BALANCE.format(balance=balance_ton, required=required_ton))
|
||||
raise WalletError(WalletError.LOW_GRAM_BALANCE.format(balance=balance_gram, required=required_gram))
|
||||
|
||||
|
||||
async def check_usdt_payment_balance(
|
||||
balance_ton: float,
|
||||
balance_gram: float,
|
||||
required_payment_amount: float | None,
|
||||
ton: Any,
|
||||
wallet_address: str,
|
||||
) -> None:
|
||||
"""Validate that the wallet can cover a USDT-denominated payment."""
|
||||
if balance_ton < MIN_TON_BALANCE:
|
||||
if balance_gram < MIN_GRAM_BALANCE:
|
||||
logger.error(
|
||||
"Failed TON gas reserve check for USDT payment: balance=%s TON, required=%s TON",
|
||||
round(balance_ton, 6),
|
||||
MIN_TON_BALANCE,
|
||||
"Failed GRAM (ex TON) gas reserve check for USDT payment: balance=%s GRAM (ex TON), required=%s GRAM (ex TON)",
|
||||
round(balance_gram, 6),
|
||||
MIN_GRAM_BALANCE,
|
||||
)
|
||||
raise WalletError(WalletError.LOW_TON_BALANCE.format(balance=balance_ton, required=MIN_TON_BALANCE))
|
||||
raise WalletError(WalletError.LOW_GRAM_BALANCE.format(balance=balance_gram, required=MIN_GRAM_BALANCE))
|
||||
|
||||
usdt_balance = await get_usdt_balance(ton, wallet_address)
|
||||
required_usdt = required_payment_amount if required_payment_amount is not None else MIN_USDT_BALANCE
|
||||
@@ -109,7 +109,7 @@ async def get_account_info(client: FragmentClient) -> dict[str, Any]:
|
||||
|
||||
|
||||
async def get_wallet_info(client: FragmentClient) -> WalletInfo:
|
||||
"""Fetch the wallet address, chain state, and TON/USDT balances."""
|
||||
"""Fetch the wallet address, chain state, and GRAM (ex TON)/USDT balances."""
|
||||
async with TonapiClient(network=NetworkGlobalID.MAINNET, api_key=client.api_key) as ton:
|
||||
try:
|
||||
wallet_cls = WALLET_CLASSES[client.wallet_version]
|
||||
@@ -120,7 +120,7 @@ async def get_wallet_info(client: FragmentClient) -> WalletInfo:
|
||||
return WalletInfo(
|
||||
address=wallet.address.to_str(is_user_friendly=True, is_bounceable=False),
|
||||
state=wallet.state.value,
|
||||
ton_balance=round(wallet.balance / 1_000_000_000, 4),
|
||||
gram_balance=round(wallet.balance / 1_000_000_000, 4),
|
||||
usdt_balance=round(usdt_balance, 4),
|
||||
)
|
||||
except Exception as exc:
|
||||
|
||||
@@ -11,7 +11,7 @@ from ton_core import Cell, NetworkGlobalID
|
||||
from tonutils.clients import TonapiClient
|
||||
from tonutils.exceptions import ProviderResponseError
|
||||
|
||||
from pyfragment.domains.tonapi.account import check_ton_payment_balance, check_usdt_payment_balance
|
||||
from pyfragment.domains.tonapi.account import check_gram_payment_balance, check_usdt_payment_balance
|
||||
from pyfragment.exceptions import ParseError, TransactionError, WalletError
|
||||
from pyfragment.models.enums import WALLET_CLASSES, PaymentMethod
|
||||
|
||||
@@ -26,7 +26,7 @@ def clean_decode(payload: str) -> str | Cell:
|
||||
"""Decode a base64 BOC comment from Fragment into text when possible.
|
||||
|
||||
Some Fragment payloads are plain text comments, while others are structured
|
||||
TON messages such as jetton transfers. Non-text payloads are returned as a
|
||||
GRAM (ex TON) messages such as jetton transfers. Non-text payloads are returned as a
|
||||
`Cell` so the caller can keep the raw binary structure.
|
||||
"""
|
||||
s = payload.strip()
|
||||
@@ -39,7 +39,7 @@ def clean_decode(payload: str) -> str | Cell:
|
||||
sl = cell.begin_parse()
|
||||
op = sl.load_uint(32)
|
||||
if op != 0:
|
||||
# Non-zero op code means this is a structured TON message, not a plain text comment.
|
||||
# Non-zero op code means this is a structured GRAM (ex TON) message, not a plain text comment.
|
||||
return cell
|
||||
try:
|
||||
return sl.load_snake_string().strip()
|
||||
@@ -62,7 +62,7 @@ def _extract_message(transaction_data: dict[str, Any]) -> dict[str, Any]:
|
||||
async def _check_payment_balances(
|
||||
wallet: Any,
|
||||
payment_method: PaymentMethod,
|
||||
amount_ton: float,
|
||||
amount_gram: float,
|
||||
required_payment_amount: float | None,
|
||||
transaction_data: dict[str, Any],
|
||||
ton: Any,
|
||||
@@ -70,18 +70,18 @@ async def _check_payment_balances(
|
||||
"""Refresh wallet and verify sufficient balance before broadcasting."""
|
||||
try:
|
||||
await wallet.refresh()
|
||||
balance_ton = wallet.balance / 1_000_000_000
|
||||
balance_gram = wallet.balance / 1_000_000_000
|
||||
if payment_method == "ton":
|
||||
await check_ton_payment_balance(balance_ton, amount_ton, required_payment_amount)
|
||||
await check_gram_payment_balance(balance_gram, amount_gram, required_payment_amount)
|
||||
else:
|
||||
# USDT is paid from the Fragment-linked wallet, not the signing wallet.
|
||||
fragment_wallet_address = transaction_data["transaction"].get("from", "")
|
||||
await check_usdt_payment_balance(balance_ton, required_payment_amount, ton, fragment_wallet_address)
|
||||
await check_usdt_payment_balance(balance_gram, required_payment_amount, ton, fragment_wallet_address)
|
||||
except WalletError:
|
||||
raise
|
||||
except Exception as exc:
|
||||
logger.exception("Failed to validate balances before broadcasting transaction")
|
||||
raise WalletError(WalletError.TON_BALANCE_CHECK_FAILED.format(exc=exc)) from exc
|
||||
raise WalletError(WalletError.GRAM_BALANCE_CHECK_FAILED.format(exc=exc)) from exc
|
||||
|
||||
|
||||
async def _broadcast_with_retry(wallet: Any, message: dict[str, Any], payload: str | Cell) -> str:
|
||||
@@ -90,7 +90,7 @@ async def _broadcast_with_retry(wallet: Any, message: dict[str, Any], payload: s
|
||||
try:
|
||||
result = await wallet.transfer(
|
||||
destination=message["address"],
|
||||
amount=int(message["amount"]), # nanotons, not TON
|
||||
amount=int(message["amount"]), # nanograms, not GRAM (ex TON)
|
||||
body=payload,
|
||||
)
|
||||
return str(result.normalized_hash)
|
||||
@@ -124,10 +124,10 @@ async def _broadcast_with_retry(wallet: Any, message: dict[str, Any], payload: s
|
||||
async def process_transaction(
|
||||
client: FragmentClient,
|
||||
transaction_data: dict[str, Any],
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
payment_method: PaymentMethod = PaymentMethod.GRAM,
|
||||
required_payment_amount: float | None = None,
|
||||
) -> str:
|
||||
"""Sign and broadcast a Fragment transaction with the seeded TON wallet.
|
||||
"""Sign and broadcast a Fragment transaction with the seeded GRAM (ex TON) wallet.
|
||||
|
||||
Args:
|
||||
client: Authenticated `FragmentClient` instance.
|
||||
@@ -139,13 +139,13 @@ async def process_transaction(
|
||||
Normalized transaction hash string.
|
||||
"""
|
||||
message = _extract_message(transaction_data)
|
||||
amount_ton = int(message["amount"]) / 1_000_000_000
|
||||
amount_gram = int(message["amount"]) / 1_000_000_000
|
||||
|
||||
async with TonapiClient(network=NetworkGlobalID.MAINNET, api_key=client.api_key) as ton:
|
||||
wallet_cls = WALLET_CLASSES[client.wallet_version]
|
||||
wallet, _, _, _ = wallet_cls.from_mnemonic(client=ton, mnemonic=client.seed)
|
||||
|
||||
await _check_payment_balances(wallet, payment_method, amount_ton, required_payment_amount, transaction_data, ton)
|
||||
await _check_payment_balances(wallet, payment_method, amount_gram, required_payment_amount, transaction_data, ton)
|
||||
|
||||
payload = clean_decode(str(message.get("payload", "")))
|
||||
|
||||
@@ -161,7 +161,7 @@ async def process_transaction(
|
||||
raise TransactionError(TransactionError.BROADCAST_FAILED_SSL.format(exc=exc)) from exc
|
||||
cause = cause.__cause__ or cause.__context__
|
||||
logger.exception(
|
||||
"Failed to broadcast transaction to '%s' for %s nanotons using payment method '%s'",
|
||||
"Failed to broadcast transaction to '%s' for %s nanograms using payment method '%s'",
|
||||
message["address"],
|
||||
message["amount"],
|
||||
payment_method,
|
||||
|
||||
Reference in New Issue
Block a user