Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ 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` |

> BSC support requires `BSC_PRIVATE_KEY` to be configured.

### 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.

---

Expand Down Expand Up @@ -100,6 +100,8 @@ BSC_PAY_TO_ADDRESS=<server_recipient_evm_address>
# Optional: GasFree gasless transactions (per-network)
GASFREE_API_KEY_NILE=<key>
GASFREE_API_SECRET_NILE=<secret>
GASFREE_API_KEY_MAINNET=<key>
GASFREE_API_SECRET_MAINNET=<secret>

# Optional: Facilitator authentication
FACILITATOR_API_KEY=<your_api_key>
Expand Down
2 changes: 1 addition & 1 deletion client/python/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]:
Expand Down
38 changes: 26 additions & 12 deletions facilitator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand All @@ -112,14 +118,21 @@ 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,
clients=gasfree_clients,
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()
Expand Down Expand Up @@ -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:")
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
39 changes: 33 additions & 6 deletions server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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())
Expand All @@ -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}")

Expand Down Expand Up @@ -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,
)
Expand Down Expand Up @@ -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,
)
Expand Down Expand Up @@ -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")
Expand Down
Loading