1extern crate alloc;
2
3use alloc::vec::Vec;
4
5use crate::types::Address;
6#[cfg(all(feature = "borsh", not(feature = "soroban")))]
7use borsh::{BorshDeserialize, BorshSerialize};
8#[cfg(all(feature = "serde", not(feature = "soroban")))]
9use serde::{Deserialize, Serialize};
10
11#[cfg_attr(
13 all(feature = "borsh", not(feature = "soroban")),
14 derive(BorshSerialize, BorshDeserialize)
15)]
16#[cfg_attr(
17 all(feature = "postcard", not(feature = "serde"), not(feature = "soroban")),
18 derive(serde::Serialize, serde::Deserialize)
19)]
20#[cfg_attr(
21 all(feature = "serde", not(feature = "soroban")),
22 derive(Serialize, Deserialize)
23)]
24#[cfg_attr(not(target_arch = "wasm32"), derive(Debug))]
25#[derive(Clone, PartialEq, Eq)]
26pub enum KernelEffect {
27 MintShares { owner: Address, shares: u128 },
29 BurnShares { owner: Address, shares: u128 },
31 BurnSharesFrom {
32 spender: Address,
33 owner: Address,
34 shares: u128,
35 },
36 TransferShares {
38 from: Address,
39 to: Address,
40 shares: u128,
41 },
42 TransferAssets { to: Address, amount: u128 },
44 TransferAssetsFrom {
46 from: Address,
47 to: Address,
48 amount: u128,
49 },
50 #[cfg(feature = "near")]
52 ExternalCall {
53 target: Address,
54 selector: u32,
55 args: Vec<u8>,
56 attached_value: u128,
57 callback: Option<KernelCallback>,
58 },
59 #[cfg(feature = "near")]
61 ChargeStorage { payer: Address, bytes: u64 },
62 EmitEvent { event: KernelEvent },
64}
65
66#[cfg_attr(
67 all(feature = "borsh", not(feature = "soroban")),
68 derive(BorshSerialize, BorshDeserialize)
69)]
70#[cfg_attr(
71 all(feature = "postcard", not(feature = "serde"), not(feature = "soroban")),
72 derive(serde::Serialize, serde::Deserialize)
73)]
74#[cfg_attr(
75 all(feature = "serde", not(feature = "soroban")),
76 derive(Serialize, Deserialize)
77)]
78#[cfg_attr(not(target_arch = "wasm32"), derive(Debug))]
79#[derive(Clone, PartialEq, Eq)]
80pub enum KernelCallback {
81 AllocationStep,
83 WithdrawalStep,
85 RefreshStep,
87 PayoutTransfer,
89}
90
91#[cfg_attr(
92 all(feature = "borsh", not(feature = "soroban")),
93 derive(BorshSerialize, BorshDeserialize)
94)]
95#[cfg_attr(
96 all(feature = "postcard", not(feature = "serde"), not(feature = "soroban")),
97 derive(serde::Serialize, serde::Deserialize)
98)]
99#[cfg_attr(
100 all(feature = "serde", not(feature = "soroban")),
101 derive(Serialize, Deserialize)
102)]
103#[cfg_attr(all(feature = "serde", feature = "soroban"), derive(serde::Serialize))]
104#[cfg_attr(not(target_arch = "wasm32"), derive(Debug))]
105#[derive(Clone, PartialEq, Eq)]
106pub enum WithdrawalSkipReason {
107 ZeroExpectedAssets,
108 Restricted,
109}
110
111#[cfg_attr(
112 all(feature = "borsh", not(feature = "soroban")),
113 derive(BorshSerialize, BorshDeserialize)
114)]
115#[cfg_attr(
116 all(feature = "postcard", not(feature = "serde"), not(feature = "soroban")),
117 derive(serde::Serialize, serde::Deserialize)
118)]
119#[cfg_attr(
120 all(feature = "serde", not(feature = "soroban")),
121 derive(Serialize, Deserialize)
122)]
123#[cfg_attr(all(feature = "serde", feature = "soroban"), derive(serde::Serialize))]
124#[cfg_attr(not(target_arch = "wasm32"), derive(Debug))]
125#[derive(Clone, PartialEq, Eq)]
126pub enum KernelEvent {
127 AllocationStarted {
129 op_id: u64,
130 total: u128,
131 plan_len: u32,
132 },
133 AllocationStepFailed {
135 op_id: u64,
136 index: u32,
137 remaining: u128,
138 total_allocated: u128,
141 },
142 AllocationCompleted { op_id: u64, has_withdrawal: bool },
144 WithdrawalStarted {
146 op_id: u64,
147 amount: u128,
148 escrow_shares: u128,
149 owner: Address,
150 receiver: Address,
151 },
152 WithdrawalCollected {
154 op_id: u64,
155 burn_shares: u128,
156 collected: u128,
157 },
158 WithdrawalStopped { op_id: u64, escrow_shares: u128 },
160 WithdrawalSkipped {
162 id: u64,
163 owner: Address,
164 receiver: Address,
165 escrow_shares: u128,
166 expected_assets: u128,
167 reason: WithdrawalSkipReason,
168 },
169 RefreshStarted { op_id: u64, plan_len: u32 },
171 RefreshCompleted { op_id: u64 },
173 PayoutCompleted {
175 op_id: u64,
176 success: bool,
177 burn_shares: u128,
178 refund_shares: u128,
179 amount: u128,
180 },
181 DepositProcessed {
183 owner: Address,
184 receiver: Address,
185 assets_in: u128,
186 shares_out: u128,
187 },
188 AtomicWithdrawProcessed {
189 owner: Address,
190 receiver: Address,
191 shares_burned: u128,
192 assets_out: u128,
193 },
194 WithdrawalRequested {
196 id: u64,
197 owner: Address,
198 receiver: Address,
199 shares: u128,
200 expected_assets: u128,
201 },
202 ExternalAssetsSynced {
204 op_id: u64,
205 new_external_assets: u128,
206 total_assets: u128,
207 },
208 FeesRefreshed { now_ns: u64, total_assets: u128 },
210 PauseUpdated { paused: bool },
212 EmergencyResetCompleted { op_id: u64, from_state: u32 },
214}
215
216impl From<KernelEvent> for KernelEffect {
217 fn from(event: KernelEvent) -> Self {
218 Self::EmitEvent { event }
219 }
220}
221
222impl KernelEffect {
223 pub fn required_addresses(&self) -> Vec<Address> {
225 match self {
226 KernelEffect::MintShares { owner, .. } => alloc::vec![*owner],
227 KernelEffect::BurnShares { owner, .. } => alloc::vec![*owner],
228 KernelEffect::BurnSharesFrom { spender, owner, .. } => alloc::vec![*spender, *owner],
229 KernelEffect::TransferShares { from, to, .. } => alloc::vec![*from, *to],
230 KernelEffect::TransferAssets { to, .. } => alloc::vec![*to],
231 KernelEffect::TransferAssetsFrom { from, to, .. } => alloc::vec![*from, *to],
232 #[cfg(feature = "near")]
233 KernelEffect::ExternalCall { target, .. } => alloc::vec![*target],
234 #[cfg(feature = "near")]
235 KernelEffect::ChargeStorage { payer, .. } => alloc::vec![*payer],
236 KernelEffect::EmitEvent { event } => event.required_addresses(),
237 }
238 }
239}
240
241impl KernelEvent {
242 pub fn required_addresses(&self) -> Vec<Address> {
244 match self {
245 KernelEvent::WithdrawalStarted {
246 owner, receiver, ..
247 } => alloc::vec![*owner, *receiver],
248 KernelEvent::DepositProcessed {
249 owner, receiver, ..
250 } => alloc::vec![*owner, *receiver],
251 KernelEvent::AtomicWithdrawProcessed {
252 owner, receiver, ..
253 } => alloc::vec![*owner, *receiver],
254 KernelEvent::WithdrawalRequested {
255 owner, receiver, ..
256 } => alloc::vec![*owner, *receiver],
257 KernelEvent::WithdrawalSkipped {
258 owner, receiver, ..
259 } => alloc::vec![*owner, *receiver],
260 _ => alloc::vec![],
261 }
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::{KernelEffect, KernelEvent};
268
269 fn address(byte: u8) -> [u8; 32] {
270 [byte; 32]
271 }
272
273 #[test]
274 fn effect_required_addresses_cover_transfer_shapes() {
275 let owner = crate::Address(address(1));
276 let from = crate::Address(address(2));
277 let to = crate::Address(address(3));
278
279 assert_eq!(
280 KernelEffect::MintShares { owner, shares: 10 }.required_addresses(),
281 alloc::vec![owner]
282 );
283 assert_eq!(
284 KernelEffect::TransferShares {
285 shares: 5,
286 from,
287 to
288 }
289 .required_addresses(),
290 alloc::vec![from, to]
291 );
292 assert_eq!(
293 KernelEffect::TransferAssetsFrom {
294 from,
295 to,
296 amount: 7
297 }
298 .required_addresses(),
299 alloc::vec![from, to]
300 );
301 assert_eq!(
302 KernelEffect::BurnSharesFrom {
303 spender: from,
304 owner,
305 shares: 9,
306 }
307 .required_addresses(),
308 alloc::vec![from, owner]
309 );
310 }
311
312 #[test]
313 fn event_required_addresses_cover_account_events() {
314 let owner = crate::Address(address(4));
315 let receiver = crate::Address(address(5));
316
317 assert_eq!(
318 KernelEvent::WithdrawalStarted {
319 op_id: 1,
320 amount: 20,
321 escrow_shares: 30,
322 owner,
323 receiver,
324 }
325 .required_addresses(),
326 alloc::vec![owner, receiver]
327 );
328 assert_eq!(
329 KernelEvent::AtomicWithdrawProcessed {
330 owner,
331 receiver,
332 shares_burned: 10,
333 assets_out: 5,
334 }
335 .required_addresses(),
336 alloc::vec![owner, receiver]
337 );
338 assert!(KernelEvent::RefreshCompleted { op_id: 9 }
339 .required_addresses()
340 .is_empty());
341 }
342
343 #[test]
344 fn event_converts_into_emit_effect() {
345 let event = KernelEvent::PauseUpdated { paused: true };
346 assert_eq!(
347 KernelEffect::from(event.clone()),
348 KernelEffect::EmitEvent { event }
349 );
350 }
351}