diff --git a/README.md b/README.md index e6b0adf..e3edda5 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ The demo simulates a payment workflow involving three conceptual agents: |---------|----------|--------|-----------------| | TRON Nile (testnet) | `tron:nile` | USDT, USDD | `exact_permit`, `exact_gasfree` | | TRON Shasta (testnet) | `tron:shasta` | USDT | `exact_permit` | -| TRON Mainnet | `tron:mainnet` | USDT, USDD | `exact_permit` | +| TRON Mainnet | `tron:mainnet` | USDT, USDD | `exact_permit`, `exact_gasfree` (USDT only) | | BSC Testnet (optional) | `eip155:97` | USDT, USDC, DHLU | `exact_permit`, `exact` | | BSC Mainnet (optional) | `eip155:56` | USDC, USDT, EPS | `exact_permit`, `exact` | @@ -58,7 +58,7 @@ The demo simulates a payment workflow involving three conceptual agents: ### GasFree (Gasless Transactions) -GasFree eliminates transaction fees for TRON payments. When enabled, the client can use a custom selection policy (`PreferGasFreeUSDTPolicy`) to automatically prefer gasless transactions. +GasFree eliminates transaction fees for TRON payments. When enabled, the client can use a custom selection policy (`PreferGasFreeUSDTPolicy`) to automatically prefer gasless transactions. In this demo, GasFree is available on Nile and Mainnet (USDT only) when the corresponding `GASFREE_API_KEY_*` / `GASFREE_API_SECRET_*` values are set. --- @@ -100,6 +100,8 @@ BSC_PAY_TO_ADDRESS= # Optional: GasFree gasless transactions (per-network) GASFREE_API_KEY_NILE= GASFREE_API_SECRET_NILE= +GASFREE_API_KEY_MAINNET= +GASFREE_API_SECRET_MAINNET= # Optional: Facilitator authentication FACILITATOR_API_KEY= diff --git a/client/python/main.py b/client/python/main.py index d5ff0b7..454d05a 100755 --- a/client/python/main.py +++ b/client/python/main.py @@ -105,7 +105,7 @@ async def main(): # Balance policy: auto-resolves signers from registered mechanisms x402_client.register_policy(SufficientBalancePolicy) # Register custom selection policy (AFTER balance check) - x402_client.register_policy(PreferGasFreeUSDTPolicy) + # x402_client.register_policy(PreferGasFreeUSDTPolicy) print(f"\nSupported Networks and Tokens:") for network_name in ["tron:mainnet", "tron:nile", "tron:shasta", "eip155:97"]: diff --git a/facilitator/main.py b/facilitator/main.py index ab5cd24..9989df0 100644 --- a/facilitator/main.py +++ b/facilitator/main.py @@ -84,17 +84,23 @@ class FeeQuoteRequest(BaseModel): gasfree_api_secret_nile = os.getenv("GASFREE_API_SECRET_NILE") or os.getenv("GASFREE_API_SECRET") gasfree_enabled_nile = bool(gasfree_api_key_nile and gasfree_api_secret_nile) -gasfree_clients = ( - { - "tron:nile": GasFreeAPIClient( - NetworkConfig.get_gasfree_api_base_url("tron:nile"), - api_key=gasfree_api_key_nile, - api_secret=gasfree_api_secret_nile, - ), - } - if gasfree_enabled_nile - else {} -) +gasfree_api_key_mainnet = os.getenv("GASFREE_API_KEY_MAINNET") or os.getenv("GASFREE_API_KEY") +gasfree_api_secret_mainnet = os.getenv("GASFREE_API_SECRET_MAINNET") or os.getenv("GASFREE_API_SECRET") +gasfree_enabled_mainnet = bool(gasfree_api_key_mainnet and gasfree_api_secret_mainnet) + +gasfree_clients: dict[str, GasFreeAPIClient] = {} +if gasfree_enabled_nile: + gasfree_clients["tron:nile"] = GasFreeAPIClient( + NetworkConfig.get_gasfree_api_base_url("tron:nile"), + api_key=gasfree_api_key_nile, + api_secret=gasfree_api_secret_nile, + ) +if gasfree_enabled_mainnet: + gasfree_clients["tron:mainnet"] = GasFreeAPIClient( + NetworkConfig.get_gasfree_api_base_url("tron:mainnet"), + api_key=gasfree_api_key_mainnet, + api_secret=gasfree_api_secret_mainnet, + ) all_networks = [f"tron:{n}" for n in TRON_NETWORKS] + [NetworkConfig.BSC_MAINNET, NetworkConfig.BSC_TESTNET] @@ -112,7 +118,7 @@ async def lifespan(app: FastAPI): ) facilitator.register([f"tron:{network}"], mechanism) - # Add GasFree support for nile + # Add GasFree support for Nile and Mainnet (USDT only; enforced by server pricing) if network == "nile" and gasfree_enabled_nile: gasfree_mechanism = ExactGasFreeFacilitatorMechanism( tron_signer, @@ -120,6 +126,13 @@ async def lifespan(app: FastAPI): base_fee=TRON_BASE_FEE, ) facilitator.register([f"tron:{network}"], gasfree_mechanism) + if network == "mainnet" and gasfree_enabled_mainnet: + gasfree_mechanism = ExactGasFreeFacilitatorMechanism( + tron_signer, + clients=gasfree_clients, + base_fee=TRON_BASE_FEE, + ) + facilitator.register([f"tron:{network}"], gasfree_mechanism) bsc_signer = await EvmFacilitatorSigner.create() bsc_facilitator_address = bsc_signer.get_address() @@ -152,6 +165,7 @@ async def lifespan(app: FastAPI): print("=" * 80) print(f"TRON Base Fee: {TRON_BASE_FEE}") print(f"GasFree Nile Enabled: {gasfree_enabled_nile}") + print(f"GasFree Mainnet Enabled: {gasfree_enabled_mainnet}") print(f"Supported Networks: {', '.join(all_networks)}") print(f"\nNetwork Details:") diff --git a/requirements.txt b/requirements.txt index ae68c9f..f2924dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ # Install with: pip install -r requirements.txt # Core bankofai-x402 SDK with TRON and FastAPI support (GitHub tag) -bankofai-x402[tron,fastapi]==0.5.0 +bankofai-x402[tron,fastapi]==0.5.1 # Web framework fastapi>=0.104.0 diff --git a/server/main.py b/server/main.py index 5b03da9..cfa7df4 100644 --- a/server/main.py +++ b/server/main.py @@ -55,6 +55,15 @@ if not PAY_TO_ADDRESS: raise ValueError("PAY_TO_ADDRESS environment variable is required") +# GasFree flags (kept in sync with facilitator envs) +gasfree_api_key_nile = os.getenv("GASFREE_API_KEY_NILE") or os.getenv("GASFREE_API_KEY") +gasfree_api_secret_nile = os.getenv("GASFREE_API_SECRET_NILE") or os.getenv("GASFREE_API_SECRET") +gasfree_enabled_nile = bool(gasfree_api_key_nile and gasfree_api_secret_nile) + +gasfree_api_key_mainnet = os.getenv("GASFREE_API_KEY_MAINNET") or os.getenv("GASFREE_API_KEY") +gasfree_api_secret_mainnet = os.getenv("GASFREE_API_SECRET_MAINNET") or os.getenv("GASFREE_API_SECRET") +gasfree_enabled_mainnet = bool(gasfree_api_key_mainnet and gasfree_api_secret_mainnet) + # Network selection - Change this to use different networks # Options: NetworkConfig.TRON_MAINNET, NetworkConfig.TRON_NILE, # NetworkConfig.TRON_SHASTA @@ -75,7 +84,10 @@ # Initialize server (TRON mechanisms auto-registered by default) server = X402Server() # Register TRON GasFree mechanism -server.register(NetworkConfig.TRON_NILE, ExactGasFreeServerMechanism()) +if gasfree_enabled_nile: + server.register(NetworkConfig.TRON_NILE, ExactGasFreeServerMechanism()) +if gasfree_enabled_mainnet: + server.register(NetworkConfig.TRON_MAINNET, ExactGasFreeServerMechanism()) # Register BSC mechanisms (optional - requires BSC_PAY_TO_ADDRESS) if BSC_PAY_TO_ADDRESS: server.register(NetworkConfig.BSC_TESTNET, ExactPermitEvmServerMechanism()) @@ -97,6 +109,8 @@ print(f"Pay To Address: {PAY_TO_ADDRESS}") print(f"Facilitator URL: {FACILITATOR_URL}") print(f"Facilitator API Key: {'*configured*' if FACILITATOR_API_KEY else '(not set)'}") +print(f"GasFree Nile Enabled: {gasfree_enabled_nile}") +print(f"GasFree Mainnet Enabled: {gasfree_enabled_mainnet}") permit_address = NetworkConfig.get_payment_permit_address(CURRENT_NETWORK) print(f"PaymentPermit Contract: {permit_address}") @@ -167,11 +181,17 @@ async def root(): } +NILE_PRICES = ["0.0001 USDT", "0.0001 USDD"] +NILE_SCHEMES = ["exact_permit", "exact_permit"] +if gasfree_enabled_nile: + NILE_PRICES.append("0.0001 USDT") + NILE_SCHEMES.append("exact_gasfree") + @app.get("/protected-nile") @x402_protected( server=server, - prices=["0.0001 USDT", "0.0001 USDD", "0.0001 USDT", "0.0001 USDD"], - schemes=["exact_permit", "exact_permit", "exact_gasfree", "exact_gasfree"], + prices=NILE_PRICES, + schemes=NILE_SCHEMES, network=CURRENT_NETWORK, pay_to=PAY_TO_ADDRESS, ) @@ -215,11 +235,18 @@ async def protected_shasta_endpoint(request: Request): return StreamingResponse(buf, media_type="image/png") +MAINNET_PRICES = ["0.0001 USDT", "0.0001 USDD"] +MAINNET_SCHEMES = ["exact_permit", "exact_permit"] +if gasfree_enabled_mainnet: + MAINNET_PRICES.append("0.0001 USDT") + MAINNET_SCHEMES.append("exact_gasfree") + + @app.get("/protected-mainnet") @x402_protected( server=server, - prices=["0.0001 USDT", "0.0001 USDD"], - schemes=["exact_permit", "exact_permit"], + prices=MAINNET_PRICES, + schemes=MAINNET_SCHEMES, network=NetworkConfig.TRON_MAINNET, pay_to=PAY_TO_ADDRESS, ) @@ -299,7 +326,7 @@ async def protected_bsc_testnet_endpoint(request: Request): print("Endpoints:") print(" /protected-nile - Payment (0.0001 USDT) [Nile testnet]") print(" /protected-shasta - Payment (0.0001 USDT) [Shasta testnet]") - print(" /protected-mainnet - Payment (0.0001 USDT/USDD) [Mainnet]") + print(" /protected-mainnet - Payment (0.0001 USDT/USDD) [Mainnet, GasFree USDT if enabled]") print(" /protected-bsc-mainnet - Payment (0.0001 USDC/USDT/EPS) [BSC Mainnet]") print(" /protected-bsc-testnet - Payment (0.0001 USDT/USDC/DHLU) [BSC Testnet]") print("=" * 80 + "\n")