From 18757ce70f69213381fe0504fae2011da503e465 Mon Sep 17 00:00:00 2001 From: Claus Matzinger Date: Fri, 6 May 2022 11:34:51 +0200 Subject: [PATCH] contract ended --- .gitignore | 1 + Cargo.toml | 8 +++ README.md | 14 +++++- src/main.rs | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2c521b3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "accounting-with-fundamental-rust-1" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/README.md b/README.md index aca9678..9f1c5a1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ -# accounting-with-fundamental-rust-lp-author +# Accounting Prototype + +This prototype was created for Salmon Finance Inc. A brief summary of the requirements: + +- Selecting names for types to represent errors, transactions, and the accounting structure +- Implement a `deposit()` function and a constructor +- Provide function signatures for `withdraw()` and `send()` +- Set up a scenario to run as a binary + +Please refer to the [original contract](https://liveproject.manning.com/module/1167_3_1/accounting-with-fundamental-rust) for details. + +Made by Trout Consulting + Repository for liveProject: Accounting with Fundamental Rust diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ea67130 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,141 @@ +use std::collections::HashMap; + + +/// An application-specific error type +#[derive(Debug)] +enum AccountingError { + // Add variants here for account not found, account underfunded and account overfunded +} + +/// A transaction type. Transactions should be able to rebuild a ledger's state +/// when they are applied in the same sequence to an empty state. +#[derive(Debug)] +pub enum Tx { + // Add variants for storing withdraw/deposit transactions +} + +/// A type for managing accounts and their current currency balance +#[derive(Debug)] +struct Accounts { + // Add a property `accounts` here +} + +impl Accounts { + + /// Returns an empty instance of the [`Accounts`] type + pub fn new() -> Self { + Accounts { + accounts: Default::default() + } + } + + /// Either deposits the `amount` provided into the `signer` account or adds the amount to the existing account. + /// # Errors + /// Attempted overflow + pub fn deposit(&mut self, signer: &str, amount: u64) -> Result { + if let Some(account) = self.accounts.get_mut(signer) { + (*account) + .checked_add(amount) + .and_then(|r| { + *account = r; + Some(r) + }) + .ok_or(AccountingError::AccountOverFunded( + signer.to_string(), + amount, + )) + // Using map() here is an easy way to only manipulate the non-error result + .map(|_| Tx::Deposit { + account: signer.to_string(), + amount, + }) + } else { + self.accounts.insert(signer.to_string(), amount); + Ok(Tx::Deposit { + account: signer.to_string(), + amount, + }) + } + } + + /// Withdraws the `amount` from the `signer` account. + /// # Errors + /// Attempted overflow + pub fn withdraw(&mut self, signer: &str, amount: u64) -> Result { + todo!(); + } + + /// Withdraws the amount from the sender account and deposits it in the recipient account. + /// + /// # Errors + /// The account doesn't exist + pub fn send( + &mut self, + sender: &str, + recipient: &str, + amount: u64, + ) -> Result<(Tx, Tx), AccountingError> { + todo!(); + } +} + +fn main() { + println!("Hello, accounting world!"); + + // We are using simple &str instances as keys + // for more sophisticated keys (e.g. hashes) + // the data type could remain the same + let bob = "bob"; + let alice = "alice"; + let charlie = "charlie"; + let initial_amount = 100; + + // Creates the basic ledger and a tx log container + let mut ledger = Accounts::new(); + let mut tx_log = vec![]; + + // Deposit an amount to each account + for signer in &[bob, alice, charlie] { + let status = ledger.deposit(*signer, initial_amount); + println!("Depositing {} for {}: {:?}", signer, initial_amount, status); + // Add the resulting transaction to a list of transactions + // .unwrap() will crash the program if the status is an error. + tx_log.push(status.unwrap()); + } + + // Send currency from one account (bob) to the other (alice) + let send_amount = 10_u64; + let status = ledger.send(bob, alice, send_amount); + println!( + "Sent {} from {} to {}: {:?}", + send_amount, bob, alice, status + ); + + // Add both transactions to the transaction log + let (tx1, tx2) = status.unwrap(); + tx_log.push(tx1); + tx_log.push(tx2); + + // Withdraw everything from the accounts + let tx = ledger.withdraw(charlie, initial_amount).unwrap(); + tx_log.push(tx); + let tx = ledger + .withdraw(alice, initial_amount + send_amount) + .unwrap(); + tx_log.push(tx); + + // Here we are withdrawing too much and there won't be a transaction + println!( + "Withdrawing {} from {}: {:?}", + initial_amount, + bob, + ledger.withdraw(bob, initial_amount) + ); + // Withdrawing the expected amount results in a transaction + let tx = ledger.withdraw(bob, initial_amount - send_amount).unwrap(); + tx_log.push(tx); + + // {:?} prints the Debug implementation, {:#?} pretty-prints it + println!("Ledger empty: {:?}", ledger); + println!("The TX log: {:#?}", tx_log); +}