t402 1.9.0__py3-none-any.whl → 1.9.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. t402/__init__.py +2 -1
  2. t402/bridge/client.py +13 -5
  3. t402/bridge/constants.py +3 -1
  4. t402/bridge/router.py +1 -1
  5. t402/bridge/scan.py +3 -1
  6. t402/chains.py +268 -1
  7. t402/cli.py +31 -9
  8. t402/common.py +2 -0
  9. t402/cosmos_paywall_template.py +2 -0
  10. t402/encoding.py +9 -3
  11. t402/erc4337/accounts.py +56 -51
  12. t402/erc4337/bundlers.py +105 -99
  13. t402/erc4337/paymasters.py +100 -109
  14. t402/erc4337/types.py +39 -26
  15. t402/evm_paywall_template.py +1 -1
  16. t402/fastapi/middleware.py +1 -3
  17. t402/mcp/server.py +79 -46
  18. t402/near_paywall_template.py +2 -0
  19. t402/networks.py +34 -1
  20. t402/paywall.py +1 -3
  21. t402/schemes/__init__.py +124 -0
  22. t402/schemes/aptos/__init__.py +70 -0
  23. t402/schemes/aptos/constants.py +349 -0
  24. t402/schemes/aptos/exact_direct/__init__.py +44 -0
  25. t402/schemes/aptos/exact_direct/client.py +202 -0
  26. t402/schemes/aptos/exact_direct/facilitator.py +426 -0
  27. t402/schemes/aptos/exact_direct/server.py +272 -0
  28. t402/schemes/aptos/types.py +237 -0
  29. t402/schemes/evm/__init__.py +46 -1
  30. t402/schemes/evm/exact/__init__.py +11 -0
  31. t402/schemes/evm/exact/client.py +3 -1
  32. t402/schemes/evm/exact/facilitator.py +894 -0
  33. t402/schemes/evm/exact/server.py +1 -1
  34. t402/schemes/evm/exact_legacy/__init__.py +38 -0
  35. t402/schemes/evm/exact_legacy/client.py +291 -0
  36. t402/schemes/evm/exact_legacy/facilitator.py +777 -0
  37. t402/schemes/evm/exact_legacy/server.py +231 -0
  38. t402/schemes/evm/upto/__init__.py +12 -0
  39. t402/schemes/evm/upto/client.py +6 -2
  40. t402/schemes/evm/upto/facilitator.py +625 -0
  41. t402/schemes/evm/upto/server.py +243 -0
  42. t402/schemes/evm/upto/types.py +3 -1
  43. t402/schemes/interfaces.py +6 -2
  44. t402/schemes/near/__init__.py +112 -0
  45. t402/schemes/near/constants.py +189 -0
  46. t402/schemes/near/exact_direct/__init__.py +21 -0
  47. t402/schemes/near/exact_direct/client.py +204 -0
  48. t402/schemes/near/exact_direct/facilitator.py +455 -0
  49. t402/schemes/near/exact_direct/server.py +303 -0
  50. t402/schemes/near/types.py +419 -0
  51. t402/schemes/polkadot/__init__.py +72 -0
  52. t402/schemes/polkadot/constants.py +155 -0
  53. t402/schemes/polkadot/exact_direct/__init__.py +43 -0
  54. t402/schemes/polkadot/exact_direct/client.py +235 -0
  55. t402/schemes/polkadot/exact_direct/facilitator.py +428 -0
  56. t402/schemes/polkadot/exact_direct/server.py +292 -0
  57. t402/schemes/polkadot/types.py +385 -0
  58. t402/schemes/registry.py +6 -2
  59. t402/schemes/stacks/__init__.py +68 -0
  60. t402/schemes/stacks/constants.py +122 -0
  61. t402/schemes/stacks/exact_direct/__init__.py +43 -0
  62. t402/schemes/stacks/exact_direct/client.py +222 -0
  63. t402/schemes/stacks/exact_direct/facilitator.py +424 -0
  64. t402/schemes/stacks/exact_direct/server.py +292 -0
  65. t402/schemes/stacks/types.py +380 -0
  66. t402/schemes/svm/__init__.py +29 -0
  67. t402/schemes/svm/exact/__init__.py +35 -0
  68. t402/schemes/svm/exact/client.py +23 -0
  69. t402/schemes/svm/exact/facilitator.py +24 -0
  70. t402/schemes/svm/exact/server.py +20 -0
  71. t402/schemes/tezos/__init__.py +84 -0
  72. t402/schemes/tezos/constants.py +372 -0
  73. t402/schemes/tezos/exact_direct/__init__.py +22 -0
  74. t402/schemes/tezos/exact_direct/client.py +226 -0
  75. t402/schemes/tezos/exact_direct/facilitator.py +491 -0
  76. t402/schemes/tezos/exact_direct/server.py +277 -0
  77. t402/schemes/tezos/types.py +220 -0
  78. t402/schemes/ton/__init__.py +9 -2
  79. t402/schemes/ton/exact/__init__.py +7 -0
  80. t402/schemes/ton/exact/facilitator.py +730 -0
  81. t402/schemes/ton/exact/server.py +1 -1
  82. t402/schemes/tron/__init__.py +11 -2
  83. t402/schemes/tron/exact/__init__.py +9 -0
  84. t402/schemes/tron/exact/facilitator.py +673 -0
  85. t402/schemes/tron/exact/server.py +1 -1
  86. t402/stacks_paywall_template.py +2 -0
  87. t402/svm.py +45 -11
  88. t402/svm_paywall_template.py +1 -1
  89. t402/ton.py +5 -1
  90. t402/ton_paywall_template.py +1 -192
  91. t402/tron.py +2 -0
  92. t402/tron_paywall_template.py +2 -0
  93. t402/types.py +3 -1
  94. t402/wdk/errors.py +15 -5
  95. t402/wdk/signer.py +11 -2
  96. {t402-1.9.0.dist-info → t402-1.9.1.dist-info}/METADATA +42 -1
  97. t402-1.9.1.dist-info/RECORD +125 -0
  98. t402-1.9.0.dist-info/RECORD +0 -72
  99. {t402-1.9.0.dist-info → t402-1.9.1.dist-info}/WHEEL +0 -0
  100. {t402-1.9.0.dist-info → t402-1.9.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,243 @@
1
+ """EVM Up-To Scheme - Server Implementation.
2
+
3
+ This module provides the server-side implementation of the upto payment scheme
4
+ for EVM networks using EIP-2612 Permit.
5
+
6
+ The server parses user-friendly prices into atomic token amounts and enhances
7
+ payment requirements with EIP-712 domain information needed by clients to
8
+ sign Permit authorizations.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from decimal import Decimal
14
+ from typing import Any, Dict, List, Optional, Union
15
+
16
+ from t402.types import (
17
+ PaymentRequirementsV2,
18
+ Network,
19
+ )
20
+ from t402.schemes.interfaces import AssetAmount, SupportedKindDict
21
+ from t402.chains import (
22
+ get_chain_id,
23
+ get_token_decimals,
24
+ get_token_name,
25
+ get_token_version,
26
+ get_default_token_address,
27
+ )
28
+
29
+
30
+ # Constants
31
+ SCHEME_UPTO = "upto"
32
+
33
+
34
+ class UptoEvmServerScheme:
35
+ """Server scheme for EVM upto payments using EIP-2612 Permit.
36
+
37
+ Handles parsing user-friendly prices and enhancing payment requirements
38
+ with EIP-712 Permit domain information needed for clients to sign
39
+ gasless token approvals.
40
+
41
+ The upto scheme allows clients to authorize a maximum amount (maxAmount)
42
+ that the facilitator can settle up to, enabling usage-based billing.
43
+
44
+ Example:
45
+ ```python
46
+ scheme = UptoEvmServerScheme()
47
+
48
+ # Parse price to get asset amount info
49
+ asset_amount = await scheme.parse_price("$1.00", "eip155:8453")
50
+ # Returns: {"amount": "1000000", "asset": "0x833589...", "extra": {...}}
51
+
52
+ # Enhance requirements with EIP-712 domain info
53
+ enhanced = await scheme.enhance_requirements(
54
+ requirements,
55
+ supported_kind,
56
+ facilitator_extensions,
57
+ )
58
+ ```
59
+ """
60
+
61
+ scheme = SCHEME_UPTO
62
+ caip_family = "eip155:*"
63
+
64
+ def __init__(
65
+ self,
66
+ router_address: Optional[str] = None,
67
+ ):
68
+ """Initialize the server scheme.
69
+
70
+ Args:
71
+ router_address: Optional default router/spender contract address.
72
+ If provided, it will be included in enhanced requirements.
73
+ """
74
+ self._router_address = router_address
75
+
76
+ async def parse_price(
77
+ self,
78
+ price: Union[str, int, float, Dict[str, Any]],
79
+ network: Network,
80
+ ) -> AssetAmount:
81
+ """Parse a user-friendly price to atomic amount and asset.
82
+
83
+ For the upto scheme, this returns the maxAmount the client should
84
+ authorize. The actual settled amount may be less.
85
+
86
+ Supports:
87
+ - String with $ prefix: "$1.00" -> 1000000 (6 decimals)
88
+ - String without prefix: "1.00" -> 1000000
89
+ - Integer/float: 1.00 -> 1000000
90
+ - Dict (TokenAmount): {"amount": "1000000", "asset": "0x..."}
91
+
92
+ Args:
93
+ price: User-friendly price (represents the max amount)
94
+ network: Network identifier (CAIP-2 format, e.g., "eip155:8453")
95
+
96
+ Returns:
97
+ AssetAmount dict with amount, asset, and extra metadata
98
+ containing EIP-712 domain info.
99
+
100
+ Raises:
101
+ ValueError: If price format is invalid or network is unsupported
102
+ """
103
+ chain_id = self._get_chain_id(network)
104
+
105
+ # Handle dict (already in TokenAmount format)
106
+ if isinstance(price, dict):
107
+ return {
108
+ "amount": str(price.get("amount", "0")),
109
+ "asset": price.get("asset", ""),
110
+ "extra": price.get("extra", {}),
111
+ }
112
+
113
+ # Get chain ID as string for token lookups
114
+ chain_id_str = str(chain_id)
115
+
116
+ # Get default token for the network
117
+ # Try USDT0 first, fall back to USDT, then USDC
118
+ try:
119
+ asset_address = get_default_token_address(chain_id_str, "usdt0")
120
+ except (ValueError, KeyError):
121
+ try:
122
+ asset_address = get_default_token_address(chain_id_str, "usdt")
123
+ except (ValueError, KeyError):
124
+ try:
125
+ asset_address = get_default_token_address(chain_id_str, "usdc")
126
+ except (ValueError, KeyError):
127
+ raise ValueError(
128
+ f"Unknown network: no known token for chain {chain_id_str}"
129
+ )
130
+
131
+ decimals = get_token_decimals(chain_id_str, asset_address)
132
+
133
+ # Parse price string/number
134
+ if isinstance(price, str):
135
+ if price.startswith("$"):
136
+ price = price[1:]
137
+ amount_decimal = Decimal(price)
138
+ else:
139
+ amount_decimal = Decimal(str(price))
140
+
141
+ # Convert to atomic units
142
+ atomic_amount = int(amount_decimal * Decimal(10**decimals))
143
+
144
+ # Get EIP-712 domain info for Permit signing
145
+ extra: Dict[str, Any] = {
146
+ "name": get_token_name(chain_id_str, asset_address),
147
+ "version": get_token_version(chain_id_str, asset_address),
148
+ "decimals": decimals,
149
+ }
150
+
151
+ # Include router address if configured
152
+ if self._router_address:
153
+ extra["routerAddress"] = self._router_address
154
+
155
+ return {
156
+ "amount": str(atomic_amount),
157
+ "asset": asset_address,
158
+ "extra": extra,
159
+ }
160
+
161
+ async def enhance_requirements(
162
+ self,
163
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
164
+ supported_kind: SupportedKindDict,
165
+ facilitator_extensions: List[str],
166
+ ) -> Union[PaymentRequirementsV2, Dict[str, Any]]:
167
+ """Enhance payment requirements with EVM Permit-specific metadata.
168
+
169
+ Adds EIP-712 domain information (token name, version) and optionally
170
+ the router/spender address to the extra field so clients can properly
171
+ sign the EIP-2612 Permit authorization.
172
+
173
+ Args:
174
+ requirements: Base payment requirements (with maxAmount/amount set)
175
+ supported_kind: Matched SupportedKind from facilitator's /supported
176
+ facilitator_extensions: Extensions supported by facilitator
177
+
178
+ Returns:
179
+ Enhanced requirements with EIP-712 Permit domain info in extra
180
+ """
181
+ # Convert to dict for modification
182
+ if hasattr(requirements, "model_dump"):
183
+ req = requirements.model_dump(by_alias=True)
184
+ else:
185
+ req = dict(requirements)
186
+
187
+ network = req.get("network", "")
188
+ asset = req.get("asset", "")
189
+
190
+ # Get chain ID as string
191
+ chain_id = str(self._get_chain_id(network))
192
+
193
+ # Ensure extra exists
194
+ if "extra" not in req or req["extra"] is None:
195
+ req["extra"] = {}
196
+
197
+ # Add EIP-712 domain info if not present
198
+ if "name" not in req["extra"]:
199
+ try:
200
+ req["extra"]["name"] = get_token_name(chain_id, asset)
201
+ except (ValueError, KeyError):
202
+ # If token not found in known tokens, use a sensible default
203
+ req["extra"]["name"] = "TetherToken"
204
+
205
+ if "version" not in req["extra"]:
206
+ try:
207
+ req["extra"]["version"] = get_token_version(chain_id, asset)
208
+ except (ValueError, KeyError):
209
+ req["extra"]["version"] = "1"
210
+
211
+ # Add router address if configured and not already present
212
+ if self._router_address and "routerAddress" not in req["extra"]:
213
+ req["extra"]["routerAddress"] = self._router_address
214
+
215
+ # Add facilitator extra data if available
216
+ if supported_kind.get("extra"):
217
+ for key, value in supported_kind["extra"].items():
218
+ if key not in req["extra"]:
219
+ req["extra"][key] = value
220
+
221
+ return req
222
+
223
+ def _get_chain_id(self, network: str) -> int:
224
+ """Get chain ID from network identifier.
225
+
226
+ Args:
227
+ network: Network identifier (CAIP-2 or legacy format)
228
+
229
+ Returns:
230
+ Chain ID as integer
231
+
232
+ Raises:
233
+ ValueError: If the network format is unrecognized
234
+ """
235
+ # Handle CAIP-2 format (eip155:8453)
236
+ if network.startswith("eip155:"):
237
+ return int(network.split(":")[1])
238
+
239
+ # Handle legacy format
240
+ try:
241
+ return int(get_chain_id(network))
242
+ except (KeyError, ValueError):
243
+ raise ValueError(f"Unknown network: {network}")
@@ -98,7 +98,9 @@ class UptoEIP2612Payload(BaseModel):
98
98
  class UptoCompactPayload(BaseModel):
99
99
  """Alternative payload with combined signature."""
100
100
 
101
- signature: str = Field(description="Combined EIP-2612 permit signature (65 bytes hex)")
101
+ signature: str = Field(
102
+ description="Combined EIP-2612 permit signature (65 bytes hex)"
103
+ )
102
104
  authorization: PermitAuthorization = Field(description="Permit parameters")
103
105
  payment_nonce: str = Field(
104
106
  alias="paymentNonce",
@@ -25,9 +25,13 @@ from t402.types import (
25
25
 
26
26
 
27
27
  # Type aliases for clarity
28
- Price = Union[str, int, float, Dict[str, Any]] # e.g., "$0.10", 0.10, {"amount": "100000", "asset": "..."}
28
+ Price = Union[
29
+ str, int, float, Dict[str, Any]
30
+ ] # e.g., "$0.10", 0.10, {"amount": "100000", "asset": "..."}
29
31
  AssetAmount = Dict[str, Any] # {"amount": str, "asset": str, "extra"?: dict}
30
- SupportedKindDict = Dict[str, Any] # {"t402Version": int, "scheme": str, "network": str, "extra"?: dict}
32
+ SupportedKindDict = Dict[
33
+ str, Any
34
+ ] # {"t402Version": int, "scheme": str, "network": str, "extra"?: dict}
31
35
 
32
36
 
33
37
  @runtime_checkable
@@ -0,0 +1,112 @@
1
+ """NEAR Blockchain Payment Schemes.
2
+
3
+ This package provides payment scheme implementations for the NEAR blockchain.
4
+
5
+ Supported schemes:
6
+ - exact-direct: Client executes NEP-141 ft_transfer, tx hash used as proof.
7
+
8
+ Usage:
9
+ ```python
10
+ from t402.schemes.near import (
11
+ # Client
12
+ ExactDirectNearClientScheme,
13
+ ExactDirectNearClientConfig,
14
+ # Server
15
+ ExactDirectNearServerScheme,
16
+ ExactDirectNearServerConfig,
17
+ # Facilitator
18
+ ExactDirectNearFacilitatorScheme,
19
+ ExactDirectNearFacilitatorConfig,
20
+ # Signer protocols
21
+ ClientNearSigner,
22
+ FacilitatorNearSigner,
23
+ # Constants
24
+ SCHEME_EXACT_DIRECT,
25
+ NEAR_MAINNET,
26
+ NEAR_TESTNET,
27
+ )
28
+ ```
29
+ """
30
+
31
+ from t402.schemes.near.exact_direct import (
32
+ ExactDirectNearClientScheme,
33
+ ExactDirectNearServerScheme,
34
+ ExactDirectNearFacilitatorScheme,
35
+ )
36
+ from t402.schemes.near.exact_direct.client import ExactDirectNearClientConfig
37
+ from t402.schemes.near.exact_direct.server import ExactDirectNearServerConfig
38
+ from t402.schemes.near.exact_direct.facilitator import ExactDirectNearFacilitatorConfig
39
+ from t402.schemes.near.types import (
40
+ ClientNearSigner,
41
+ FacilitatorNearSigner,
42
+ ExactDirectPayload,
43
+ FtTransferArgs,
44
+ is_valid_account_id,
45
+ )
46
+ from t402.schemes.near.constants import (
47
+ SCHEME_EXACT_DIRECT,
48
+ NEAR_MAINNET,
49
+ NEAR_TESTNET,
50
+ NEAR_MAINNET_RPC,
51
+ NEAR_TESTNET_RPC,
52
+ CAIP_FAMILY,
53
+ DEFAULT_GAS,
54
+ DEFAULT_GAS_INT,
55
+ STORAGE_DEPOSIT,
56
+ FUNCTION_FT_TRANSFER,
57
+ USDT_MAINNET,
58
+ USDT_TESTNET,
59
+ USDC_MAINNET,
60
+ USDC_TESTNET,
61
+ TokenInfo,
62
+ NetworkConfig,
63
+ get_network_config,
64
+ get_token_info,
65
+ get_token_by_contract,
66
+ is_valid_network,
67
+ get_supported_networks,
68
+ )
69
+
70
+ __all__ = [
71
+ # Scheme implementations
72
+ "ExactDirectNearClientScheme",
73
+ "ExactDirectNearServerScheme",
74
+ "ExactDirectNearFacilitatorScheme",
75
+ # Configurations
76
+ "ExactDirectNearClientConfig",
77
+ "ExactDirectNearServerConfig",
78
+ "ExactDirectNearFacilitatorConfig",
79
+ # Signer protocols
80
+ "ClientNearSigner",
81
+ "FacilitatorNearSigner",
82
+ # Payload types
83
+ "ExactDirectPayload",
84
+ "FtTransferArgs",
85
+ # Validation
86
+ "is_valid_account_id",
87
+ "is_valid_network",
88
+ # Constants
89
+ "SCHEME_EXACT_DIRECT",
90
+ "NEAR_MAINNET",
91
+ "NEAR_TESTNET",
92
+ "NEAR_MAINNET_RPC",
93
+ "NEAR_TESTNET_RPC",
94
+ "CAIP_FAMILY",
95
+ "DEFAULT_GAS",
96
+ "DEFAULT_GAS_INT",
97
+ "STORAGE_DEPOSIT",
98
+ "FUNCTION_FT_TRANSFER",
99
+ # Token definitions
100
+ "USDT_MAINNET",
101
+ "USDT_TESTNET",
102
+ "USDC_MAINNET",
103
+ "USDC_TESTNET",
104
+ # Data classes
105
+ "TokenInfo",
106
+ "NetworkConfig",
107
+ # Lookup functions
108
+ "get_network_config",
109
+ "get_token_info",
110
+ "get_token_by_contract",
111
+ "get_supported_networks",
112
+ ]
@@ -0,0 +1,189 @@
1
+ """NEAR blockchain constants for the T402 protocol.
2
+
3
+ This module contains network configurations, token contract addresses,
4
+ and other constants used by the NEAR exact-direct payment scheme.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Dict, Optional
10
+
11
+
12
+ # Scheme identifier
13
+ SCHEME_EXACT_DIRECT = "exact-direct"
14
+
15
+ # CAIP-2 network identifiers
16
+ NEAR_MAINNET = "near:mainnet"
17
+ NEAR_TESTNET = "near:testnet"
18
+
19
+ # RPC endpoints
20
+ NEAR_MAINNET_RPC = "https://rpc.mainnet.near.org"
21
+ NEAR_TESTNET_RPC = "https://rpc.testnet.near.org"
22
+
23
+ # Default gas for ft_transfer (30 TGas)
24
+ DEFAULT_GAS = "30000000000000"
25
+ DEFAULT_GAS_INT = 30_000_000_000_000
26
+
27
+ # Storage deposit required (1 yoctoNEAR) for ft_transfer
28
+ STORAGE_DEPOSIT = "1"
29
+
30
+ # NEP-141 function names
31
+ FUNCTION_FT_TRANSFER = "ft_transfer"
32
+ FUNCTION_FT_BALANCE_OF = "ft_balance_of"
33
+ FUNCTION_STORAGE_BALANCE = "storage_balance_of"
34
+
35
+ # CAIP family pattern
36
+ CAIP_FAMILY = "near:*"
37
+
38
+
39
+ class TokenInfo:
40
+ """Contains information about a NEAR fungible token.
41
+
42
+ Attributes:
43
+ contract_id: The NEAR account ID of the token contract.
44
+ symbol: The token symbol (e.g., "USDT").
45
+ decimals: The number of decimal places for the token.
46
+ """
47
+
48
+ def __init__(self, contract_id: str, symbol: str, decimals: int) -> None:
49
+ self.contract_id = contract_id
50
+ self.symbol = symbol
51
+ self.decimals = decimals
52
+
53
+ def __repr__(self) -> str:
54
+ return f"TokenInfo(contract_id={self.contract_id!r}, symbol={self.symbol!r}, decimals={self.decimals})"
55
+
56
+
57
+ class NetworkConfig:
58
+ """Network-specific configuration for NEAR.
59
+
60
+ Attributes:
61
+ network_id: The short network identifier (e.g., "mainnet").
62
+ rpc_url: The RPC endpoint URL.
63
+ default_token: The default token for this network.
64
+ """
65
+
66
+ def __init__(self, network_id: str, rpc_url: str, default_token: TokenInfo) -> None:
67
+ self.network_id = network_id
68
+ self.rpc_url = rpc_url
69
+ self.default_token = default_token
70
+
71
+
72
+ # Token definitions
73
+ USDT_MAINNET = TokenInfo(
74
+ contract_id="usdt.tether-token.near",
75
+ symbol="USDT",
76
+ decimals=6,
77
+ )
78
+
79
+ USDT_TESTNET = TokenInfo(
80
+ contract_id="usdt.fakes.testnet",
81
+ symbol="USDT",
82
+ decimals=6,
83
+ )
84
+
85
+ USDC_MAINNET = TokenInfo(
86
+ contract_id="17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
87
+ symbol="USDC",
88
+ decimals=6,
89
+ )
90
+
91
+ USDC_TESTNET = TokenInfo(
92
+ contract_id="usdc.fakes.testnet",
93
+ symbol="USDC",
94
+ decimals=6,
95
+ )
96
+
97
+ # Network configurations
98
+ NETWORK_CONFIGS: Dict[str, NetworkConfig] = {
99
+ NEAR_MAINNET: NetworkConfig(
100
+ network_id="mainnet",
101
+ rpc_url=NEAR_MAINNET_RPC,
102
+ default_token=USDT_MAINNET,
103
+ ),
104
+ NEAR_TESTNET: NetworkConfig(
105
+ network_id="testnet",
106
+ rpc_url=NEAR_TESTNET_RPC,
107
+ default_token=USDT_TESTNET,
108
+ ),
109
+ }
110
+
111
+ # Token registry: network -> symbol -> TokenInfo
112
+ TOKEN_REGISTRY: Dict[str, Dict[str, TokenInfo]] = {
113
+ NEAR_MAINNET: {
114
+ "USDT": USDT_MAINNET,
115
+ "USDC": USDC_MAINNET,
116
+ },
117
+ NEAR_TESTNET: {
118
+ "USDT": USDT_TESTNET,
119
+ "USDC": USDC_TESTNET,
120
+ },
121
+ }
122
+
123
+
124
+ def get_network_config(network: str) -> Optional[NetworkConfig]:
125
+ """Get the configuration for a NEAR network.
126
+
127
+ Args:
128
+ network: The CAIP-2 network identifier (e.g., "near:mainnet").
129
+
130
+ Returns:
131
+ NetworkConfig if the network is supported, None otherwise.
132
+ """
133
+ return NETWORK_CONFIGS.get(network)
134
+
135
+
136
+ def is_valid_network(network: str) -> bool:
137
+ """Check if a network identifier is a supported NEAR network.
138
+
139
+ Args:
140
+ network: The CAIP-2 network identifier.
141
+
142
+ Returns:
143
+ True if the network is supported.
144
+ """
145
+ return network in NETWORK_CONFIGS
146
+
147
+
148
+ def get_token_info(network: str, symbol: str) -> Optional[TokenInfo]:
149
+ """Get token info for a network and symbol.
150
+
151
+ Args:
152
+ network: The CAIP-2 network identifier.
153
+ symbol: The token symbol (e.g., "USDT").
154
+
155
+ Returns:
156
+ TokenInfo if found, None otherwise.
157
+ """
158
+ tokens = TOKEN_REGISTRY.get(network)
159
+ if tokens is None:
160
+ return None
161
+ return tokens.get(symbol)
162
+
163
+
164
+ def get_token_by_contract(network: str, contract_id: str) -> Optional[TokenInfo]:
165
+ """Get token info by contract address.
166
+
167
+ Args:
168
+ network: The CAIP-2 network identifier.
169
+ contract_id: The token contract account ID.
170
+
171
+ Returns:
172
+ TokenInfo if found, None otherwise.
173
+ """
174
+ tokens = TOKEN_REGISTRY.get(network)
175
+ if tokens is None:
176
+ return None
177
+ for token in tokens.values():
178
+ if token.contract_id == contract_id:
179
+ return token
180
+ return None
181
+
182
+
183
+ def get_supported_networks() -> list:
184
+ """Get a list of supported NEAR network identifiers.
185
+
186
+ Returns:
187
+ List of CAIP-2 network identifier strings.
188
+ """
189
+ return [NEAR_MAINNET, NEAR_TESTNET]
@@ -0,0 +1,21 @@
1
+ """NEAR Exact-Direct Payment Scheme.
2
+
3
+ This package provides the exact-direct payment scheme implementation for NEAR.
4
+ In this scheme, the client executes the NEP-141 ft_transfer on-chain directly,
5
+ and the transaction hash is used as proof of payment.
6
+
7
+ Components:
8
+ - ExactDirectNearClientScheme: Client-side (executes transfer, returns tx hash)
9
+ - ExactDirectNearServerScheme: Server-side (parses prices, enhances requirements)
10
+ - ExactDirectNearFacilitatorScheme: Facilitator-side (verifies tx, marks settled)
11
+ """
12
+
13
+ from t402.schemes.near.exact_direct.client import ExactDirectNearClientScheme
14
+ from t402.schemes.near.exact_direct.server import ExactDirectNearServerScheme
15
+ from t402.schemes.near.exact_direct.facilitator import ExactDirectNearFacilitatorScheme
16
+
17
+ __all__ = [
18
+ "ExactDirectNearClientScheme",
19
+ "ExactDirectNearServerScheme",
20
+ "ExactDirectNearFacilitatorScheme",
21
+ ]