## preconditions * Amount sufficient * Grab CPFs * CPFs reserved ```rust= // sender::State pub enum State { Initiated, Authorizing{ transferred: Vec<Uuid>, authorized: Vec<Uuid>, }, Sending, Completed, } struct NewTransction { amount: proto::Amount receiver: DynamicVerifier, } type Action = Fn(HashMap<Uuid, Transction>, Db, UnboundedSender<Packet>, UnboundedSender<Trigger>, Keychain) -> Result<(), E>; ``` ## Sender | trigger | process/forward | processor | | ------------------ | --------------- | -------------------------- | | `NewTransaction` | process | `Sender::new_transaction` | | `SimplePaymentAck` | forward | `Transaction::process_ack` | | `AuthorizedPromissory`| forward | `Transaction::process_promissory` | 1. ```rust= fn forward(&self, uetr: Uuid, trigger: Trigger) -> Result<Action, E> { if let Some(mut tranasction) = self.map.get(uetr) { return transaction.process(trigger); }; let action = |receiver| { tracing::error!("Tranasction not found {uetr}"); }; Ok(action) } fn new_transaction(&self, txn: NewTransction) -> Result<Action, E> { uetr = Uuid::new_v4(); let action = |map, db, gw_tx, tr_tx| { map.insert(uetr, Transction::new(txn)); db.set_state(uetr, State::Initiated); gw_tx.send(proto::SimplePaymentRequest::new(uetr, txn.receiver, txn.amount)) }; Ok(action) } ``` ## SenderTransaction ```rust impl SenderTransaction for transaction::Transaction { fn process_ack(&mut self, trigger: Trigger) -> Result<Action, E> { self.state = State::Authorizing; let action = |sender| { sender.db.set_state(self.uetr, State::Authorizing); let promissories: Vec<AuthorizedPromissory> = db.get_reserved(self.uetr); for promissory in promissories { let packet: proto::Packet = AuthorizePromissoryPacket::new(self.uetr, promissory); gw_tx.send(packet)?; } }; } fn process_promissory(&mut self, promissory: Trigger) -> Result<Action, E> { let promissory = Promissory::decode(promissory.data)?; self.state.authorized.push(promissory.id); if self.state.authorized != self.state.transferred { let action = |sender: &Sender| { // and all IDs as vec : [authorized...]/[transferred...] tracing::info!("{authorized}/{transferred}") sender.db.set_state(self.uetr, self.state); sender.db.set_authorized_promissory(promissory); let promissories: Vec<AuthorizedPromissory> = db.set(self.uetr); }; return Ok(action); } else { let authorized_ids = self.state.authorized; self.state = State::Sending; let action = |sender: &Sender| { tracing::info!("{authorized}/{transferred}") sender.db.set_state(self.uetr, self.state); sender.db.set_authorized_promissory(promissory); let promissories: Vec<AuthorizedPromissory> = sender.db.get_authorized_promissories(authorized_ids); for promissory in promissores { sender.gw_tx.send(promissory)?; } }; Ok(action) } ``` ## Receiver | trigger | process/forward | action | | ---------------- | ------------- | ----------------- | | `SimplePaymentRequest` | process | `Receiver::new_transaction` | | `AuthorizedPromissory`| forward | `Transaction::process_promissory`| 1. ```rust= fn new_transaction(&self, packet: proto::Packet) -> Result<Action, E> { let msg = deserialize(packet); let action = |map, db, gw_tx, tr_tx| { msg = deserialize.map_ok_and_err(); if let Ok(header, req) = msg { // we auto accept db.set_state(header.uetr, State::Receiving{expected_amount, vec![]}; map.insert(header.uetr, Transction::new(req)); gw_tx.send(Ack::new(header, req)); } else { gw_tx.send(Nack::new()); } }; Ok(action) } ``` ## ReceiverTransaction ```rust! impl ReceiverTransaction for transaction::Transaction { fn process_promissory(&mut self, trigger: Trigger) -> Result<Action, E> { let promissory: AuthorziedPromissory = Promissory::decode(trigger)?; self.state.received_ids.push(promissory.id); self.state.received_amount += promissory.amount; if received_amount < expeceted_amount { let action = |sender| { sender.db.set_state(self.uetr, self.state); sender.db.set_authorized_promissory(promissory); tracing::info!("{received_amount}/{expected_amount}"); }; return Ok(action); } else { self.state = State::Completed{ self.state.received_ids}; let action = |sender| { sender.db.set_state(self.uetr, self.state); sender.db.set_authorized_promissory(promissory); tracing::info!("{received_amount}/{expected_amount}"); sender.gw_tx .send(SimplePaymentResponse::new(self.state.received_ids)); Ok(()) }; Ok(action) } } ```