strike_sdk/chain/
redeem.rs1use alloy::primitives::{Address, Bytes, U256};
4use alloy::providers::DynProvider;
5use alloy::rpc::types::TransactionRequest;
6use alloy::sol_types::SolCall;
7use std::sync::Arc;
8use tokio::sync::Mutex;
9use tracing::info;
10
11use crate::chain::send_tx;
12use crate::config::StrikeConfig;
13use crate::contracts::{OutcomeToken, RedemptionContract, Vault};
14use crate::error::{Result, StrikeError};
15use crate::nonce::NonceSender;
16
17pub struct RedeemClient<'a> {
19 provider: &'a DynProvider,
20 signer_addr: Option<Address>,
21 config: &'a StrikeConfig,
22 nonce_sender: Option<Arc<Mutex<NonceSender>>>,
23}
24
25impl<'a> RedeemClient<'a> {
26 pub(crate) fn new(
27 provider: &'a DynProvider,
28 signer_addr: Option<Address>,
29 config: &'a StrikeConfig,
30 nonce_sender: Option<Arc<Mutex<NonceSender>>>,
31 ) -> Self {
32 Self {
33 provider,
34 signer_addr,
35 config,
36 nonce_sender,
37 }
38 }
39
40 fn require_wallet(&self) -> Result<Address> {
41 self.signer_addr.ok_or(StrikeError::NoWallet)
42 }
43
44 pub async fn redeem(&self, market_id: u64, amount: U256) -> Result<()> {
49 self.require_wallet()?;
50
51 info!(market_id, amount = %amount, "redeeming outcome tokens");
52
53 let calldata = RedemptionContract::redeemCall {
54 factoryMarketId: U256::from(market_id),
55 amount,
56 }
57 .abi_encode();
58
59 let mut tx = TransactionRequest::default()
60 .to(self.config.addresses.redemption)
61 .input(Bytes::from(calldata).into());
62 tx.gas = Some(300_000);
63
64 let pending = send_tx(self.provider, &self.nonce_sender, tx).await?;
65 let receipt = pending
66 .get_receipt()
67 .await
68 .map_err(|e| StrikeError::Contract(e.to_string()))?;
69
70 info!(market_id, tx = %receipt.transaction_hash, gas_used = receipt.gas_used, "redemption confirmed");
71 Ok(())
72 }
73
74 pub async fn internal_positions(&self, market_id: u64, owner: Address) -> Result<(u128, u128)> {
78 let vault = Vault::new(self.config.addresses.vault, self.provider);
79 let result = vault
80 .positions(owner, U256::from(market_id))
81 .call()
82 .await
83 .map_err(|e| StrikeError::Contract(e.to_string()))?;
84 Ok((result.yesLots, result.noLots))
85 }
86
87 pub async fn balances(&self, market_id: u64, owner: Address) -> Result<(U256, U256)> {
89 let ot = OutcomeToken::new(self.config.addresses.outcome_token, self.provider);
90 let mid = U256::from(market_id);
91
92 let yes_id = ot
93 .yesTokenId(mid)
94 .call()
95 .await
96 .map_err(|e| StrikeError::Contract(e.to_string()))?;
97 let no_id = ot
98 .noTokenId(mid)
99 .call()
100 .await
101 .map_err(|e| StrikeError::Contract(e.to_string()))?;
102
103 let yes_bal = ot
104 .balanceOf(owner, yes_id)
105 .call()
106 .await
107 .map_err(|e| StrikeError::Contract(e.to_string()))?;
108 let no_bal = ot
109 .balanceOf(owner, no_id)
110 .call()
111 .await
112 .map_err(|e| StrikeError::Contract(e.to_string()))?;
113
114 Ok((yes_bal, no_bal))
115 }
116}