Skip to content

Commit

Permalink
feat: simple defi vault (#37)
Browse files Browse the repository at this point in the history
* feat: simple defi vault

* feat: add Simple defi vault description

* fix: typo

* fix: simple vault wrapped IERC20Dispatcher
  • Loading branch information
julio4 authored Jun 23, 2023
1 parent 1116d93 commit f0fadc9
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 0 deletions.
1 change: 1 addition & 0 deletions listings/ch01-applications/simple_vault/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
11 changes: 11 additions & 0 deletions listings/ch01-applications/simple_vault/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "simple_vault"
version = "0.1.0"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest

[dependencies]
starknet = "1.1.0"

[[target.starknet-contract]]
allowed-libfuncs-list.name = "experimental_v0.1.0"
1 change: 1 addition & 0 deletions listings/ch01-applications/simple_vault/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod simple_vault;
109 changes: 109 additions & 0 deletions listings/ch01-applications/simple_vault/src/simple_vault.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use starknet::{ContractAddress};

// In order to make contract calls within our Vault,
// we need to have the ABI of the remote contract defined to import the Dispatcher
#[abi]
trait IERC20 {
#[view]
fn name() -> felt252;

#[view]
fn symbol() -> felt252;

#[view]
fn decimals() -> u8;

#[view]
fn total_supply() -> u256;

#[view]
fn balance_of(account: ContractAddress) -> u256;

#[view]
fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256;

#[external]
fn transfer(recipient: ContractAddress, amount: u256) -> bool;

#[external]
fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool;

#[external]
fn approve(spender: ContractAddress, amount: u256) -> bool;
}

#[contract]
mod SimpleVault {
use super::{IERC20Dispatcher, IERC20DispatcherTrait};
use starknet::{
ContractAddress,
get_caller_address,
get_contract_address
};

struct Storage {
_token: IERC20Dispatcher,
_total_supply: u256,
_balance_of: LegacyMap<ContractAddress, u256>
}

#[constructor]
fn constructor(token: ContractAddress) {
_token::write(IERC20Dispatcher { contract_address: token });
}

fn _mint(to: ContractAddress, shares: u256) {
_total_supply::write(_total_supply::read() + shares);
_balance_of::write(to, _balance_of::read(to) + shares);
}

fn _burn(from: ContractAddress, shares: u256) {
_total_supply::write(_total_supply::read() - shares);
_balance_of::write(from, _balance_of::read(from) - shares);
}

#[external]
fn deposit(amount: u256) {
// a = amount
// B = balance of token before deposit
// T = total supply
// s = shares to mint
//
// (T + s) / T = (a + B) / B
//
// s = aT / B
let caller = get_caller_address();
let this = get_contract_address();

let mut shares = 0;
if _total_supply::read() == 0 {
shares = amount;
} else {
let balance = _token::read().balance_of(this);
shares = (amount * _total_supply::read()) / balance;
}

_mint(caller, shares);
_token::read().transfer_from(caller, this, amount);
}

#[external]
fn withdraw(shares: u256) {
// a = amount
// B = balance of token before withdraw
// T = total supply
// s = shares to burn
//
// (T - s) / T = (B - a) / B
//
// a = sB / T
let caller = get_caller_address();
let this = get_contract_address();

let balance = _token::read().balance_of(this);
let amount = (shares * balance) / _total_supply::read();
_burn(caller, shares);
_token::read().transfer(caller, amount);
}
}

1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Summary

- [Applications](./ch01-00-applications.md)
- [Upgradeable Contract](./ch01-01-upgradeable_contract.md)
- [Defi Vault](./ch01-02-simple_vault.md)
16 changes: 16 additions & 0 deletions src/ch01-02-simple_vault.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Simple Defi Vault

This is the Cairo adaptation of the [Solidity by example Vault](https://solidity-by-example.org/defi/vault/).
Here's how it works:

- When a user deposits a token, the contract calculates the amount of shares to mint.

- When a user withdraws, the contract burns their shares, calculates the yield, and withdraw both the yield and the initial amount of token deposited.

```rust
{{#include ../listings/ch01-applications/simple_vault/src/simple_vault.cairo}}
```

> **Note**
> As of version v1.1.0, we need to enable `experimental_v0.1.0` libfuncs to use `u256_divmod_safe` as it hasn't been audited yet.
> It'll be included in v2.0.0.

0 comments on commit f0fadc9

Please sign in to comment.