1use crate::error::LitSdkError;
2use crate::network::NetworkConfig;
3use ethers::contract::abigen;
4use ethers::prelude::*;
5use ethers::providers::{Http, Provider};
6use ethers::types::{Address, Bytes, I256, U256};
7use ethers::utils::{keccak256, to_checksum};
8use std::sync::Arc;
9use tokio::time::{sleep, Duration};
10
11abigen!(
12 LedgerContract,
13 r#"[{
14 "inputs":[],
15 "name":"deposit",
16 "outputs":[],
17 "stateMutability":"payable",
18 "type":"function"
19 },{
20 "inputs":[{"internalType":"address","name":"user","type":"address"}],
21 "name":"depositForUser",
22 "outputs":[],
23 "stateMutability":"payable",
24 "type":"function"
25 },{
26 "inputs":[{"internalType":"int256","name":"amount","type":"int256"}],
27 "name":"requestWithdraw",
28 "outputs":[],
29 "stateMutability":"nonpayable",
30 "type":"function"
31 },{
32 "inputs":[{"internalType":"int256","name":"amount","type":"int256"}],
33 "name":"withdraw",
34 "outputs":[],
35 "stateMutability":"nonpayable",
36 "type":"function"
37 },{
38 "inputs":[{"internalType":"address","name":"user","type":"address"}],
39 "name":"balance",
40 "outputs":[{"internalType":"int256","name":"","type":"int256"}],
41 "stateMutability":"view",
42 "type":"function"
43 },{
44 "inputs":[{"internalType":"address","name":"user","type":"address"}],
45 "name":"stableBalance",
46 "outputs":[{"internalType":"int256","name":"","type":"int256"}],
47 "stateMutability":"view",
48 "type":"function"
49 },{
50 "inputs":[{"internalType":"address","name":"user","type":"address"}],
51 "name":"latestWithdrawRequest",
52 "outputs":[{"components":[
53 {"internalType":"uint256","name":"timestamp","type":"uint256"},
54 {"internalType":"uint256","name":"amount","type":"uint256"}
55 ],"internalType":"struct LibLedgerStorage.WithdrawRequest","name":"","type":"tuple"}],
56 "stateMutability":"view",
57 "type":"function"
58 },{
59 "inputs":[],
60 "name":"userWithdrawDelay",
61 "outputs":[{"internalType":"uint256","name":"","type":"uint256"}],
62 "stateMutability":"view",
63 "type":"function"
64 }]"#,
65);
66
67abigen!(
68 PaymentDelegationContract,
69 r#"[{
70 "inputs":[{"internalType":"address","name":"user","type":"address"}],
71 "name":"delegatePayments",
72 "outputs":[],
73 "stateMutability":"nonpayable",
74 "type":"function"
75 },{
76 "inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],
77 "name":"delegatePaymentsBatch",
78 "outputs":[],
79 "stateMutability":"nonpayable",
80 "type":"function"
81 },{
82 "inputs":[{"components":[
83 {"internalType":"uint128","name":"totalMaxPrice","type":"uint128"},
84 {"internalType":"uint256","name":"requestsPerPeriod","type":"uint256"},
85 {"internalType":"uint256","name":"periodSeconds","type":"uint256"}
86 ],"internalType":"struct LibPaymentDelegationStorage.Restriction","name":"r","type":"tuple"}],
87 "name":"setRestriction",
88 "outputs":[],
89 "stateMutability":"nonpayable",
90 "type":"function"
91 },{
92 "inputs":[{"internalType":"address","name":"payer","type":"address"}],
93 "name":"getRestriction",
94 "outputs":[{"components":[
95 {"internalType":"uint128","name":"totalMaxPrice","type":"uint128"},
96 {"internalType":"uint256","name":"requestsPerPeriod","type":"uint256"},
97 {"internalType":"uint256","name":"periodSeconds","type":"uint256"}
98 ],"internalType":"struct LibPaymentDelegationStorage.Restriction","name":"","type":"tuple"}],
99 "stateMutability":"view",
100 "type":"function"
101 },{
102 "inputs":[{"internalType":"address","name":"user","type":"address"}],
103 "name":"getPayers",
104 "outputs":[{"internalType":"address[]","name":"","type":"address[]"}],
105 "stateMutability":"view",
106 "type":"function"
107 },{
108 "inputs":[{"internalType":"address","name":"payer","type":"address"}],
109 "name":"getUsers",
110 "outputs":[{"internalType":"address[]","name":"","type":"address[]"}],
111 "stateMutability":"view",
112 "type":"function"
113 },{
114 "inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],
115 "name":"getPayersAndRestrictions",
116 "outputs":[
117 {"internalType":"address[][]","name":"","type":"address[][]"},
118 {"components":[
119 {"internalType":"uint128","name":"totalMaxPrice","type":"uint128"},
120 {"internalType":"uint256","name":"requestsPerPeriod","type":"uint256"},
121 {"internalType":"uint256","name":"periodSeconds","type":"uint256"}
122 ],"internalType":"struct LibPaymentDelegationStorage.Restriction[][]","name":"","type":"tuple[][]"}
123 ],
124 "stateMutability":"view",
125 "type":"function"
126 },{
127 "inputs":[{"internalType":"address","name":"user","type":"address"}],
128 "name":"undelegatePayments",
129 "outputs":[],
130 "stateMutability":"nonpayable",
131 "type":"function"
132 },{
133 "inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],
134 "name":"undelegatePaymentsBatch",
135 "outputs":[],
136 "stateMutability":"nonpayable",
137 "type":"function"
138 }]"#,
139);
140
141abigen!(
142 PkpNftEnumerableContract,
143 r#"[{
144 "inputs":[
145 {"internalType":"address","name":"owner","type":"address"},
146 {"internalType":"uint256","name":"index","type":"uint256"}
147 ],
148 "name":"tokenOfOwnerByIndex",
149 "outputs":[{"internalType":"uint256","name":"","type":"uint256"}],
150 "stateMutability":"view",
151 "type":"function"
152 }]"#,
153);
154
155abigen!(
156 PkpNftMintContract,
157 r#"[{
158 "inputs":[],
159 "name":"mintCost",
160 "outputs":[{"internalType":"uint256","name":"","type":"uint256"}],
161 "stateMutability":"view",
162 "type":"function"
163 },{
164 "inputs":[
165 {"internalType":"uint256","name":"keyType","type":"uint256"},
166 {"internalType":"string","name":"keySetId","type":"string"}
167 ],
168 "name":"mintNext",
169 "outputs":[{"internalType":"uint256","name":"","type":"uint256"}],
170 "stateMutability":"payable",
171 "type":"function"
172 }]"#,
173);
174
175abigen!(
176 PkpHelperContract,
177 r#"[{
178 "inputs":[
179 {"internalType":"uint256","name":"keyType","type":"uint256"},
180 {"internalType":"string","name":"keySetId","type":"string"},
181 {"internalType":"uint256[]","name":"permittedAuthMethodTypes","type":"uint256[]"},
182 {"internalType":"bytes[]","name":"permittedAuthMethodIds","type":"bytes[]"},
183 {"internalType":"bytes[]","name":"permittedAuthMethodPubkeys","type":"bytes[]"},
184 {"internalType":"uint256[][]","name":"permittedAuthMethodScopes","type":"uint256[][]"},
185 {"internalType":"bool","name":"addPkpEthAddressAsPermittedAddress","type":"bool"},
186 {"internalType":"bool","name":"sendPkpToItself","type":"bool"}
187 ],
188 "name":"mintNextAndAddAuthMethods",
189 "outputs":[{"internalType":"uint256","name":"","type":"uint256"}],
190 "stateMutability":"payable",
191 "type":"function"
192 }]"#,
193);
194
195abigen!(
196 PubkeyRouterContract,
197 r#"[{
198 "inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],
199 "name":"getPubkey",
200 "outputs":[{"internalType":"bytes","name":"","type":"bytes"}],
201 "stateMutability":"view",
202 "type":"function"
203 },{
204 "inputs":[
205 {"internalType":"address","name":"stakingContract","type":"address"},
206 {"internalType":"string","name":"keySetId","type":"string"},
207 {"internalType":"bytes32","name":"derivedKeyId","type":"bytes32"}
208 ],
209 "name":"getDerivedPubkey",
210 "outputs":[{"internalType":"bytes","name":"","type":"bytes"}],
211 "stateMutability":"view",
212 "type":"function"
213 }]"#,
214);
215
216abigen!(
217 PkpPermissionsContract,
218 r#"[{
219 "inputs":[
220 {"internalType":"uint256","name":"tokenId","type":"uint256"},
221 {"components":[
222 {"internalType":"uint256","name":"authMethodType","type":"uint256"},
223 {"internalType":"bytes","name":"id","type":"bytes"},
224 {"internalType":"bytes","name":"userPubkey","type":"bytes"}
225 ],"internalType":"struct LibPKPPermissionsStorage.AuthMethod","name":"authMethod","type":"tuple"},
226 {"internalType":"uint256[]","name":"scopes","type":"uint256[]"}
227 ],
228 "name":"addPermittedAuthMethod",
229 "outputs":[],
230 "stateMutability":"nonpayable",
231 "type":"function"
232 },{
233 "inputs":[
234 {"internalType":"uint256","name":"tokenId","type":"uint256"},
235 {"internalType":"uint256","name":"authMethodType","type":"uint256"},
236 {"internalType":"bytes","name":"id","type":"bytes"},
237 {"internalType":"uint256","name":"scopeId","type":"uint256"}
238 ],
239 "name":"removePermittedAuthMethodScope",
240 "outputs":[],
241 "stateMutability":"nonpayable",
242 "type":"function"
243 },{
244 "inputs":[
245 {"internalType":"uint256","name":"tokenId","type":"uint256"},
246 {"internalType":"uint256","name":"authMethodType","type":"uint256"},
247 {"internalType":"bytes","name":"id","type":"bytes"}
248 ],
249 "name":"removePermittedAuthMethod",
250 "outputs":[],
251 "stateMutability":"nonpayable",
252 "type":"function"
253 },{
254 "inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],
255 "name":"getPermittedActions",
256 "outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],
257 "stateMutability":"view",
258 "type":"function"
259 },{
260 "inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],
261 "name":"getPermittedAddresses",
262 "outputs":[{"internalType":"address[]","name":"","type":"address[]"}],
263 "stateMutability":"view",
264 "type":"function"
265 },{
266 "inputs":[
267 {"internalType":"uint256","name":"tokenId","type":"uint256"},
268 {"internalType":"uint256","name":"authMethodType","type":"uint256"},
269 {"internalType":"bytes","name":"id","type":"bytes"},
270 {"internalType":"uint256","name":"maxScopeId","type":"uint256"}
271 ],
272 "name":"getPermittedAuthMethodScopes",
273 "outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],
274 "stateMutability":"view",
275 "type":"function"
276 },{
277 "inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],
278 "name":"getPermittedAuthMethods",
279 "outputs":[{"components":[
280 {"internalType":"uint256","name":"authMethodType","type":"uint256"},
281 {"internalType":"bytes","name":"id","type":"bytes"},
282 {"internalType":"bytes","name":"userPubkey","type":"bytes"}
283 ],"internalType":"struct LibPKPPermissionsStorage.AuthMethod[]","name":"","type":"tuple[]"}],
284 "stateMutability":"view",
285 "type":"function"
286 },{
287 "inputs":[
288 {"internalType":"uint256","name":"authMethodType","type":"uint256"},
289 {"internalType":"bytes","name":"id","type":"bytes"}
290 ],
291 "name":"getTokenIdsForAuthMethod",
292 "outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],
293 "stateMutability":"view",
294 "type":"function"
295 },{
296 "inputs":[
297 {"internalType":"uint256","name":"tokenId","type":"uint256"},
298 {"internalType":"bytes","name":"ipfsCID","type":"bytes"}
299 ],
300 "name":"isPermittedAction",
301 "outputs":[{"internalType":"bool","name":"","type":"bool"}],
302 "stateMutability":"view",
303 "type":"function"
304 },{
305 "inputs":[
306 {"internalType":"uint256","name":"tokenId","type":"uint256"},
307 {"internalType":"address","name":"user","type":"address"}
308 ],
309 "name":"isPermittedAddress",
310 "outputs":[{"internalType":"bool","name":"","type":"bool"}],
311 "stateMutability":"view",
312 "type":"function"
313 }]"#,
314);
315
316pub fn ledger_address_for(network: &str) -> Option<Address> {
317 match network {
318 "naga-dev" => Some("0x81061b50a66EBB3E7F9CEbeF2b1C1A961aE858F4".parse().ok()?),
319 "naga-test" => Some("0xbA0aEB6Bbf58F1B74E896416A20DB5be51C991f2".parse().ok()?),
320 "naga-staging" => Some("0x23Be686cAFCe69C5Fb075E2be7a4505598E338E8".parse().ok()?),
321 "naga-proto" => Some("0x25be72246358491Ac7a1eF138C39Ff3b240E50b5".parse().ok()?),
322 "naga" => Some("0x9BD023448d2D3b2D73fe61E4d7859007F6dA372c".parse().ok()?),
323 _ => None,
324 }
325}
326
327pub fn payment_delegation_address_for(network: &str) -> Option<Address> {
328 match network {
329 "naga-dev" => Some("0x2F202f846CBB27Aa5EbE6b9cfad50D65c49c01FF".parse().ok()?),
330 "naga-test" => Some("0xd1E59c174BcF85012c54086AB600Dd0aB032e88B".parse().ok()?),
331 "naga-staging" => Some("0x13fC0864A37B38D3C2A7d5E9C08D5124B9Cec4bF".parse().ok()?),
332 "naga-proto" => Some("0x5033b79388EBBAf466B4CF82c0b72Abd9bB940d6".parse().ok()?),
333 "naga" => Some("0x5EF658cB6ab3C3BfB75C8293B9a6C8ccb0b96C3c".parse().ok()?),
334 _ => None,
335 }
336}
337
338pub fn pkp_nft_address_for(network: &str) -> Option<Address> {
339 match network {
340 "naga-dev" => Some("0xB144B88514316a2f155D22937C76795b8fC9aDCd".parse().ok()?),
341 "naga-test" => Some("0xaf4Dddb07Cdde48042e93eb5bf266b49950bC5BD".parse().ok()?),
342 "naga-staging" => Some("0x92d2a4Acb70E498a486E0523AD42fF3F6d3D3642".parse().ok()?),
343 "naga-proto" => Some("0xaeEA5fE3654919c8Bb2b356aDCb5dF4eC082C168".parse().ok()?),
344 "naga" => Some("0x11eBfFeab32f6cb5775BeF83E09124B9322E4026".parse().ok()?),
345 _ => None,
346 }
347}
348
349pub fn pkp_helper_address_for(network: &str) -> Option<Address> {
350 match network {
351 "naga-dev" => Some("0xDC62fcb77554229FF2d9857B25f5BB824d33aE71".parse().ok()?),
352 "naga-test" => Some("0x13428A18C0b181344F97ceaC5596F31a9d182e5c".parse().ok()?),
353 "naga-staging" => Some("0xe97fFbc4eDa5CdF70375D4b8f87e476D40b628EC".parse().ok()?),
354 "naga-proto" => Some("0xCCb4A87731B3eFd6732e257381486912eEde24C5".parse().ok()?),
355 "naga" => Some("0xAe666c3080AA5Dd935574099c18E1eD779FFB231".parse().ok()?),
356 _ => None,
357 }
358}
359
360fn pubkey_router_address_for(network: &str) -> Option<Address> {
361 match network {
362 "naga-dev" => Some("0x9067d809df0CF7DaF6a9f20E39d572fee1564c8E".parse().ok()?),
363 "naga-test" => Some("0x054Ddcfef7E9434413ad62A6F37946Bf6B6CFc1A".parse().ok()?),
364 "naga-staging" => Some("0xE37847746012c756d5D91d37B311eeB8e59684e9".parse().ok()?),
365 "naga-proto" => Some("0xB0c6B245B25F2e542c3570b53439825615371231".parse().ok()?),
366 "naga" => Some("0x5655D71832f6f2AFD72c3012a60144f5572897F1".parse().ok()?),
367 _ => None,
368 }
369}
370
371fn pkp_permissions_address_for(network: &str) -> Option<Address> {
372 match network {
373 "naga-dev" => Some("0x85Fa92469Ed765791818b17C926d29fA824E25Ca".parse().ok()?),
374 "naga-test" => Some("0x7255737630fCFb4914cF51552123eEe9abEc6120".parse().ok()?),
375 "naga-staging" => Some("0x1E382ef3957218423C6e1a992a4cE6294861cC93".parse().ok()?),
376 "naga-proto" => Some("0x3894cae120A6ca08150e6e51cBcBdD5c16115F9c".parse().ok()?),
377 "naga" => Some("0xEB1F9A8567bC01b8cfa9d6e7078bEf587D908342".parse().ok()?),
378 _ => None,
379 }
380}
381
382fn staking_address_for(network: &str) -> Option<Address> {
383 match network {
384 "naga-dev" => Some("0x544ac098670a266d3598B543aefBEbAb0A2C86C6".parse().ok()?),
385 "naga-test" => Some("0x9f3cE810695180C5f693a7cD2a0203A381fd57E1".parse().ok()?),
386 "naga-staging" => Some("0x9b8Ed3FD964Bc38dDc32CF637439e230CD50e3Dd".parse().ok()?),
387 "naga-proto" => Some("0x28759afC5989B961D0A8EB236C9074c4141Baea1".parse().ok()?),
388 "naga" => Some("0x8a861B3640c1ff058CCB109ba11CA3224d228159".parse().ok()?),
389 _ => None,
390 }
391}
392
393fn provider_from_config(config: &NetworkConfig) -> Result<Arc<Provider<Http>>, LitSdkError> {
394 let rpc_url = config
395 .rpc_url
396 .as_deref()
397 .ok_or_else(|| LitSdkError::Config("rpc_url is required for chain APIs".into()))?;
398 let provider =
399 Provider::<Http>::try_from(rpc_url).map_err(|e| LitSdkError::Config(e.to_string()))?;
400 Ok(Arc::new(provider))
401}
402
403fn parse_hex_bytes(hex_str: &str) -> Result<Bytes, LitSdkError> {
404 let s = hex_str.strip_prefix("0x").unwrap_or(hex_str);
405 let bytes = hex::decode(s).map_err(|e| LitSdkError::Config(e.to_string()))?;
406 Ok(Bytes::from(bytes))
407}
408
409pub fn auth_method_id_for_eth_wallet(address: Address) -> Bytes {
410 let checksum = to_checksum(&address, None);
411 let msg = format!("{checksum}:lit");
412 Bytes::from(keccak256(msg.as_bytes()).to_vec())
413}
414
415fn eth_address_from_pubkey(pubkey: &[u8]) -> Result<Address, LitSdkError> {
416 if pubkey.len() < 2 {
417 return Err(LitSdkError::Config("pubkey too short".into()));
418 }
419 let hash = keccak256(&pubkey[1..]);
420 Ok(Address::from_slice(&hash[12..]))
421}
422
423#[derive(Clone, Debug, Default)]
424pub struct Pagination {
425 pub limit: usize,
426 pub offset: usize,
427}
428
429#[derive(Clone, Debug)]
430pub struct PaginationInfo {
431 pub limit: usize,
432 pub offset: usize,
433 pub total: usize,
434 pub has_more: bool,
435}
436
437#[derive(Clone, Debug)]
438pub struct PkpData {
439 pub token_id: U256,
440 pub pubkey: String,
441 pub eth_address: Address,
442}
443
444#[derive(Clone, Debug)]
445pub struct MintPkpTx {
446 pub hash: TxHash,
447 pub receipt: TransactionReceipt,
448 pub data: PkpData,
449}
450
451#[derive(Clone, Debug)]
452pub struct PaginatedPkps {
453 pub pkps: Vec<PkpData>,
454 pub pagination: PaginationInfo,
455}
456
457async fn token_ids_for_owner<M: Middleware>(
458 pkp_nft: &PkpNftEnumerableContract<M>,
459 owner: Address,
460) -> Vec<U256> {
461 const BATCH_SIZE: usize = 5;
462 const MAX_BATCHES: usize = 20;
463
464 let mut out = vec![];
465 for batch_index in 0..MAX_BATCHES {
466 let start_index = batch_index * BATCH_SIZE;
467 let calls = (0..BATCH_SIZE)
468 .map(|i| {
469 let index = U256::from((start_index + i) as u64);
470 let call = pkp_nft.token_of_owner_by_index(owner, index);
471 async move { call.call().await }
472 })
473 .collect::<Vec<_>>();
474
475 let results = futures::future::join_all(calls).await;
476
477 let mut successes = 0usize;
478 for token_id in results.into_iter().flatten() {
479 successes += 1;
480 out.push(token_id);
481 }
482
483 if successes == 0 {
484 break;
485 }
486 }
487
488 out
489}
490
491async fn pkp_details_for_token_ids(
492 config: &NetworkConfig,
493 token_ids: &[U256],
494) -> Result<Vec<PkpData>, LitSdkError> {
495 let provider = provider_from_config(config)?;
496 let router_addr = pubkey_router_address_for(config.network).ok_or_else(|| {
497 LitSdkError::Config(format!(
498 "unknown PubkeyRouter address for network {}",
499 config.network
500 ))
501 })?;
502 let router = PubkeyRouterContract::new(router_addr, provider);
503
504 let mut out = Vec::with_capacity(token_ids.len());
505 for token_id in token_ids {
506 let pubkey_bytes: Bytes = router
507 .get_pubkey(*token_id)
508 .call()
509 .await
510 .map_err(|e| LitSdkError::Network(e.to_string()))?;
511
512 let pubkey_hex = format!("0x{}", hex::encode(pubkey_bytes.as_ref()));
513 let eth_address = eth_address_from_pubkey(pubkey_bytes.as_ref())?;
514
515 out.push(PkpData {
516 token_id: *token_id,
517 pubkey: pubkey_hex,
518 eth_address,
519 });
520 }
521
522 Ok(out)
523}
524
525pub async fn get_derived_pubkey(
529 config: &NetworkConfig,
530 derived_key_id: H256,
531) -> Result<String, LitSdkError> {
532 const DEFAULT_KEY_SET_ID: &str = "naga-keyset1";
533
534 let provider = provider_from_config(config)?;
535 let router_addr = pubkey_router_address_for(config.network).ok_or_else(|| {
536 LitSdkError::Config(format!(
537 "unknown PubkeyRouter address for network {}",
538 config.network
539 ))
540 })?;
541 let staking_addr = staking_address_for(config.network).ok_or_else(|| {
542 LitSdkError::Config(format!(
543 "unknown Staking contract address for network {}",
544 config.network
545 ))
546 })?;
547
548 let router = PubkeyRouterContract::new(router_addr, provider);
549 let pubkey_bytes: Bytes = router
550 .get_derived_pubkey(
551 staking_addr,
552 DEFAULT_KEY_SET_ID.to_string(),
553 derived_key_id.0,
554 )
555 .call()
556 .await
557 .map_err(|e| LitSdkError::Network(e.to_string()))?;
558
559 Ok(format!("0x{}", hex::encode(pubkey_bytes.as_ref())))
560}
561
562pub async fn view_pkps_by_address(
563 config: &NetworkConfig,
564 owner_address: Address,
565 pagination: Pagination,
566) -> Result<PaginatedPkps, LitSdkError> {
567 let provider = provider_from_config(config)?;
568 let pkp_nft_addr = pkp_nft_address_for(config.network).ok_or_else(|| {
569 LitSdkError::Config(format!(
570 "unknown PKPNFT address for network {}",
571 config.network
572 ))
573 })?;
574
575 let pkp_nft = PkpNftEnumerableContract::new(pkp_nft_addr, provider);
576 let all_token_ids = token_ids_for_owner(&pkp_nft, owner_address).await;
577
578 let total = all_token_ids.len();
579 let limit = if pagination.limit == 0 {
580 10
581 } else {
582 pagination.limit
583 };
584 let offset = pagination.offset;
585 let has_more = offset + limit < total;
586
587 let paginated = all_token_ids
588 .iter()
589 .skip(offset)
590 .take(limit)
591 .copied()
592 .collect::<Vec<_>>();
593 let pkps = pkp_details_for_token_ids(config, &paginated).await?;
594
595 Ok(PaginatedPkps {
596 pkps,
597 pagination: PaginationInfo {
598 limit,
599 offset,
600 total,
601 has_more,
602 },
603 })
604}
605
606pub async fn view_pkps_by_auth_data(
607 config: &NetworkConfig,
608 auth_method_type: U256,
609 auth_method_id_hex: &str,
610 pagination: Pagination,
611) -> Result<PaginatedPkps, LitSdkError> {
612 let provider = provider_from_config(config)?;
613 let permissions_addr = pkp_permissions_address_for(config.network).ok_or_else(|| {
614 LitSdkError::Config(format!(
615 "unknown PKPPermissions address for network {}",
616 config.network
617 ))
618 })?;
619 let permissions = PkpPermissionsContract::new(permissions_addr, provider);
620 let auth_method_id = parse_hex_bytes(auth_method_id_hex)?;
621
622 let token_ids: Vec<U256> = permissions
623 .get_token_ids_for_auth_method(auth_method_type, auth_method_id)
624 .call()
625 .await
626 .map_err(|e| LitSdkError::Network(e.to_string()))?;
627
628 let total = token_ids.len();
629 let limit = if pagination.limit == 0 {
630 50
631 } else {
632 pagination.limit
633 };
634 let offset = pagination.offset;
635 let has_more = offset + limit < total;
636
637 let paginated = token_ids
638 .iter()
639 .skip(offset)
640 .take(limit)
641 .copied()
642 .collect::<Vec<_>>();
643
644 let pkps = pkp_details_for_token_ids(config, &paginated).await?;
645
646 Ok(PaginatedPkps {
647 pkps,
648 pagination: PaginationInfo {
649 limit,
650 offset,
651 total,
652 has_more,
653 },
654 })
655}
656
657fn pkp_data_from_mint_receipt(receipt: &TransactionReceipt) -> Result<PkpData, LitSdkError> {
658 let event_sig = H256::from(keccak256("PKPMinted(uint256,bytes)".as_bytes()));
659 for log in &receipt.logs {
660 if log.topics.first() != Some(&event_sig) || log.topics.len() < 2 {
661 continue;
662 }
663
664 let token_id = U256::from_big_endian(log.topics[1].as_bytes());
665 let decoded = ethers::abi::decode(&[ethers::abi::ParamType::Bytes], log.data.as_ref())
666 .map_err(|e| LitSdkError::Network(e.to_string()))?;
667 let Some(ethers::abi::Token::Bytes(pubkey_bytes)) = decoded.into_iter().next() else {
668 continue;
669 };
670
671 let pubkey_hex = format!("0x{}", hex::encode(pubkey_bytes.as_slice()));
672 let eth_address = eth_address_from_pubkey(pubkey_bytes.as_slice())?;
673 return Ok(PkpData {
674 token_id,
675 pubkey: pubkey_hex,
676 eth_address,
677 });
678 }
679
680 Err(LitSdkError::Network("PKPMinted event not found".into()))
681}
682
683pub struct PkpMintManager<M: Middleware> {
684 pkp_nft: PkpNftMintContract<M>,
685 pkp_helper: PkpHelperContract<M>,
686}
687
688impl<M: Middleware> PkpMintManager<M> {
689 pub fn new(config: &NetworkConfig, middleware: Arc<M>) -> Result<Self, LitSdkError> {
690 let pkp_nft_addr = pkp_nft_address_for(config.network).ok_or_else(|| {
691 LitSdkError::Config(format!(
692 "unknown PKPNFT address for network {}",
693 config.network
694 ))
695 })?;
696 let pkp_helper_addr = pkp_helper_address_for(config.network).ok_or_else(|| {
697 LitSdkError::Config(format!(
698 "unknown PKPHelper address for network {}",
699 config.network
700 ))
701 })?;
702 Ok(Self {
703 pkp_nft: PkpNftMintContract::new(pkp_nft_addr, middleware.clone()),
704 pkp_helper: PkpHelperContract::new(pkp_helper_addr, middleware),
705 })
706 }
707
708 async fn receipt_with_pkp_data(
709 &self,
710 tx_hash: TxHash,
711 mut receipt: TransactionReceipt,
712 ) -> Result<(TransactionReceipt, PkpData), LitSdkError> {
713 if receipt.status.unwrap_or_default().as_u64() != 1 {
714 return Err(LitSdkError::Network("PKP mint transaction failed".into()));
715 }
716
717 match pkp_data_from_mint_receipt(&receipt) {
718 Ok(data) => Ok((receipt, data)),
719 Err(err) => {
720 let mut last_err = err;
721 let middleware = self.pkp_nft.client();
722 for _ in 0..3 {
723 sleep(Duration::from_secs(2)).await;
724 let refreshed = middleware
725 .get_transaction_receipt(tx_hash)
726 .await
727 .map_err(|e| LitSdkError::Network(e.to_string()))?;
728 if let Some(r) = refreshed {
729 receipt = r;
730 match pkp_data_from_mint_receipt(&receipt) {
731 Ok(data) => return Ok((receipt, data)),
732 Err(err) => last_err = err,
733 }
734 }
735 }
736 Err(last_err)
737 }
738 }
739 }
740
741 pub async fn mint_next(
742 &self,
743 key_type: U256,
744 key_set_id: impl Into<String>,
745 ) -> Result<MintPkpTx, LitSdkError> {
746 let mint_cost = self
747 .pkp_nft
748 .mint_cost()
749 .call()
750 .await
751 .map_err(|e| LitSdkError::Network(e.to_string()))?;
752
753 let call = self
754 .pkp_nft
755 .mint_next(key_type, key_set_id.into())
756 .value(mint_cost);
757
758 let pending = call
759 .send()
760 .await
761 .map_err(|e| LitSdkError::Network(e.to_string()))?;
762 let hash = *pending;
763 let receipt = pending
764 .await
765 .map_err(|e| LitSdkError::Network(e.to_string()))?
766 .ok_or_else(|| LitSdkError::Network("mintNext tx dropped from mempool".into()))?;
767 let (receipt, data) = self.receipt_with_pkp_data(hash, receipt).await?;
768 Ok(MintPkpTx {
769 hash,
770 receipt,
771 data,
772 })
773 }
774
775 #[allow(clippy::too_many_arguments)]
776 pub async fn mint_next_and_add_auth_methods(
777 &self,
778 key_type: U256,
779 key_set_id: impl Into<String>,
780 permitted_auth_method_types: Vec<U256>,
781 permitted_auth_method_ids: Vec<Bytes>,
782 permitted_auth_method_pubkeys: Vec<Bytes>,
783 permitted_auth_method_scopes: Vec<Vec<U256>>,
784 add_pkp_eth_address_as_permitted_address: bool,
785 send_pkp_to_itself: bool,
786 ) -> Result<MintPkpTx, LitSdkError> {
787 let n = permitted_auth_method_types.len();
788 if permitted_auth_method_ids.len() != n
789 || permitted_auth_method_pubkeys.len() != n
790 || permitted_auth_method_scopes.len() != n
791 {
792 return Err(LitSdkError::Config(
793 "permitted auth method arrays must be the same length".into(),
794 ));
795 }
796
797 let mint_cost = self
798 .pkp_nft
799 .mint_cost()
800 .call()
801 .await
802 .map_err(|e| LitSdkError::Network(e.to_string()))?;
803
804 let call = self
805 .pkp_helper
806 .mint_next_and_add_auth_methods(
807 key_type,
808 key_set_id.into(),
809 permitted_auth_method_types,
810 permitted_auth_method_ids,
811 permitted_auth_method_pubkeys,
812 permitted_auth_method_scopes,
813 add_pkp_eth_address_as_permitted_address,
814 send_pkp_to_itself,
815 )
816 .value(mint_cost);
817
818 let pending = call
819 .send()
820 .await
821 .map_err(|e| LitSdkError::Network(e.to_string()))?;
822 let hash = *pending;
823 let receipt = pending
824 .await
825 .map_err(|e| LitSdkError::Network(e.to_string()))?
826 .ok_or_else(|| {
827 LitSdkError::Network("mintNextAndAddAuthMethods tx dropped from mempool".into())
828 })?;
829 let (receipt, data) = self.receipt_with_pkp_data(hash, receipt).await?;
830 Ok(MintPkpTx {
831 hash,
832 receipt,
833 data,
834 })
835 }
836
837 pub async fn mint_with_custom_auth(
838 &self,
839 custom_auth_method_type: U256,
840 custom_auth_method_id: Bytes,
841 validation_ipfs_cid_v0: &str,
842 scope: &str,
843 add_pkp_eth_address_as_permitted_address: bool,
844 send_pkp_to_itself: bool,
845 ) -> Result<MintPkpTx, LitSdkError> {
846 let scope_id = scope_id_for(scope)
847 .ok_or_else(|| LitSdkError::Config(format!("unsupported auth scope: {scope}")))?;
848 let validation_ipfs_id = ipfs_cid_v0_to_bytes(validation_ipfs_cid_v0)?;
849
850 self.mint_next_and_add_auth_methods(
851 U256::from(2u64),
852 "naga-keyset1",
853 vec![custom_auth_method_type, U256::from(2u64)],
854 vec![custom_auth_method_id, validation_ipfs_id],
855 vec![Bytes::from(vec![]), Bytes::from(vec![])],
856 vec![vec![U256::from(scope_id)], vec![U256::from(scope_id)]],
857 add_pkp_eth_address_as_permitted_address,
858 send_pkp_to_itself,
859 )
860 .await
861 }
862
863 pub async fn mint_with_eoa(&self) -> Result<MintPkpTx, LitSdkError> {
864 self.mint_next(U256::from(2u64), "naga-keyset1").await
865 }
866}
867
868#[derive(Clone, Debug)]
869pub struct PaymentBalance {
870 pub total_balance_wei: I256,
871 pub available_balance_wei: I256,
872}
873
874#[derive(Clone, Debug)]
875pub struct WithdrawRequest {
876 pub timestamp: U256,
877 pub amount: U256,
878}
879
880#[derive(Clone, Debug)]
881pub struct WithdrawRequestInfo {
882 pub request: WithdrawRequest,
883 pub is_pending: bool,
884}
885
886#[derive(Clone, Debug)]
887pub struct PaymentTx {
888 pub hash: TxHash,
889 pub receipt: TransactionReceipt,
890}
891
892pub struct PaymentManager<M: Middleware> {
893 ledger: LedgerContract<M>,
894}
895
896impl<M: Middleware> PaymentManager<M> {
897 pub fn new(config: &NetworkConfig, middleware: Arc<M>) -> Result<Self, LitSdkError> {
898 let addr = ledger_address_for(config.network).ok_or_else(|| {
899 LitSdkError::Config(format!(
900 "unknown Ledger address for network {}",
901 config.network
902 ))
903 })?;
904 Ok(Self {
905 ledger: LedgerContract::new(addr, middleware),
906 })
907 }
908
909 pub async fn deposit(&self, amount_wei: U256) -> Result<PaymentTx, LitSdkError> {
910 let call = self.ledger.deposit().value(amount_wei);
911 let pending = call
912 .send()
913 .await
914 .map_err(|e| LitSdkError::Network(e.to_string()))?;
915 let hash = *pending;
916 let receipt = pending
917 .await
918 .map_err(|e| LitSdkError::Network(e.to_string()))?
919 .ok_or_else(|| LitSdkError::Network("deposit tx dropped from mempool".into()))?;
920 Ok(PaymentTx { hash, receipt })
921 }
922
923 pub async fn deposit_for_user(
924 &self,
925 user_address: Address,
926 amount_wei: U256,
927 ) -> Result<PaymentTx, LitSdkError> {
928 let call = self.ledger.deposit_for_user(user_address).value(amount_wei);
929 let pending = call
930 .send()
931 .await
932 .map_err(|e| LitSdkError::Network(e.to_string()))?;
933 let hash = *pending;
934 let receipt = pending
935 .await
936 .map_err(|e| LitSdkError::Network(e.to_string()))?
937 .ok_or_else(|| LitSdkError::Network("depositForUser tx dropped from mempool".into()))?;
938 Ok(PaymentTx { hash, receipt })
939 }
940
941 pub async fn get_balance(&self, user_address: Address) -> Result<PaymentBalance, LitSdkError> {
942 let total = self
943 .ledger
944 .balance(user_address)
945 .call()
946 .await
947 .map_err(|e| LitSdkError::Network(e.to_string()))?;
948 let available = self
949 .ledger
950 .stable_balance(user_address)
951 .call()
952 .await
953 .map_err(|e| LitSdkError::Network(e.to_string()))?;
954
955 Ok(PaymentBalance {
956 total_balance_wei: total,
957 available_balance_wei: available,
958 })
959 }
960
961 pub async fn request_withdraw(&self, amount_wei: U256) -> Result<PaymentTx, LitSdkError> {
962 let amount = I256::from_raw(amount_wei);
963 let call = self.ledger.request_withdraw(amount);
964 let pending = call
965 .send()
966 .await
967 .map_err(|e| LitSdkError::Network(e.to_string()))?;
968 let hash = *pending;
969 let receipt = pending
970 .await
971 .map_err(|e| LitSdkError::Network(e.to_string()))?
972 .ok_or_else(|| {
973 LitSdkError::Network("requestWithdraw tx dropped from mempool".into())
974 })?;
975 Ok(PaymentTx { hash, receipt })
976 }
977
978 pub async fn withdraw(&self, amount_wei: U256) -> Result<PaymentTx, LitSdkError> {
979 let amount = I256::from_raw(amount_wei);
980 let call = self.ledger.withdraw(amount);
981 let pending = call
982 .send()
983 .await
984 .map_err(|e| LitSdkError::Network(e.to_string()))?;
985 let hash = *pending;
986 let receipt = pending
987 .await
988 .map_err(|e| LitSdkError::Network(e.to_string()))?
989 .ok_or_else(|| LitSdkError::Network("withdraw tx dropped from mempool".into()))?;
990 Ok(PaymentTx { hash, receipt })
991 }
992
993 pub async fn get_withdraw_request(
994 &self,
995 user_address: Address,
996 ) -> Result<WithdrawRequestInfo, LitSdkError> {
997 let wr = self
998 .ledger
999 .latest_withdraw_request(user_address)
1000 .call()
1001 .await
1002 .map_err(|e| LitSdkError::Network(e.to_string()))?;
1003 let is_pending = wr.timestamp > U256::zero() && wr.amount > U256::zero();
1004 Ok(WithdrawRequestInfo {
1005 request: WithdrawRequest {
1006 timestamp: wr.timestamp,
1007 amount: wr.amount,
1008 },
1009 is_pending,
1010 })
1011 }
1012
1013 pub async fn get_withdraw_delay_seconds(&self) -> Result<U256, LitSdkError> {
1014 self.ledger
1015 .user_withdraw_delay()
1016 .call()
1017 .await
1018 .map_err(|e| LitSdkError::Network(e.to_string()))
1019 }
1020
1021 pub async fn can_execute_withdraw(
1022 &self,
1023 user_address: Address,
1024 ) -> Result<(bool, Option<u64>, WithdrawRequestInfo), LitSdkError> {
1025 let wr = self.get_withdraw_request(user_address).await?;
1026 let delay = self.get_withdraw_delay_seconds().await?;
1027 if !wr.is_pending {
1028 return Ok((false, None, wr));
1029 }
1030
1031 let now_secs = std::time::SystemTime::now()
1032 .duration_since(std::time::SystemTime::UNIX_EPOCH)
1033 .map_err(|e| LitSdkError::Network(e.to_string()))?
1034 .as_secs();
1035
1036 let req_time = wr.request.timestamp.as_u64();
1037 let delay_secs = delay.as_u64();
1038 let execute_time = req_time.saturating_add(delay_secs);
1039 if now_secs >= execute_time {
1040 Ok((true, None, wr))
1041 } else {
1042 Ok((false, Some(execute_time - now_secs), wr))
1043 }
1044 }
1045}
1046
1047fn ipfs_cid_v0_to_bytes(cid_v0: &str) -> Result<Bytes, LitSdkError> {
1048 let bytes = bs58::decode(cid_v0)
1049 .into_vec()
1050 .map_err(|e| LitSdkError::Config(format!("invalid ipfs cid: {e}")))?;
1051 Ok(Bytes::from(bytes))
1052}
1053
1054fn bytes_to_ipfs_cid_v0(bytes: &[u8]) -> String {
1055 bs58::encode(bytes).into_string()
1056}
1057
1058fn scope_id_for(scope: &str) -> Option<u64> {
1059 match scope {
1060 "no-permissions" => Some(0),
1061 "sign-anything" => Some(1),
1062 "personal-sign" => Some(2),
1063 _ => None,
1064 }
1065}
1066
1067fn scopes_to_u256(scopes: &[String]) -> Result<Vec<U256>, LitSdkError> {
1068 scopes
1069 .iter()
1070 .map(|s| {
1071 scope_id_for(s)
1072 .map(U256::from)
1073 .ok_or_else(|| LitSdkError::Config(format!("unknown scope: {s}")))
1074 })
1075 .collect()
1076}
1077
1078#[derive(Clone, Debug)]
1079pub struct PkpAuthMethod {
1080 pub auth_method_type: U256,
1081 pub id: String,
1082 pub user_pubkey: String,
1083}
1084
1085#[derive(Clone, Debug)]
1086pub struct PkpAuthMethodWithScopes {
1087 pub auth_method_type: U256,
1088 pub id: String,
1089 pub user_pubkey: String,
1090 pub scopes: Vec<String>,
1091}
1092
1093#[derive(Clone, Debug)]
1094pub struct PkpPermissionsContext {
1095 pub actions: Vec<String>,
1096 pub addresses: Vec<Address>,
1097 pub auth_methods: Vec<PkpAuthMethodWithScopes>,
1098}
1099
1100impl PkpPermissionsContext {
1101 pub fn is_address_permitted(&self, address: Address) -> bool {
1102 self.addresses.contains(&address)
1103 }
1104
1105 pub fn is_action_permitted(&self, ipfs_cid_v0: &str) -> bool {
1106 self.actions.iter().any(|a| a == ipfs_cid_v0)
1107 }
1108
1109 pub fn is_auth_method_permitted(
1110 &self,
1111 auth_method_type: U256,
1112 auth_method_id_hex: &str,
1113 ) -> bool {
1114 let id = auth_method_id_hex.to_lowercase();
1115 self.auth_methods
1116 .iter()
1117 .any(|m| m.auth_method_type == auth_method_type && m.id.to_lowercase() == id)
1118 }
1119}
1120
1121pub struct PkpPermissionsManager<M: Middleware> {
1122 contract: PkpPermissionsContract<M>,
1123 token_id: U256,
1124}
1125
1126impl<M: Middleware> PkpPermissionsManager<M> {
1127 pub fn new(
1128 config: &NetworkConfig,
1129 middleware: Arc<M>,
1130 token_id: U256,
1131 ) -> Result<Self, LitSdkError> {
1132 let addr = pkp_permissions_address_for(config.network).ok_or_else(|| {
1133 LitSdkError::Config(format!(
1134 "unknown PKPPermissions address for network {}",
1135 config.network
1136 ))
1137 })?;
1138 Ok(Self {
1139 contract: PkpPermissionsContract::new(addr, middleware),
1140 token_id,
1141 })
1142 }
1143
1144 pub async fn get_permitted_addresses(&self) -> Result<Vec<Address>, LitSdkError> {
1145 self.contract
1146 .get_permitted_addresses(self.token_id)
1147 .call()
1148 .await
1149 .map_err(|e| LitSdkError::Network(e.to_string()))
1150 }
1151
1152 pub async fn get_permitted_actions(&self) -> Result<Vec<String>, LitSdkError> {
1153 let actions = self
1154 .contract
1155 .get_permitted_actions(self.token_id)
1156 .call()
1157 .await
1158 .map_err(|e| LitSdkError::Network(e.to_string()))?;
1159 Ok(actions
1160 .iter()
1161 .map(|b| bytes_to_ipfs_cid_v0(b.as_ref()))
1162 .collect())
1163 }
1164
1165 pub async fn is_permitted_address(&self, user: Address) -> Result<bool, LitSdkError> {
1166 self.contract
1167 .is_permitted_address(self.token_id, user)
1168 .call()
1169 .await
1170 .map_err(|e| LitSdkError::Network(e.to_string()))
1171 }
1172
1173 pub async fn is_permitted_action(&self, ipfs_cid_v0: &str) -> Result<bool, LitSdkError> {
1174 let ipfs_bytes = ipfs_cid_v0_to_bytes(ipfs_cid_v0)?;
1175 self.contract
1176 .is_permitted_action(self.token_id, ipfs_bytes)
1177 .call()
1178 .await
1179 .map_err(|e| LitSdkError::Network(e.to_string()))
1180 }
1181
1182 pub async fn get_permitted_auth_methods(&self) -> Result<Vec<PkpAuthMethod>, LitSdkError> {
1183 let auth_methods = self
1184 .contract
1185 .get_permitted_auth_methods(self.token_id)
1186 .call()
1187 .await
1188 .map_err(|e| LitSdkError::Network(e.to_string()))?;
1189
1190 Ok(auth_methods
1191 .into_iter()
1192 .map(|am| PkpAuthMethod {
1193 auth_method_type: am.auth_method_type,
1194 id: format!("0x{}", hex::encode(am.id.as_ref())),
1195 user_pubkey: format!("0x{}", hex::encode(am.user_pubkey.as_ref())),
1196 })
1197 .collect())
1198 }
1199
1200 pub async fn get_permitted_auth_method_scopes(
1201 &self,
1202 auth_method_type: U256,
1203 auth_method_id_hex: &str,
1204 scope_id: Option<u64>,
1205 ) -> Result<Vec<bool>, LitSdkError> {
1206 let max_scope_id = scope_id.unwrap_or(3);
1207 let id_bytes = parse_hex_bytes(auth_method_id_hex)?;
1208 self.contract
1209 .get_permitted_auth_method_scopes(
1210 self.token_id,
1211 auth_method_type,
1212 id_bytes,
1213 U256::from(max_scope_id),
1214 )
1215 .call()
1216 .await
1217 .map_err(|e| LitSdkError::Network(e.to_string()))
1218 }
1219
1220 pub async fn get_permissions_context(&self) -> Result<PkpPermissionsContext, LitSdkError> {
1221 let (actions, addresses, auth_methods) = futures::try_join!(
1222 self.get_permitted_actions(),
1223 self.get_permitted_addresses(),
1224 self.get_permitted_auth_methods()
1225 )?;
1226
1227 let mut auth_methods_with_scopes = Vec::with_capacity(auth_methods.len());
1228 for am in &auth_methods {
1229 let flags = self
1230 .get_permitted_auth_method_scopes(am.auth_method_type, &am.id, None)
1231 .await?;
1232 let names = ["no-permissions", "sign-anything", "personal-sign"];
1233 let scopes: Vec<String> = flags
1234 .iter()
1235 .enumerate()
1236 .filter_map(|(i, enabled)| {
1237 (*enabled && i < names.len()).then_some(names[i].to_string())
1238 })
1239 .collect();
1240 auth_methods_with_scopes.push(PkpAuthMethodWithScopes {
1241 auth_method_type: am.auth_method_type,
1242 id: am.id.clone(),
1243 user_pubkey: am.user_pubkey.clone(),
1244 scopes,
1245 });
1246 }
1247
1248 Ok(PkpPermissionsContext {
1249 actions,
1250 addresses,
1251 auth_methods: auth_methods_with_scopes,
1252 })
1253 }
1254
1255 pub async fn add_permitted_auth_method(
1256 &self,
1257 auth_method_type: U256,
1258 auth_method_id_hex: &str,
1259 user_pubkey_hex: &str,
1260 scopes: Vec<String>,
1261 ) -> Result<PaymentTx, LitSdkError> {
1262 let id = parse_hex_bytes(auth_method_id_hex)?;
1263 let user_pubkey = parse_hex_bytes(user_pubkey_hex)?;
1264 let scopes = scopes_to_u256(&scopes)?;
1265
1266 let auth_method = pkp_permissions_contract::AuthMethod {
1267 auth_method_type,
1268 id,
1269 user_pubkey,
1270 };
1271
1272 let call = self
1273 .contract
1274 .add_permitted_auth_method(self.token_id, auth_method, scopes);
1275 let pending = call
1276 .send()
1277 .await
1278 .map_err(|e| LitSdkError::Network(e.to_string()))?;
1279 let hash = *pending;
1280 let receipt = pending
1281 .await
1282 .map_err(|e| LitSdkError::Network(e.to_string()))?
1283 .ok_or_else(|| LitSdkError::Network("addPermittedAuthMethod tx dropped".into()))?;
1284 Ok(PaymentTx { hash, receipt })
1285 }
1286
1287 pub async fn remove_permitted_auth_method_scope(
1288 &self,
1289 auth_method_type: U256,
1290 auth_method_id_hex: &str,
1291 scope_id: U256,
1292 ) -> Result<PaymentTx, LitSdkError> {
1293 let id = parse_hex_bytes(auth_method_id_hex)?;
1294 let call = self.contract.remove_permitted_auth_method_scope(
1295 self.token_id,
1296 auth_method_type,
1297 id,
1298 scope_id,
1299 );
1300 let pending = call
1301 .send()
1302 .await
1303 .map_err(|e| LitSdkError::Network(e.to_string()))?;
1304 let hash = *pending;
1305 let receipt = pending
1306 .await
1307 .map_err(|e| LitSdkError::Network(e.to_string()))?
1308 .ok_or_else(|| {
1309 LitSdkError::Network("removePermittedAuthMethodScope tx dropped".into())
1310 })?;
1311 Ok(PaymentTx { hash, receipt })
1312 }
1313
1314 pub async fn remove_permitted_auth_method(
1315 &self,
1316 auth_method_type: U256,
1317 auth_method_id_hex: &str,
1318 ) -> Result<PaymentTx, LitSdkError> {
1319 let id = parse_hex_bytes(auth_method_id_hex)?;
1320 let call = self
1321 .contract
1322 .remove_permitted_auth_method(self.token_id, auth_method_type, id);
1323 let pending = call
1324 .send()
1325 .await
1326 .map_err(|e| LitSdkError::Network(e.to_string()))?;
1327 let hash = *pending;
1328 let receipt = pending
1329 .await
1330 .map_err(|e| LitSdkError::Network(e.to_string()))?
1331 .ok_or_else(|| LitSdkError::Network("removePermittedAuthMethod tx dropped".into()))?;
1332 Ok(PaymentTx { hash, receipt })
1333 }
1334}