safe-kit 0.0.11__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.
- safe_kit/__init__.py +22 -0
- safe_kit/abis.py +366 -0
- safe_kit/adapter.py +147 -0
- safe_kit/contract_types.py +151 -0
- safe_kit/errors.py +57 -0
- safe_kit/factory.py +143 -0
- safe_kit/managers/__init__.py +15 -0
- safe_kit/managers/guard_manager.py +61 -0
- safe_kit/managers/module_manager.py +85 -0
- safe_kit/managers/owner_manager.py +94 -0
- safe_kit/managers/token_manager.py +100 -0
- safe_kit/multisend.py +41 -0
- safe_kit/py.typed +0 -0
- safe_kit/safe.py +386 -0
- safe_kit/service.py +343 -0
- safe_kit/types.py +239 -0
- safe_kit-0.0.11.dist-info/METADATA +137 -0
- safe_kit-0.0.11.dist-info/RECORD +20 -0
- safe_kit-0.0.11.dist-info/WHEEL +4 -0
- safe_kit-0.0.11.dist-info/licenses/LICENSE +21 -0
safe_kit/service.py
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
from typing import Any, cast
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
from safe_kit.errors import SafeServiceError
|
|
6
|
+
from safe_kit.types import (
|
|
7
|
+
SafeBalanceResponse,
|
|
8
|
+
SafeCollectibleResponse,
|
|
9
|
+
SafeCreationInfoResponse,
|
|
10
|
+
SafeDataDecoderResponse,
|
|
11
|
+
SafeDelegateResponse,
|
|
12
|
+
SafeIncomingTransactionResponse,
|
|
13
|
+
SafeInfoResponse,
|
|
14
|
+
SafeModuleTransactionResponse,
|
|
15
|
+
SafeMultisigTransactionResponse,
|
|
16
|
+
SafeServiceInfo,
|
|
17
|
+
SafeTokenResponse,
|
|
18
|
+
SafeTransactionData,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SafeServiceClient:
|
|
23
|
+
"""
|
|
24
|
+
Client for interacting with the Safe Transaction Service API.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, service_url: str):
|
|
28
|
+
self.service_url = service_url.rstrip("/")
|
|
29
|
+
|
|
30
|
+
def _handle_response(self, response: requests.Response) -> Any:
|
|
31
|
+
try:
|
|
32
|
+
response.raise_for_status()
|
|
33
|
+
if response.content:
|
|
34
|
+
return response.json()
|
|
35
|
+
return None
|
|
36
|
+
except requests.HTTPError as e:
|
|
37
|
+
raise SafeServiceError(f"Service error: {e}", response.status_code) from e
|
|
38
|
+
except Exception as e:
|
|
39
|
+
raise SafeServiceError(f"Unexpected error: {e}") from e
|
|
40
|
+
|
|
41
|
+
def get_service_info(self) -> SafeServiceInfo:
|
|
42
|
+
"""
|
|
43
|
+
Returns information about the Safe Transaction Service.
|
|
44
|
+
"""
|
|
45
|
+
response = requests.get(f"{self.service_url}/v1/about/")
|
|
46
|
+
data = self._handle_response(response)
|
|
47
|
+
return SafeServiceInfo(**data)
|
|
48
|
+
|
|
49
|
+
def propose_transaction(
|
|
50
|
+
self,
|
|
51
|
+
safe_address: str,
|
|
52
|
+
safe_tx_data: SafeTransactionData,
|
|
53
|
+
safe_tx_hash: str,
|
|
54
|
+
sender_address: str,
|
|
55
|
+
signature: str,
|
|
56
|
+
origin: str | None = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Proposes a transaction to the Safe Transaction Service.
|
|
60
|
+
"""
|
|
61
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/multisig-transactions/"
|
|
62
|
+
|
|
63
|
+
payload = {
|
|
64
|
+
"to": safe_tx_data.to,
|
|
65
|
+
"value": safe_tx_data.value,
|
|
66
|
+
"data": safe_tx_data.data if safe_tx_data.data else None,
|
|
67
|
+
"operation": safe_tx_data.operation,
|
|
68
|
+
"safeTxGas": safe_tx_data.safe_tx_gas,
|
|
69
|
+
"baseGas": safe_tx_data.base_gas,
|
|
70
|
+
"gasPrice": safe_tx_data.gas_price,
|
|
71
|
+
"gasToken": safe_tx_data.gas_token,
|
|
72
|
+
"refundReceiver": safe_tx_data.refund_receiver,
|
|
73
|
+
"nonce": safe_tx_data.nonce,
|
|
74
|
+
"contractTransactionHash": safe_tx_hash,
|
|
75
|
+
"sender": sender_address,
|
|
76
|
+
"signature": signature,
|
|
77
|
+
"origin": origin,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
response = requests.post(url, json=payload)
|
|
81
|
+
self._handle_response(response)
|
|
82
|
+
|
|
83
|
+
def get_pending_transactions(
|
|
84
|
+
self, safe_address: str, current_nonce: int | None = None
|
|
85
|
+
) -> list[SafeMultisigTransactionResponse]:
|
|
86
|
+
"""
|
|
87
|
+
Returns the list of pending transactions for a Safe.
|
|
88
|
+
"""
|
|
89
|
+
return self.get_multisig_transactions(
|
|
90
|
+
safe_address,
|
|
91
|
+
executed=False,
|
|
92
|
+
trust=True,
|
|
93
|
+
nonce_gte=current_nonce,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def get_multisig_transactions(
|
|
97
|
+
self,
|
|
98
|
+
safe_address: str,
|
|
99
|
+
executed: bool | None = None,
|
|
100
|
+
trust: bool | None = None,
|
|
101
|
+
nonce_gte: int | None = None,
|
|
102
|
+
ordering: str | None = None,
|
|
103
|
+
limit: int | None = None,
|
|
104
|
+
offset: int | None = None,
|
|
105
|
+
) -> list[SafeMultisigTransactionResponse]:
|
|
106
|
+
"""
|
|
107
|
+
Returns the list of multisig transactions for a Safe.
|
|
108
|
+
"""
|
|
109
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/multisig-transactions/"
|
|
110
|
+
params: dict[str, Any] = {}
|
|
111
|
+
|
|
112
|
+
if executed is not None:
|
|
113
|
+
params["executed"] = str(executed).lower()
|
|
114
|
+
if trust is not None:
|
|
115
|
+
params["trusted"] = str(trust).lower()
|
|
116
|
+
if nonce_gte is not None:
|
|
117
|
+
params["nonce__gte"] = str(nonce_gte)
|
|
118
|
+
if ordering:
|
|
119
|
+
params["ordering"] = ordering
|
|
120
|
+
if limit is not None:
|
|
121
|
+
params["limit"] = str(limit)
|
|
122
|
+
if offset is not None:
|
|
123
|
+
params["offset"] = str(offset)
|
|
124
|
+
|
|
125
|
+
response = requests.get(url, params=params)
|
|
126
|
+
data = self._handle_response(response)
|
|
127
|
+
results = data.get("results", [])
|
|
128
|
+
return [SafeMultisigTransactionResponse(**tx) for tx in results]
|
|
129
|
+
|
|
130
|
+
def confirm_transaction(self, safe_tx_hash: str, signature: str) -> None:
|
|
131
|
+
"""
|
|
132
|
+
Adds a confirmation (signature) to a pending transaction.
|
|
133
|
+
"""
|
|
134
|
+
url = (
|
|
135
|
+
f"{self.service_url}/v1/multisig-transactions/{safe_tx_hash}/confirmations/"
|
|
136
|
+
)
|
|
137
|
+
payload = {"signature": signature}
|
|
138
|
+
|
|
139
|
+
response = requests.post(url, json=payload)
|
|
140
|
+
self._handle_response(response)
|
|
141
|
+
|
|
142
|
+
def delete_transaction(self, safe_tx_hash: str, signature: str) -> None:
|
|
143
|
+
"""
|
|
144
|
+
Deletes a pending transaction from the Safe Transaction Service.
|
|
145
|
+
Requires the signature of the proposer.
|
|
146
|
+
"""
|
|
147
|
+
url = f"{self.service_url}/v1/multisig-transactions/{safe_tx_hash}/"
|
|
148
|
+
payload = {"signature": signature}
|
|
149
|
+
response = requests.delete(url, json=payload)
|
|
150
|
+
self._handle_response(response)
|
|
151
|
+
|
|
152
|
+
def get_transaction(self, safe_tx_hash: str) -> SafeMultisigTransactionResponse:
|
|
153
|
+
"""
|
|
154
|
+
Returns the details of a specific Safe transaction.
|
|
155
|
+
"""
|
|
156
|
+
url = f"{self.service_url}/v1/multisig-transactions/{safe_tx_hash}/"
|
|
157
|
+
response = requests.get(url)
|
|
158
|
+
data = self._handle_response(response)
|
|
159
|
+
return SafeMultisigTransactionResponse(**data)
|
|
160
|
+
|
|
161
|
+
def get_safes_by_owner(self, owner_address: str) -> list[str]:
|
|
162
|
+
"""
|
|
163
|
+
Returns the list of Safes owned by an address.
|
|
164
|
+
"""
|
|
165
|
+
url = f"{self.service_url}/v1/owners/{owner_address}/safes/"
|
|
166
|
+
response = requests.get(url)
|
|
167
|
+
data = self._handle_response(response)
|
|
168
|
+
return cast(list[str], data.get("safes", []))
|
|
169
|
+
|
|
170
|
+
def get_balances(
|
|
171
|
+
self, safe_address: str, trusted: bool = False, exclude_spam: bool = True
|
|
172
|
+
) -> list[SafeBalanceResponse]:
|
|
173
|
+
"""
|
|
174
|
+
Returns the balances of a Safe (ETH and ERC20).
|
|
175
|
+
"""
|
|
176
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/balances/"
|
|
177
|
+
params = {
|
|
178
|
+
"trusted": str(trusted).lower(),
|
|
179
|
+
"exclude_spam": str(exclude_spam).lower(),
|
|
180
|
+
}
|
|
181
|
+
response = requests.get(url, params=params)
|
|
182
|
+
data = self._handle_response(response)
|
|
183
|
+
return [SafeBalanceResponse(**item) for item in data]
|
|
184
|
+
|
|
185
|
+
def get_incoming_transactions(
|
|
186
|
+
self,
|
|
187
|
+
safe_address: str,
|
|
188
|
+
executed: bool | None = None,
|
|
189
|
+
limit: int | None = None,
|
|
190
|
+
offset: int | None = None,
|
|
191
|
+
) -> list[SafeIncomingTransactionResponse]:
|
|
192
|
+
"""
|
|
193
|
+
Returns the incoming transactions (ETH/ERC20) for a Safe.
|
|
194
|
+
"""
|
|
195
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/incoming-transfers/"
|
|
196
|
+
params: dict[str, Any] = {}
|
|
197
|
+
if executed is not None:
|
|
198
|
+
params["executed"] = str(executed).lower()
|
|
199
|
+
if limit is not None:
|
|
200
|
+
params["limit"] = str(limit)
|
|
201
|
+
if offset is not None:
|
|
202
|
+
params["offset"] = str(offset)
|
|
203
|
+
|
|
204
|
+
response = requests.get(url, params=params)
|
|
205
|
+
data = self._handle_response(response)
|
|
206
|
+
results = data.get("results", [])
|
|
207
|
+
return [SafeIncomingTransactionResponse(**tx) for tx in results]
|
|
208
|
+
|
|
209
|
+
def get_module_transactions(
|
|
210
|
+
self,
|
|
211
|
+
safe_address: str,
|
|
212
|
+
limit: int | None = None,
|
|
213
|
+
offset: int | None = None,
|
|
214
|
+
) -> list[SafeModuleTransactionResponse]:
|
|
215
|
+
"""
|
|
216
|
+
Returns the module transactions for a Safe.
|
|
217
|
+
"""
|
|
218
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/module-transactions/"
|
|
219
|
+
params: dict[str, Any] = {}
|
|
220
|
+
if limit is not None:
|
|
221
|
+
params["limit"] = str(limit)
|
|
222
|
+
if offset is not None:
|
|
223
|
+
params["offset"] = str(offset)
|
|
224
|
+
|
|
225
|
+
response = requests.get(url, params=params)
|
|
226
|
+
data = self._handle_response(response)
|
|
227
|
+
results = data.get("results", [])
|
|
228
|
+
return [SafeModuleTransactionResponse(**tx) for tx in results]
|
|
229
|
+
|
|
230
|
+
def get_safe_info(self, safe_address: str) -> SafeInfoResponse:
|
|
231
|
+
"""
|
|
232
|
+
Returns detailed information about a Safe.
|
|
233
|
+
"""
|
|
234
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/"
|
|
235
|
+
response = requests.get(url)
|
|
236
|
+
data = self._handle_response(response)
|
|
237
|
+
return SafeInfoResponse(**data)
|
|
238
|
+
|
|
239
|
+
def get_creation_info(self, safe_address: str) -> SafeCreationInfoResponse:
|
|
240
|
+
"""
|
|
241
|
+
Returns information about when and how a Safe was created.
|
|
242
|
+
"""
|
|
243
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/creation/"
|
|
244
|
+
response = requests.get(url)
|
|
245
|
+
data = self._handle_response(response)
|
|
246
|
+
return SafeCreationInfoResponse(**data)
|
|
247
|
+
|
|
248
|
+
def get_collectibles(
|
|
249
|
+
self,
|
|
250
|
+
safe_address: str,
|
|
251
|
+
trusted: bool = False,
|
|
252
|
+
exclude_spam: bool = True,
|
|
253
|
+
) -> list[SafeCollectibleResponse]:
|
|
254
|
+
"""
|
|
255
|
+
Returns NFTs (ERC721) owned by the Safe.
|
|
256
|
+
"""
|
|
257
|
+
url = f"{self.service_url}/v1/safes/{safe_address}/collectibles/"
|
|
258
|
+
params = {
|
|
259
|
+
"trusted": str(trusted).lower(),
|
|
260
|
+
"exclude_spam": str(exclude_spam).lower(),
|
|
261
|
+
}
|
|
262
|
+
response = requests.get(url, params=params)
|
|
263
|
+
data = self._handle_response(response)
|
|
264
|
+
return [SafeCollectibleResponse(**item) for item in data]
|
|
265
|
+
|
|
266
|
+
def get_delegates(self, safe_address: str) -> list[SafeDelegateResponse]:
|
|
267
|
+
"""
|
|
268
|
+
Returns the list of delegates for a Safe.
|
|
269
|
+
"""
|
|
270
|
+
url = f"{self.service_url}/v1/delegates/"
|
|
271
|
+
params = {"safe": safe_address}
|
|
272
|
+
response = requests.get(url, params=params)
|
|
273
|
+
data = self._handle_response(response)
|
|
274
|
+
results = data.get("results", [])
|
|
275
|
+
return [SafeDelegateResponse(**item) for item in results]
|
|
276
|
+
|
|
277
|
+
def add_delegate(
|
|
278
|
+
self,
|
|
279
|
+
safe_address: str,
|
|
280
|
+
delegate_address: str,
|
|
281
|
+
delegator: str,
|
|
282
|
+
label: str,
|
|
283
|
+
signature: str,
|
|
284
|
+
) -> None:
|
|
285
|
+
"""
|
|
286
|
+
Adds a delegate to a Safe.
|
|
287
|
+
"""
|
|
288
|
+
url = f"{self.service_url}/v1/delegates/"
|
|
289
|
+
payload = {
|
|
290
|
+
"safe": safe_address,
|
|
291
|
+
"delegate": delegate_address,
|
|
292
|
+
"delegator": delegator,
|
|
293
|
+
"label": label,
|
|
294
|
+
"signature": signature,
|
|
295
|
+
}
|
|
296
|
+
response = requests.post(url, json=payload)
|
|
297
|
+
self._handle_response(response)
|
|
298
|
+
|
|
299
|
+
def remove_delegate(
|
|
300
|
+
self,
|
|
301
|
+
delegate_address: str,
|
|
302
|
+
delegator: str,
|
|
303
|
+
signature: str,
|
|
304
|
+
) -> None:
|
|
305
|
+
"""
|
|
306
|
+
Removes a delegate.
|
|
307
|
+
"""
|
|
308
|
+
url = f"{self.service_url}/v1/delegates/{delegate_address}/"
|
|
309
|
+
payload = {
|
|
310
|
+
"delegator": delegator,
|
|
311
|
+
"signature": signature,
|
|
312
|
+
}
|
|
313
|
+
response = requests.delete(url, json=payload)
|
|
314
|
+
self._handle_response(response)
|
|
315
|
+
|
|
316
|
+
def get_tokens(self) -> list[SafeTokenResponse]:
|
|
317
|
+
"""
|
|
318
|
+
Returns the list of ERC20 tokens supported by the Safe Transaction Service.
|
|
319
|
+
"""
|
|
320
|
+
url = f"{self.service_url}/v1/tokens/"
|
|
321
|
+
response = requests.get(url)
|
|
322
|
+
data = self._handle_response(response)
|
|
323
|
+
results = data.get("results", [])
|
|
324
|
+
return [SafeTokenResponse(**item) for item in results]
|
|
325
|
+
|
|
326
|
+
def get_token(self, token_address: str) -> SafeTokenResponse:
|
|
327
|
+
"""
|
|
328
|
+
Returns information about a specific token.
|
|
329
|
+
"""
|
|
330
|
+
url = f"{self.service_url}/v1/tokens/{token_address}/"
|
|
331
|
+
response = requests.get(url)
|
|
332
|
+
data = self._handle_response(response)
|
|
333
|
+
return SafeTokenResponse(**data)
|
|
334
|
+
|
|
335
|
+
def decode_data(self, data: str) -> SafeDataDecoderResponse:
|
|
336
|
+
"""
|
|
337
|
+
Decodes transaction data using the Safe Transaction Service.
|
|
338
|
+
"""
|
|
339
|
+
url = f"{self.service_url}/v1/data-decoder/"
|
|
340
|
+
payload = {"data": data}
|
|
341
|
+
response = requests.post(url, json=payload)
|
|
342
|
+
data_json = self._handle_response(response)
|
|
343
|
+
return SafeDataDecoderResponse(**data_json)
|
safe_kit/types.py
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SafeAccountConfig(BaseModel):
|
|
7
|
+
"""
|
|
8
|
+
Configuration for deploying a new Safe.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
owners: list[str]
|
|
12
|
+
threshold: int
|
|
13
|
+
to: str = "0x0000000000000000000000000000000000000000"
|
|
14
|
+
data: str = "0x"
|
|
15
|
+
fallback_handler: str = "0x0000000000000000000000000000000000000000"
|
|
16
|
+
payment_token: str = "0x0000000000000000000000000000000000000000"
|
|
17
|
+
payment: int = 0
|
|
18
|
+
payment_receiver: str = "0x0000000000000000000000000000000000000000"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SafeTransactionData(BaseModel):
|
|
22
|
+
"""
|
|
23
|
+
Model representing the data of a Safe transaction.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
to: str
|
|
27
|
+
value: int
|
|
28
|
+
data: str
|
|
29
|
+
operation: int = 0
|
|
30
|
+
safe_tx_gas: int = 0
|
|
31
|
+
base_gas: int = 0
|
|
32
|
+
gas_price: int = 0
|
|
33
|
+
gas_token: str = "0x0000000000000000000000000000000000000000"
|
|
34
|
+
refund_receiver: str = "0x0000000000000000000000000000000000000000"
|
|
35
|
+
nonce: int | None = None
|
|
36
|
+
|
|
37
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
38
|
+
|
|
39
|
+
def get_eip712_data(self, chain_id: int, safe_address: str) -> dict[str, Any]:
|
|
40
|
+
from hexbytes import HexBytes
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
"types": {
|
|
44
|
+
"EIP712Domain": [
|
|
45
|
+
{"name": "chainId", "type": "uint256"},
|
|
46
|
+
{"name": "verifyingContract", "type": "address"},
|
|
47
|
+
],
|
|
48
|
+
"SafeTx": [
|
|
49
|
+
{"name": "to", "type": "address"},
|
|
50
|
+
{"name": "value", "type": "uint256"},
|
|
51
|
+
{"name": "data", "type": "bytes"},
|
|
52
|
+
{"name": "operation", "type": "uint8"},
|
|
53
|
+
{"name": "safeTxGas", "type": "uint256"},
|
|
54
|
+
{"name": "baseGas", "type": "uint256"},
|
|
55
|
+
{"name": "gasPrice", "type": "uint256"},
|
|
56
|
+
{"name": "gasToken", "type": "address"},
|
|
57
|
+
{"name": "refundReceiver", "type": "address"},
|
|
58
|
+
{"name": "nonce", "type": "uint256"},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
"primaryType": "SafeTx",
|
|
62
|
+
"domain": {
|
|
63
|
+
"chainId": chain_id,
|
|
64
|
+
"verifyingContract": safe_address,
|
|
65
|
+
},
|
|
66
|
+
"message": {
|
|
67
|
+
"to": self.to,
|
|
68
|
+
"value": self.value,
|
|
69
|
+
"data": HexBytes(self.data),
|
|
70
|
+
"operation": self.operation,
|
|
71
|
+
"safeTxGas": self.safe_tx_gas,
|
|
72
|
+
"baseGas": self.base_gas,
|
|
73
|
+
"gasPrice": self.gas_price,
|
|
74
|
+
"gasToken": self.gas_token,
|
|
75
|
+
"refundReceiver": self.refund_receiver,
|
|
76
|
+
"nonce": self.nonce if self.nonce is not None else 0,
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class SafeTransaction(BaseModel):
|
|
82
|
+
"""
|
|
83
|
+
Model representing a complete Safe transaction including signatures.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
data: SafeTransactionData
|
|
87
|
+
signatures: dict[str, str] = Field(default_factory=dict)
|
|
88
|
+
|
|
89
|
+
def add_signature(self, owner: str, signature: str) -> None:
|
|
90
|
+
self.signatures[owner] = signature
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def sorted_signatures_bytes(self) -> bytes:
|
|
94
|
+
from hexbytes import HexBytes
|
|
95
|
+
|
|
96
|
+
# Sort by owner address
|
|
97
|
+
sorted_owners = sorted(self.signatures.keys(), key=lambda x: int(x, 16))
|
|
98
|
+
signature_bytes = b""
|
|
99
|
+
for owner in sorted_owners:
|
|
100
|
+
signature_bytes += HexBytes(self.signatures[owner])
|
|
101
|
+
return signature_bytes
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class SafeServiceInfo(BaseModel):
|
|
105
|
+
name: str
|
|
106
|
+
version: str
|
|
107
|
+
api_version: str
|
|
108
|
+
secure: bool
|
|
109
|
+
settings: dict[str, Any]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class SafeMultisigTransactionResponse(BaseModel):
|
|
113
|
+
safe: str
|
|
114
|
+
to: str
|
|
115
|
+
value: str
|
|
116
|
+
data: str | None
|
|
117
|
+
operation: int
|
|
118
|
+
gas_token: str = Field(alias="gasToken")
|
|
119
|
+
safe_tx_gas: int = Field(alias="safeTxGas")
|
|
120
|
+
base_gas: int = Field(alias="baseGas")
|
|
121
|
+
gas_price: str = Field(alias="gasPrice")
|
|
122
|
+
refund_receiver: str = Field(alias="refundReceiver")
|
|
123
|
+
nonce: int
|
|
124
|
+
execution_date: str | None = Field(alias="executionDate")
|
|
125
|
+
submission_date: str = Field(alias="submissionDate")
|
|
126
|
+
modified: str
|
|
127
|
+
block_number: int | None = Field(alias="blockNumber")
|
|
128
|
+
transaction_hash: str | None = Field(alias="transactionHash")
|
|
129
|
+
safe_tx_hash: str = Field(alias="safeTxHash")
|
|
130
|
+
executor: str | None
|
|
131
|
+
is_executed: bool = Field(alias="isExecuted")
|
|
132
|
+
is_successful: bool | None = Field(alias="isSuccessful")
|
|
133
|
+
eth_gas_price: str | None = Field(alias="ethGasPrice")
|
|
134
|
+
max_fee_per_gas: str | None = Field(alias="maxFeePerGas")
|
|
135
|
+
max_priority_fee_per_gas: str | None = Field(alias="maxPriorityFeePerGas")
|
|
136
|
+
gas_used: int | None = Field(alias="gasUsed")
|
|
137
|
+
fee: str | None
|
|
138
|
+
origin: str | None
|
|
139
|
+
data_decoded: dict[str, Any] | None = Field(alias="dataDecoded")
|
|
140
|
+
confirmations_required: int = Field(alias="confirmationsRequired")
|
|
141
|
+
confirmations: list[dict[str, Any]] | None
|
|
142
|
+
trusted: bool
|
|
143
|
+
signatures: str | None
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class SafeBalanceResponse(BaseModel):
|
|
147
|
+
token_address: str | None = Field(alias="tokenAddress")
|
|
148
|
+
token: dict[str, Any] | None
|
|
149
|
+
balance: str
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class SafeIncomingTransactionResponse(BaseModel):
|
|
153
|
+
execution_date: str = Field(alias="executionDate")
|
|
154
|
+
transaction_hash: str = Field(alias="transactionHash")
|
|
155
|
+
to: str
|
|
156
|
+
value: str
|
|
157
|
+
token_address: str | None = Field(alias="tokenAddress")
|
|
158
|
+
from_: str = Field(alias="from")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class SafeModuleTransactionResponse(BaseModel):
|
|
162
|
+
created: str
|
|
163
|
+
execution_date: str = Field(alias="executionDate")
|
|
164
|
+
block_number: int = Field(alias="blockNumber")
|
|
165
|
+
is_successful: bool = Field(alias="isSuccessful")
|
|
166
|
+
transaction_hash: str = Field(alias="transactionHash")
|
|
167
|
+
safe: str
|
|
168
|
+
module: str
|
|
169
|
+
to: str
|
|
170
|
+
value: str
|
|
171
|
+
data: str | None
|
|
172
|
+
operation: int
|
|
173
|
+
data_decoded: dict[str, Any] | None = Field(alias="dataDecoded")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class SafeInfoResponse(BaseModel):
|
|
177
|
+
"""Information about a Safe from the Transaction Service."""
|
|
178
|
+
|
|
179
|
+
address: str
|
|
180
|
+
nonce: int
|
|
181
|
+
threshold: int
|
|
182
|
+
owners: list[str]
|
|
183
|
+
master_copy: str = Field(alias="masterCopy")
|
|
184
|
+
modules: list[str]
|
|
185
|
+
fallback_handler: str = Field(alias="fallbackHandler")
|
|
186
|
+
guard: str
|
|
187
|
+
version: str | None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class SafeCreationInfoResponse(BaseModel):
|
|
191
|
+
"""Information about Safe creation."""
|
|
192
|
+
|
|
193
|
+
created: str
|
|
194
|
+
creator: str
|
|
195
|
+
transaction_hash: str = Field(alias="transactionHash")
|
|
196
|
+
factory_address: str = Field(alias="factoryAddress")
|
|
197
|
+
master_copy: str = Field(alias="masterCopy")
|
|
198
|
+
setup_data: str | None = Field(alias="setupData")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class SafeCollectibleResponse(BaseModel):
|
|
202
|
+
"""NFT/Collectible owned by a Safe."""
|
|
203
|
+
|
|
204
|
+
address: str
|
|
205
|
+
token_name: str = Field(alias="tokenName")
|
|
206
|
+
token_symbol: str = Field(alias="tokenSymbol")
|
|
207
|
+
logo_uri: str = Field(alias="logoUri")
|
|
208
|
+
id: str
|
|
209
|
+
uri: str | None
|
|
210
|
+
name: str | None
|
|
211
|
+
description: str | None
|
|
212
|
+
image_uri: str | None = Field(alias="imageUri")
|
|
213
|
+
metadata: dict[str, Any] | None
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class SafeDelegateResponse(BaseModel):
|
|
217
|
+
"""Delegate for a Safe."""
|
|
218
|
+
|
|
219
|
+
safe: str | None
|
|
220
|
+
delegate: str
|
|
221
|
+
delegator: str
|
|
222
|
+
label: str
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class SafeTokenResponse(BaseModel):
|
|
226
|
+
"""Information about a Token."""
|
|
227
|
+
|
|
228
|
+
address: str
|
|
229
|
+
name: str
|
|
230
|
+
symbol: str
|
|
231
|
+
decimals: int
|
|
232
|
+
logo_uri: str | None = Field(alias="logoUri")
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class SafeDataDecoderResponse(BaseModel):
|
|
236
|
+
"""Decoded data from the Safe Transaction Service."""
|
|
237
|
+
|
|
238
|
+
method: str
|
|
239
|
+
parameters: list[dict[str, Any]] | None
|