|
1 |
| -use std::{collections::HashMap, marker::PhantomData}; |
2 |
| - |
3 |
| -use balius_sdk::{ |
4 |
| - txbuilder::{primitives::TransactionInput, BuildContext, BuildError, InputExpr, UtxoSource}, |
5 |
| - wit, Ack, Params, Utxo, Worker, WorkerResult, |
6 |
| - _internal::Handler, |
7 |
| -}; |
8 |
| -use serde::{Deserialize, Serialize}; |
9 |
| - |
10 |
| -pub struct CoinSelectionInput(pub UtxoSource, pub u64); |
11 |
| - |
12 |
| -// TODO: this is a naive approach to coin selection, |
13 |
| -// balius can probably help with a better one |
14 |
| -impl InputExpr for CoinSelectionInput { |
15 |
| - fn eval(&self, ctx: &BuildContext) -> Result<Vec<TransactionInput>, BuildError> { |
16 |
| - let utxos = self.0.resolve(ctx)?; |
17 |
| - // If we know the fee, add it to the target amount. |
18 |
| - // If not, overestimate the fee so we pick at least as many TXOs as needed. |
19 |
| - let target_lovelace = self.1 |
20 |
| - + if ctx.estimated_fee == 0 { |
21 |
| - 2_000_000 |
22 |
| - } else { |
23 |
| - ctx.estimated_fee |
24 |
| - }; |
25 |
| - |
26 |
| - let mut inputs = vec![]; |
27 |
| - let mut lovelace_so_far = 0; |
28 |
| - let mut pairs: Vec<_> = utxos.iter().collect(); |
29 |
| - pairs.sort_by_key(|(ref_, _)| (ref_.hash, ref_.index)); |
30 |
| - for (ref_, txo) in pairs { |
31 |
| - let coin = txo.value().coin(); |
32 |
| - if coin == 0 { |
33 |
| - continue; |
34 |
| - } |
35 |
| - inputs.push(TransactionInput { |
36 |
| - transaction_id: ref_.hash, |
37 |
| - index: ref_.index, |
38 |
| - }); |
39 |
| - lovelace_so_far += coin; |
40 |
| - if lovelace_so_far >= target_lovelace { |
41 |
| - break; |
42 |
| - } |
43 |
| - } |
44 |
| - if lovelace_so_far >= target_lovelace { |
45 |
| - Ok(inputs) |
46 |
| - } else { |
47 |
| - Err(BuildError::OutputsTooHigh) |
48 |
| - } |
49 |
| - } |
50 |
| -} |
51 |
| - |
52 |
| -#[derive(Deserialize)] |
53 |
| -pub struct SubmittedTx { |
54 |
| - pub method: String, |
55 |
| - pub hash: String, |
56 |
| -} |
57 |
| - |
58 |
| -pub struct SubmittedTxHandler<F, C> |
59 |
| -where |
60 |
| - F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + 'static, |
61 |
| - C: TryFrom<wit::Config>, |
62 |
| -{ |
63 |
| - func: F, |
64 |
| - phantom: PhantomData<C>, |
65 |
| -} |
66 |
| - |
67 |
| -impl<F, C> From<F> for SubmittedTxHandler<F, C> |
68 |
| -where |
69 |
| - F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + 'static, |
70 |
| - C: TryFrom<wit::Config>, |
71 |
| -{ |
72 |
| - fn from(func: F) -> Self { |
73 |
| - Self { |
74 |
| - func, |
75 |
| - phantom: PhantomData, |
76 |
| - } |
77 |
| - } |
78 |
| -} |
79 |
| - |
80 |
| -impl<F, C> Handler for SubmittedTxHandler<F, C> |
81 |
| -where |
82 |
| - F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + Send + Sync + 'static, |
83 |
| - C: TryFrom<wit::Config, Error = balius_sdk::Error> + Send + Sync + 'static, |
84 |
| -{ |
85 |
| - fn handle( |
86 |
| - &self, |
87 |
| - config: wit::Config, |
88 |
| - event: wit::Event, |
89 |
| - ) -> Result<wit::Response, wit::HandleError> { |
90 |
| - let config: C = config.try_into()?; |
91 |
| - let event: Params<SubmittedTx> = event.try_into()?; |
92 |
| - let response = (self.func)(config, event.0)?; |
93 |
| - Ok(response.try_into()?) |
94 |
| - } |
95 |
| -} |
96 |
| - |
97 |
| -pub trait WorkerExt { |
98 |
| - fn with_tx_submitted_handler<C, F>(self, func: F) -> Self |
99 |
| - where |
100 |
| - C: TryFrom<wit::Config, Error = balius_sdk::Error> + Send + Sync + 'static, |
101 |
| - F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + Send + Sync + 'static; |
102 |
| -} |
103 |
| - |
104 |
| -impl WorkerExt for Worker { |
105 |
| - fn with_tx_submitted_handler<C, F>(self, func: F) -> Self |
106 |
| - where |
107 |
| - C: TryFrom<wit::Config, Error = balius_sdk::Error> + Send + Sync + 'static, |
108 |
| - F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + Send + Sync + 'static, |
109 |
| - { |
110 |
| - self.with_request_handler("__tx_submitted", SubmittedTxHandler::from(func)) |
111 |
| - } |
112 |
| -} |
113 |
| - |
114 |
| -pub mod kv { |
115 |
| - use balius_sdk::{wit::balius::app::kv, WorkerResult}; |
116 |
| - use serde::{Deserialize, Serialize}; |
117 |
| - |
118 |
| - pub fn get<D: for<'a> Deserialize<'a>>(key: &str) -> WorkerResult<Option<D>> { |
119 |
| - match kv::get_value(key) { |
120 |
| - Ok(bytes) => Ok(Some(serde_json::from_slice(&bytes)?)), |
121 |
| - Err(kv::KvError::NotFound(_)) => Ok(None), |
122 |
| - Err(err) => Err(err.into()), |
123 |
| - } |
124 |
| - } |
125 |
| - |
126 |
| - pub fn set<S: Serialize>(key: &str, value: &S) -> WorkerResult<()> { |
127 |
| - kv::set_value(key, &serde_json::to_vec(value)?)?; |
128 |
| - Ok(()) |
129 |
| - } |
130 |
| -} |
131 |
| - |
132 |
| -pub trait EventData: Serialize { |
133 |
| - fn signature(&self) -> String; |
134 |
| -} |
135 |
| - |
136 |
| -#[derive(Serialize, Deserialize)] |
137 |
| -pub struct Event { |
138 |
| - pub block_hash: Vec<u8>, |
139 |
| - pub tx_hash: Vec<u8>, |
140 |
| - pub signature: String, |
141 |
| - pub data: serde_json::Value, |
142 |
| -} |
143 |
| - |
144 |
| -impl Event { |
145 |
| - pub fn new<D, E: EventData>(utxo: &Utxo<D>, data: &E) -> WorkerResult<Self> { |
146 |
| - Ok(Self { |
147 |
| - block_hash: utxo.block_hash.clone(), |
148 |
| - tx_hash: utxo.tx_hash.clone(), |
149 |
| - signature: data.signature(), |
150 |
| - data: serde_json::to_value(data)?, |
151 |
| - }) |
152 |
| - } |
153 |
| -} |
154 |
| - |
155 |
| -pub fn emit_events(events: Vec<Event>) -> WorkerResult<()> { |
156 |
| - if events.is_empty() { |
157 |
| - return Ok(()); |
158 |
| - } |
159 |
| - |
160 |
| - let mut block_events: HashMap<String, Vec<Event>> = HashMap::new(); |
161 |
| - for event in events { |
162 |
| - let block_hash = hex::encode(&event.block_hash); |
163 |
| - block_events.entry(block_hash).or_default().push(event); |
164 |
| - } |
165 |
| - |
166 |
| - for (block, mut events) in block_events { |
167 |
| - let events_key = format!("__events_{block}"); |
168 |
| - let mut all_events: Vec<Event> = kv::get(&events_key)?.unwrap_or_default(); |
169 |
| - all_events.append(&mut events); |
170 |
| - kv::set(&events_key, &all_events)?; |
171 |
| - } |
172 |
| - |
173 |
| - Ok(()) |
174 |
| -} |
| 1 | +mod events; |
| 2 | +pub mod kv; |
| 3 | +mod logic; |
| 4 | +mod monitor; |
| 5 | +mod worker; |
| 6 | + |
| 7 | +pub use events::*; |
| 8 | +pub use logic::*; |
| 9 | +pub use monitor::*; |
| 10 | +pub use worker::*; |
0 commit comments