Skip to content

Commit

Permalink
feat: mock erc4626 + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
JordyRo1 committed Dec 2, 2024
1 parent cb33ec5 commit 11aa256
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 103 deletions.
270 changes: 170 additions & 100 deletions pragma-oracle/src/erc4626/erc4626.cairo
Original file line number Diff line number Diff line change
@@ -1,116 +1,186 @@
// Forked from https://github.com/0xEniotna/ERC4626/blob/main/src/erc4626/interface.cairo
// Mock contract to be used for TESTING PURPOSE ONLY
use starknet::ContractAddress;

#[starknet::interface]
trait IERC4626<TState> {
// ************************************
// * Metadata
// ************************************
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;

// ************************************
// * snake_case
// ************************************
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
trait IERC4626<TContractState> {
// Metadata (match implementation)
fn name(self: @TContractState) -> felt252;
fn symbol(self: @TContractState) -> felt252;
fn decimals(self: @TContractState) -> u8;

// ERC20-like methods (match implementation)
fn total_supply(self: @TContractState) -> u256;
fn balance_of(self: @TContractState, account: ContractAddress) -> u256;
fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;

// ************************************
// * camelCase
// ************************************
fn totalSupply(self: @TState) -> u256;
fn balanceOf(self: @TState, account: ContractAddress) -> u256;
fn transferFrom(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool;

// ************************************
// * Additional functions
// ************************************
fn asset(self: @TState) -> starknet::ContractAddress;
fn convert_to_assets(self: @TState, shares: u256) -> u256;
fn convert_to_shares(self: @TState, assets: u256) -> u256;
fn deposit(ref self: TState, assets: u256, receiver: starknet::ContractAddress) -> u256;
fn max_deposit(self: @TState, address: starknet::ContractAddress) -> u256;
fn max_mint(self: @TState, receiver: starknet::ContractAddress) -> u256;
fn max_redeem(self: @TState, owner: starknet::ContractAddress) -> u256;
fn max_withdraw(self: @TState, owner: starknet::ContractAddress) -> u256;
fn mint(ref self: TState, shares: u256, receiver: starknet::ContractAddress) -> u256;
fn preview_deposit(self: @TState, assets: u256) -> u256;
fn preview_mint(self: @TState, shares: u256) -> u256;
fn preview_redeem(self: @TState, shares: u256) -> u256;
fn preview_withdraw(self: @TState, assets: u256) -> u256;
fn redeem(
ref self: TState,
shares: u256,
receiver: starknet::ContractAddress,
owner: starknet::ContractAddress
) -> u256;
fn total_assets(self: @TState) -> u256;
// Remove camelCase methods as they're not in the implementation

// Additional ERC4626 methods (match implementation)
fn asset(self: @TContractState) -> ContractAddress;
fn total_assets(self: @TContractState) -> u256;
fn convert_to_shares(self: @TContractState, assets: u256) -> u256;
fn convert_to_assets(self: @TContractState, shares: u256) -> u256;
fn max_deposit(self: @TContractState, receiver: ContractAddress) -> u256;
fn preview_deposit(self: @TContractState, assets: u256) -> u256;
fn deposit(ref self: TContractState, assets: u256, receiver: ContractAddress) -> u256;
fn max_mint(self: @TContractState, receiver: ContractAddress) -> u256;
fn preview_mint(self: @TContractState, shares: u256) -> u256;
fn mint(ref self: TContractState, shares: u256, receiver: ContractAddress) -> u256;
fn max_withdraw(self: @TContractState, owner: ContractAddress) -> u256;
fn preview_withdraw(self: @TContractState, assets: u256) -> u256;
fn withdraw(
ref self: TState,
assets: u256,
receiver: starknet::ContractAddress,
owner: starknet::ContractAddress
ref self: TContractState, assets: u256, receiver: ContractAddress, owner: ContractAddress
) -> u256;
fn max_redeem(self: @TContractState, owner: ContractAddress) -> u256;
fn preview_redeem(self: @TContractState, shares: u256) -> u256;
fn redeem(
ref self: TContractState, shares: u256, receiver: ContractAddress, owner: ContractAddress
) -> u256;
}

#[starknet::contract]
mod ERC4626 {
use super::IERC4626;
use starknet::get_caller_address;
use starknet::get_contract_address;
use starknet::ContractAddress;
use starknet::contract_address::ContractAddressZeroable;
use zeroable::Zeroable;
use traits::Into;
use traits::TryInto;
use option::OptionTrait;
use integer::BoundedInt;
use debug::PrintTrait;

#[starknet::interface]
trait IERC4626Metadata<TState> {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;
}
#[storage]
struct Storage {}

#[starknet::interface]
trait IERC4626Camel<TState> {
fn totalSupply(self: @TState) -> u256;
fn balanceOf(self: @TState, account: ContractAddress) -> u256;
fn transferFrom(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
}
#[external(v0)]
impl ERC4626Impl of IERC4626<ContractState> {
////////////////////////////////
// ERC20 implementation
////////////////////////////////

#[starknet::interface]
trait IERC4626Snake<TState> {
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}
fn name(self: @ContractState) -> felt252 {
0
}

#[starknet::interface]
trait IERC4626Additional<TState> {
fn asset(self: @TState) -> ContractAddress;
fn convert_to_assets(self: @TState, shares: u256) -> u256;
fn convert_to_shares(self: @TState, assets: u256) -> u256;
fn deposit(ref self: TState, assets: u256, receiver: ContractAddress) -> u256;
fn max_deposit(self: @TState, address: ContractAddress) -> u256;
fn max_mint(self: @TState, receiver: ContractAddress) -> u256;
fn max_redeem(self: @TState, owner: ContractAddress) -> u256;
fn max_withdraw(self: @TState, owner: ContractAddress) -> u256;
fn mint(ref self: TState, shares: u256, receiver: ContractAddress) -> u256;
fn preview_deposit(self: @TState, assets: u256) -> u256;
fn preview_mint(self: @TState, shares: u256) -> u256;
fn preview_redeem(self: @TState, shares: u256) -> u256;
fn preview_withdraw(self: @TState, assets: u256) -> u256;
fn redeem(
ref self: TState, shares: u256, receiver: ContractAddress, owner: ContractAddress
) -> u256;
fn total_assets(self: @TState) -> u256;
fn withdraw(
ref self: TState, assets: u256, receiver: ContractAddress, owner: ContractAddress
) -> u256;
fn symbol(self: @ContractState) -> felt252 {
0
}

fn decimals(self: @ContractState) -> u8 {
0
}

fn total_supply(self: @ContractState) -> u256 {
0
}

fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {
0
}

fn allowance(
self: @ContractState, owner: ContractAddress, spender: ContractAddress
) -> u256 {
0
}

fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {
true
}

fn transfer_from(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) -> bool {
true
}

fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {
true
}

////////////////////////////////
// ERC4626-specific implementation
////////////////////////////////

fn asset(self: @ContractState) -> ContractAddress {
0.try_into().unwrap()
}

fn total_assets(self: @ContractState) -> u256 {
0
}

fn convert_to_shares(self: @ContractState, assets: u256) -> u256 {
0
}

fn convert_to_assets(self: @ContractState, shares: u256) -> u256 {
0
}

fn max_deposit(self: @ContractState, receiver: ContractAddress) -> u256 {
0
}

fn preview_deposit(self: @ContractState, assets: u256) -> u256 {
0
}

fn deposit(ref self: ContractState, assets: u256, receiver: ContractAddress) -> u256 {
0
}

fn max_mint(self: @ContractState, receiver: ContractAddress) -> u256 {
BoundedInt::<u256>::max()
}

fn preview_mint(self: @ContractState, shares: u256) -> u256 {
// TESTING
1002465544733197129
}

fn mint(ref self: ContractState, shares: u256, receiver: ContractAddress) -> u256 {
0
}

fn max_withdraw(self: @ContractState, owner: ContractAddress) -> u256 {
0
}

fn preview_withdraw(self: @ContractState, assets: u256) -> u256 {
0
}

fn withdraw(
ref self: ContractState, assets: u256, receiver: ContractAddress, owner: ContractAddress
) -> u256 {
0
}

fn max_redeem(self: @ContractState, owner: ContractAddress) -> u256 {
0
}

fn preview_redeem(self: @ContractState, shares: u256) -> u256 {
0
}

fn redeem(
ref self: ContractState, shares: u256, receiver: ContractAddress, owner: ContractAddress
) -> u256 {
0
}
}
}
17 changes: 14 additions & 3 deletions pragma-oracle/src/oracle/oracle.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ trait IOracleABI<TContractState> {
fn add_currency(ref self: TContractState, new_currency: Currency);
fn update_currency(ref self: TContractState, currency_id: felt252, currency: Currency);
fn get_currency(self: @TContractState, currency_id: felt252) -> Currency;
fn get_tokenized_vaults(self: @TContractState, token: felt252) -> ContractAddress;
fn update_pair(ref self: TContractState, pair_id: felt252, pair: Pair);
fn add_pair(ref self: TContractState, new_pair: Pair);
fn get_pair(self: @TContractState, pair_id: felt252) -> Pair;
Expand Down Expand Up @@ -547,16 +548,19 @@ mod Oracle {
assert(base_asset != 0, 'Asset not registered');
let pool_address: ContractAddress = self.tokenized_vault.read((base_asset, 'STRK'));
assert(
pool_address != contract_address_const::<0>(), 'No pool address for given token'
pool_address != starknet::contract_address_const::<0>(),
'No pool address for given token'
);
let pool = IERC4626Dispatcher { contract_address: pool_address };

// Compute adjusted price
// `preview_mint` takes as argument an e18 and returns an e18
// We operate under u256 to avoid overflow
let price: u256 = response.price.into()
* pool.preview_mint(1000000000000000000)
/ 1000000000000000000;

// The conversion should not fail because we scaled the price to 8 decimals
// The conversion should not fail because we scaled the price to response.decimals
let converted_price: u128 = price.try_into().expect('Conversion should not fail');
assert(converted_price != 0, 'Price conversion failed');
PragmaPricesResponse {
Expand Down Expand Up @@ -971,6 +975,10 @@ mod Oracle {
Ownable::OwnableImpl::owner(@state)
}

fn get_tokenized_vaults(self: @ContractState, token: felt252) -> ContractAddress {
self.tokenized_vault.read((token, 'STRK'))
}


// @notice retrieve the last checkpoint before a given timestamp
// @param data_type: an enum of DataType (e.g : DataType::SpotEntry(ASSET_ID) or DataType::FutureEntry((ASSSET_ID, expiration_timestamp)))
Expand Down Expand Up @@ -1826,7 +1834,10 @@ mod Oracle {
) {
OracleInternal::assert_only_admin();
assert(token != 0, 'Token cannot be 0');
assert(token_address != contract_address_const::<0>(), 'Token address cannot be 0');
assert(
token_address != starknet::contract_address_const::<0>(),
'Token address cannot be 0'
);
self.tokenized_vault.write((token, 'STRK'), token_address)
}

Expand Down
Loading

0 comments on commit 11aa256

Please sign in to comment.