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 ADDED
@@ -0,0 +1,22 @@
1
+ # Init file for safe_kit package
2
+ from safe_kit.adapter import EthAdapter, Web3Adapter
3
+ from safe_kit.errors import SafeKitError, SafeTransactionError
4
+ from safe_kit.factory import SafeFactory
5
+ from safe_kit.multisend import MultiSend
6
+ from safe_kit.safe import Safe
7
+ from safe_kit.service import SafeServiceClient
8
+ from safe_kit.types import SafeAccountConfig, SafeTransaction, SafeTransactionData
9
+
10
+ __all__ = [
11
+ "Safe",
12
+ "SafeFactory",
13
+ "SafeAccountConfig",
14
+ "SafeTransaction",
15
+ "SafeTransactionData",
16
+ "EthAdapter",
17
+ "Web3Adapter",
18
+ "SafeKitError",
19
+ "SafeTransactionError",
20
+ "MultiSend",
21
+ "SafeServiceClient",
22
+ ]
safe_kit/abis.py ADDED
@@ -0,0 +1,366 @@
1
+ from typing import Any
2
+
3
+ SAFE_ABI: list[dict[str, Any]] = [
4
+ {
5
+ "inputs": [
6
+ {"internalType": "address", "name": "to", "type": "address"},
7
+ {"internalType": "uint256", "name": "value", "type": "uint256"},
8
+ {"internalType": "bytes", "name": "data", "type": "bytes"},
9
+ {
10
+ "internalType": "enum Enum.Operation",
11
+ "name": "operation",
12
+ "type": "uint8",
13
+ },
14
+ {"internalType": "uint256", "name": "safeTxGas", "type": "uint256"},
15
+ {"internalType": "uint256", "name": "baseGas", "type": "uint256"},
16
+ {"internalType": "uint256", "name": "gasPrice", "type": "uint256"},
17
+ {"internalType": "address", "name": "gasToken", "type": "address"},
18
+ {
19
+ "internalType": "address payable",
20
+ "name": "refundReceiver",
21
+ "type": "address",
22
+ },
23
+ {"internalType": "bytes", "name": "signatures", "type": "bytes"},
24
+ ],
25
+ "name": "execTransaction",
26
+ "outputs": [{"internalType": "bool", "name": "", "type": "bool"}],
27
+ "stateMutability": "payable",
28
+ "type": "function",
29
+ },
30
+ {
31
+ "inputs": [
32
+ {"internalType": "bytes32", "name": "hashToApprove", "type": "bytes32"}
33
+ ],
34
+ "name": "approveHash",
35
+ "outputs": [],
36
+ "stateMutability": "nonpayable",
37
+ "type": "function",
38
+ },
39
+ {
40
+ "inputs": [
41
+ {"internalType": "address", "name": "to", "type": "address"},
42
+ {"internalType": "uint256", "name": "value", "type": "uint256"},
43
+ {"internalType": "bytes", "name": "data", "type": "bytes"},
44
+ {
45
+ "internalType": "enum Enum.Operation",
46
+ "name": "operation",
47
+ "type": "uint8",
48
+ },
49
+ {"internalType": "uint256", "name": "safeTxGas", "type": "uint256"},
50
+ {"internalType": "uint256", "name": "baseGas", "type": "uint256"},
51
+ {"internalType": "uint256", "name": "gasPrice", "type": "uint256"},
52
+ {"internalType": "address", "name": "gasToken", "type": "address"},
53
+ {
54
+ "internalType": "address payable",
55
+ "name": "refundReceiver",
56
+ "type": "address",
57
+ },
58
+ {"internalType": "uint256", "name": "_nonce", "type": "uint256"},
59
+ ],
60
+ "name": "getTransactionHash",
61
+ "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}],
62
+ "stateMutability": "view",
63
+ "type": "function",
64
+ },
65
+ {
66
+ "inputs": [
67
+ {"internalType": "address", "name": "to", "type": "address"},
68
+ {"internalType": "uint256", "name": "value", "type": "uint256"},
69
+ {"internalType": "bytes", "name": "data", "type": "bytes"},
70
+ {
71
+ "internalType": "enum Enum.Operation",
72
+ "name": "operation",
73
+ "type": "uint8",
74
+ },
75
+ {"internalType": "uint256", "name": "safeTxGas", "type": "uint256"},
76
+ {"internalType": "uint256", "name": "baseGas", "type": "uint256"},
77
+ {"internalType": "uint256", "name": "gasPrice", "type": "uint256"},
78
+ {"internalType": "address", "name": "gasToken", "type": "address"},
79
+ {
80
+ "internalType": "address payable",
81
+ "name": "refundReceiver",
82
+ "type": "address",
83
+ },
84
+ {"internalType": "bytes", "name": "signatures", "type": "bytes"},
85
+ ],
86
+ "name": "requiredTxGas",
87
+ "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
88
+ "stateMutability": "view",
89
+ "type": "function",
90
+ },
91
+ {
92
+ "inputs": [],
93
+ "name": "nonce",
94
+ "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
95
+ "stateMutability": "view",
96
+ "type": "function",
97
+ },
98
+ {
99
+ "inputs": [],
100
+ "name": "getThreshold",
101
+ "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
102
+ "stateMutability": "view",
103
+ "type": "function",
104
+ },
105
+ {
106
+ "inputs": [],
107
+ "name": "getOwners",
108
+ "outputs": [{"internalType": "address[]", "name": "", "type": "address[]"}],
109
+ "stateMutability": "view",
110
+ "type": "function",
111
+ },
112
+ {
113
+ "inputs": [],
114
+ "name": "getChainId",
115
+ "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
116
+ "stateMutability": "view",
117
+ "type": "function",
118
+ },
119
+ {
120
+ "inputs": [],
121
+ "name": "VERSION",
122
+ "outputs": [{"internalType": "string", "name": "", "type": "string"}],
123
+ "stateMutability": "view",
124
+ "type": "function",
125
+ },
126
+ {
127
+ "inputs": [{"internalType": "address", "name": "owner", "type": "address"}],
128
+ "name": "isOwner",
129
+ "outputs": [{"internalType": "bool", "name": "", "type": "bool"}],
130
+ "stateMutability": "view",
131
+ "type": "function",
132
+ },
133
+ {
134
+ "inputs": [
135
+ {"internalType": "address[]", "name": "_owners", "type": "address[]"},
136
+ {"internalType": "uint256", "name": "_threshold", "type": "uint256"},
137
+ {"internalType": "address", "name": "to", "type": "address"},
138
+ {"internalType": "bytes", "name": "data", "type": "bytes"},
139
+ {"internalType": "address", "name": "fallbackHandler", "type": "address"},
140
+ {"internalType": "address", "name": "paymentToken", "type": "address"},
141
+ {"internalType": "uint256", "name": "payment", "type": "uint256"},
142
+ {
143
+ "internalType": "address payable",
144
+ "name": "paymentReceiver",
145
+ "type": "address",
146
+ },
147
+ ],
148
+ "name": "setup",
149
+ "outputs": [],
150
+ "stateMutability": "nonpayable",
151
+ "type": "function",
152
+ },
153
+ {
154
+ "inputs": [
155
+ {"internalType": "address", "name": "owner", "type": "address"},
156
+ {"internalType": "uint256", "name": "_threshold", "type": "uint256"},
157
+ ],
158
+ "name": "addOwnerWithThreshold",
159
+ "outputs": [],
160
+ "stateMutability": "nonpayable",
161
+ "type": "function",
162
+ },
163
+ {
164
+ "inputs": [
165
+ {"internalType": "address", "name": "prevOwner", "type": "address"},
166
+ {"internalType": "address", "name": "owner", "type": "address"},
167
+ {"internalType": "uint256", "name": "_threshold", "type": "uint256"},
168
+ ],
169
+ "name": "removeOwner",
170
+ "outputs": [],
171
+ "stateMutability": "nonpayable",
172
+ "type": "function",
173
+ },
174
+ {
175
+ "inputs": [
176
+ {"internalType": "address", "name": "prevOwner", "type": "address"},
177
+ {"internalType": "address", "name": "oldOwner", "type": "address"},
178
+ {"internalType": "address", "name": "newOwner", "type": "address"},
179
+ ],
180
+ "name": "swapOwner",
181
+ "outputs": [],
182
+ "stateMutability": "nonpayable",
183
+ "type": "function",
184
+ },
185
+ {
186
+ "inputs": [
187
+ {"internalType": "uint256", "name": "_threshold", "type": "uint256"}
188
+ ],
189
+ "name": "changeThreshold",
190
+ "outputs": [],
191
+ "stateMutability": "nonpayable",
192
+ "type": "function",
193
+ },
194
+ {
195
+ "inputs": [{"internalType": "address", "name": "module", "type": "address"}],
196
+ "name": "enableModule",
197
+ "outputs": [],
198
+ "stateMutability": "nonpayable",
199
+ "type": "function",
200
+ },
201
+ {
202
+ "inputs": [
203
+ {"internalType": "address", "name": "prevModule", "type": "address"},
204
+ {"internalType": "address", "name": "module", "type": "address"},
205
+ ],
206
+ "name": "disableModule",
207
+ "outputs": [],
208
+ "stateMutability": "nonpayable",
209
+ "type": "function",
210
+ },
211
+ {
212
+ "inputs": [
213
+ {"internalType": "address", "name": "start", "type": "address"},
214
+ {"internalType": "uint256", "name": "pageSize", "type": "uint256"},
215
+ ],
216
+ "name": "getModulesPaginated",
217
+ "outputs": [
218
+ {"internalType": "address[]", "name": "array", "type": "address[]"},
219
+ {"internalType": "address", "name": "next", "type": "address"},
220
+ ],
221
+ "stateMutability": "view",
222
+ "type": "function",
223
+ },
224
+ {
225
+ "inputs": [{"internalType": "address", "name": "module", "type": "address"}],
226
+ "name": "isModuleEnabled",
227
+ "outputs": [{"internalType": "bool", "name": "", "type": "bool"}],
228
+ "stateMutability": "view",
229
+ "type": "function",
230
+ },
231
+ {
232
+ "inputs": [
233
+ {"internalType": "bytes32", "name": "dataHash", "type": "bytes32"},
234
+ {"internalType": "bytes", "name": "data", "type": "bytes"},
235
+ {"internalType": "bytes", "name": "signatures", "type": "bytes"},
236
+ ],
237
+ "name": "checkSignatures",
238
+ "outputs": [],
239
+ "stateMutability": "view",
240
+ "type": "function",
241
+ },
242
+ {
243
+ "inputs": [{"internalType": "address", "name": "guard", "type": "address"}],
244
+ "name": "setGuard",
245
+ "outputs": [],
246
+ "stateMutability": "nonpayable",
247
+ "type": "function",
248
+ },
249
+ {
250
+ "inputs": [{"internalType": "address", "name": "handler", "type": "address"}],
251
+ "name": "setFallbackHandler",
252
+ "outputs": [],
253
+ "stateMutability": "nonpayable",
254
+ "type": "function",
255
+ },
256
+ ]
257
+
258
+ SAFE_PROXY_FACTORY_ABI: list[dict[str, Any]] = [
259
+ {
260
+ "inputs": [
261
+ {"internalType": "address", "name": "_singleton", "type": "address"},
262
+ {"internalType": "bytes", "name": "initializer", "type": "bytes"},
263
+ {"internalType": "uint256", "name": "saltNonce", "type": "uint256"},
264
+ ],
265
+ "name": "createProxyWithNonce",
266
+ "outputs": [{"internalType": "address", "name": "proxy", "type": "address"}],
267
+ "stateMutability": "nonpayable",
268
+ "type": "function",
269
+ },
270
+ {
271
+ "anonymous": False,
272
+ "inputs": [
273
+ {
274
+ "indexed": True,
275
+ "internalType": "address",
276
+ "name": "proxy",
277
+ "type": "address",
278
+ },
279
+ {
280
+ "indexed": False,
281
+ "internalType": "address",
282
+ "name": "singleton",
283
+ "type": "address",
284
+ },
285
+ ],
286
+ "name": "ProxyCreation",
287
+ "type": "event",
288
+ },
289
+ {
290
+ "inputs": [
291
+ {"internalType": "address", "name": "_singleton", "type": "address"},
292
+ {"internalType": "bytes", "name": "initializer", "type": "bytes"},
293
+ {"internalType": "uint256", "name": "saltNonce", "type": "uint256"},
294
+ ],
295
+ "name": "createChainSpecificProxyWithNonce",
296
+ "outputs": [{"internalType": "address", "name": "proxy", "type": "address"}],
297
+ "stateMutability": "nonpayable",
298
+ "type": "function",
299
+ },
300
+ {
301
+ "inputs": [
302
+ {"internalType": "address", "name": "_singleton", "type": "address"},
303
+ {"internalType": "bytes", "name": "initializer", "type": "bytes"},
304
+ {"internalType": "uint256", "name": "saltNonce", "type": "uint256"},
305
+ {
306
+ "internalType": "address",
307
+ "name": "callback",
308
+ "type": "address",
309
+ },
310
+ ],
311
+ "name": "createProxyWithCallback",
312
+ "outputs": [{"internalType": "address", "name": "proxy", "type": "address"}],
313
+ "stateMutability": "nonpayable",
314
+ "type": "function",
315
+ },
316
+ ]
317
+
318
+ ERC20_ABI: list[dict[str, Any]] = [
319
+ {
320
+ "constant": False,
321
+ "inputs": [
322
+ {"name": "_to", "type": "address"},
323
+ {"name": "_value", "type": "uint256"},
324
+ ],
325
+ "name": "transfer",
326
+ "outputs": [{"name": "", "type": "bool"}],
327
+ "payable": False,
328
+ "stateMutability": "nonpayable",
329
+ "type": "function",
330
+ }
331
+ ]
332
+
333
+ ERC721_ABI: list[dict[str, Any]] = [
334
+ {
335
+ "inputs": [
336
+ {"internalType": "address", "name": "from", "type": "address"},
337
+ {"internalType": "address", "name": "to", "type": "address"},
338
+ {"internalType": "uint256", "name": "tokenId", "type": "uint256"},
339
+ ],
340
+ "name": "safeTransferFrom",
341
+ "outputs": [],
342
+ "stateMutability": "nonpayable",
343
+ "type": "function",
344
+ },
345
+ {
346
+ "inputs": [
347
+ {"internalType": "address", "name": "from", "type": "address"},
348
+ {"internalType": "address", "name": "to", "type": "address"},
349
+ {"internalType": "uint256", "name": "tokenId", "type": "uint256"},
350
+ ],
351
+ "name": "transferFrom",
352
+ "outputs": [],
353
+ "stateMutability": "nonpayable",
354
+ "type": "function",
355
+ },
356
+ ]
357
+
358
+ MULTI_SEND_ABI: list[dict[str, Any]] = [
359
+ {
360
+ "inputs": [{"internalType": "bytes", "name": "transactions", "type": "bytes"}],
361
+ "name": "multiSend",
362
+ "outputs": [],
363
+ "stateMutability": "payable",
364
+ "type": "function",
365
+ }
366
+ ]
safe_kit/adapter.py ADDED
@@ -0,0 +1,147 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any
3
+
4
+ from eth_account.signers.local import LocalAccount
5
+ from web3 import Web3
6
+
7
+
8
+ class EthAdapter(ABC):
9
+ """
10
+ Abstract base class for Ethereum adapters.
11
+ """
12
+
13
+ @abstractmethod
14
+ def get_balance(self, address: str) -> int:
15
+ pass
16
+
17
+ @abstractmethod
18
+ def get_chain_id(self) -> int:
19
+ pass
20
+
21
+ @abstractmethod
22
+ def get_safe_contract(self, safe_address: str) -> Any:
23
+ pass
24
+
25
+ @abstractmethod
26
+ def get_contract(self, address: str, abi: list[Any]) -> Any:
27
+ pass
28
+
29
+ @abstractmethod
30
+ def get_signer_address(self) -> str | None:
31
+ pass
32
+
33
+ @abstractmethod
34
+ def sign_message(self, message: str) -> str:
35
+ pass
36
+
37
+ @abstractmethod
38
+ def sign_typed_data(self, data: dict[str, Any]) -> str:
39
+ pass
40
+
41
+ @abstractmethod
42
+ def get_storage_at(self, address: str, position: int) -> bytes:
43
+ pass
44
+
45
+ @abstractmethod
46
+ def get_code(self, address: str) -> bytes:
47
+ pass
48
+
49
+ @abstractmethod
50
+ def get_transaction_count(self, address: str) -> int:
51
+ pass
52
+
53
+ @abstractmethod
54
+ def is_contract(self, address: str) -> bool:
55
+ pass
56
+
57
+ @abstractmethod
58
+ def to_checksum_address(self, address: str) -> str:
59
+ pass
60
+
61
+ @abstractmethod
62
+ def wait_for_transaction_receipt(self, tx_hash: str, timeout: int = 120) -> Any:
63
+ pass
64
+
65
+
66
+ class Web3Adapter(EthAdapter):
67
+ """
68
+ Web3.py implementation of the EthAdapter.
69
+ """
70
+
71
+ def __init__(self, web3: Web3, signer: LocalAccount | None = None):
72
+ self.web3 = web3
73
+ self.signer = signer
74
+
75
+ def get_balance(self, address: str) -> int:
76
+ return self.web3.eth.get_balance(self.web3.to_checksum_address(address))
77
+
78
+ def get_chain_id(self) -> int:
79
+ return self.web3.eth.chain_id
80
+
81
+ def get_safe_contract(self, safe_address: str) -> Any:
82
+ from safe_kit.abis import SAFE_ABI
83
+
84
+ return self.web3.eth.contract(
85
+ address=self.web3.to_checksum_address(safe_address), abi=SAFE_ABI
86
+ )
87
+
88
+ def get_contract(self, address: str, abi: list[Any]) -> Any:
89
+ return self.web3.eth.contract(
90
+ address=self.web3.to_checksum_address(address), abi=abi
91
+ )
92
+
93
+ def get_signer_address(self) -> str | None:
94
+ if self.signer:
95
+ return str(self.signer.address)
96
+ return None
97
+
98
+ def sign_message(self, message: str) -> str:
99
+ if not self.signer:
100
+ raise ValueError("No signer available")
101
+
102
+ from eth_account.messages import encode_defunct
103
+
104
+ # Check if message is a hex string (likely a hash)
105
+ if message.startswith("0x"):
106
+ signable_message = encode_defunct(hexstr=message)
107
+ else:
108
+ signable_message = encode_defunct(text=message)
109
+
110
+ signed_message = self.signer.sign_message(signable_message) # type: ignore[no-untyped-call]
111
+ return str(signed_message.signature.hex())
112
+
113
+ def sign_typed_data(self, data: dict[str, Any]) -> str:
114
+ if not self.signer:
115
+ raise ValueError("No signer available")
116
+ from eth_account.messages import encode_typed_data
117
+
118
+ signable_message = encode_typed_data(full_message=data)
119
+ signed_message = self.signer.sign_message(signable_message) # type: ignore[no-untyped-call]
120
+ return str(signed_message.signature.hex())
121
+
122
+ def get_storage_at(self, address: str, position: int) -> bytes:
123
+ return self.web3.eth.get_storage_at(
124
+ self.web3.to_checksum_address(address), position
125
+ )
126
+
127
+ def get_code(self, address: str) -> bytes:
128
+ return self.web3.eth.get_code(self.web3.to_checksum_address(address))
129
+
130
+ def get_transaction_count(self, address: str) -> int:
131
+ return self.web3.eth.get_transaction_count(
132
+ self.web3.to_checksum_address(address)
133
+ )
134
+
135
+ def is_contract(self, address: str) -> bool:
136
+ code = self.get_code(address)
137
+ return len(code) > 0
138
+
139
+ def to_checksum_address(self, address: str) -> str:
140
+ return self.web3.to_checksum_address(address)
141
+
142
+ def wait_for_transaction_receipt(self, tx_hash: str, timeout: int = 120) -> Any:
143
+ from hexbytes import HexBytes
144
+
145
+ return self.web3.eth.wait_for_transaction_receipt(
146
+ HexBytes(tx_hash), timeout=timeout
147
+ )
@@ -0,0 +1,151 @@
1
+ # This file is automatically generated by scripts/generate_types.py
2
+ # Do not edit manually.
3
+
4
+ from typing import Any, TypedDict # noqa: F401
5
+
6
+
7
+ class SafeExecTransactionParams(TypedDict):
8
+ to: str
9
+ value: int
10
+ data: bytes
11
+ operation: int
12
+ safeTxGas: int
13
+ baseGas: int
14
+ gasPrice: int
15
+ gasToken: str
16
+ refundReceiver: str
17
+ signatures: bytes
18
+
19
+
20
+ class SafeApproveHashParams(TypedDict):
21
+ hashToApprove: bytes
22
+
23
+
24
+ class SafeGetTransactionHashParams(TypedDict):
25
+ to: str
26
+ value: int
27
+ data: bytes
28
+ operation: int
29
+ safeTxGas: int
30
+ baseGas: int
31
+ gasPrice: int
32
+ gasToken: str
33
+ refundReceiver: str
34
+ _nonce: int
35
+
36
+
37
+ class SafeRequiredTxGasParams(TypedDict):
38
+ to: str
39
+ value: int
40
+ data: bytes
41
+ operation: int
42
+ safeTxGas: int
43
+ baseGas: int
44
+ gasPrice: int
45
+ gasToken: str
46
+ refundReceiver: str
47
+ signatures: bytes
48
+
49
+
50
+ class SafeIsOwnerParams(TypedDict):
51
+ owner: str
52
+
53
+
54
+ class SafeSetupParams(TypedDict):
55
+ _owners: list[str]
56
+ _threshold: int
57
+ to: str
58
+ data: bytes
59
+ fallbackHandler: str
60
+ paymentToken: str
61
+ payment: int
62
+ paymentReceiver: str
63
+
64
+
65
+ class SafeAddOwnerWithThresholdParams(TypedDict):
66
+ owner: str
67
+ _threshold: int
68
+
69
+
70
+ class SafeRemoveOwnerParams(TypedDict):
71
+ prevOwner: str
72
+ owner: str
73
+ _threshold: int
74
+
75
+
76
+ class SafeSwapOwnerParams(TypedDict):
77
+ prevOwner: str
78
+ oldOwner: str
79
+ newOwner: str
80
+
81
+
82
+ class SafeChangeThresholdParams(TypedDict):
83
+ _threshold: int
84
+
85
+
86
+ class SafeEnableModuleParams(TypedDict):
87
+ module: str
88
+
89
+
90
+ class SafeDisableModuleParams(TypedDict):
91
+ prevModule: str
92
+ module: str
93
+
94
+
95
+ class SafeGetModulesPaginatedParams(TypedDict):
96
+ start: str
97
+ pageSize: int
98
+
99
+
100
+ class SafeIsModuleEnabledParams(TypedDict):
101
+ module: str
102
+
103
+
104
+ class SafeCheckSignaturesParams(TypedDict):
105
+ dataHash: bytes
106
+ data: bytes
107
+ signatures: bytes
108
+
109
+
110
+ class SafeSetGuardParams(TypedDict):
111
+ guard: str
112
+
113
+
114
+ class SafeSetFallbackHandlerParams(TypedDict):
115
+ handler: str
116
+
117
+
118
+ class SafeProxyFactoryCreateProxyWithNonceParams(TypedDict):
119
+ _singleton: str
120
+ initializer: bytes
121
+ saltNonce: int
122
+
123
+
124
+ class SafeProxyFactoryCreateChainSpecificProxyWithNonceParams(TypedDict):
125
+ _singleton: str
126
+ initializer: bytes
127
+ saltNonce: int
128
+
129
+
130
+ class SafeProxyFactoryCreateProxyWithCallbackParams(TypedDict):
131
+ _singleton: str
132
+ initializer: bytes
133
+ saltNonce: int
134
+ callback: str
135
+
136
+
137
+ class Erc20TransferParams(TypedDict):
138
+ _to: str
139
+ _value: int
140
+
141
+
142
+ class Erc721SafeTransferFromParams(TypedDict):
143
+ from_: str
144
+ to: str
145
+ tokenId: int
146
+
147
+
148
+ class Erc721TransferFromParams(TypedDict):
149
+ from_: str
150
+ to: str
151
+ tokenId: int