swig-developer-sdk 0.6.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.
- swig_developer_sdk/__init__.py +180 -0
- swig_developer_sdk/client.py +36 -0
- swig_developer_sdk/common.py +104 -0
- swig_developer_sdk/core.py +162 -0
- swig_developer_sdk/evm.py +64 -0
- swig_developer_sdk/one_business.py +163 -0
- swig_developer_sdk/passkeys.py +122 -0
- swig_developer_sdk/paymaster.py +106 -0
- swig_developer_sdk/proxy.py +724 -0
- swig_developer_sdk/ramp.py +724 -0
- swig_developer_sdk/signing.py +461 -0
- swig_developer_sdk/transactions.py +277 -0
- swig_developer_sdk/wallets.py +1393 -0
- swig_developer_sdk-0.6.0.dist-info/METADATA +89 -0
- swig_developer_sdk-0.6.0.dist-info/RECORD +16 -0
- swig_developer_sdk-0.6.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
from collections.abc import Mapping, Sequence
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
import base58
|
|
9
|
+
|
|
10
|
+
from .common import (
|
|
11
|
+
Network,
|
|
12
|
+
WalletAddressInfo,
|
|
13
|
+
normalize_network,
|
|
14
|
+
wallet_address_info_from_wire,
|
|
15
|
+
)
|
|
16
|
+
from .core import HttpClient
|
|
17
|
+
|
|
18
|
+
TransactionEncoding = Literal["base64"]
|
|
19
|
+
PreparedTransactionKind = Literal[
|
|
20
|
+
"create-swig-wallet", "add-authority", "configure-recovery"
|
|
21
|
+
]
|
|
22
|
+
SignatureScheme = Literal["secp256r1", "secp256k1"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True, slots=True)
|
|
26
|
+
class ClientSignatureRequest:
|
|
27
|
+
scheme: SignatureScheme
|
|
28
|
+
signer: str
|
|
29
|
+
message_hash: str
|
|
30
|
+
slot: int
|
|
31
|
+
counter: int
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True, slots=True)
|
|
35
|
+
class PreparedTransaction:
|
|
36
|
+
transaction: str
|
|
37
|
+
signature_requests: tuple[ClientSignatureRequest, ...]
|
|
38
|
+
transaction_encoding: TransactionEncoding | None = None
|
|
39
|
+
wallet: WalletAddressInfo | None = None
|
|
40
|
+
expires_at: str | None = None
|
|
41
|
+
network: Network | None = None
|
|
42
|
+
recent_blockhash: str | None = None
|
|
43
|
+
kind: PreparedTransactionKind | None = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True, slots=True)
|
|
47
|
+
class SignedPreparedTransaction:
|
|
48
|
+
transaction: str
|
|
49
|
+
transaction_encoding: TransactionEncoding | None = None
|
|
50
|
+
network: Network | None = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True, slots=True)
|
|
54
|
+
class SubmittedTransaction:
|
|
55
|
+
signature: str
|
|
56
|
+
status: Literal["submitted", "confirmed"] | None = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(frozen=True, slots=True)
|
|
60
|
+
class SponsorSignedTransactionArgs:
|
|
61
|
+
transaction: str
|
|
62
|
+
transaction_encoding: TransactionEncoding | None = None
|
|
63
|
+
network: Network | None = None
|
|
64
|
+
idempotency_key: str | None = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(frozen=True, slots=True)
|
|
68
|
+
class PreparedTransactionsResult:
|
|
69
|
+
transactions: tuple[PreparedTransaction, ...]
|
|
70
|
+
client_authority_transactions: tuple[PreparedTransaction, ...]
|
|
71
|
+
fee_payer_only_transactions: tuple[PreparedTransaction, ...]
|
|
72
|
+
wallet: WalletAddressInfo | None = None
|
|
73
|
+
network: Network | None = None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TransactionsClient:
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
http: HttpClient,
|
|
80
|
+
default_network: Network | None = None,
|
|
81
|
+
) -> None:
|
|
82
|
+
self._http = http
|
|
83
|
+
self._default_network = default_network
|
|
84
|
+
|
|
85
|
+
async def sponsor(
|
|
86
|
+
self,
|
|
87
|
+
args: SponsorSignedTransactionArgs,
|
|
88
|
+
) -> SubmittedTransaction:
|
|
89
|
+
transaction_bytes = base64.b64decode(args.transaction)
|
|
90
|
+
response = await self._http.post(
|
|
91
|
+
"/paymaster/sponsor",
|
|
92
|
+
{
|
|
93
|
+
"base58_encoded_transaction": base58.b58encode(
|
|
94
|
+
transaction_bytes
|
|
95
|
+
).decode("ascii"),
|
|
96
|
+
"network": args.network or self._default_network,
|
|
97
|
+
"idempotencyKey": args.idempotency_key,
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
return normalize_submitted_transaction(response)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def normalize_prepared_transaction(response: object) -> PreparedTransaction:
|
|
104
|
+
body = _mapping(response, "Prepared transaction response")
|
|
105
|
+
transaction = _pick(
|
|
106
|
+
body, "transaction", "unsignedTransaction", "unsigned_transaction"
|
|
107
|
+
)
|
|
108
|
+
if not isinstance(transaction, str) or not transaction:
|
|
109
|
+
raise ValueError("Prepared transaction response is missing transaction")
|
|
110
|
+
|
|
111
|
+
wallet_value = body.get("wallet")
|
|
112
|
+
return PreparedTransaction(
|
|
113
|
+
transaction=transaction,
|
|
114
|
+
transaction_encoding=_normalize_transaction_encoding(
|
|
115
|
+
_pick(body, "transactionEncoding", "transaction_encoding")
|
|
116
|
+
),
|
|
117
|
+
wallet=(
|
|
118
|
+
wallet_address_info_from_wire(wallet_value)
|
|
119
|
+
if wallet_value is not None
|
|
120
|
+
else None
|
|
121
|
+
),
|
|
122
|
+
expires_at=_optional_string(_pick(body, "expiresAt", "expires_at")),
|
|
123
|
+
network=normalize_network(body.get("network")),
|
|
124
|
+
recent_blockhash=_optional_string(
|
|
125
|
+
_pick(body, "recentBlockhash", "recent_blockhash")
|
|
126
|
+
),
|
|
127
|
+
kind=_normalize_kind(body.get("kind")),
|
|
128
|
+
signature_requests=_normalize_signature_requests(
|
|
129
|
+
_pick(body, "signatureRequests", "signature_requests")
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def normalize_prepared_transactions_result(
|
|
135
|
+
response: object,
|
|
136
|
+
) -> PreparedTransactionsResult:
|
|
137
|
+
body = _mapping(response, "Prepare transactions response")
|
|
138
|
+
network = normalize_network(body.get("network"))
|
|
139
|
+
raw_transactions = body.get("transactions", [])
|
|
140
|
+
if not isinstance(raw_transactions, Sequence) or isinstance(
|
|
141
|
+
raw_transactions, (str, bytes)
|
|
142
|
+
):
|
|
143
|
+
raise ValueError("Prepare transactions response has invalid transactions")
|
|
144
|
+
transactions = tuple(
|
|
145
|
+
normalize_prepared_transaction(
|
|
146
|
+
{
|
|
147
|
+
**_mapping(item, "Prepared transaction"),
|
|
148
|
+
"network": _mapping(item, "Prepared transaction").get(
|
|
149
|
+
"network", body.get("network")
|
|
150
|
+
),
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
for item in raw_transactions
|
|
154
|
+
)
|
|
155
|
+
wallet_value = body.get("wallet")
|
|
156
|
+
wallet = (
|
|
157
|
+
wallet_address_info_from_wire(wallet_value)
|
|
158
|
+
if wallet_value is not None
|
|
159
|
+
else None
|
|
160
|
+
)
|
|
161
|
+
if wallet is not None and wallet.network is None and network is not None:
|
|
162
|
+
wallet = WalletAddressInfo(
|
|
163
|
+
wallet.swig_config_address,
|
|
164
|
+
wallet.wallet_address,
|
|
165
|
+
network,
|
|
166
|
+
)
|
|
167
|
+
return PreparedTransactionsResult(
|
|
168
|
+
wallet=wallet,
|
|
169
|
+
transactions=transactions,
|
|
170
|
+
client_authority_transactions=tuple(
|
|
171
|
+
item for item in transactions if item.signature_requests
|
|
172
|
+
),
|
|
173
|
+
fee_payer_only_transactions=tuple(
|
|
174
|
+
item for item in transactions if not item.signature_requests
|
|
175
|
+
),
|
|
176
|
+
network=network,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def normalize_submitted_transaction(response: object) -> SubmittedTransaction:
|
|
181
|
+
body = _mapping(response, "Sponsor response")
|
|
182
|
+
signature = body.get("signature")
|
|
183
|
+
if not isinstance(signature, str) or not signature:
|
|
184
|
+
raise ValueError("Sponsor response is missing signature")
|
|
185
|
+
status = body.get("status")
|
|
186
|
+
if status not in (None, "submitted", "confirmed"):
|
|
187
|
+
raise ValueError("Sponsor response has invalid status")
|
|
188
|
+
return SubmittedTransaction(signature=signature, status=status)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _normalize_signature_requests(value: object) -> tuple[ClientSignatureRequest, ...]:
|
|
192
|
+
if value is None:
|
|
193
|
+
return ()
|
|
194
|
+
if not isinstance(value, Sequence) or isinstance(value, (str, bytes)):
|
|
195
|
+
raise ValueError("Prepared transaction has invalid signature request")
|
|
196
|
+
requests: list[ClientSignatureRequest] = []
|
|
197
|
+
for item in value:
|
|
198
|
+
request = _mapping(item, "Prepared transaction signature request")
|
|
199
|
+
scheme = _normalize_signature_scheme(request.get("scheme"))
|
|
200
|
+
signer = request.get("signer")
|
|
201
|
+
message_hash = _pick(request, "messageHash", "message_hash")
|
|
202
|
+
slot = request.get("slot")
|
|
203
|
+
counter = request.get("counter")
|
|
204
|
+
if isinstance(slot, str):
|
|
205
|
+
try:
|
|
206
|
+
slot = int(slot, 10)
|
|
207
|
+
except ValueError as error:
|
|
208
|
+
raise ValueError(
|
|
209
|
+
"Prepared transaction has invalid signature request"
|
|
210
|
+
) from error
|
|
211
|
+
if (
|
|
212
|
+
scheme is None
|
|
213
|
+
or not isinstance(signer, str)
|
|
214
|
+
or not isinstance(message_hash, str)
|
|
215
|
+
or not isinstance(slot, int)
|
|
216
|
+
or not isinstance(counter, int)
|
|
217
|
+
):
|
|
218
|
+
raise ValueError("Prepared transaction has invalid signature request")
|
|
219
|
+
requests.append(
|
|
220
|
+
ClientSignatureRequest(
|
|
221
|
+
scheme=scheme,
|
|
222
|
+
signer=signer,
|
|
223
|
+
message_hash=message_hash,
|
|
224
|
+
slot=slot,
|
|
225
|
+
counter=counter,
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
return tuple(requests)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _normalize_signature_scheme(value: object) -> SignatureScheme | None:
|
|
232
|
+
if value in ("secp256r1", "AUTHORITY_SIGNATURE_SCHEME_SECP256R1", 1):
|
|
233
|
+
return "secp256r1"
|
|
234
|
+
if value in ("secp256k1", "AUTHORITY_SIGNATURE_SCHEME_SECP256K1", 2):
|
|
235
|
+
return "secp256k1"
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _normalize_transaction_encoding(value: object) -> TransactionEncoding | None:
|
|
240
|
+
if value in ("base64", "TRANSACTION_ENCODING_BASE64", 1):
|
|
241
|
+
return "base64"
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _normalize_kind(value: object) -> PreparedTransactionKind | None:
|
|
246
|
+
if value in (
|
|
247
|
+
"create-swig-wallet",
|
|
248
|
+
"PREPARED_TRANSACTION_KIND_CREATE_SWIG_WALLET",
|
|
249
|
+
1,
|
|
250
|
+
):
|
|
251
|
+
return "create-swig-wallet"
|
|
252
|
+
if value in ("add-authority", "PREPARED_TRANSACTION_KIND_ADD_AUTHORITY", 2):
|
|
253
|
+
return "add-authority"
|
|
254
|
+
if value in (
|
|
255
|
+
"configure-recovery",
|
|
256
|
+
"PREPARED_TRANSACTION_KIND_CONFIGURE_RECOVERY",
|
|
257
|
+
3,
|
|
258
|
+
):
|
|
259
|
+
return "configure-recovery"
|
|
260
|
+
return None
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _mapping(value: object, label: str) -> Mapping[str, object]:
|
|
264
|
+
if isinstance(value, Mapping):
|
|
265
|
+
return value
|
|
266
|
+
raise ValueError(f"{label} must be an object")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _pick(value: Mapping[str, object], *keys: str) -> object:
|
|
270
|
+
for key in keys:
|
|
271
|
+
if key in value:
|
|
272
|
+
return value[key]
|
|
273
|
+
return None
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _optional_string(value: object) -> str | None:
|
|
277
|
+
return value if isinstance(value, str) else None
|