Skip to content

Commit

Permalink
hyp_erc20_vault_tests (#114)
Browse files Browse the repository at this point in the history
* hyp_erc20_vaul_tests

* remove unused import

* remove unused import
  • Loading branch information
EgeCaner authored Sep 24, 2024
1 parent 05a132c commit f0b05d4
Show file tree
Hide file tree
Showing 11 changed files with 1,025 additions and 101 deletions.
101 changes: 71 additions & 30 deletions cairo/crates/mocks/src/erc4626_component.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Modified from {https://github.com/0xHashstack/hashstack_contracts/blob/main/src/token/erc4626/erc4626component.cairo}
//! Modified from {https://github.com/nodeset-org/erc4626-cairo/blob/main/src/erc4626/erc4626.cairo}
use starknet::ContractAddress;

#[starknet::component]
Expand All @@ -16,7 +17,6 @@ pub mod ERC4626Component {
ERC20Component, ERC20HooksEmptyImpl, ERC20Component::Errors as ERC20Errors
};
use starknet::{ContractAddress, get_caller_address, get_contract_address};

use token::interfaces::ierc4626::{IERC4626, IERC4626Camel, IERC4626Metadata};

#[storage]
Expand Down Expand Up @@ -55,11 +55,11 @@ pub mod ERC4626Component {
shares: u256
}

mod Errors {
const EXCEEDED_MAX_DEPOSIT: felt252 = 'ERC4626: exceeded max deposit';
const EXCEEDED_MAX_MINT: felt252 = 'ERC4626: exceeded max mint';
const EXCEEDED_MAX_REDEEM: felt252 = 'ERC4626: exceeded max redeem';
const EXCEEDED_MAX_WITHDRAW: felt252 = 'ERC4626: exceeded max withdraw';
pub mod Errors {
pub const EXCEEDED_MAX_DEPOSIT: felt252 = 'ERC4626: exceeded max deposit';
pub const EXCEEDED_MAX_MINT: felt252 = 'ERC4626: exceeded max mint';
pub const EXCEEDED_MAX_REDEEM: felt252 = 'ERC4626: exceeded max redeem';
pub const EXCEEDED_MAX_WITHDRAW: felt252 = 'ERC4626: exceeded max withdraw';
}

pub trait ERC4626HooksTrait<TContractState> {
Expand Down Expand Up @@ -166,16 +166,19 @@ pub mod ERC4626Component {
}

fn convert_to_assets(self: @ComponentState<TContractState>, shares: u256) -> u256 {
self._convert_to_assets(shares)
self._convert_to_assets(shares, false)
}

fn convert_to_shares(self: @ComponentState<TContractState>, assets: u256) -> u256 {
self._convert_to_shares(assets)
self._convert_to_shares(assets, false)
}

fn deposit(
ref self: ComponentState<TContractState>, assets: u256, receiver: ContractAddress
) -> u256 {
let max_assets = self.max_deposit(receiver);
assert(max_assets >= assets, Errors::EXCEEDED_MAX_DEPOSIT);

let caller = get_caller_address();
let shares = self.preview_deposit(assets);
self._deposit(caller, receiver, assets, shares);
Expand All @@ -185,26 +188,29 @@ pub mod ERC4626Component {
fn mint(
ref self: ComponentState<TContractState>, shares: u256, receiver: ContractAddress
) -> u256 {
let max_shares = self.max_mint(receiver);
assert(max_shares >= shares, Errors::EXCEEDED_MAX_MINT);

let caller = get_caller_address();
let assets = self.preview_mint(shares);
self._deposit(caller, receiver, assets, shares);
assets
}

fn preview_deposit(self: @ComponentState<TContractState>, assets: u256) -> u256 {
self._convert_to_shares(assets)
self._convert_to_shares(assets, false)
}

fn preview_mint(self: @ComponentState<TContractState>, shares: u256) -> u256 {
self._convert_to_assets(shares)
self._convert_to_assets(shares, true)
}

fn preview_redeem(self: @ComponentState<TContractState>, shares: u256) -> u256 {
self._convert_to_assets(shares)
self._convert_to_assets(shares, false)
}

fn preview_withdraw(self: @ComponentState<TContractState>, assets: u256) -> u256 {
self._convert_to_shares(assets)
self._convert_to_shares(assets, true)
}

fn max_deposit(self: @ComponentState<TContractState>, receiver: ContractAddress) -> u256 {
Expand All @@ -223,7 +229,7 @@ pub mod ERC4626Component {
fn max_withdraw(self: @ComponentState<TContractState>, owner: ContractAddress) -> u256 {
let erc20 = get_dep_component!(self, ERC20);
let balance = erc20.balance_of(owner);
self._convert_to_assets(balance)
self._convert_to_assets(balance, false)
}

fn redeem(
Expand All @@ -232,6 +238,9 @@ pub mod ERC4626Component {
receiver: ContractAddress,
owner: ContractAddress
) -> u256 {
let max_shares = self.max_redeem(owner);
assert(shares <= max_shares, Errors::EXCEEDED_MAX_REDEEM);

let caller = get_caller_address();
let assets = self.preview_redeem(shares);
self._withdraw(caller, receiver, owner, assets, shares);
Expand All @@ -249,6 +258,9 @@ pub mod ERC4626Component {
receiver: ContractAddress,
owner: ContractAddress
) -> u256 {
let max_assets = self.max_withdraw(owner);
assert(assets <= max_assets, Errors::EXCEEDED_MAX_WITHDRAW);

let caller = get_caller_address();
let shares = self.preview_withdraw(assets);
self._withdraw(caller, receiver, owner, assets, shares);
Expand Down Expand Up @@ -303,27 +315,27 @@ pub mod ERC4626Component {
}

fn convertToAssets(self: @ComponentState<TContractState>, shares: u256) -> u256 {
self._convert_to_assets(shares)
self._convert_to_assets(shares, false)
}

fn convertToShares(self: @ComponentState<TContractState>, assets: u256) -> u256 {
self._convert_to_shares(assets)
self._convert_to_shares(assets, false)
}

fn previewDeposit(self: @ComponentState<TContractState>, assets: u256) -> u256 {
self._convert_to_shares(assets)
self._convert_to_shares(assets, false)
}

fn previewMint(self: @ComponentState<TContractState>, shares: u256) -> u256 {
self._convert_to_assets(shares)
self._convert_to_assets(shares, true)
}

fn previewRedeem(self: @ComponentState<TContractState>, shares: u256) -> u256 {
self._convert_to_assets(shares)
self._convert_to_assets(shares, false)
}

fn previewWithdraw(self: @ComponentState<TContractState>, assets: u256) -> u256 {
self._convert_to_shares(assets)
self._convert_to_shares(assets, true)
}

fn totalAssets(self: @ComponentState<TContractState>) -> u256 {
Expand All @@ -348,6 +360,27 @@ pub mod ERC4626Component {
}
}

fn pow_256(self: u256, mut exponent: u8) -> u256 {
if self == 0 {
return 0;
}
let mut result = 1;
let mut base = self;

loop {
if exponent & 1 == 1 {
result = result * base;
}

exponent = exponent / 2;
if exponent == 0 {
break result;
}

base = base * base;
}
}

#[generate_trait]
pub impl InternalImpl<
TContractState,
Expand All @@ -373,21 +406,29 @@ pub mod ERC4626Component {
self.ERC4626_underlying_decimals.write(decimals);
}

fn _convert_to_assets(self: @ComponentState<TContractState>, shares: u256) -> u256 {
let supply: u256 = self.total_supply();
if (supply == 0) {
shares
fn _convert_to_assets(
self: @ComponentState<TContractState>, shares: u256, round: bool
) -> u256 {
let total_assets = self.total_assets() + 1;
let total_shares = self.total_supply() + pow_256(10, self.ERC4626_offset.read());
let assets = shares * total_assets / total_shares;
if round && ((assets * total_shares) / total_assets < shares) {
assets + 1
} else {
(shares * self.total_assets()) / supply
assets
}
}

fn _convert_to_shares(self: @ComponentState<TContractState>, assets: u256) -> u256 {
let supply: u256 = self.total_supply();
if (assets == 0 || supply == 0) {
assets
fn _convert_to_shares(
self: @ComponentState<TContractState>, assets: u256, round: bool
) -> u256 {
let total_assets = self.total_assets() + 1;
let total_shares = self.total_supply() + pow_256(10, self.ERC4626_offset.read());
let share = assets * total_shares / total_assets;
if round && ((share * total_assets) / total_shares < assets) {
share + 1
} else {
(assets * supply) / self.total_assets()
share
}
}

Expand Down Expand Up @@ -436,7 +477,7 @@ pub mod ERC4626Component {

self.emit(Withdraw { sender: caller, receiver, owner, assets, shares });

Hooks::before_withdraw(ref self, caller, receiver, owner, assets, shares);
Hooks::after_withdraw(ref self, caller, receiver, owner, assets, shares);
}

fn _decimals_offset(self: @ComponentState<TContractState>) -> u8 {
Expand Down
Loading

0 comments on commit f0b05d4

Please sign in to comment.