flexvaults 0.1.5__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.
flexvaults/__init__.py ADDED
@@ -0,0 +1,168 @@
1
+ from .client import (
2
+ AccountingApiError,
3
+ FlexvaultsClient,
4
+ HttpClient,
5
+ NetworkError,
6
+ ValidationError,
7
+ )
8
+ from .signatures import (
9
+ LOCK_TYPES,
10
+ TRANSFER_LOCKED_TYPES,
11
+ TRANSFER_TYPES,
12
+ WITHDRAW_TYPES,
13
+ EIP712Domain,
14
+ LockMessage,
15
+ SignLockParams,
16
+ SignTransferLockedParams,
17
+ SignTransferParams,
18
+ SignWithdrawParams,
19
+ TransferLockedMessage,
20
+ TransferMessage,
21
+ WithdrawMessage,
22
+ create_domain,
23
+ create_lock_expiry,
24
+ sign_lock_message,
25
+ sign_transfer_locked_message,
26
+ sign_transfer_message,
27
+ sign_withdraw_message,
28
+ )
29
+ from .types import (
30
+ NETWORK_CONFIG,
31
+ SUPPORTED_CHAINS,
32
+ SUPPORTED_TOKENS,
33
+ Address,
34
+ BalanceResponse,
35
+ BatchBalancesRequest,
36
+ BatchBalancesResponse,
37
+ Bytes32,
38
+ ChainConfig,
39
+ DepositQuoteRequest,
40
+ DepositQuoteResponse,
41
+ ExpiredLocksResponse,
42
+ HexString,
43
+ IncludeDepositRequest,
44
+ IncludeDepositResponse,
45
+ LockedFundsResponse,
46
+ LockFundsRequest,
47
+ LockInfo,
48
+ Network,
49
+ NetworkConfig,
50
+ PendingWithdrawal,
51
+ PendingWithdrawalsResponse,
52
+ SupportedToken,
53
+ TokenBalance,
54
+ TokenConfig,
55
+ TokenInfoResponse,
56
+ TotalLockedBalanceResponse,
57
+ TransactionData,
58
+ TransactionSubmissionResponse,
59
+ TransferFundsRequest,
60
+ TransferLockedFundsRequest,
61
+ UnlockAllExpiredRequest,
62
+ UnlockFundsRequest,
63
+ WithdrawalInfoResponse,
64
+ WithdrawalRequest,
65
+ get_accounting_contract,
66
+ get_all_tokens,
67
+ get_api_url,
68
+ get_chain_by_id,
69
+ get_chain_id,
70
+ get_explorer_address_url,
71
+ get_token_by_id,
72
+ get_token_config,
73
+ is_valid_token,
74
+ normalize_address,
75
+ normalize_hex,
76
+ )
77
+ from .utils import (
78
+ format_relative_time,
79
+ format_time_remaining,
80
+ format_timestamp,
81
+ format_token_amount,
82
+ is_expired,
83
+ parse_token_amount,
84
+ shorten_address,
85
+ )
86
+
87
+ __version__ = "0.1.5"
88
+
89
+ __all__ = [
90
+ "__version__",
91
+ "Address",
92
+ "Bytes32",
93
+ "HexString",
94
+ "Network",
95
+ "NetworkConfig",
96
+ "NETWORK_CONFIG",
97
+ "get_chain_id",
98
+ "get_accounting_contract",
99
+ "get_api_url",
100
+ "normalize_hex",
101
+ "normalize_address",
102
+ "TokenConfig",
103
+ "SupportedToken",
104
+ "SUPPORTED_TOKENS",
105
+ "get_token_config",
106
+ "get_token_by_id",
107
+ "is_valid_token",
108
+ "ChainConfig",
109
+ "SUPPORTED_CHAINS",
110
+ "get_chain_by_id",
111
+ "get_explorer_address_url",
112
+ "get_all_tokens",
113
+ "DepositQuoteRequest",
114
+ "IncludeDepositRequest",
115
+ "LockFundsRequest",
116
+ "UnlockFundsRequest",
117
+ "UnlockAllExpiredRequest",
118
+ "TransferFundsRequest",
119
+ "TransferLockedFundsRequest",
120
+ "WithdrawalRequest",
121
+ "BatchBalancesRequest",
122
+ "TransactionData",
123
+ "DepositQuoteResponse",
124
+ "IncludeDepositResponse",
125
+ "TransactionSubmissionResponse",
126
+ "BalanceResponse",
127
+ "TokenBalance",
128
+ "BatchBalancesResponse",
129
+ "TokenInfoResponse",
130
+ "LockInfo",
131
+ "LockedFundsResponse",
132
+ "ExpiredLocksResponse",
133
+ "TotalLockedBalanceResponse",
134
+ "PendingWithdrawal",
135
+ "PendingWithdrawalsResponse",
136
+ "WithdrawalInfoResponse",
137
+ "FlexvaultsClient",
138
+ "HttpClient",
139
+ "AccountingApiError",
140
+ "NetworkError",
141
+ "ValidationError",
142
+ "EIP712Domain",
143
+ "create_domain",
144
+ "LOCK_TYPES",
145
+ "TRANSFER_TYPES",
146
+ "TRANSFER_LOCKED_TYPES",
147
+ "WITHDRAW_TYPES",
148
+ "LockMessage",
149
+ "TransferMessage",
150
+ "TransferLockedMessage",
151
+ "WithdrawMessage",
152
+ "SignLockParams",
153
+ "sign_lock_message",
154
+ "create_lock_expiry",
155
+ "SignTransferParams",
156
+ "sign_transfer_message",
157
+ "SignTransferLockedParams",
158
+ "sign_transfer_locked_message",
159
+ "SignWithdrawParams",
160
+ "sign_withdraw_message",
161
+ "format_token_amount",
162
+ "parse_token_amount",
163
+ "shorten_address",
164
+ "format_timestamp",
165
+ "is_expired",
166
+ "format_time_remaining",
167
+ "format_relative_time",
168
+ ]
@@ -0,0 +1,11 @@
1
+ from .errors import AccountingApiError, NetworkError, ValidationError
2
+ from .flexvaults_client import FlexvaultsClient
3
+ from .http_client import HttpClient
4
+
5
+ __all__ = [
6
+ "AccountingApiError",
7
+ "NetworkError",
8
+ "ValidationError",
9
+ "HttpClient",
10
+ "FlexvaultsClient",
11
+ ]
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ class AccountingApiError(Exception):
5
+ def __init__(
6
+ self,
7
+ message: str,
8
+ status_code: int,
9
+ detail: str | None = None,
10
+ ) -> None:
11
+ super().__init__(message)
12
+ self.status_code = status_code
13
+ self.detail = detail
14
+
15
+
16
+ class NetworkError(Exception):
17
+ def __init__(
18
+ self,
19
+ message: str,
20
+ cause: Exception | None = None,
21
+ ) -> None:
22
+ super().__init__(message)
23
+ self.__cause__ = cause
24
+
25
+
26
+ class ValidationError(Exception):
27
+ def __init__(
28
+ self,
29
+ message: str,
30
+ field: str | None = None,
31
+ ) -> None:
32
+ super().__init__(message)
33
+ self.field = field
@@ -0,0 +1,358 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from ..types import (
6
+ normalize_address,
7
+ normalize_hex,
8
+ )
9
+ from ..types.requests import (
10
+ BatchBalancesRequest,
11
+ DepositQuoteRequest,
12
+ IncludeDepositRequest,
13
+ LockFundsRequest,
14
+ TransferFundsRequest,
15
+ TransferLockedFundsRequest,
16
+ UnlockAllExpiredRequest,
17
+ UnlockFundsRequest,
18
+ WithdrawalRequest,
19
+ )
20
+ from ..types.responses import (
21
+ BalanceResponse,
22
+ BatchBalancesResponse,
23
+ DepositQuoteResponse,
24
+ ExpiredLocksResponse,
25
+ IncludeDepositResponse,
26
+ LockedFundsResponse,
27
+ LockInfo,
28
+ PendingWithdrawal,
29
+ PendingWithdrawalsResponse,
30
+ TokenBalance,
31
+ TokenInfoResponse,
32
+ TotalLockedBalanceResponse,
33
+ TransactionData,
34
+ TransactionSubmissionResponse,
35
+ WithdrawalInfoResponse,
36
+ )
37
+ from .http_client import HttpClient
38
+
39
+
40
+ def _parse_transaction_data(data: dict[str, Any]) -> TransactionData:
41
+ return TransactionData(
42
+ to=data["to"],
43
+ value=data["value"],
44
+ data=data["data"],
45
+ chain_id=data["chain_id"],
46
+ )
47
+
48
+
49
+ def _parse_deposit_quote(data: dict[str, Any]) -> DepositQuoteResponse:
50
+ return DepositQuoteResponse(
51
+ user_address=data["user_address"],
52
+ token_id=data["token_id"],
53
+ amount=data["amount"],
54
+ deposit_address=data["deposit_address"],
55
+ transaction=_parse_transaction_data(data["transaction"]),
56
+ instructions=data["instructions"],
57
+ )
58
+
59
+
60
+ def _parse_lock_info(data: dict[str, Any]) -> LockInfo:
61
+ return LockInfo(
62
+ lock_index=data["lock_index"],
63
+ user_address=data["user_address"],
64
+ service_address=data["service_address"],
65
+ token_id=data["token_id"],
66
+ amount=data["amount"],
67
+ expiry=data["expiry"],
68
+ is_expired=data["is_expired"],
69
+ )
70
+
71
+
72
+ def _parse_token_balance(data: dict[str, Any]) -> TokenBalance:
73
+ return TokenBalance(
74
+ token_id=data["token_id"],
75
+ balance=data["balance"],
76
+ token_symbol=data["token_symbol"],
77
+ chain_id=data["chain_id"],
78
+ )
79
+
80
+
81
+ def _parse_pending_withdrawal(data: dict[str, Any]) -> PendingWithdrawal:
82
+ return PendingWithdrawal(
83
+ index=data["index"],
84
+ user_address=data["user_address"],
85
+ token_id=data["token_id"],
86
+ amount=data["amount"],
87
+ status=data["status"],
88
+ created_at=data["created_at"],
89
+ )
90
+
91
+
92
+ class FlexvaultsClient:
93
+ def __init__(
94
+ self,
95
+ base_url: str,
96
+ timeout: float = 30.0,
97
+ headers: dict[str, str] | None = None,
98
+ ) -> None:
99
+ self._http = HttpClient(
100
+ base_url=base_url,
101
+ timeout=timeout,
102
+ headers=headers,
103
+ )
104
+
105
+ async def get_deposit_quote(self, request: DepositQuoteRequest) -> DepositQuoteResponse:
106
+ data = await self._http.post(
107
+ "/v1/accounting/quote/deposit",
108
+ {
109
+ "user_address": normalize_address(request.user_address),
110
+ "token_id": normalize_hex(request.token_id),
111
+ "amount": request.amount,
112
+ },
113
+ )
114
+ return _parse_deposit_quote(data)
115
+
116
+ async def include_deposit(self, request: IncludeDepositRequest) -> IncludeDepositResponse:
117
+ body: dict[str, Any] = {
118
+ "user_address": normalize_address(request.user_address),
119
+ "token_id": normalize_hex(request.token_id),
120
+ "evm_transaction_data": normalize_hex(request.evm_transaction_data),
121
+ }
122
+ if request.rlp_block_header is not None:
123
+ body["rlp_block_header"] = normalize_hex(request.rlp_block_header)
124
+ if request.transaction_index_rlp is not None:
125
+ body["transaction_index_rlp"] = normalize_hex(request.transaction_index_rlp)
126
+ if request.transaction_proof_stack is not None:
127
+ body["transaction_proof_stack"] = normalize_hex(request.transaction_proof_stack)
128
+
129
+ data = await self._http.post("/v1/accounting/deposits", body)
130
+ return IncludeDepositResponse(
131
+ submission_id=data["submission_id"],
132
+ status=data["status"],
133
+ )
134
+
135
+ async def get_balance(
136
+ self,
137
+ user_address: str,
138
+ token_id: str,
139
+ ) -> BalanceResponse:
140
+ user = normalize_address(user_address)
141
+ token = normalize_hex(token_id)
142
+ data = await self._http.get(f"/v1/accounting/balances/{user}/{token}")
143
+ return BalanceResponse(
144
+ user_address=data["user_address"],
145
+ token_id=data["token_id"],
146
+ balance=data["balance"],
147
+ token_symbol=data["token_symbol"],
148
+ chain_id=data["chain_id"],
149
+ )
150
+
151
+ async def get_batch_balances(
152
+ self, request: BatchBalancesRequest
153
+ ) -> BatchBalancesResponse:
154
+ data = await self._http.post(
155
+ "/v1/accounting/balances/batch",
156
+ {
157
+ "user_address": normalize_address(request.user_address),
158
+ "token_ids": [normalize_hex(tid) for tid in request.token_ids],
159
+ },
160
+ )
161
+ return BatchBalancesResponse(
162
+ user_address=data["user_address"],
163
+ balances=[_parse_token_balance(b) for b in data.get("balances", [])],
164
+ )
165
+
166
+ async def get_token_info(self, token_id: str) -> TokenInfoResponse:
167
+ token = normalize_hex(token_id)
168
+ data = await self._http.get(f"/v1/accounting/tokens/{token}")
169
+ return TokenInfoResponse(
170
+ token_id=data["token_id"],
171
+ symbol=data["symbol"],
172
+ decimals=data["decimals"],
173
+ chain_id=data["chain_id"],
174
+ contract_address=data.get("contract_address"),
175
+ )
176
+
177
+ async def lock_funds(
178
+ self, request: LockFundsRequest
179
+ ) -> TransactionSubmissionResponse:
180
+ data = await self._http.post(
181
+ "/v1/accounting/funds/lock",
182
+ {
183
+ "user_address": normalize_address(request.user_address),
184
+ "service_address": normalize_address(request.service_address),
185
+ "token_id": normalize_hex(request.token_id),
186
+ "amount": request.amount,
187
+ "expiry": request.expiry,
188
+ "signature": normalize_hex(request.signature),
189
+ },
190
+ )
191
+ return TransactionSubmissionResponse(
192
+ submission_id=data["submission_id"],
193
+ status=data["status"],
194
+ detail=data.get("detail"),
195
+ )
196
+
197
+ async def unlock_funds(
198
+ self, request: UnlockFundsRequest
199
+ ) -> TransactionSubmissionResponse:
200
+ data = await self._http.post(
201
+ "/v1/accounting/funds/unlock",
202
+ {
203
+ "user_address": normalize_address(request.user_address),
204
+ "lock_index": request.lock_index,
205
+ },
206
+ )
207
+ return TransactionSubmissionResponse(
208
+ submission_id=data["submission_id"],
209
+ status=data["status"],
210
+ detail=data.get("detail"),
211
+ )
212
+
213
+ async def unlock_all_expired(
214
+ self, request: UnlockAllExpiredRequest
215
+ ) -> TransactionSubmissionResponse:
216
+ data = await self._http.post(
217
+ "/v1/accounting/funds/unlock-all-expired",
218
+ {
219
+ "user_address": normalize_address(request.user_address),
220
+ },
221
+ )
222
+ return TransactionSubmissionResponse(
223
+ submission_id=data["submission_id"],
224
+ status=data["status"],
225
+ detail=data.get("detail"),
226
+ )
227
+
228
+ async def get_locked_funds(
229
+ self,
230
+ user_address: str,
231
+ service_address: str | None = None,
232
+ ) -> LockedFundsResponse:
233
+ user = normalize_address(user_address)
234
+ query_params = ""
235
+ if service_address:
236
+ query_params = f"?service_address={normalize_address(service_address)}"
237
+ data = await self._http.get(f"/v1/accounting/funds/locked/{user}{query_params}")
238
+ return LockedFundsResponse(
239
+ user_address=data["user_address"],
240
+ service_address=data.get("service_address"),
241
+ locks=[_parse_lock_info(lock) for lock in data.get("locks", [])],
242
+ total_locked=data.get("total_locked", 0),
243
+ )
244
+
245
+ async def get_total_locked_balance(
246
+ self,
247
+ user_address: str,
248
+ token_id: str,
249
+ ) -> TotalLockedBalanceResponse:
250
+ user = normalize_address(user_address)
251
+ token = normalize_hex(token_id)
252
+ data = await self._http.get(
253
+ f"/v1/accounting/funds/locked/total/{user}/{token}"
254
+ )
255
+ return TotalLockedBalanceResponse(
256
+ user_address=data["user_address"],
257
+ token_id=data["token_id"],
258
+ total_locked=data["total_locked"],
259
+ )
260
+
261
+ async def get_expired_locks(self, user_address: str) -> ExpiredLocksResponse:
262
+ user = normalize_address(user_address)
263
+ data = await self._http.get(f"/v1/accounting/funds/expired/{user}")
264
+ return ExpiredLocksResponse(
265
+ user_address=data["user_address"],
266
+ expired_locks=[_parse_lock_info(lock) for lock in data.get("expired_locks", [])],
267
+ )
268
+
269
+ async def transfer_funds(
270
+ self, request: TransferFundsRequest
271
+ ) -> TransactionSubmissionResponse:
272
+ data = await self._http.post(
273
+ "/v1/accounting/funds/transfer",
274
+ {
275
+ "user_address": normalize_address(request.user_address),
276
+ "to_address": normalize_address(request.to_address),
277
+ "token_id": normalize_hex(request.token_id),
278
+ "amount": request.amount,
279
+ "signature": normalize_hex(request.signature),
280
+ },
281
+ )
282
+ return TransactionSubmissionResponse(
283
+ submission_id=data["submission_id"],
284
+ status=data["status"],
285
+ detail=data.get("detail"),
286
+ )
287
+
288
+ async def transfer_locked_funds(
289
+ self, request: TransferLockedFundsRequest
290
+ ) -> TransactionSubmissionResponse:
291
+ data = await self._http.post(
292
+ "/v1/accounting/funds/transfer-locked",
293
+ {
294
+ "user_address": normalize_address(request.user_address),
295
+ "lock_index": request.lock_index,
296
+ "to_address": normalize_address(request.to_address),
297
+ "amount": request.amount,
298
+ "signature": normalize_hex(request.signature),
299
+ },
300
+ )
301
+ return TransactionSubmissionResponse(
302
+ submission_id=data["submission_id"],
303
+ status=data["status"],
304
+ detail=data.get("detail"),
305
+ )
306
+
307
+ async def request_withdrawal(
308
+ self, request: WithdrawalRequest
309
+ ) -> TransactionSubmissionResponse:
310
+ data = await self._http.post(
311
+ "/v1/accounting/withdraw",
312
+ {
313
+ "user_address": normalize_address(request.user_address),
314
+ "token_id": normalize_hex(request.token_id),
315
+ "amount": request.amount,
316
+ "nonce": request.nonce,
317
+ "signature": normalize_hex(request.signature),
318
+ },
319
+ )
320
+ return TransactionSubmissionResponse(
321
+ submission_id=data["submission_id"],
322
+ status=data["status"],
323
+ detail=data.get("detail"),
324
+ )
325
+
326
+ async def get_pending_withdrawals(
327
+ self, user_address: str
328
+ ) -> PendingWithdrawalsResponse:
329
+ user = normalize_address(user_address)
330
+ data = await self._http.get(f"/v1/accounting/withdraw/pending/{user}")
331
+ return PendingWithdrawalsResponse(
332
+ user_address=data["user_address"],
333
+ withdrawals=[
334
+ _parse_pending_withdrawal(w) for w in data.get("withdrawals", [])
335
+ ],
336
+ )
337
+
338
+ async def get_withdrawal_info(self, index: int) -> WithdrawalInfoResponse:
339
+ data = await self._http.get(f"/v1/accounting/withdraw/{index}")
340
+ return WithdrawalInfoResponse(
341
+ index=data["index"],
342
+ user_address=data["user_address"],
343
+ token_id=data["token_id"],
344
+ amount=data["amount"],
345
+ status=data["status"],
346
+ created_at=data["created_at"],
347
+ completed_at=data.get("completed_at"),
348
+ transaction_hash=data.get("transaction_hash"),
349
+ )
350
+
351
+ async def close(self) -> None:
352
+ await self._http.close()
353
+
354
+ async def __aenter__(self) -> FlexvaultsClient:
355
+ return self
356
+
357
+ async def __aexit__(self, *args: Any) -> None:
358
+ await self.close()
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+ from .errors import AccountingApiError, NetworkError
8
+
9
+
10
+ class HttpClient:
11
+ def __init__(
12
+ self,
13
+ base_url: str,
14
+ timeout: float = 30.0,
15
+ headers: dict[str, str] | None = None,
16
+ ) -> None:
17
+ self._base_url = base_url.rstrip("/")
18
+ self._timeout = timeout
19
+ self._headers = {
20
+ "Content-Type": "application/json",
21
+ **(headers or {}),
22
+ }
23
+ self._client = httpx.AsyncClient(
24
+ base_url=self._base_url,
25
+ headers=self._headers,
26
+ timeout=httpx.Timeout(self._timeout),
27
+ )
28
+
29
+ async def get(self, path: str) -> Any:
30
+ return await self._request("GET", path)
31
+
32
+ async def post(self, path: str, body: Any | None = None) -> Any:
33
+ return await self._request("POST", path, body)
34
+
35
+ async def _request(
36
+ self,
37
+ method: str,
38
+ path: str,
39
+ body: Any | None = None,
40
+ ) -> Any:
41
+ try:
42
+ response = await self._client.request(
43
+ method=method,
44
+ url=path,
45
+ json=body,
46
+ )
47
+
48
+ if not response.is_success:
49
+ detail: str | None = None
50
+ try:
51
+ error_body = response.json()
52
+ detail = error_body.get("detail") or error_body.get("message")
53
+ except Exception:
54
+ try:
55
+ detail = response.text
56
+ except Exception:
57
+ pass
58
+
59
+ raise AccountingApiError(
60
+ f"API request failed: {response.status_code} {response.reason_phrase}",
61
+ response.status_code,
62
+ detail,
63
+ )
64
+
65
+ return response.json()
66
+
67
+ except AccountingApiError:
68
+ raise
69
+ except httpx.TimeoutException:
70
+ raise NetworkError(f"Request timeout after {self._timeout}s")
71
+ except httpx.HTTPError as e:
72
+ raise NetworkError(f"Network request failed: {str(e)}", e)
73
+ except Exception as e:
74
+ if isinstance(e, (AccountingApiError, NetworkError)):
75
+ raise
76
+ cause = e if isinstance(e, Exception) else None
77
+ raise NetworkError(f"Unknown network error occurred: {str(e)}", cause)
78
+
79
+ async def close(self) -> None:
80
+ await self._client.aclose()
81
+
82
+ async def __aenter__(self) -> HttpClient:
83
+ return self
84
+
85
+ async def __aexit__(self, *args: Any) -> None:
86
+ await self.close()
flexvaults/py.typed ADDED
File without changes
@@ -0,0 +1,38 @@
1
+ from .eip712_types import (
2
+ LOCK_TYPES,
3
+ TRANSFER_LOCKED_TYPES,
4
+ TRANSFER_TYPES,
5
+ WITHDRAW_TYPES,
6
+ EIP712Domain,
7
+ LockMessage,
8
+ TransferLockedMessage,
9
+ TransferMessage,
10
+ WithdrawMessage,
11
+ create_domain,
12
+ )
13
+ from .sign_lock import SignLockParams, create_lock_expiry, sign_lock_message
14
+ from .sign_transfer import SignTransferParams, sign_transfer_message
15
+ from .sign_transfer_locked import SignTransferLockedParams, sign_transfer_locked_message
16
+ from .sign_withdraw import SignWithdrawParams, sign_withdraw_message
17
+
18
+ __all__ = [
19
+ "EIP712Domain",
20
+ "create_domain",
21
+ "LOCK_TYPES",
22
+ "TRANSFER_TYPES",
23
+ "TRANSFER_LOCKED_TYPES",
24
+ "WITHDRAW_TYPES",
25
+ "LockMessage",
26
+ "TransferMessage",
27
+ "TransferLockedMessage",
28
+ "WithdrawMessage",
29
+ "SignLockParams",
30
+ "sign_lock_message",
31
+ "create_lock_expiry",
32
+ "SignTransferParams",
33
+ "sign_transfer_message",
34
+ "SignTransferLockedParams",
35
+ "sign_transfer_locked_message",
36
+ "SignWithdrawParams",
37
+ "sign_withdraw_message",
38
+ ]