-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: oracle adpater for pricing
kSTRK
token (#88)
- Loading branch information
1 parent
787f344
commit c123549
Showing
8 changed files
with
211 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,5 @@ mod dual_oracle_adapter; | |
mod pragma_oracle_adapter; | ||
|
||
mod chainlink_oracle_adapter; | ||
|
||
mod kstrk_oracle_adapter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
mod errors { | ||
const PRICE_OVERFLOW: felt252 = 'KSTRK_PRICE_OVERFLOW'; | ||
} | ||
|
||
/// An oracle implementation that prices the `kSTRK` token by multiplying the `STRK` price from | ||
/// another "upstream" adapter by the `kSTRK/STRK` exchange rate. | ||
#[starknet::contract] | ||
mod KstrkOracleAdapter { | ||
use starknet::{ContractAddress, get_block_timestamp}; | ||
|
||
// Hack to simulate the `crate` keyword | ||
use super::super::super as crate; | ||
|
||
use crate::interfaces::{ | ||
IERC20Dispatcher, IERC20DispatcherTrait, IKstrkPoolDispatcher, IKstrkPoolDispatcherTrait, | ||
IPriceOracleSource, IPriceOracleSourceDispatcher, IPriceOracleSourceDispatcherTrait, | ||
PriceWithUpdateTime | ||
}; | ||
use crate::libraries::safe_decimal_math; | ||
|
||
use super::errors; | ||
|
||
#[storage] | ||
struct Storage { | ||
strk_upstream: ContractAddress, | ||
kstrk_pool: ContractAddress, | ||
} | ||
|
||
#[constructor] | ||
fn constructor( | ||
ref self: ContractState, strk_upstream: ContractAddress, kstrk_pool: ContractAddress | ||
) { | ||
self.strk_upstream.write(strk_upstream); | ||
self.kstrk_pool.write(kstrk_pool); | ||
} | ||
|
||
#[abi(embed_v0)] | ||
impl IPriceOracleSourceImpl of IPriceOracleSource<ContractState> { | ||
fn get_price(self: @ContractState) -> felt252 { | ||
get_data(self).price | ||
} | ||
|
||
fn get_price_with_time(self: @ContractState) -> PriceWithUpdateTime { | ||
get_data(self) | ||
} | ||
} | ||
|
||
fn get_data(self: @ContractState) -> PriceWithUpdateTime { | ||
// There is no need to scale the prices as all `IPriceOracleSource` implementations are | ||
// guaranteed to return at target decimals. | ||
let strk_price = IPriceOracleSourceDispatcher { | ||
contract_address: self.strk_upstream.read() | ||
} | ||
.get_price_with_time(); | ||
|
||
let strk_price_u256: u256 = strk_price.price.into(); | ||
|
||
let kstrk_pool = IKstrkPoolDispatcher { contract_address: self.kstrk_pool.read() }; | ||
let kstrk_token = IERC20Dispatcher { contract_address: kstrk_pool.get_staked_token() }; | ||
|
||
let pool_size: u256 = kstrk_pool.get_total_stake().into(); | ||
let total_supply = kstrk_token.totalSupply(); | ||
|
||
let kstrk_price: felt252 = (strk_price_u256 * pool_size / total_supply) | ||
.try_into() | ||
.expect(errors::PRICE_OVERFLOW); | ||
|
||
PriceWithUpdateTime { price: kstrk_price, update_time: get_block_timestamp().into() } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use starknet::contract_address_const; | ||
|
||
use test::test_utils::assert_eq; | ||
|
||
use zklend::interfaces::IPriceOracleSourceDispatcherTrait; | ||
|
||
use tests::deploy; | ||
use tests::mock::{IMockKstrkPoolDispatcherTrait, IMockPragmaOracleDispatcherTrait}; | ||
|
||
#[test] | ||
#[available_gas(30000000)] | ||
fn test_price() { | ||
let mock_pragma_oracle = deploy::deploy_mock_pragma_oracle(); | ||
|
||
// STRK price: 0.5 | ||
mock_pragma_oracle.set_price('STRK/USD', 0_50000000, 8, 100, 5); | ||
|
||
// kSTRK total supply: 100 | ||
let mock_kstrk_token = deploy::deploy_erc20( | ||
'kSTRK', 'kSTRK', 18, 100_000000000000000000, contract_address_const::<1>() | ||
); | ||
|
||
let mock_kstrk_pool = deploy::deploy_mock_kstrk_pool(); | ||
mock_kstrk_pool.set_staked_token(mock_kstrk_token.contract_address); | ||
|
||
let pragma_oracle_adpater = deploy::deploy_pragma_oracle_adapter( | ||
mock_pragma_oracle.contract_address, 'STRK/USD', 500 | ||
); | ||
let kstrk_oracle_adapter = deploy::deploy_kstrk_oracle_adapter( | ||
pragma_oracle_adpater.contract_address, mock_kstrk_pool.contract_address | ||
); | ||
|
||
// Pool size: 100 STRK | ||
// Exchange rate: 1 kSTRK = 1 STRK | ||
// Price: 0.5 | ||
mock_kstrk_pool.set_total_stake(100_000000000000000000); | ||
assert(kstrk_oracle_adapter.get_price() == 0_50000000, 'FAILED'); | ||
|
||
// Pool size: 120 STRK | ||
// Exchange rate: 1 kSTRK = 1.2 STRK | ||
// Price: 0.6 | ||
mock_kstrk_pool.set_total_stake(120_000000000000000000); | ||
assert(kstrk_oracle_adapter.get_price() == 0_60000000, 'FAILED'); | ||
|
||
// NOTE: this scenario should be impossible but is tested anyway | ||
// | ||
// Pool size: 80 STRK | ||
// Exchange rate: 1 kSTRK = 0.8 STRK | ||
// Price: 0.4 | ||
mock_kstrk_pool.set_total_stake(80_000000000000000000); | ||
assert(kstrk_oracle_adapter.get_price() == 0_40000000, 'FAILED'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use super::IMockKstrkPool; | ||
|
||
#[starknet::contract] | ||
mod MockKstrkPool { | ||
use starknet::ContractAddress; | ||
|
||
use super::IMockKstrkPool; | ||
|
||
#[storage] | ||
struct Storage { | ||
staked_token: ContractAddress, | ||
total_stake: u128, | ||
} | ||
|
||
#[abi(embed_v0)] | ||
impl IMockKstrkPoolImpl of IMockKstrkPool<ContractState> { | ||
fn get_staked_token(self: @ContractState) -> ContractAddress { | ||
self.staked_token.read() | ||
} | ||
|
||
fn get_total_stake(self: @ContractState) -> u128 { | ||
self.total_stake.read() | ||
} | ||
|
||
fn set_staked_token(ref self: ContractState, staked_token: ContractAddress) { | ||
self.staked_token.write(staked_token) | ||
} | ||
|
||
fn set_total_stake(ref self: ContractState, total_stake: u128) { | ||
self.total_stake.write(total_stake) | ||
} | ||
} | ||
} |