From 0031832d95dc85bbb9b1adfbc889bcf55fc3313b Mon Sep 17 00:00:00 2001 From: kylexqian Date: Tue, 31 Mar 2026 00:19:19 -0700 Subject: [PATCH 1/6] feat: remove USDC payment option, accept OPG only Strips all USDC/OUSDC payment options from the x402 middleware routes and removes associated constants and network registrations. The gateway now only accepts $OPG (Base Testnet, eip155:84532) for both the pre-check and dynamic settlement. Removed: - EVM_NETWORK (OG EVM / eip155:10740) and its scheme registrations - USDC_ADDRESS, CHAT_COMPLETIONS_USDC_AMOUNT, COMPLETIONS_USDC_AMOUNT - USDC entry in ASSET_DECIMALS_BY_ADDRESS - POST /v1/completions route (was USDC-only) - OUSDC PaymentOption from POST /v1/chat/completions Co-Authored-By: Claude Sonnet 4.6 --- tee_gateway/__main__.py | 36 ------------------------------------ tee_gateway/definitions.py | 13 ------------- 2 files changed, 49 deletions(-) diff --git a/tee_gateway/__main__.py b/tee_gateway/__main__.py index fbaca68..89a325d 100644 --- a/tee_gateway/__main__.py +++ b/tee_gateway/__main__.py @@ -34,14 +34,10 @@ from .util import dynamic_session_cost_calculator from .definitions import ( - EVM_NETWORK, BASE_TESTNET_NETWORK, EVM_PAYMENT_ADDRESS, - USDC_ADDRESS, BASE_OPG_ADDRESS, - CHAT_COMPLETIONS_USDC_AMOUNT, CHAT_COMPLETIONS_OPG_AMOUNT, - COMPLETIONS_USDC_AMOUNT, FACILITATOR_URL, ) @@ -110,28 +106,12 @@ def _shutdown_heartbeat(): server = x402ResourceServerSync(facilitator) store = SessionStore() -server.register(EVM_NETWORK, ExactEvmServerScheme()) server.register(BASE_TESTNET_NETWORK, ExactEvmServerScheme()) -server.register(EVM_NETWORK, UptoEvmServerScheme()) server.register(BASE_TESTNET_NETWORK, UptoEvmServerScheme()) routes = { "POST /v1/chat/completions": RouteConfig( accepts=[ - PaymentOption( - scheme="upto", - pay_to=EVM_PAYMENT_ADDRESS, - price=AssetAmount( - amount=CHAT_COMPLETIONS_USDC_AMOUNT, - asset=USDC_ADDRESS, - extra={ - "name": "OUSDC", - "version": "2", - "assetTransferMethod": "permit2", - }, - ), - network=EVM_NETWORK, - ), PaymentOption( scheme="upto", pay_to=EVM_PAYMENT_ADDRESS, @@ -150,22 +130,6 @@ def _shutdown_heartbeat(): mime_type="application/json", description="Chat completion", ), - "POST /v1/completions": RouteConfig( - accepts=[ - PaymentOption( - scheme="upto", - pay_to=EVM_PAYMENT_ADDRESS, - price=AssetAmount( - amount=COMPLETIONS_USDC_AMOUNT, - asset=USDC_ADDRESS, - extra={"name": "USDC", "version": "2"}, - ), - network=EVM_NETWORK, - ), - ], - mime_type="application/json", - description="Completion", - ), } diff --git a/tee_gateway/definitions.py b/tee_gateway/definitions.py index 0d62dfb..44077ed 100644 --- a/tee_gateway/definitions.py +++ b/tee_gateway/definitions.py @@ -19,9 +19,6 @@ # Network IDs (EIP-155 chain identifiers) # --------------------------------------------------------------------------- -# OG EVM — where USDC payments are accepted -EVM_NETWORK: str = "eip155:10740" - # Base Testnet — where OPG payments are accepted BASE_TESTNET_NETWORK: str = "eip155:84532" @@ -41,9 +38,6 @@ # ERC-20 token contract addresses # --------------------------------------------------------------------------- -# USDC Address -USDC_ADDRESS: str = "0x094E464A23B90A71a0894D5D1e5D470FfDD074e1" - # OpenGradient token (OPG) on Base Testnet BASE_OPG_ADDRESS: str = "0x240b09731D96979f50B2C649C9CE10FcF9C7987F" @@ -53,7 +47,6 @@ # Maps lowercase contract address → number of decimals for unit conversion. ASSET_DECIMALS_BY_ADDRESS: dict[str, int] = { - USDC_ADDRESS.lower(): 6, # USDC / OUSDC standard: 6 decimals BASE_OPG_ADDRESS.lower(): 18, # OPG: 18 decimals (ERC-20 standard) } @@ -68,11 +61,5 @@ # by dynamic_session_cost_calculator() in util.py. # --------------------------------------------------------------------------- -# /v1/chat/completions — 0.01 OUSDC precheck (6 decimals: 10_000 = $0.01) -CHAT_COMPLETIONS_USDC_AMOUNT: str = "10000" - # /v1/chat/completions — 0.05 OPG precheck (18 decimals) CHAT_COMPLETIONS_OPG_AMOUNT: str = "50000000000000000" - -# /v1/completions — 0.01 USDC precheck (6 decimals: 10_000 = $0.01) -COMPLETIONS_USDC_AMOUNT: str = "10000" From 07e8f79c6e60a38fefa1c940509729c5971e394f Mon Sep 17 00:00:00 2001 From: kylexqian Date: Tue, 31 Mar 2026 01:02:03 -0700 Subject: [PATCH 2/6] feat: re-add /v1/completions route with OPG-only payment Mirrors the /v1/chat/completions payment setup: accepts OPG on Base Testnet (eip155:84532) via the upto scheme, with a 0.05 OPG session pre-check ceiling. Adds COMPLETIONS_OPG_AMOUNT constant alongside the existing CHAT_COMPLETIONS_OPG_AMOUNT in definitions.py. Co-Authored-By: Claude Sonnet 4.6 --- tee_gateway/__main__.py | 21 +++++++++++++++++++++ tee_gateway/definitions.py | 3 +++ 2 files changed, 24 insertions(+) diff --git a/tee_gateway/__main__.py b/tee_gateway/__main__.py index 89a325d..bfce357 100644 --- a/tee_gateway/__main__.py +++ b/tee_gateway/__main__.py @@ -38,6 +38,7 @@ EVM_PAYMENT_ADDRESS, BASE_OPG_ADDRESS, CHAT_COMPLETIONS_OPG_AMOUNT, + COMPLETIONS_OPG_AMOUNT, FACILITATOR_URL, ) @@ -130,6 +131,26 @@ def _shutdown_heartbeat(): mime_type="application/json", description="Chat completion", ), + "POST /v1/completions": RouteConfig( + accepts=[ + PaymentOption( + scheme="upto", + pay_to=EVM_PAYMENT_ADDRESS, + price=AssetAmount( + amount=COMPLETIONS_OPG_AMOUNT, + asset=BASE_OPG_ADDRESS, + extra={ + "name": "OPG", + "version": "2", + "assetTransferMethod": "permit2", + }, + ), + network=BASE_TESTNET_NETWORK, + ), + ], + mime_type="application/json", + description="Completion", + ), } diff --git a/tee_gateway/definitions.py b/tee_gateway/definitions.py index 44077ed..78adee9 100644 --- a/tee_gateway/definitions.py +++ b/tee_gateway/definitions.py @@ -63,3 +63,6 @@ # /v1/chat/completions — 0.05 OPG precheck (18 decimals) CHAT_COMPLETIONS_OPG_AMOUNT: str = "50000000000000000" + +# /v1/completions — 0.05 OPG precheck (18 decimals) +COMPLETIONS_OPG_AMOUNT: str = "50000000000000000" From c91f964ca8aed1bfade1ed28cc2080902ec937ff Mon Sep 17 00:00:00 2001 From: kylexqian Date: Tue, 31 Mar 2026 01:54:25 -0700 Subject: [PATCH 3/6] fix: remove USDC references from test_pricing.py USDC_ADDRESS no longer exists in definitions.py since the gateway was updated to accept OPG only. Removes the USDC import, _usdc_requirements helper, _expected_cost_usdc helper, and the TestDynamicSessionCostCalculatorUSDC test class that relied on them. Co-Authored-By: Claude Sonnet 4.6 --- tests/test_pricing.py | 50 +++---------------------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/tests/test_pricing.py b/tests/test_pricing.py index 2b397c3..770138d 100644 --- a/tests/test_pricing.py +++ b/tests/test_pricing.py @@ -3,15 +3,15 @@ Tests verify that: - Every user-facing model name resolves to the correct ModelConfig - - dynamic_session_cost_calculator produces the right amount in token - smallest-units for supported models and token currencies (OPG / USDC) + - dynamic_session_cost_calculator produces the right amount in OPG token + smallest-units for supported models - Edge cases (no usage, unknown model, bad context) are handled correctly """ import unittest from decimal import Decimal -from tee_gateway.definitions import BASE_OPG_ADDRESS, USDC_ADDRESS +from tee_gateway.definitions import BASE_OPG_ADDRESS from tee_gateway.model_registry import ( _MODEL_LOOKUP, get_model_config, @@ -29,10 +29,6 @@ def _opg_requirements() -> dict: return {"asset": BASE_OPG_ADDRESS, "amount": "50000000000000000"} -def _usdc_requirements() -> dict: - """Fake PaymentRequirements dict for USDC (6 decimals).""" - return {"asset": USDC_ADDRESS, "amount": "10000"} - def _ctx(model: str, input_tokens: int, output_tokens: int, requirements=None) -> dict: """Build a minimal calculator context.""" @@ -62,17 +58,6 @@ def _expected_cost_opg(model: str, input_tokens: int, output_tokens: int) -> int return int((total_usd * Decimal(10**18)).to_integral_value(rounding=ROUND_CEILING)) -def _expected_cost_usdc(model: str, input_tokens: int, output_tokens: int) -> int: - """Compute expected cost in USDC smallest units (6 decimals, ROUND_CEILING).""" - from decimal import ROUND_CEILING - - cfg = get_model_config(model) - total_usd = ( - Decimal(input_tokens) * cfg.input_price_usd - + Decimal(output_tokens) * cfg.output_price_usd - ) - return int((total_usd * Decimal(10**6)).to_integral_value(rounding=ROUND_CEILING)) - # --------------------------------------------------------------------------- # Model registry tests @@ -368,35 +353,6 @@ def test_grok_4_fast_cheaper_than_grok_4(self): self.assertLess(fast, full) -class TestDynamicSessionCostCalculatorUSDC(unittest.TestCase): - """dynamic_session_cost_calculator with USDC (6 decimals).""" - - def _calc(self, model, input_tokens, output_tokens): - return dynamic_session_cost_calculator( - _ctx(model, input_tokens, output_tokens, _usdc_requirements()) - ) - - def test_gpt_4_1_usdc_cost(self): - cost = self._calc("gpt-4.1", 1000, 500) - expected = _expected_cost_usdc("gpt-4.1", 1000, 500) - self.assertEqual(cost, expected) - # 0.006 USD in USDC (6 decimals) = 6000 units - self.assertEqual(cost, 6000) - - def test_claude_sonnet_4_5_usdc_cost(self): - cost = self._calc("claude-sonnet-4-5", 1000, 500) - expected = _expected_cost_usdc("claude-sonnet-4-5", 1000, 500) - self.assertEqual(cost, expected) - # 0.0105 USD = 10500 units - self.assertEqual(cost, 10500) - - def test_gemini_flash_lite_usdc_cost(self): - cost = self._calc("gemini-2.5-flash-lite", 1000, 500) - expected = _expected_cost_usdc("gemini-2.5-flash-lite", 1000, 500) - self.assertEqual(cost, expected) - # 0.0003 USD = 300 units - self.assertEqual(cost, 300) - class TestDynamicSessionCostCalculatorEdgeCases(unittest.TestCase): """Edge cases for dynamic_session_cost_calculator.""" From 547d89a4984e3e3a18c434ca4f478067622c5014 Mon Sep 17 00:00:00 2001 From: kylexqian Date: Tue, 31 Mar 2026 02:02:49 -0700 Subject: [PATCH 4/6] Fix lint --- tests/test_pricing.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_pricing.py b/tests/test_pricing.py index 770138d..2f3ed90 100644 --- a/tests/test_pricing.py +++ b/tests/test_pricing.py @@ -29,7 +29,6 @@ def _opg_requirements() -> dict: return {"asset": BASE_OPG_ADDRESS, "amount": "50000000000000000"} - def _ctx(model: str, input_tokens: int, output_tokens: int, requirements=None) -> dict: """Build a minimal calculator context.""" return { @@ -58,7 +57,6 @@ def _expected_cost_opg(model: str, input_tokens: int, output_tokens: int) -> int return int((total_usd * Decimal(10**18)).to_integral_value(rounding=ROUND_CEILING)) - # --------------------------------------------------------------------------- # Model registry tests # --------------------------------------------------------------------------- @@ -353,7 +351,6 @@ def test_grok_4_fast_cheaper_than_grok_4(self): self.assertLess(fast, full) - class TestDynamicSessionCostCalculatorEdgeCases(unittest.TestCase): """Edge cases for dynamic_session_cost_calculator.""" From e1a2ea8b8ce5063971e5b09df02d683003461eb8 Mon Sep 17 00:00:00 2001 From: kylexqian Date: Wed, 1 Apr 2026 00:31:55 -0700 Subject: [PATCH 5/6] refactor: rename OPG amount constants to *_SESSION_MAX_SPEND with full comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renames CHAT_COMPLETIONS_OPG_AMOUNT → CHAT_COMPLETIONS_OPG_SESSION_MAX_SPEND and COMPLETIONS_OPG_AMOUNT → COMPLETIONS_OPG_SESSION_MAX_SPEND to make the purpose explicit: these are the upper-bound caps shown during the x402 pre-check, not fixed charges. Adds the same multi-line comment block used for the chat completions constant to the completions constant as well. Updates all references in __main__.py. Co-Authored-By: Claude Sonnet 4.6 --- tee_gateway/__main__.py | 8 ++++---- tee_gateway/definitions.py | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tee_gateway/__main__.py b/tee_gateway/__main__.py index 287435a..18f8117 100644 --- a/tee_gateway/__main__.py +++ b/tee_gateway/__main__.py @@ -38,8 +38,8 @@ BASE_TESTNET_NETWORK, EVM_PAYMENT_ADDRESS, BASE_OPG_ADDRESS, - CHAT_COMPLETIONS_OPG_AMOUNT, - COMPLETIONS_OPG_AMOUNT, + CHAT_COMPLETIONS_OPG_SESSION_MAX_SPEND, + COMPLETIONS_OPG_SESSION_MAX_SPEND, FACILITATOR_URL, ) @@ -118,7 +118,7 @@ def _shutdown_heartbeat(): scheme="upto", pay_to=EVM_PAYMENT_ADDRESS, price=AssetAmount( - amount=CHAT_COMPLETIONS_OPG_AMOUNT, + amount=CHAT_COMPLETIONS_OPG_SESSION_MAX_SPEND, asset=BASE_OPG_ADDRESS, extra={ "name": "OPG", @@ -138,7 +138,7 @@ def _shutdown_heartbeat(): scheme="upto", pay_to=EVM_PAYMENT_ADDRESS, price=AssetAmount( - amount=COMPLETIONS_OPG_AMOUNT, + amount=COMPLETIONS_OPG_SESSION_MAX_SPEND, asset=BASE_OPG_ADDRESS, extra={ "name": "OPG", diff --git a/tee_gateway/definitions.py b/tee_gateway/definitions.py index 78adee9..37d6ff2 100644 --- a/tee_gateway/definitions.py +++ b/tee_gateway/definitions.py @@ -61,8 +61,16 @@ # by dynamic_session_cost_calculator() in util.py. # --------------------------------------------------------------------------- -# /v1/chat/completions — 0.05 OPG precheck (18 decimals) -CHAT_COMPLETIONS_OPG_AMOUNT: str = "50000000000000000" - -# /v1/completions — 0.05 OPG precheck (18 decimals) -COMPLETIONS_OPG_AMOUNT: str = "50000000000000000" +# /v1/chat/completions — maximum OPG spend per session (18 decimals: 50000000000000000 = 0.05 OPG). +# This is the upper-bound amount presented to the client during the x402 pre-check handshake. +# The x402 "upto" scheme allows the actual charge to be any value up to this cap; +# the real per-request cost is settled dynamically by dynamic_session_cost_calculator() in util.py +# based on actual token usage, so clients are never overcharged beyond what they consumed. +CHAT_COMPLETIONS_OPG_SESSION_MAX_SPEND: str = "50000000000000000" + +# /v1/completions — maximum OPG spend per session (18 decimals: 50000000000000000 = 0.05 OPG). +# This is the upper-bound amount presented to the client during the x402 pre-check handshake. +# The x402 "upto" scheme allows the actual charge to be any value up to this cap; +# the real per-request cost is settled dynamically by dynamic_session_cost_calculator() in util.py +# based on actual token usage, so clients are never overcharged beyond what they consumed. +COMPLETIONS_OPG_SESSION_MAX_SPEND: str = "50000000000000000" From e6cb87794538976e22ff78b7e30b13a550a10b03 Mon Sep 17 00:00:00 2001 From: kylexqian Date: Wed, 1 Apr 2026 00:32:18 -0700 Subject: [PATCH 6/6] fix: set OPG session max spend to 0.1 OPG (100000000000000000 wei) Updates both CHAT_COMPLETIONS_OPG_SESSION_MAX_SPEND and COMPLETIONS_OPG_SESSION_MAX_SPEND from 0.05 OPG to 0.1 OPG. Co-Authored-By: Claude Sonnet 4.6 --- tee_gateway/definitions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tee_gateway/definitions.py b/tee_gateway/definitions.py index 37d6ff2..83d9d8c 100644 --- a/tee_gateway/definitions.py +++ b/tee_gateway/definitions.py @@ -61,16 +61,16 @@ # by dynamic_session_cost_calculator() in util.py. # --------------------------------------------------------------------------- -# /v1/chat/completions — maximum OPG spend per session (18 decimals: 50000000000000000 = 0.05 OPG). +# /v1/chat/completions — maximum OPG spend per session (18 decimals: 100000000000000000 = 0.1 OPG). # This is the upper-bound amount presented to the client during the x402 pre-check handshake. # The x402 "upto" scheme allows the actual charge to be any value up to this cap; # the real per-request cost is settled dynamically by dynamic_session_cost_calculator() in util.py # based on actual token usage, so clients are never overcharged beyond what they consumed. -CHAT_COMPLETIONS_OPG_SESSION_MAX_SPEND: str = "50000000000000000" +CHAT_COMPLETIONS_OPG_SESSION_MAX_SPEND: str = "100000000000000000" -# /v1/completions — maximum OPG spend per session (18 decimals: 50000000000000000 = 0.05 OPG). +# /v1/completions — maximum OPG spend per session (18 decimals: 100000000000000000 = 0.1 OPG). # This is the upper-bound amount presented to the client during the x402 pre-check handshake. # The x402 "upto" scheme allows the actual charge to be any value up to this cap; # the real per-request cost is settled dynamically by dynamic_session_cost_calculator() in util.py # based on actual token usage, so clients are never overcharged beyond what they consumed. -COMPLETIONS_OPG_SESSION_MAX_SPEND: str = "50000000000000000" +COMPLETIONS_OPG_SESSION_MAX_SPEND: str = "100000000000000000"