arete-sdk 0.11.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.
- arete/__init__.py +310 -0
- arete/amounts.py +157 -0
- arete/auth.py +626 -0
- arete/chain.py +350 -0
- arete/client.py +811 -0
- arete/connection.py +631 -0
- arete/errors.py +88 -0
- arete/extensions.py +239 -0
- arete/gateway.py +235 -0
- arete/http.py +569 -0
- arete/instructions/__init__.py +89 -0
- arete/instructions/_curve.py +76 -0
- arete/instructions/accounts.py +285 -0
- arete/instructions/args.py +375 -0
- arete/instructions/errors.py +53 -0
- arete/instructions/handler.py +170 -0
- arete/instructions/pda.py +276 -0
- arete/operations.py +1402 -0
- arete/program_read_transport.py +443 -0
- arete/read.py +418 -0
- arete/session.py +563 -0
- arete/spl.py +75 -0
- arete/stack.py +551 -0
- arete/store.py +591 -0
- arete/subscription.py +552 -0
- arete/transactions.py +342 -0
- arete/views.py +556 -0
- arete/wallet.py +405 -0
- arete/wire.py +477 -0
- arete_sdk-0.11.0.dist-info/METADATA +157 -0
- arete_sdk-0.11.0.dist-info/RECORD +34 -0
- arete_sdk-0.11.0.dist-info/WHEEL +5 -0
- arete_sdk-0.11.0.dist-info/licenses/LICENSE +21 -0
- arete_sdk-0.11.0.dist-info/top_level.txt +1 -0
arete/__init__.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Arete Python SDK — idiomatic Python projection of the Arete core SDK API.
|
|
2
|
+
|
|
3
|
+
See docs/internal/sdk-core-api.md (canonical surface) and
|
|
4
|
+
docs/internal/sdk-python-alignment.md (Python projection).
|
|
5
|
+
|
|
6
|
+
import arete
|
|
7
|
+
a4 = await arete.Arete.connect(STACK, wallet=wallet)
|
|
8
|
+
async for round in a4.views.ore_round.latest.use(take=10):
|
|
9
|
+
...
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
__version__ = "0.4.0"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _Unset:
|
|
18
|
+
"""Sentinel distinguishing "no active subscription" from an empty result."""
|
|
19
|
+
|
|
20
|
+
_instance = None
|
|
21
|
+
|
|
22
|
+
def __new__(cls):
|
|
23
|
+
if cls._instance is None:
|
|
24
|
+
cls._instance = super().__new__(cls)
|
|
25
|
+
return cls._instance
|
|
26
|
+
|
|
27
|
+
def __repr__(self) -> str:
|
|
28
|
+
return "arete.UNSET"
|
|
29
|
+
|
|
30
|
+
def __bool__(self) -> bool:
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
UNSET = _Unset()
|
|
35
|
+
|
|
36
|
+
# NOTE: UNSET must exist before the submodule imports below (arete.views
|
|
37
|
+
# imports it at module load).
|
|
38
|
+
|
|
39
|
+
from arete.errors import ( # noqa: E402
|
|
40
|
+
AreteConnectionError,
|
|
41
|
+
AreteError,
|
|
42
|
+
AuthError,
|
|
43
|
+
HttpRequestError,
|
|
44
|
+
ProcessedSlotTimeoutError,
|
|
45
|
+
SubscriptionError,
|
|
46
|
+
)
|
|
47
|
+
from arete.auth import AuthConfig # noqa: E402
|
|
48
|
+
from arete.wire import RichUpdate, Update # noqa: E402
|
|
49
|
+
from arete.views import ( # noqa: E402
|
|
50
|
+
DEFAULT_INITIAL_DATA_TIMEOUT,
|
|
51
|
+
InitialDataTimeoutError,
|
|
52
|
+
ListViewHandle,
|
|
53
|
+
StateViewHandle,
|
|
54
|
+
ViewDef,
|
|
55
|
+
ViewsNamespace,
|
|
56
|
+
)
|
|
57
|
+
from arete.chain import ( # noqa: E402
|
|
58
|
+
ChainClient,
|
|
59
|
+
ChainClock,
|
|
60
|
+
ChainError,
|
|
61
|
+
HttpChainClient,
|
|
62
|
+
MintAccountInfo,
|
|
63
|
+
NativeBalanceInfo,
|
|
64
|
+
RawAccountInfo,
|
|
65
|
+
TokenAccountInfo,
|
|
66
|
+
TokenBalanceInfo,
|
|
67
|
+
)
|
|
68
|
+
from arete.transactions import ( # noqa: E402
|
|
69
|
+
HttpTransactionTransport,
|
|
70
|
+
TransactionTransport,
|
|
71
|
+
TransactionTransportError,
|
|
72
|
+
)
|
|
73
|
+
from arete.gateway import ( # noqa: E402
|
|
74
|
+
HostedSolanaGatewayBindings,
|
|
75
|
+
create_hosted_solana_gateway_transports,
|
|
76
|
+
)
|
|
77
|
+
from arete.amounts import ( # noqa: E402
|
|
78
|
+
format_raw_to_ui,
|
|
79
|
+
get_mint_decimals,
|
|
80
|
+
parse_ui_amount_to_raw,
|
|
81
|
+
resolve_amount,
|
|
82
|
+
resolve_amount_to_raw,
|
|
83
|
+
resolve_amounts_to_raw,
|
|
84
|
+
to_raw_amount,
|
|
85
|
+
)
|
|
86
|
+
from arete.spl import ( # noqa: E402
|
|
87
|
+
ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
88
|
+
SPL_TOKEN_PROGRAM_ADDRESS,
|
|
89
|
+
SYSTEM_PROGRAM_ADDRESS,
|
|
90
|
+
TOKEN_2022_PROGRAM_ADDRESS,
|
|
91
|
+
derive_associated_token_account,
|
|
92
|
+
resolve_token_program_address,
|
|
93
|
+
)
|
|
94
|
+
from arete.instructions import ( # noqa: E402
|
|
95
|
+
BuiltAccountMeta,
|
|
96
|
+
BuiltInstruction,
|
|
97
|
+
ErrorMetadata,
|
|
98
|
+
InstructionError,
|
|
99
|
+
InstructionHandler,
|
|
100
|
+
PdaConfig,
|
|
101
|
+
derive_pda,
|
|
102
|
+
find_program_address,
|
|
103
|
+
format_program_error,
|
|
104
|
+
parse_program_error,
|
|
105
|
+
)
|
|
106
|
+
from arete.read import ( # noqa: E402
|
|
107
|
+
AccountBatchItem,
|
|
108
|
+
AccountBatchResult,
|
|
109
|
+
AccountReader,
|
|
110
|
+
ProgramAccountReadDef,
|
|
111
|
+
ProgramQueryDef,
|
|
112
|
+
ReadRequestError,
|
|
113
|
+
StackQueryDef,
|
|
114
|
+
)
|
|
115
|
+
from arete.program_read_transport import ( # noqa: E402
|
|
116
|
+
ProgramReadDescriptor,
|
|
117
|
+
ProgramReleaseReference,
|
|
118
|
+
validate_program_read_descriptor,
|
|
119
|
+
)
|
|
120
|
+
from arete.wallet import ( # noqa: E402
|
|
121
|
+
ConfirmedTransactionOutcome,
|
|
122
|
+
SendOptions,
|
|
123
|
+
SendResult,
|
|
124
|
+
TransactionFailureOutcome,
|
|
125
|
+
TransactionInspectionResult,
|
|
126
|
+
WalletAdapter,
|
|
127
|
+
WalletError,
|
|
128
|
+
WalletExecutionContext,
|
|
129
|
+
)
|
|
130
|
+
from arete.operations import ( # noqa: E402
|
|
131
|
+
OperationCallbackError,
|
|
132
|
+
OperationExecutionError,
|
|
133
|
+
OperationReceipt,
|
|
134
|
+
OperationTransactionReceipt,
|
|
135
|
+
PreparedFlow,
|
|
136
|
+
PreparedInstruction,
|
|
137
|
+
PreparedOperation,
|
|
138
|
+
PreparedTransaction,
|
|
139
|
+
PreparedTransactionBody,
|
|
140
|
+
SignerRegistry,
|
|
141
|
+
TransactionExecutionError,
|
|
142
|
+
append_flow_transactions,
|
|
143
|
+
append_transaction_instructions,
|
|
144
|
+
create_prepared_flow,
|
|
145
|
+
create_prepared_instruction,
|
|
146
|
+
create_prepared_transaction,
|
|
147
|
+
create_prepared_transaction_body,
|
|
148
|
+
create_signer_registry,
|
|
149
|
+
describe_prepared_operation,
|
|
150
|
+
execute_prepared_operation,
|
|
151
|
+
format_prepared_operation,
|
|
152
|
+
get_transaction_failure_outcome,
|
|
153
|
+
inspect_prepared_operation,
|
|
154
|
+
prepend_flow_transaction_instructions,
|
|
155
|
+
prepend_transaction_instructions,
|
|
156
|
+
unwrap_operation_execution_error,
|
|
157
|
+
)
|
|
158
|
+
from arete.stack import ( # noqa: E402
|
|
159
|
+
ConnectedProgram,
|
|
160
|
+
Operation,
|
|
161
|
+
ProgramDef,
|
|
162
|
+
ProgramOperationContext,
|
|
163
|
+
ProgramOperations,
|
|
164
|
+
StackDef,
|
|
165
|
+
StackEndpoints,
|
|
166
|
+
flow_operation,
|
|
167
|
+
instruction_operation,
|
|
168
|
+
transaction_operation,
|
|
169
|
+
with_programs,
|
|
170
|
+
)
|
|
171
|
+
from arete.extensions import ( # noqa: E402
|
|
172
|
+
apply_connected_stack_extensions,
|
|
173
|
+
extend_program,
|
|
174
|
+
extend_programs,
|
|
175
|
+
extend_stack,
|
|
176
|
+
)
|
|
177
|
+
from arete.client import Arete # noqa: E402
|
|
178
|
+
from arete.session import Session, SessionError, create_session # noqa: E402
|
|
179
|
+
|
|
180
|
+
__all__ = [
|
|
181
|
+
"UNSET",
|
|
182
|
+
"__version__",
|
|
183
|
+
# client & session
|
|
184
|
+
"Arete",
|
|
185
|
+
"Session",
|
|
186
|
+
"SessionError",
|
|
187
|
+
"create_session",
|
|
188
|
+
# errors
|
|
189
|
+
"AreteError",
|
|
190
|
+
"AreteConnectionError",
|
|
191
|
+
"AuthError",
|
|
192
|
+
"ChainError",
|
|
193
|
+
"HttpRequestError",
|
|
194
|
+
"InitialDataTimeoutError",
|
|
195
|
+
"InstructionError",
|
|
196
|
+
"OperationCallbackError",
|
|
197
|
+
"OperationExecutionError",
|
|
198
|
+
"ProcessedSlotTimeoutError",
|
|
199
|
+
"ReadRequestError",
|
|
200
|
+
"SubscriptionError",
|
|
201
|
+
"TransactionExecutionError",
|
|
202
|
+
"TransactionTransportError",
|
|
203
|
+
"WalletError",
|
|
204
|
+
# auth
|
|
205
|
+
"AuthConfig",
|
|
206
|
+
# views & updates
|
|
207
|
+
"Update",
|
|
208
|
+
"RichUpdate",
|
|
209
|
+
"ViewDef",
|
|
210
|
+
"ViewsNamespace",
|
|
211
|
+
"DEFAULT_INITIAL_DATA_TIMEOUT",
|
|
212
|
+
"ListViewHandle",
|
|
213
|
+
"StateViewHandle",
|
|
214
|
+
# stack binding model
|
|
215
|
+
"StackDef",
|
|
216
|
+
"StackEndpoints",
|
|
217
|
+
"ProgramDef",
|
|
218
|
+
"ProgramOperations",
|
|
219
|
+
"ProgramOperationContext",
|
|
220
|
+
"ConnectedProgram",
|
|
221
|
+
"with_programs",
|
|
222
|
+
# extensions
|
|
223
|
+
"extend_stack",
|
|
224
|
+
"extend_program",
|
|
225
|
+
"extend_programs",
|
|
226
|
+
"apply_connected_stack_extensions",
|
|
227
|
+
"Operation",
|
|
228
|
+
"instruction_operation",
|
|
229
|
+
"transaction_operation",
|
|
230
|
+
"flow_operation",
|
|
231
|
+
# wallet & outcomes
|
|
232
|
+
"WalletAdapter",
|
|
233
|
+
"WalletExecutionContext",
|
|
234
|
+
"SendOptions",
|
|
235
|
+
"SendResult",
|
|
236
|
+
"TransactionInspectionResult",
|
|
237
|
+
"ConfirmedTransactionOutcome",
|
|
238
|
+
"TransactionFailureOutcome",
|
|
239
|
+
"get_transaction_failure_outcome",
|
|
240
|
+
# prepared operations
|
|
241
|
+
"PreparedInstruction",
|
|
242
|
+
"PreparedTransaction",
|
|
243
|
+
"PreparedFlow",
|
|
244
|
+
"PreparedOperation",
|
|
245
|
+
"PreparedTransactionBody",
|
|
246
|
+
"create_prepared_instruction",
|
|
247
|
+
"create_prepared_transaction",
|
|
248
|
+
"create_prepared_flow",
|
|
249
|
+
"create_prepared_transaction_body",
|
|
250
|
+
"prepend_transaction_instructions",
|
|
251
|
+
"append_transaction_instructions",
|
|
252
|
+
"append_flow_transactions",
|
|
253
|
+
"prepend_flow_transaction_instructions",
|
|
254
|
+
"execute_prepared_operation",
|
|
255
|
+
"inspect_prepared_operation",
|
|
256
|
+
"describe_prepared_operation",
|
|
257
|
+
"format_prepared_operation",
|
|
258
|
+
"unwrap_operation_execution_error",
|
|
259
|
+
"OperationReceipt",
|
|
260
|
+
"OperationTransactionReceipt",
|
|
261
|
+
"SignerRegistry",
|
|
262
|
+
"create_signer_registry",
|
|
263
|
+
# chain & transactions
|
|
264
|
+
"ChainClient",
|
|
265
|
+
"HttpChainClient",
|
|
266
|
+
"ChainClock",
|
|
267
|
+
"RawAccountInfo",
|
|
268
|
+
"MintAccountInfo",
|
|
269
|
+
"TokenAccountInfo",
|
|
270
|
+
"TokenBalanceInfo",
|
|
271
|
+
"NativeBalanceInfo",
|
|
272
|
+
"TransactionTransport",
|
|
273
|
+
"HttpTransactionTransport",
|
|
274
|
+
"HostedSolanaGatewayBindings",
|
|
275
|
+
"create_hosted_solana_gateway_transports",
|
|
276
|
+
# amounts & SPL
|
|
277
|
+
"parse_ui_amount_to_raw",
|
|
278
|
+
"format_raw_to_ui",
|
|
279
|
+
"to_raw_amount",
|
|
280
|
+
"get_mint_decimals",
|
|
281
|
+
"resolve_amount",
|
|
282
|
+
"resolve_amount_to_raw",
|
|
283
|
+
"resolve_amounts_to_raw",
|
|
284
|
+
"SPL_TOKEN_PROGRAM_ADDRESS",
|
|
285
|
+
"TOKEN_2022_PROGRAM_ADDRESS",
|
|
286
|
+
"ASSOCIATED_TOKEN_PROGRAM_ADDRESS",
|
|
287
|
+
"SYSTEM_PROGRAM_ADDRESS",
|
|
288
|
+
"derive_associated_token_account",
|
|
289
|
+
"resolve_token_program_address",
|
|
290
|
+
# instruction runtime
|
|
291
|
+
"InstructionHandler",
|
|
292
|
+
"BuiltInstruction",
|
|
293
|
+
"BuiltAccountMeta",
|
|
294
|
+
"ErrorMetadata",
|
|
295
|
+
"PdaConfig",
|
|
296
|
+
"derive_pda",
|
|
297
|
+
"find_program_address",
|
|
298
|
+
"parse_program_error",
|
|
299
|
+
"format_program_error",
|
|
300
|
+
# program reads
|
|
301
|
+
"AccountReader",
|
|
302
|
+
"AccountBatchItem",
|
|
303
|
+
"AccountBatchResult",
|
|
304
|
+
"ProgramAccountReadDef",
|
|
305
|
+
"ProgramQueryDef",
|
|
306
|
+
"StackQueryDef",
|
|
307
|
+
"ProgramReadDescriptor",
|
|
308
|
+
"ProgramReleaseReference",
|
|
309
|
+
"validate_program_read_descriptor",
|
|
310
|
+
]
|
arete/amounts.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""Token amount helpers (port of ``typescript/core/src/amounts.ts``).
|
|
2
|
+
|
|
3
|
+
An :data:`AmountInput` is either raw base units (a bare ``int``, or
|
|
4
|
+
``{"raw": int | str}``) or UI units (``{"ui": str | int | float}``). UI
|
|
5
|
+
parsing is exact string math pinned to the mint's decimals — no float
|
|
6
|
+
precision loss. Decimals are fetched from the chain read endpoint only when
|
|
7
|
+
they are unknown and actually needed.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import Any, Dict, Mapping, Optional, Union
|
|
15
|
+
|
|
16
|
+
from arete.chain import ChainClient
|
|
17
|
+
|
|
18
|
+
AmountInput = Union[int, Mapping[str, Any]]
|
|
19
|
+
|
|
20
|
+
_UI_AMOUNT_RE = re.compile(r"^\d+(?:\.\d+)?$")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class ResolvedAmount:
|
|
25
|
+
raw: int
|
|
26
|
+
decimals: int
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def parse_ui_amount_to_raw(value: Union[str, int, float], decimals: int) -> int:
|
|
30
|
+
"""Convert a UI amount ("1.5") to raw base units using string math."""
|
|
31
|
+
trimmed = str(value).strip()
|
|
32
|
+
if not _UI_AMOUNT_RE.match(trimmed):
|
|
33
|
+
raise ValueError(f"Invalid UI amount: {value}")
|
|
34
|
+
|
|
35
|
+
whole_part, _, fraction_part = trimmed.partition(".")
|
|
36
|
+
if len(fraction_part) > decimals:
|
|
37
|
+
excess = fraction_part[decimals:]
|
|
38
|
+
if any(ch != "0" for ch in excess):
|
|
39
|
+
raise ValueError(
|
|
40
|
+
f"UI amount {value} has more fractional digits than the mint's "
|
|
41
|
+
f"{decimals} decimals"
|
|
42
|
+
)
|
|
43
|
+
fraction = fraction_part.ljust(decimals, "0")[:decimals]
|
|
44
|
+
whole = int(whole_part or "0") * 10**decimals
|
|
45
|
+
return whole + int(fraction or "0")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def format_raw_to_ui(raw: Union[int, str], decimals: int) -> str:
|
|
49
|
+
"""Format raw base units as a UI decimal string (inverse of
|
|
50
|
+
:func:`parse_ui_amount_to_raw`)."""
|
|
51
|
+
value = _to_int(raw, "raw amount")
|
|
52
|
+
negative = value < 0
|
|
53
|
+
magnitude = -value if negative else value
|
|
54
|
+
scale = 10**decimals
|
|
55
|
+
whole, fraction = divmod(magnitude, scale)
|
|
56
|
+
sign = "-" if negative else ""
|
|
57
|
+
if decimals == 0 or fraction == 0:
|
|
58
|
+
return f"{sign}{whole}"
|
|
59
|
+
fraction_text = str(fraction).rjust(decimals, "0").rstrip("0")
|
|
60
|
+
return f"{sign}{whole}.{fraction_text}"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _to_int(value: Any, name: str) -> int:
|
|
64
|
+
if isinstance(value, bool):
|
|
65
|
+
raise ValueError(f"Invalid {name}: {value!r}")
|
|
66
|
+
if isinstance(value, int):
|
|
67
|
+
return value
|
|
68
|
+
if isinstance(value, str):
|
|
69
|
+
text = value.strip()
|
|
70
|
+
if re.match(r"^-?\d+$", text):
|
|
71
|
+
return int(text)
|
|
72
|
+
raise ValueError(f"Invalid {name}: {value!r}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _is_raw_input(amount: AmountInput) -> bool:
|
|
76
|
+
return isinstance(amount, int) or (
|
|
77
|
+
isinstance(amount, Mapping) and "raw" in amount
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def to_raw_amount(amount: AmountInput, decimals: int) -> int:
|
|
82
|
+
"""Resolve an :data:`AmountInput` to raw base units with known decimals."""
|
|
83
|
+
if isinstance(amount, bool):
|
|
84
|
+
raise ValueError(f"Invalid amount input: {amount!r}")
|
|
85
|
+
if isinstance(amount, int):
|
|
86
|
+
return amount
|
|
87
|
+
if isinstance(amount, Mapping):
|
|
88
|
+
if "raw" in amount:
|
|
89
|
+
return _to_int(amount["raw"], "raw amount")
|
|
90
|
+
if "ui" in amount:
|
|
91
|
+
return parse_ui_amount_to_raw(amount["ui"], decimals)
|
|
92
|
+
raise ValueError(f"Invalid amount input: {amount!r}")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
async def get_mint_decimals(chain: ChainClient, mint: str) -> int:
|
|
96
|
+
"""Fetch a mint's decimals via the chain read endpoint, raising when
|
|
97
|
+
unavailable."""
|
|
98
|
+
account = await chain.mint(mint)
|
|
99
|
+
if account is None or account.decimals is None:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f"Mint {mint} is missing decimals on the configured read endpoint."
|
|
102
|
+
)
|
|
103
|
+
return account.decimals
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
async def resolve_amount(
|
|
107
|
+
chain: ChainClient,
|
|
108
|
+
*,
|
|
109
|
+
mint: str,
|
|
110
|
+
amount: AmountInput,
|
|
111
|
+
decimals: Optional[int] = None,
|
|
112
|
+
) -> ResolvedAmount:
|
|
113
|
+
"""Resolve an :data:`AmountInput` to raw base units, fetching the mint's
|
|
114
|
+
decimals only when they are unknown (a bare int or ``{"raw"}`` input with
|
|
115
|
+
explicit ``decimals`` never touches the network)."""
|
|
116
|
+
if _is_raw_input(amount):
|
|
117
|
+
raw = amount if isinstance(amount, int) else _to_int(amount["raw"], "raw amount")
|
|
118
|
+
resolved = decimals if decimals is not None else await get_mint_decimals(chain, mint)
|
|
119
|
+
return ResolvedAmount(raw=raw, decimals=resolved)
|
|
120
|
+
|
|
121
|
+
resolved = decimals if decimals is not None else await get_mint_decimals(chain, mint)
|
|
122
|
+
return ResolvedAmount(raw=to_raw_amount(amount, resolved), decimals=resolved)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def resolve_amount_to_raw(
|
|
126
|
+
chain: ChainClient,
|
|
127
|
+
*,
|
|
128
|
+
mint: str,
|
|
129
|
+
amount: AmountInput,
|
|
130
|
+
decimals: Optional[int] = None,
|
|
131
|
+
) -> int:
|
|
132
|
+
"""Resolve an :data:`AmountInput` to raw base units without forcing a
|
|
133
|
+
decimals fetch when the input is already expressed in raw units."""
|
|
134
|
+
if isinstance(amount, int) and not isinstance(amount, bool):
|
|
135
|
+
return amount
|
|
136
|
+
if isinstance(amount, Mapping) and "raw" in amount:
|
|
137
|
+
return _to_int(amount["raw"], "raw amount")
|
|
138
|
+
|
|
139
|
+
resolved = decimals if decimals is not None else await get_mint_decimals(chain, mint)
|
|
140
|
+
return to_raw_amount(amount, resolved)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async def resolve_amounts_to_raw(
|
|
144
|
+
chain: ChainClient,
|
|
145
|
+
inputs: Mapping[str, Mapping[str, Any]],
|
|
146
|
+
) -> Dict[str, int]:
|
|
147
|
+
"""Resolve a named set of amount inputs (each ``{"mint", "amount"[,
|
|
148
|
+
"decimals"]}``) to raw base units, preserving keys."""
|
|
149
|
+
resolved: Dict[str, int] = {}
|
|
150
|
+
for name, entry in inputs.items():
|
|
151
|
+
resolved[name] = await resolve_amount_to_raw(
|
|
152
|
+
chain,
|
|
153
|
+
mint=entry["mint"],
|
|
154
|
+
amount=entry["amount"],
|
|
155
|
+
decimals=entry.get("decimals"),
|
|
156
|
+
)
|
|
157
|
+
return resolved
|