t402 1.9.1__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.
- t402/__init__.py +1 -1
- t402/a2a/__init__.py +73 -0
- t402/a2a/helpers.py +158 -0
- t402/a2a/types.py +145 -0
- t402/bridge/constants.py +1 -1
- t402/django/__init__.py +42 -0
- t402/django/middleware.py +596 -0
- t402/errors.py +213 -0
- t402/facilitator.py +125 -0
- t402/mcp/constants.py +3 -6
- t402/mcp/server.py +428 -44
- t402/mcp/web3_utils.py +493 -0
- t402/multisig/__init__.py +120 -0
- t402/multisig/constants.py +54 -0
- t402/multisig/safe.py +441 -0
- t402/multisig/signature.py +228 -0
- t402/multisig/transaction.py +238 -0
- t402/multisig/types.py +108 -0
- t402/multisig/utils.py +77 -0
- t402/schemes/__init__.py +19 -0
- t402/schemes/cosmos/__init__.py +114 -0
- t402/schemes/cosmos/constants.py +211 -0
- t402/schemes/cosmos/exact_direct/__init__.py +21 -0
- t402/schemes/cosmos/exact_direct/client.py +198 -0
- t402/schemes/cosmos/exact_direct/facilitator.py +493 -0
- t402/schemes/cosmos/exact_direct/server.py +315 -0
- t402/schemes/cosmos/types.py +501 -0
- t402/schemes/evm/__init__.py +1 -1
- t402/schemes/evm/exact_legacy/server.py +1 -1
- t402/schemes/near/__init__.py +25 -0
- t402/schemes/near/upto/__init__.py +54 -0
- t402/schemes/near/upto/types.py +272 -0
- t402/schemes/svm/__init__.py +15 -0
- t402/schemes/svm/upto/__init__.py +23 -0
- t402/schemes/svm/upto/types.py +193 -0
- t402/schemes/ton/__init__.py +15 -0
- t402/schemes/ton/upto/__init__.py +31 -0
- t402/schemes/ton/upto/types.py +215 -0
- t402/schemes/tron/__init__.py +21 -4
- t402/schemes/tron/upto/__init__.py +30 -0
- t402/schemes/tron/upto/types.py +213 -0
- t402/starlette/__init__.py +38 -0
- t402/starlette/middleware.py +522 -0
- t402/ton.py +1 -1
- t402/ton_paywall_template.py +1 -1
- t402/types.py +100 -2
- t402/wdk/chains.py +1 -1
- {t402-1.9.1.dist-info → t402-1.10.0.dist-info}/METADATA +3 -3
- {t402-1.9.1.dist-info → t402-1.10.0.dist-info}/RECORD +51 -20
- {t402-1.9.1.dist-info → t402-1.10.0.dist-info}/WHEEL +0 -0
- {t402-1.9.1.dist-info → t402-1.10.0.dist-info}/entry_points.txt +0 -0
t402/errors.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Standardized T402 error codes returned by the facilitator API.
|
|
2
|
+
|
|
3
|
+
Error codes follow the format T402-XYYY where X is the category (1-8)
|
|
4
|
+
and YYY is the specific error within that category.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Client Errors (T402-1xxx): Invalid input, malformed requests
|
|
13
|
+
ERR_INVALID_REQUEST = "T402-1001"
|
|
14
|
+
ERR_MISSING_PAYLOAD = "T402-1002"
|
|
15
|
+
ERR_MISSING_REQUIREMENTS = "T402-1003"
|
|
16
|
+
ERR_INVALID_PAYLOAD = "T402-1004"
|
|
17
|
+
ERR_INVALID_REQUIREMENTS = "T402-1005"
|
|
18
|
+
ERR_INVALID_SIGNATURE = "T402-1006"
|
|
19
|
+
ERR_INVALID_NETWORK = "T402-1007"
|
|
20
|
+
ERR_INVALID_SCHEME = "T402-1008"
|
|
21
|
+
ERR_INVALID_AMOUNT = "T402-1009"
|
|
22
|
+
ERR_INVALID_ADDRESS = "T402-1010"
|
|
23
|
+
ERR_EXPIRED_PAYMENT = "T402-1011"
|
|
24
|
+
ERR_INVALID_NONCE = "T402-1012"
|
|
25
|
+
ERR_INSUFFICIENT_AMOUNT = "T402-1013"
|
|
26
|
+
ERR_INVALID_IDEMPOTENCY_KEY = "T402-1014"
|
|
27
|
+
ERR_SIGNATURE_EXPIRED = "T402-1015"
|
|
28
|
+
|
|
29
|
+
# Server Errors (T402-2xxx): Internal failures, dependency issues
|
|
30
|
+
ERR_INTERNAL = "T402-2001"
|
|
31
|
+
ERR_DATABASE_UNAVAILABLE = "T402-2002"
|
|
32
|
+
ERR_CACHE_UNAVAILABLE = "T402-2003"
|
|
33
|
+
ERR_RPC_UNAVAILABLE = "T402-2004"
|
|
34
|
+
ERR_RATE_LIMITED = "T402-2005"
|
|
35
|
+
ERR_SERVICE_UNAVAILABLE = "T402-2006"
|
|
36
|
+
|
|
37
|
+
# Facilitator Errors (T402-3xxx): Verification and settlement failures
|
|
38
|
+
ERR_VERIFICATION_FAILED = "T402-3001"
|
|
39
|
+
ERR_SETTLEMENT_FAILED = "T402-3002"
|
|
40
|
+
ERR_INSUFFICIENT_BALANCE = "T402-3003"
|
|
41
|
+
ERR_ALLOWANCE_INSUFFICIENT = "T402-3004"
|
|
42
|
+
ERR_PAYMENT_MISMATCH = "T402-3005"
|
|
43
|
+
ERR_DUPLICATE_PAYMENT = "T402-3006"
|
|
44
|
+
ERR_SETTLEMENT_PENDING = "T402-3007"
|
|
45
|
+
ERR_SETTLEMENT_TIMEOUT = "T402-3008"
|
|
46
|
+
ERR_NONCE_REPLAY = "T402-3009"
|
|
47
|
+
ERR_IDEMPOTENCY_CONFLICT = "T402-3010"
|
|
48
|
+
ERR_IDEMPOTENCY_UNAVAILABLE = "T402-3011"
|
|
49
|
+
ERR_PREVIOUS_REQUEST_FAILED = "T402-3012"
|
|
50
|
+
ERR_REQUEST_IN_PROGRESS = "T402-3013"
|
|
51
|
+
|
|
52
|
+
# Chain-Specific Errors (T402-4xxx): Network and transaction issues
|
|
53
|
+
ERR_CHAIN_UNAVAILABLE = "T402-4001"
|
|
54
|
+
ERR_TRANSACTION_FAILED = "T402-4002"
|
|
55
|
+
ERR_TRANSACTION_REVERTED = "T402-4003"
|
|
56
|
+
ERR_GAS_ESTIMATION_FAILED = "T402-4004"
|
|
57
|
+
ERR_NONCE_CONFLICT = "T402-4005"
|
|
58
|
+
ERR_CHAIN_CONGESTED = "T402-4006"
|
|
59
|
+
ERR_CONTRACT_ERROR = "T402-4007"
|
|
60
|
+
|
|
61
|
+
# Bridge Errors (T402-5xxx): Cross-chain operation failures
|
|
62
|
+
ERR_BRIDGE_UNAVAILABLE = "T402-5001"
|
|
63
|
+
ERR_BRIDGE_QUOTE_FAILED = "T402-5002"
|
|
64
|
+
ERR_BRIDGE_TRANSFER_FAILED = "T402-5003"
|
|
65
|
+
ERR_BRIDGE_TIMEOUT = "T402-5004"
|
|
66
|
+
ERR_UNSUPPORTED_ROUTE = "T402-5005"
|
|
67
|
+
|
|
68
|
+
# Streaming Errors (T402-6xxx): Payment stream issues
|
|
69
|
+
ERR_STREAM_NOT_FOUND = "T402-6001"
|
|
70
|
+
ERR_STREAM_ALREADY_CLOSED = "T402-6002"
|
|
71
|
+
ERR_STREAM_ALREADY_PAUSED = "T402-6003"
|
|
72
|
+
ERR_STREAM_NOT_PAUSED = "T402-6004"
|
|
73
|
+
ERR_STREAM_AMOUNT_EXCEEDED = "T402-6005"
|
|
74
|
+
ERR_STREAM_EXPIRED = "T402-6006"
|
|
75
|
+
ERR_STREAM_INVALID_STATE = "T402-6007"
|
|
76
|
+
ERR_STREAM_RATE_LIMITED = "T402-6008"
|
|
77
|
+
|
|
78
|
+
# Intent Errors (T402-7xxx): Payment intent issues
|
|
79
|
+
ERR_INTENT_NOT_FOUND = "T402-7001"
|
|
80
|
+
ERR_INTENT_ALREADY_EXECUTED = "T402-7002"
|
|
81
|
+
ERR_INTENT_CANCELLED = "T402-7003"
|
|
82
|
+
ERR_INTENT_EXPIRED = "T402-7004"
|
|
83
|
+
ERR_NO_ROUTES_AVAILABLE = "T402-7005"
|
|
84
|
+
ERR_ROUTE_EXPIRED = "T402-7006"
|
|
85
|
+
ERR_ROUTE_NOT_SELECTED = "T402-7007"
|
|
86
|
+
ERR_INTENT_INVALID_STATE = "T402-7008"
|
|
87
|
+
|
|
88
|
+
# Discovery Errors (T402-8xxx): Resource marketplace issues
|
|
89
|
+
ERR_RESOURCE_NOT_FOUND = "T402-8001"
|
|
90
|
+
ERR_RESOURCE_ALREADY_EXISTS = "T402-8002"
|
|
91
|
+
ERR_INVALID_PARAMETERS = "T402-8003"
|
|
92
|
+
ERR_NOT_AUTHORIZED = "T402-8004"
|
|
93
|
+
|
|
94
|
+
# All error code constants for iteration/validation
|
|
95
|
+
ALL_ERROR_CODES: list[str] = [
|
|
96
|
+
ERR_INVALID_REQUEST, ERR_MISSING_PAYLOAD, ERR_MISSING_REQUIREMENTS,
|
|
97
|
+
ERR_INVALID_PAYLOAD, ERR_INVALID_REQUIREMENTS, ERR_INVALID_SIGNATURE,
|
|
98
|
+
ERR_INVALID_NETWORK, ERR_INVALID_SCHEME, ERR_INVALID_AMOUNT,
|
|
99
|
+
ERR_INVALID_ADDRESS, ERR_EXPIRED_PAYMENT, ERR_INVALID_NONCE,
|
|
100
|
+
ERR_INSUFFICIENT_AMOUNT, ERR_INVALID_IDEMPOTENCY_KEY, ERR_SIGNATURE_EXPIRED,
|
|
101
|
+
ERR_INTERNAL, ERR_DATABASE_UNAVAILABLE, ERR_CACHE_UNAVAILABLE,
|
|
102
|
+
ERR_RPC_UNAVAILABLE, ERR_RATE_LIMITED, ERR_SERVICE_UNAVAILABLE,
|
|
103
|
+
ERR_VERIFICATION_FAILED, ERR_SETTLEMENT_FAILED, ERR_INSUFFICIENT_BALANCE,
|
|
104
|
+
ERR_ALLOWANCE_INSUFFICIENT, ERR_PAYMENT_MISMATCH, ERR_DUPLICATE_PAYMENT,
|
|
105
|
+
ERR_SETTLEMENT_PENDING, ERR_SETTLEMENT_TIMEOUT, ERR_NONCE_REPLAY,
|
|
106
|
+
ERR_IDEMPOTENCY_CONFLICT, ERR_IDEMPOTENCY_UNAVAILABLE,
|
|
107
|
+
ERR_PREVIOUS_REQUEST_FAILED, ERR_REQUEST_IN_PROGRESS,
|
|
108
|
+
ERR_CHAIN_UNAVAILABLE, ERR_TRANSACTION_FAILED, ERR_TRANSACTION_REVERTED,
|
|
109
|
+
ERR_GAS_ESTIMATION_FAILED, ERR_NONCE_CONFLICT, ERR_CHAIN_CONGESTED,
|
|
110
|
+
ERR_CONTRACT_ERROR,
|
|
111
|
+
ERR_BRIDGE_UNAVAILABLE, ERR_BRIDGE_QUOTE_FAILED, ERR_BRIDGE_TRANSFER_FAILED,
|
|
112
|
+
ERR_BRIDGE_TIMEOUT, ERR_UNSUPPORTED_ROUTE,
|
|
113
|
+
ERR_STREAM_NOT_FOUND, ERR_STREAM_ALREADY_CLOSED, ERR_STREAM_ALREADY_PAUSED,
|
|
114
|
+
ERR_STREAM_NOT_PAUSED, ERR_STREAM_AMOUNT_EXCEEDED, ERR_STREAM_EXPIRED,
|
|
115
|
+
ERR_STREAM_INVALID_STATE, ERR_STREAM_RATE_LIMITED,
|
|
116
|
+
ERR_INTENT_NOT_FOUND, ERR_INTENT_ALREADY_EXECUTED, ERR_INTENT_CANCELLED,
|
|
117
|
+
ERR_INTENT_EXPIRED, ERR_NO_ROUTES_AVAILABLE, ERR_ROUTE_EXPIRED,
|
|
118
|
+
ERR_ROUTE_NOT_SELECTED, ERR_INTENT_INVALID_STATE,
|
|
119
|
+
ERR_RESOURCE_NOT_FOUND, ERR_RESOURCE_ALREADY_EXISTS,
|
|
120
|
+
ERR_INVALID_PARAMETERS, ERR_NOT_AUTHORIZED,
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class APIError(Exception):
|
|
126
|
+
"""Structured error response from the facilitator API."""
|
|
127
|
+
|
|
128
|
+
code: str
|
|
129
|
+
message: str
|
|
130
|
+
details: str = ""
|
|
131
|
+
retry: bool = False
|
|
132
|
+
|
|
133
|
+
def __str__(self) -> str:
|
|
134
|
+
if self.details:
|
|
135
|
+
return f"[{self.code}] {self.message}: {self.details}"
|
|
136
|
+
return f"[{self.code}] {self.message}"
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def http_status(self) -> int:
|
|
140
|
+
"""Returns the expected HTTP status code for this error code."""
|
|
141
|
+
return http_status_for_code(self.code)
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def is_client_error(self) -> bool:
|
|
145
|
+
return len(self.code) >= 6 and self.code[5] == "1"
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def is_server_error(self) -> bool:
|
|
149
|
+
return len(self.code) >= 6 and self.code[5] == "2"
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def is_facilitator_error(self) -> bool:
|
|
153
|
+
return len(self.code) >= 6 and self.code[5] == "3"
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def is_chain_error(self) -> bool:
|
|
157
|
+
return len(self.code) >= 6 and self.code[5] == "4"
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def is_bridge_error(self) -> bool:
|
|
161
|
+
return len(self.code) >= 6 and self.code[5] == "5"
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def is_retryable(self) -> bool:
|
|
165
|
+
return self.retry
|
|
166
|
+
|
|
167
|
+
@classmethod
|
|
168
|
+
def from_dict(cls, data: dict) -> "APIError":
|
|
169
|
+
"""Create an APIError from a dictionary (e.g., from JSON response)."""
|
|
170
|
+
return cls(
|
|
171
|
+
code=data.get("code", ""),
|
|
172
|
+
message=data.get("message", ""),
|
|
173
|
+
details=data.get("details", ""),
|
|
174
|
+
retry=data.get("retry", False),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def http_status_for_code(code: str) -> int:
|
|
179
|
+
"""Returns the expected HTTP status code for a given T402 error code."""
|
|
180
|
+
if len(code) < 6:
|
|
181
|
+
return 500
|
|
182
|
+
category = code[5]
|
|
183
|
+
if category == "1":
|
|
184
|
+
return 400
|
|
185
|
+
if category == "2":
|
|
186
|
+
if code == ERR_RATE_LIMITED:
|
|
187
|
+
return 429
|
|
188
|
+
return 500
|
|
189
|
+
if category == "3":
|
|
190
|
+
if code in (ERR_VERIFICATION_FAILED, ERR_PAYMENT_MISMATCH):
|
|
191
|
+
return 422
|
|
192
|
+
return 500
|
|
193
|
+
if category == "4":
|
|
194
|
+
return 502
|
|
195
|
+
if category == "5":
|
|
196
|
+
return 502
|
|
197
|
+
if category == "6":
|
|
198
|
+
if code == ERR_STREAM_NOT_FOUND:
|
|
199
|
+
return 404
|
|
200
|
+
return 400
|
|
201
|
+
if category == "7":
|
|
202
|
+
if code == ERR_INTENT_NOT_FOUND:
|
|
203
|
+
return 404
|
|
204
|
+
return 400
|
|
205
|
+
if category == "8":
|
|
206
|
+
if code == ERR_RESOURCE_NOT_FOUND:
|
|
207
|
+
return 404
|
|
208
|
+
if code == ERR_RESOURCE_ALREADY_EXISTS:
|
|
209
|
+
return 409
|
|
210
|
+
if code == ERR_NOT_AUTHORIZED:
|
|
211
|
+
return 403
|
|
212
|
+
return 400
|
|
213
|
+
return 500
|
t402/facilitator.py
CHANGED
|
@@ -10,6 +10,10 @@ from t402.types import (
|
|
|
10
10
|
SettleResponse,
|
|
11
11
|
ListDiscoveryResourcesRequest,
|
|
12
12
|
ListDiscoveryResourcesResponse,
|
|
13
|
+
DiscoveryItem,
|
|
14
|
+
RegisterResourceRequest,
|
|
15
|
+
RegisterResourceResponse,
|
|
16
|
+
UpdateResourceRequest,
|
|
13
17
|
)
|
|
14
18
|
|
|
15
19
|
|
|
@@ -133,3 +137,124 @@ class FacilitatorClient:
|
|
|
133
137
|
|
|
134
138
|
data = response.json()
|
|
135
139
|
return ListDiscoveryResourcesResponse(**data)
|
|
140
|
+
|
|
141
|
+
async def get_resource(self, resource_id: str) -> DiscoveryItem:
|
|
142
|
+
"""Get details of a specific discoverable resource.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
resource_id: The unique ID of the resource
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
DiscoveryItem with resource details
|
|
149
|
+
"""
|
|
150
|
+
headers = {"Content-Type": "application/json"}
|
|
151
|
+
|
|
152
|
+
if self.config.get("create_headers"):
|
|
153
|
+
custom_headers = await self.config["create_headers"]()
|
|
154
|
+
headers.update(custom_headers.get("discovery", {}))
|
|
155
|
+
|
|
156
|
+
async with httpx.AsyncClient() as client:
|
|
157
|
+
response = await client.get(
|
|
158
|
+
f"{self.config['url']}/discovery/resources/{resource_id}",
|
|
159
|
+
headers=headers,
|
|
160
|
+
follow_redirects=True,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if response.status_code != 200:
|
|
164
|
+
raise ValueError(
|
|
165
|
+
f"Failed to get resource: {response.status_code} {response.text}"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
data = response.json()
|
|
169
|
+
return DiscoveryItem(**data)
|
|
170
|
+
|
|
171
|
+
async def register_resource(
|
|
172
|
+
self, request: RegisterResourceRequest
|
|
173
|
+
) -> RegisterResourceResponse:
|
|
174
|
+
"""Register a new resource in the Bazaar.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
request: Resource registration data
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
RegisterResourceResponse with the new resource ID and metadata
|
|
181
|
+
"""
|
|
182
|
+
headers = {"Content-Type": "application/json"}
|
|
183
|
+
|
|
184
|
+
if self.config.get("create_headers"):
|
|
185
|
+
custom_headers = await self.config["create_headers"]()
|
|
186
|
+
headers.update(custom_headers.get("discovery", {}))
|
|
187
|
+
|
|
188
|
+
async with httpx.AsyncClient() as client:
|
|
189
|
+
response = await client.post(
|
|
190
|
+
f"{self.config['url']}/discovery/register",
|
|
191
|
+
json=request.model_dump(by_alias=True, exclude_none=True),
|
|
192
|
+
headers=headers,
|
|
193
|
+
follow_redirects=True,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
if response.status_code != 201:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
f"Failed to register resource: {response.status_code} {response.text}"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
data = response.json()
|
|
202
|
+
return RegisterResourceResponse(**data)
|
|
203
|
+
|
|
204
|
+
async def update_resource(
|
|
205
|
+
self, resource_id: str, request: UpdateResourceRequest
|
|
206
|
+
) -> DiscoveryItem:
|
|
207
|
+
"""Update an existing resource in the Bazaar.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
resource_id: The unique ID of the resource to update
|
|
211
|
+
request: Resource update data
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
DiscoveryItem with updated resource details
|
|
215
|
+
"""
|
|
216
|
+
headers = {"Content-Type": "application/json"}
|
|
217
|
+
|
|
218
|
+
if self.config.get("create_headers"):
|
|
219
|
+
custom_headers = await self.config["create_headers"]()
|
|
220
|
+
headers.update(custom_headers.get("discovery", {}))
|
|
221
|
+
|
|
222
|
+
async with httpx.AsyncClient() as client:
|
|
223
|
+
response = await client.put(
|
|
224
|
+
f"{self.config['url']}/discovery/resources/{resource_id}",
|
|
225
|
+
json=request.model_dump(by_alias=True, exclude_none=True),
|
|
226
|
+
headers=headers,
|
|
227
|
+
follow_redirects=True,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
if response.status_code != 200:
|
|
231
|
+
raise ValueError(
|
|
232
|
+
f"Failed to update resource: {response.status_code} {response.text}"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
data = response.json()
|
|
236
|
+
return DiscoveryItem(**data)
|
|
237
|
+
|
|
238
|
+
async def delete_resource(self, resource_id: str) -> None:
|
|
239
|
+
"""Delete a resource from the Bazaar.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
resource_id: The unique ID of the resource to delete
|
|
243
|
+
"""
|
|
244
|
+
headers = {"Content-Type": "application/json"}
|
|
245
|
+
|
|
246
|
+
if self.config.get("create_headers"):
|
|
247
|
+
custom_headers = await self.config["create_headers"]()
|
|
248
|
+
headers.update(custom_headers.get("discovery", {}))
|
|
249
|
+
|
|
250
|
+
async with httpx.AsyncClient() as client:
|
|
251
|
+
response = await client.delete(
|
|
252
|
+
f"{self.config['url']}/discovery/resources/{resource_id}",
|
|
253
|
+
headers=headers,
|
|
254
|
+
follow_redirects=True,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if response.status_code != 204:
|
|
258
|
+
raise ValueError(
|
|
259
|
+
f"Failed to delete resource: {response.status_code} {response.text}"
|
|
260
|
+
)
|
t402/mcp/constants.py
CHANGED
|
@@ -51,8 +51,8 @@ DEFAULT_RPC_URLS: dict[SupportedNetwork, str] = {
|
|
|
51
51
|
"optimism": "https://mainnet.optimism.io",
|
|
52
52
|
"polygon": "https://polygon-rpc.com",
|
|
53
53
|
"avalanche": "https://api.avax.network/ext/bc/C/rpc",
|
|
54
|
-
"ink": "https://rpc-
|
|
55
|
-
"berachain": "https://
|
|
54
|
+
"ink": "https://rpc-gel.inkonchain.com",
|
|
55
|
+
"berachain": "https://rpc.berachain.com",
|
|
56
56
|
"unichain": "https://mainnet.unichain.org",
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -64,9 +64,6 @@ USDC_ADDRESSES: dict[SupportedNetwork, str] = {
|
|
|
64
64
|
"optimism": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
65
65
|
"polygon": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
66
66
|
"avalanche": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
67
|
-
"ink": "0x0200C29006150606B650577BBE7B6248F58470c1",
|
|
68
|
-
"berachain": "0x779Ded0c9e1022225f8E0630b35a9b54bE713736",
|
|
69
|
-
"unichain": "0x588ce4F028D8e7B53B687865d6A67b3A54C75518",
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
# USDT contract addresses by network
|
|
@@ -84,7 +81,7 @@ USDT0_ADDRESSES: dict[SupportedNetwork, str] = {
|
|
|
84
81
|
"arbitrum": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
|
|
85
82
|
"ink": "0x0200C29006150606B650577BBE7B6248F58470c1",
|
|
86
83
|
"berachain": "0x779Ded0c9e1022225f8E0630b35a9b54bE713736",
|
|
87
|
-
"unichain": "
|
|
84
|
+
"unichain": "0x9151434b16b9763660705744891fA906F660EcC5",
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
# Networks that support USDT0 bridging via LayerZero
|