contract ended
This commit is contained in:
parent
52caa8066d
commit
18757ce70f
4 changed files with 163 additions and 1 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -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]
|
14
README.md
14
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
|
||||
|
|
141
src/main.rs
Normal file
141
src/main.rs
Normal file
|
@ -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<Tx, AccountingError> {
|
||||
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<Tx, AccountingError> {
|
||||
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);
|
||||
}
|
Loading…
Reference in a new issue