t402 1.9.0__py3-none-any.whl → 1.10.0__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 (134) hide show
  1. t402/__init__.py +2 -1
  2. t402/a2a/__init__.py +73 -0
  3. t402/a2a/helpers.py +158 -0
  4. t402/a2a/types.py +145 -0
  5. t402/bridge/client.py +13 -5
  6. t402/bridge/constants.py +4 -2
  7. t402/bridge/router.py +1 -1
  8. t402/bridge/scan.py +3 -1
  9. t402/chains.py +268 -1
  10. t402/cli.py +31 -9
  11. t402/common.py +2 -0
  12. t402/cosmos_paywall_template.py +2 -0
  13. t402/django/__init__.py +42 -0
  14. t402/django/middleware.py +596 -0
  15. t402/encoding.py +9 -3
  16. t402/erc4337/accounts.py +56 -51
  17. t402/erc4337/bundlers.py +105 -99
  18. t402/erc4337/paymasters.py +100 -109
  19. t402/erc4337/types.py +39 -26
  20. t402/errors.py +213 -0
  21. t402/evm_paywall_template.py +1 -1
  22. t402/facilitator.py +125 -0
  23. t402/fastapi/middleware.py +1 -3
  24. t402/mcp/constants.py +3 -6
  25. t402/mcp/server.py +501 -84
  26. t402/mcp/web3_utils.py +493 -0
  27. t402/multisig/__init__.py +120 -0
  28. t402/multisig/constants.py +54 -0
  29. t402/multisig/safe.py +441 -0
  30. t402/multisig/signature.py +228 -0
  31. t402/multisig/transaction.py +238 -0
  32. t402/multisig/types.py +108 -0
  33. t402/multisig/utils.py +77 -0
  34. t402/near_paywall_template.py +2 -0
  35. t402/networks.py +34 -1
  36. t402/paywall.py +1 -3
  37. t402/schemes/__init__.py +143 -0
  38. t402/schemes/aptos/__init__.py +70 -0
  39. t402/schemes/aptos/constants.py +349 -0
  40. t402/schemes/aptos/exact_direct/__init__.py +44 -0
  41. t402/schemes/aptos/exact_direct/client.py +202 -0
  42. t402/schemes/aptos/exact_direct/facilitator.py +426 -0
  43. t402/schemes/aptos/exact_direct/server.py +272 -0
  44. t402/schemes/aptos/types.py +237 -0
  45. t402/schemes/cosmos/__init__.py +114 -0
  46. t402/schemes/cosmos/constants.py +211 -0
  47. t402/schemes/cosmos/exact_direct/__init__.py +21 -0
  48. t402/schemes/cosmos/exact_direct/client.py +198 -0
  49. t402/schemes/cosmos/exact_direct/facilitator.py +493 -0
  50. t402/schemes/cosmos/exact_direct/server.py +315 -0
  51. t402/schemes/cosmos/types.py +501 -0
  52. t402/schemes/evm/__init__.py +46 -1
  53. t402/schemes/evm/exact/__init__.py +11 -0
  54. t402/schemes/evm/exact/client.py +3 -1
  55. t402/schemes/evm/exact/facilitator.py +894 -0
  56. t402/schemes/evm/exact/server.py +1 -1
  57. t402/schemes/evm/exact_legacy/__init__.py +38 -0
  58. t402/schemes/evm/exact_legacy/client.py +291 -0
  59. t402/schemes/evm/exact_legacy/facilitator.py +777 -0
  60. t402/schemes/evm/exact_legacy/server.py +231 -0
  61. t402/schemes/evm/upto/__init__.py +12 -0
  62. t402/schemes/evm/upto/client.py +6 -2
  63. t402/schemes/evm/upto/facilitator.py +625 -0
  64. t402/schemes/evm/upto/server.py +243 -0
  65. t402/schemes/evm/upto/types.py +3 -1
  66. t402/schemes/interfaces.py +6 -2
  67. t402/schemes/near/__init__.py +137 -0
  68. t402/schemes/near/constants.py +189 -0
  69. t402/schemes/near/exact_direct/__init__.py +21 -0
  70. t402/schemes/near/exact_direct/client.py +204 -0
  71. t402/schemes/near/exact_direct/facilitator.py +455 -0
  72. t402/schemes/near/exact_direct/server.py +303 -0
  73. t402/schemes/near/types.py +419 -0
  74. t402/schemes/near/upto/__init__.py +54 -0
  75. t402/schemes/near/upto/types.py +272 -0
  76. t402/schemes/polkadot/__init__.py +72 -0
  77. t402/schemes/polkadot/constants.py +155 -0
  78. t402/schemes/polkadot/exact_direct/__init__.py +43 -0
  79. t402/schemes/polkadot/exact_direct/client.py +235 -0
  80. t402/schemes/polkadot/exact_direct/facilitator.py +428 -0
  81. t402/schemes/polkadot/exact_direct/server.py +292 -0
  82. t402/schemes/polkadot/types.py +385 -0
  83. t402/schemes/registry.py +6 -2
  84. t402/schemes/stacks/__init__.py +68 -0
  85. t402/schemes/stacks/constants.py +122 -0
  86. t402/schemes/stacks/exact_direct/__init__.py +43 -0
  87. t402/schemes/stacks/exact_direct/client.py +222 -0
  88. t402/schemes/stacks/exact_direct/facilitator.py +424 -0
  89. t402/schemes/stacks/exact_direct/server.py +292 -0
  90. t402/schemes/stacks/types.py +380 -0
  91. t402/schemes/svm/__init__.py +44 -0
  92. t402/schemes/svm/exact/__init__.py +35 -0
  93. t402/schemes/svm/exact/client.py +23 -0
  94. t402/schemes/svm/exact/facilitator.py +24 -0
  95. t402/schemes/svm/exact/server.py +20 -0
  96. t402/schemes/svm/upto/__init__.py +23 -0
  97. t402/schemes/svm/upto/types.py +193 -0
  98. t402/schemes/tezos/__init__.py +84 -0
  99. t402/schemes/tezos/constants.py +372 -0
  100. t402/schemes/tezos/exact_direct/__init__.py +22 -0
  101. t402/schemes/tezos/exact_direct/client.py +226 -0
  102. t402/schemes/tezos/exact_direct/facilitator.py +491 -0
  103. t402/schemes/tezos/exact_direct/server.py +277 -0
  104. t402/schemes/tezos/types.py +220 -0
  105. t402/schemes/ton/__init__.py +24 -2
  106. t402/schemes/ton/exact/__init__.py +7 -0
  107. t402/schemes/ton/exact/facilitator.py +730 -0
  108. t402/schemes/ton/exact/server.py +1 -1
  109. t402/schemes/ton/upto/__init__.py +31 -0
  110. t402/schemes/ton/upto/types.py +215 -0
  111. t402/schemes/tron/__init__.py +28 -2
  112. t402/schemes/tron/exact/__init__.py +9 -0
  113. t402/schemes/tron/exact/facilitator.py +673 -0
  114. t402/schemes/tron/exact/server.py +1 -1
  115. t402/schemes/tron/upto/__init__.py +30 -0
  116. t402/schemes/tron/upto/types.py +213 -0
  117. t402/stacks_paywall_template.py +2 -0
  118. t402/starlette/__init__.py +38 -0
  119. t402/starlette/middleware.py +522 -0
  120. t402/svm.py +45 -11
  121. t402/svm_paywall_template.py +1 -1
  122. t402/ton.py +6 -2
  123. t402/ton_paywall_template.py +1 -192
  124. t402/tron.py +2 -0
  125. t402/tron_paywall_template.py +2 -0
  126. t402/types.py +103 -3
  127. t402/wdk/chains.py +1 -1
  128. t402/wdk/errors.py +15 -5
  129. t402/wdk/signer.py +11 -2
  130. {t402-1.9.0.dist-info → t402-1.10.0.dist-info}/METADATA +42 -1
  131. t402-1.10.0.dist-info/RECORD +156 -0
  132. t402-1.9.0.dist-info/RECORD +0 -72
  133. {t402-1.9.0.dist-info → t402-1.10.0.dist-info}/WHEEL +0 -0
  134. {t402-1.9.0.dist-info → t402-1.10.0.dist-info}/entry_points.txt +0 -0
t402/networks.py CHANGED
@@ -2,7 +2,16 @@ from typing import Literal, Union, get_args
2
2
 
3
3
 
4
4
  # EVM Networks
5
- EVMNetworks = Literal["base", "base-sepolia", "avalanche-fuji", "avalanche"]
5
+ EVMNetworks = Literal[
6
+ # Standard networks
7
+ "base", "base-sepolia", "avalanche-fuji", "avalanche",
8
+ # Core USDT0 Networks
9
+ "ethereum", "arbitrum", "optimism", "polygon", "ink", "berachain", "unichain",
10
+ # Phase 1: High Priority USDT0 Networks
11
+ "mantle", "plasma", "sei", "conflux", "monad",
12
+ # Phase 2: Medium Priority USDT0 Networks
13
+ "flare", "rootstock", "xlayer", "stable", "hyperevm", "megaeth", "corn",
14
+ ]
6
15
 
7
16
  # TON Networks (CAIP-2 format)
8
17
  TONNetworks = Literal["ton:mainnet", "ton:testnet"]
@@ -32,11 +41,35 @@ def get_all_supported_networks() -> tuple[str, ...]:
32
41
  svm = get_args(SVMNetworks)
33
42
  return evm + ton + tron + svm
34
43
 
44
+
35
45
  EVM_NETWORK_TO_CHAIN_ID = {
46
+ # Standard networks
36
47
  "base-sepolia": 84532,
37
48
  "base": 8453,
38
49
  "avalanche-fuji": 43113,
39
50
  "avalanche": 43114,
51
+ # Core USDT0 Networks
52
+ "ethereum": 1,
53
+ "arbitrum": 42161,
54
+ "optimism": 10,
55
+ "polygon": 137,
56
+ "ink": 57073,
57
+ "berachain": 80094,
58
+ "unichain": 130,
59
+ # Phase 1: High Priority USDT0 Networks
60
+ "mantle": 5000,
61
+ "plasma": 9745,
62
+ "sei": 1329,
63
+ "conflux": 1030,
64
+ "monad": 143,
65
+ # Phase 2: Medium Priority USDT0 Networks
66
+ "flare": 14,
67
+ "rootstock": 30,
68
+ "xlayer": 196,
69
+ "stable": 988,
70
+ "hyperevm": 999,
71
+ "megaeth": 4326,
72
+ "corn": 21000000,
40
73
  }
41
74
 
42
75
  # TON Network configurations
t402/paywall.py CHANGED
@@ -127,6 +127,4 @@ def get_paywall_html(
127
127
  raise ValueError("payment_requirements cannot be empty")
128
128
  network = payment_requirements[0].network
129
129
  template = get_paywall_template(network)
130
- return inject_payment_data(
131
- template, error, payment_requirements, paywall_config
132
- )
130
+ return inject_payment_data(template, error, payment_requirements, paywall_config)
t402/schemes/__init__.py CHANGED
@@ -70,9 +70,15 @@ from t402.schemes.registry import (
70
70
  from t402.schemes.evm import (
71
71
  ExactEvmClientScheme,
72
72
  ExactEvmServerScheme,
73
+ ExactEvmFacilitatorScheme,
74
+ FacilitatorEvmSigner,
75
+ EvmVerifyResult,
76
+ EvmTransactionConfirmation,
73
77
  EvmSigner,
74
78
  # Upto EVM
75
79
  UptoEvmClientScheme,
80
+ UptoEvmServerScheme,
81
+ UptoEvmFacilitatorScheme,
76
82
  PermitSignature,
77
83
  PermitAuthorization,
78
84
  UptoEIP2612Payload,
@@ -98,14 +104,90 @@ from t402.schemes.upto import (
98
104
  from t402.schemes.ton import (
99
105
  ExactTonClientScheme,
100
106
  ExactTonServerScheme,
107
+ ExactTonFacilitatorScheme,
101
108
  TonSigner,
109
+ FacilitatorTonSigner,
102
110
  )
103
111
 
104
112
  # TRON Schemes
105
113
  from t402.schemes.tron import (
106
114
  ExactTronClientScheme,
107
115
  ExactTronServerScheme,
116
+ ExactTronFacilitatorScheme,
117
+ ExactTronFacilitatorConfig,
108
118
  TronSigner,
119
+ FacilitatorTronSigner,
120
+ )
121
+
122
+ # SVM Schemes
123
+ from t402.schemes.svm import (
124
+ ExactSvmClientScheme,
125
+ ExactSvmServerScheme,
126
+ ExactSvmFacilitatorScheme,
127
+ ClientSvmSigner as SvmClientSigner,
128
+ FacilitatorSvmSigner as SvmFacilitatorSigner,
129
+ SCHEME_EXACT as SVM_SCHEME_EXACT,
130
+ )
131
+
132
+ # NEAR Schemes
133
+ from t402.schemes.near import (
134
+ ExactDirectNearClientScheme,
135
+ ExactDirectNearServerScheme,
136
+ ExactDirectNearFacilitatorScheme,
137
+ ClientNearSigner,
138
+ FacilitatorNearSigner,
139
+ SCHEME_EXACT_DIRECT as NEAR_SCHEME_EXACT_DIRECT,
140
+ )
141
+
142
+ # Aptos Schemes
143
+ from t402.schemes.aptos import (
144
+ ExactDirectAptosClientScheme,
145
+ ExactDirectAptosServerScheme,
146
+ ExactDirectAptosFacilitatorScheme,
147
+ ClientAptosSigner,
148
+ FacilitatorAptosSigner,
149
+ SCHEME_EXACT_DIRECT,
150
+ )
151
+
152
+ # Polkadot Schemes
153
+ from t402.schemes.polkadot import (
154
+ ExactDirectPolkadotClientScheme,
155
+ ExactDirectPolkadotServerScheme,
156
+ ExactDirectPolkadotFacilitatorScheme,
157
+ ClientPolkadotSigner,
158
+ FacilitatorPolkadotSigner,
159
+ SCHEME_EXACT_DIRECT as POLKADOT_SCHEME_EXACT_DIRECT,
160
+ )
161
+
162
+ # Tezos Schemes
163
+ from t402.schemes.tezos import (
164
+ ExactDirectTezosClient,
165
+ ExactDirectTezosServer,
166
+ ExactDirectTezosFacilitator,
167
+ ClientTezosSigner,
168
+ FacilitatorTezosSigner,
169
+ SCHEME_EXACT_DIRECT as TEZOS_SCHEME_EXACT_DIRECT,
170
+ )
171
+
172
+ # Stacks Schemes
173
+ from t402.schemes.stacks import (
174
+ ExactDirectStacksClientScheme,
175
+ ExactDirectStacksServerScheme,
176
+ ExactDirectStacksFacilitatorScheme,
177
+ ClientStacksSigner,
178
+ FacilitatorStacksSigner,
179
+ SCHEME_EXACT_DIRECT as STACKS_SCHEME_EXACT_DIRECT,
180
+ )
181
+
182
+ # Cosmos Schemes
183
+ from t402.schemes.cosmos import (
184
+ ExactDirectCosmosClientScheme,
185
+ ExactDirectCosmosServerScheme,
186
+ ExactDirectCosmosFacilitatorScheme,
187
+ ExactDirectCosmosFacilitatorConfig,
188
+ ClientCosmosSigner,
189
+ FacilitatorCosmosSigner,
190
+ SCHEME_EXACT_DIRECT as COSMOS_SCHEME_EXACT_DIRECT,
109
191
  )
110
192
 
111
193
  __all__ = [
@@ -134,9 +216,15 @@ __all__ = [
134
216
  # EVM Exact Schemes
135
217
  "ExactEvmClientScheme",
136
218
  "ExactEvmServerScheme",
219
+ "ExactEvmFacilitatorScheme",
220
+ "FacilitatorEvmSigner",
221
+ "EvmVerifyResult",
222
+ "EvmTransactionConfirmation",
137
223
  "EvmSigner",
138
224
  # EVM Upto Schemes
139
225
  "UptoEvmClientScheme",
226
+ "UptoEvmServerScheme",
227
+ "UptoEvmFacilitatorScheme",
140
228
  "PermitSignature",
141
229
  "PermitAuthorization",
142
230
  "UptoEIP2612Payload",
@@ -156,9 +244,64 @@ __all__ = [
156
244
  # TON Schemes
157
245
  "ExactTonClientScheme",
158
246
  "ExactTonServerScheme",
247
+ "ExactTonFacilitatorScheme",
159
248
  "TonSigner",
249
+ "FacilitatorTonSigner",
160
250
  # TRON Schemes
161
251
  "ExactTronClientScheme",
162
252
  "ExactTronServerScheme",
253
+ "ExactTronFacilitatorScheme",
254
+ "ExactTronFacilitatorConfig",
163
255
  "TronSigner",
256
+ "FacilitatorTronSigner",
257
+ # SVM Schemes
258
+ "ExactSvmClientScheme",
259
+ "ExactSvmServerScheme",
260
+ "ExactSvmFacilitatorScheme",
261
+ "SvmClientSigner",
262
+ "SvmFacilitatorSigner",
263
+ "SVM_SCHEME_EXACT",
264
+ # NEAR Schemes
265
+ "ExactDirectNearClientScheme",
266
+ "ExactDirectNearServerScheme",
267
+ "ExactDirectNearFacilitatorScheme",
268
+ "ClientNearSigner",
269
+ "FacilitatorNearSigner",
270
+ "NEAR_SCHEME_EXACT_DIRECT",
271
+ # Aptos Schemes
272
+ "ExactDirectAptosClientScheme",
273
+ "ExactDirectAptosServerScheme",
274
+ "ExactDirectAptosFacilitatorScheme",
275
+ "ClientAptosSigner",
276
+ "FacilitatorAptosSigner",
277
+ "SCHEME_EXACT_DIRECT",
278
+ # Polkadot Schemes
279
+ "ExactDirectPolkadotClientScheme",
280
+ "ExactDirectPolkadotServerScheme",
281
+ "ExactDirectPolkadotFacilitatorScheme",
282
+ "ClientPolkadotSigner",
283
+ "FacilitatorPolkadotSigner",
284
+ "POLKADOT_SCHEME_EXACT_DIRECT",
285
+ # Tezos Schemes
286
+ "ExactDirectTezosClient",
287
+ "ExactDirectTezosServer",
288
+ "ExactDirectTezosFacilitator",
289
+ "ClientTezosSigner",
290
+ "FacilitatorTezosSigner",
291
+ "TEZOS_SCHEME_EXACT_DIRECT",
292
+ # Stacks Schemes
293
+ "ExactDirectStacksClientScheme",
294
+ "ExactDirectStacksServerScheme",
295
+ "ExactDirectStacksFacilitatorScheme",
296
+ "ClientStacksSigner",
297
+ "FacilitatorStacksSigner",
298
+ "STACKS_SCHEME_EXACT_DIRECT",
299
+ # Cosmos Schemes
300
+ "ExactDirectCosmosClientScheme",
301
+ "ExactDirectCosmosServerScheme",
302
+ "ExactDirectCosmosFacilitatorScheme",
303
+ "ExactDirectCosmosFacilitatorConfig",
304
+ "ClientCosmosSigner",
305
+ "FacilitatorCosmosSigner",
306
+ "COSMOS_SCHEME_EXACT_DIRECT",
164
307
  ]
@@ -0,0 +1,70 @@
1
+ """Aptos Blockchain Payment Schemes.
2
+
3
+ This package provides payment scheme implementations for the Aptos blockchain.
4
+
5
+ Supported schemes:
6
+ - exact-direct: Fungible Asset transfers via 0x1::primary_fungible_store::transfer
7
+ """
8
+
9
+ from t402.schemes.aptos.exact_direct import (
10
+ ExactDirectAptosClientScheme,
11
+ ExactDirectAptosServerScheme,
12
+ ExactDirectAptosFacilitatorScheme,
13
+ ClientAptosSigner,
14
+ FacilitatorAptosSigner,
15
+ ExactDirectPayload,
16
+ SCHEME_EXACT_DIRECT,
17
+ )
18
+ from t402.schemes.aptos.constants import (
19
+ APTOS_MAINNET,
20
+ APTOS_TESTNET,
21
+ APTOS_DEVNET,
22
+ CAIP_FAMILY,
23
+ USDT_MAINNET_METADATA,
24
+ USDC_MAINNET_METADATA,
25
+ FA_TRANSFER_FUNCTION,
26
+ DEFAULT_DECIMALS,
27
+ is_valid_address,
28
+ is_valid_tx_hash,
29
+ is_valid_network,
30
+ compare_addresses,
31
+ normalize_address,
32
+ parse_amount,
33
+ format_amount,
34
+ get_network_config,
35
+ get_token_info,
36
+ get_token_by_address,
37
+ )
38
+
39
+ __all__ = [
40
+ # Exact-Direct scheme
41
+ "ExactDirectAptosClientScheme",
42
+ "ExactDirectAptosServerScheme",
43
+ "ExactDirectAptosFacilitatorScheme",
44
+ # Signer protocols
45
+ "ClientAptosSigner",
46
+ "FacilitatorAptosSigner",
47
+ # Types
48
+ "ExactDirectPayload",
49
+ # Constants
50
+ "SCHEME_EXACT_DIRECT",
51
+ "APTOS_MAINNET",
52
+ "APTOS_TESTNET",
53
+ "APTOS_DEVNET",
54
+ "CAIP_FAMILY",
55
+ "USDT_MAINNET_METADATA",
56
+ "USDC_MAINNET_METADATA",
57
+ "FA_TRANSFER_FUNCTION",
58
+ "DEFAULT_DECIMALS",
59
+ # Utility functions
60
+ "is_valid_address",
61
+ "is_valid_tx_hash",
62
+ "is_valid_network",
63
+ "compare_addresses",
64
+ "normalize_address",
65
+ "parse_amount",
66
+ "format_amount",
67
+ "get_network_config",
68
+ "get_token_info",
69
+ "get_token_by_address",
70
+ ]
@@ -0,0 +1,349 @@
1
+ """Aptos Network Constants and Token Registry.
2
+
3
+ This module defines constants for Aptos blockchain networks, token metadata
4
+ addresses, and network configurations used by the exact-direct payment scheme.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Dict, Optional
10
+
11
+ # Scheme identifier
12
+ SCHEME_EXACT_DIRECT = "exact-direct"
13
+
14
+ # CAIP-2 family pattern
15
+ CAIP_FAMILY = "aptos:*"
16
+
17
+ # CAIP-2 network identifiers
18
+ APTOS_MAINNET = "aptos:1"
19
+ APTOS_TESTNET = "aptos:2"
20
+ APTOS_DEVNET = "aptos:149"
21
+
22
+ # RPC endpoints
23
+ APTOS_MAINNET_RPC = "https://fullnode.mainnet.aptoslabs.com/v1"
24
+ APTOS_TESTNET_RPC = "https://fullnode.testnet.aptoslabs.com/v1"
25
+ APTOS_DEVNET_RPC = "https://fullnode.devnet.aptoslabs.com/v1"
26
+
27
+ # Fungible Asset transfer function
28
+ FA_TRANSFER_FUNCTION = "0x1::primary_fungible_store::transfer"
29
+
30
+ # Default decimals for USDT on Aptos
31
+ DEFAULT_DECIMALS = 6
32
+
33
+ # USDT Fungible Asset metadata address on Aptos mainnet
34
+ USDT_MAINNET_METADATA = (
35
+ "0xf73e887a8754f540ee6e1a93bdc6dde2af69fc7ca5de32013e89dd44244473cb"
36
+ )
37
+
38
+ # USDC metadata address on Aptos mainnet
39
+ USDC_MAINNET_METADATA = (
40
+ "0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b"
41
+ )
42
+
43
+
44
+ # Token information structure
45
+ class TokenInfo:
46
+ """Contains information about an Aptos fungible asset.
47
+
48
+ Attributes:
49
+ metadata_address: The on-chain FA metadata object address.
50
+ symbol: Token ticker symbol (e.g., "USDT").
51
+ name: Human-readable token name (e.g., "Tether USD").
52
+ decimals: Number of decimal places for the token.
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ metadata_address: str,
58
+ symbol: str,
59
+ name: str,
60
+ decimals: int,
61
+ ) -> None:
62
+ self.metadata_address = metadata_address
63
+ self.symbol = symbol
64
+ self.name = name
65
+ self.decimals = decimals
66
+
67
+ def to_dict(self) -> Dict[str, Any]:
68
+ """Convert to dictionary representation."""
69
+ return {
70
+ "metadata_address": self.metadata_address,
71
+ "symbol": self.symbol,
72
+ "name": self.name,
73
+ "decimals": self.decimals,
74
+ }
75
+
76
+
77
+ # Token definitions
78
+ USDT_MAINNET = TokenInfo(
79
+ metadata_address=USDT_MAINNET_METADATA,
80
+ symbol="USDT",
81
+ name="Tether USD",
82
+ decimals=6,
83
+ )
84
+
85
+ USDC_MAINNET = TokenInfo(
86
+ metadata_address=USDC_MAINNET_METADATA,
87
+ symbol="USDC",
88
+ name="USD Coin",
89
+ decimals=6,
90
+ )
91
+
92
+
93
+ # Network configuration
94
+ class NetworkConfig:
95
+ """Network-specific configuration for Aptos.
96
+
97
+ Attributes:
98
+ chain_id: Numeric chain ID.
99
+ rpc_url: Default RPC endpoint URL.
100
+ default_token: Default token for this network.
101
+ """
102
+
103
+ def __init__(
104
+ self,
105
+ chain_id: int,
106
+ rpc_url: str,
107
+ default_token: TokenInfo,
108
+ ) -> None:
109
+ self.chain_id = chain_id
110
+ self.rpc_url = rpc_url
111
+ self.default_token = default_token
112
+
113
+
114
+ # Network configurations registry
115
+ NETWORK_CONFIGS: Dict[str, NetworkConfig] = {
116
+ APTOS_MAINNET: NetworkConfig(
117
+ chain_id=1,
118
+ rpc_url=APTOS_MAINNET_RPC,
119
+ default_token=USDT_MAINNET,
120
+ ),
121
+ APTOS_TESTNET: NetworkConfig(
122
+ chain_id=2,
123
+ rpc_url=APTOS_TESTNET_RPC,
124
+ default_token=USDT_MAINNET,
125
+ ),
126
+ APTOS_DEVNET: NetworkConfig(
127
+ chain_id=149,
128
+ rpc_url=APTOS_DEVNET_RPC,
129
+ default_token=USDT_MAINNET,
130
+ ),
131
+ }
132
+
133
+ # Token registry by network
134
+ TOKEN_REGISTRY: Dict[str, Dict[str, TokenInfo]] = {
135
+ APTOS_MAINNET: {
136
+ "USDT": USDT_MAINNET,
137
+ "USDC": USDC_MAINNET,
138
+ },
139
+ APTOS_TESTNET: {
140
+ "USDT": USDT_MAINNET,
141
+ },
142
+ }
143
+
144
+
145
+ def get_network_config(network: str) -> Optional[NetworkConfig]:
146
+ """Get the configuration for a given network.
147
+
148
+ Args:
149
+ network: CAIP-2 network identifier (e.g., "aptos:1").
150
+
151
+ Returns:
152
+ NetworkConfig if found, None otherwise.
153
+ """
154
+ return NETWORK_CONFIGS.get(network)
155
+
156
+
157
+ def get_token_info(network: str, symbol: str) -> Optional[TokenInfo]:
158
+ """Get token info for a network and symbol.
159
+
160
+ Args:
161
+ network: CAIP-2 network identifier.
162
+ symbol: Token symbol (e.g., "USDT").
163
+
164
+ Returns:
165
+ TokenInfo if found, None otherwise.
166
+ """
167
+ tokens = TOKEN_REGISTRY.get(network)
168
+ if not tokens:
169
+ return None
170
+ return tokens.get(symbol)
171
+
172
+
173
+ def get_token_by_address(network: str, metadata_address: str) -> Optional[TokenInfo]:
174
+ """Get token info by FA metadata address.
175
+
176
+ Args:
177
+ network: CAIP-2 network identifier.
178
+ metadata_address: The on-chain metadata object address.
179
+
180
+ Returns:
181
+ TokenInfo if found, None otherwise.
182
+ """
183
+ tokens = TOKEN_REGISTRY.get(network)
184
+ if not tokens:
185
+ return None
186
+ normalized = normalize_address(metadata_address)
187
+ for token in tokens.values():
188
+ if normalize_address(token.metadata_address) == normalized:
189
+ return token
190
+ return None
191
+
192
+
193
+ def is_valid_network(network: str) -> bool:
194
+ """Check if a network identifier is supported.
195
+
196
+ Args:
197
+ network: CAIP-2 network identifier.
198
+
199
+ Returns:
200
+ True if the network is known and supported.
201
+ """
202
+ return network in NETWORK_CONFIGS
203
+
204
+
205
+ def is_valid_address(address: str) -> bool:
206
+ """Validate an Aptos address format.
207
+
208
+ Aptos addresses are 0x-prefixed hex strings, up to 64 hex characters.
209
+
210
+ Args:
211
+ address: The address to validate.
212
+
213
+ Returns:
214
+ True if the address is valid.
215
+ """
216
+ if not address:
217
+ return False
218
+ if not address.startswith("0x"):
219
+ return False
220
+ hex_part = address[2:]
221
+ if len(hex_part) == 0 or len(hex_part) > 64:
222
+ return False
223
+ try:
224
+ int(hex_part, 16)
225
+ return True
226
+ except ValueError:
227
+ return False
228
+
229
+
230
+ def is_valid_tx_hash(tx_hash: str) -> bool:
231
+ """Validate an Aptos transaction hash format.
232
+
233
+ Transaction hashes are 0x-prefixed hex strings of exactly 64 hex characters.
234
+
235
+ Args:
236
+ tx_hash: The transaction hash to validate.
237
+
238
+ Returns:
239
+ True if the hash is valid.
240
+ """
241
+ if not tx_hash:
242
+ return False
243
+ if not tx_hash.startswith("0x"):
244
+ return False
245
+ hex_part = tx_hash[2:]
246
+ if len(hex_part) != 64:
247
+ return False
248
+ try:
249
+ int(hex_part, 16)
250
+ return True
251
+ except ValueError:
252
+ return False
253
+
254
+
255
+ def normalize_address(address: str) -> str:
256
+ """Normalize an Aptos address for comparison.
257
+
258
+ Converts to lowercase and ensures 0x prefix.
259
+
260
+ Args:
261
+ address: The address to normalize.
262
+
263
+ Returns:
264
+ Normalized address string.
265
+ """
266
+ if not address:
267
+ return ""
268
+ if address.startswith("0x"):
269
+ return "0x" + address[2:].lower()
270
+ return "0x" + address.lower()
271
+
272
+
273
+ def compare_addresses(addr1: str, addr2: str) -> bool:
274
+ """Compare two Aptos addresses (case-insensitive).
275
+
276
+ Args:
277
+ addr1: First address.
278
+ addr2: Second address.
279
+
280
+ Returns:
281
+ True if addresses are equivalent.
282
+ """
283
+ if not addr1 or not addr2:
284
+ return False
285
+ return normalize_address(addr1) == normalize_address(addr2)
286
+
287
+
288
+ def parse_amount(amount: str, decimals: int) -> int:
289
+ """Convert a decimal string amount to atomic units.
290
+
291
+ Args:
292
+ amount: Decimal amount string (e.g., "1.5").
293
+ decimals: Number of decimal places for the token.
294
+
295
+ Returns:
296
+ Amount in smallest atomic units.
297
+
298
+ Raises:
299
+ ValueError: If the amount format is invalid.
300
+ """
301
+ amount = amount.strip()
302
+ parts = amount.split(".")
303
+
304
+ if len(parts) > 2:
305
+ raise ValueError(f"Invalid amount format: {amount}")
306
+
307
+ try:
308
+ int_part = int(parts[0])
309
+ except ValueError:
310
+ raise ValueError(f"Invalid integer part: {parts[0]}")
311
+
312
+ dec_part = 0
313
+ if len(parts) == 2 and parts[1]:
314
+ dec_str = parts[1]
315
+ if len(dec_str) > decimals:
316
+ dec_str = dec_str[:decimals]
317
+ else:
318
+ dec_str += "0" * (decimals - len(dec_str))
319
+ try:
320
+ dec_part = int(dec_str)
321
+ except ValueError:
322
+ raise ValueError(f"Invalid decimal part: {parts[1]}")
323
+
324
+ multiplier = 10**decimals
325
+ return int_part * multiplier + dec_part
326
+
327
+
328
+ def format_amount(atomic_amount: int, decimals: int) -> str:
329
+ """Convert atomic units to a human-readable decimal string.
330
+
331
+ Args:
332
+ atomic_amount: Amount in smallest atomic units.
333
+ decimals: Number of decimal places for the token.
334
+
335
+ Returns:
336
+ Formatted decimal string.
337
+ """
338
+ if atomic_amount == 0:
339
+ return "0"
340
+
341
+ multiplier = 10**decimals
342
+ int_part = atomic_amount // multiplier
343
+ dec_part = atomic_amount % multiplier
344
+
345
+ if dec_part == 0:
346
+ return str(int_part)
347
+
348
+ dec_str = str(dec_part).zfill(decimals).rstrip("0")
349
+ return f"{int_part}.{dec_str}"
@@ -0,0 +1,44 @@
1
+ """Aptos Exact-Direct Payment Scheme.
2
+
3
+ This package provides the exact-direct payment scheme implementation for Aptos
4
+ using Fungible Asset (FA) transfers via ``0x1::primary_fungible_store::transfer``.
5
+
6
+ The exact-direct scheme works as follows:
7
+ 1. Client executes the FA transfer on-chain directly.
8
+ 2. Client returns the transaction hash as proof of payment.
9
+ 3. Facilitator queries the Aptos REST API to verify the transaction details.
10
+
11
+ This is a "push" payment model where the client performs the transfer first,
12
+ unlike permit-based models where the facilitator executes settlement.
13
+ """
14
+
15
+ from t402.schemes.aptos.exact_direct.client import (
16
+ ExactDirectAptosClientScheme,
17
+ )
18
+ from t402.schemes.aptos.exact_direct.server import (
19
+ ExactDirectAptosServerScheme,
20
+ )
21
+ from t402.schemes.aptos.exact_direct.facilitator import (
22
+ ExactDirectAptosFacilitatorScheme,
23
+ )
24
+ from t402.schemes.aptos.constants import SCHEME_EXACT_DIRECT
25
+ from t402.schemes.aptos.types import (
26
+ ClientAptosSigner,
27
+ FacilitatorAptosSigner,
28
+ ExactDirectPayload,
29
+ )
30
+
31
+ __all__ = [
32
+ # Client
33
+ "ExactDirectAptosClientScheme",
34
+ "ClientAptosSigner",
35
+ # Server
36
+ "ExactDirectAptosServerScheme",
37
+ # Facilitator
38
+ "ExactDirectAptosFacilitatorScheme",
39
+ "FacilitatorAptosSigner",
40
+ # Types
41
+ "ExactDirectPayload",
42
+ # Constants
43
+ "SCHEME_EXACT_DIRECT",
44
+ ]