-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Init: staking component * WIP: added more function signatures in the IStaking interface * created event enum and enum variant structs * implemented initializer() to be used in constructors * implemented read functions * WIP: created helper functions in the InternalImpl * FEAT: staking component implemented * MOD: added custom Errors * LINTING: scarb fmt * MOD: emitted event for stake(), withdraw() and get_reward() functions * MOD: modified notify_reward_amount() and added transfer_from() * FIXESL fixed get_reward() impl to update rewards before calculating user rewards * MOD: changed get_reward() to claim_reward() for clarity. * FEAT: implemented staking_reward contract to use StakingComponent * TEST: completed test setup for staking contract and component * TEST: implemented test_notify_reward_amount() and test_stake() * TEST: implemented test_stake(), test_rewards_earned(), test_claim_reward() and test_withdraw() * MOD: created interfaces.cairo and modified imports. * MOD: uncommented some test mods * MOD: added requested review changes * pulled from main * merge main
- Loading branch information
Showing
11 changed files
with
945 additions
and
16 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,14 @@ | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_test_calculation | ||
afk::tests::launchpad_tests::launchpad_tests::test_get_coin_amount_by_quote_amount_for_buy_steps | ||
afk::tests::launchpad_tests::launchpad_tests::test_get_coin_launch | ||
afk::tests::launchpad_tests::launchpad_tests::test_get_share_key_of_user | ||
afk::tests::launchpad_tests::launchpad_tests::test_launch_token | ||
afk::tests::launchpad_tests::launchpad_tests::test_launch_token_with_uncreated_token | ||
afk::tests::launchpad_tests::launchpad_tests::test_sell_coin_when_quote_amount_is_greater_than_liquidity_raised | ||
afk::tests::launchpad_tests::launchpad_tests::test_sell_coin_when_share_too_low | ||
afk::tests::launchpad_tests::launchpad_tests::test_set_protocol_fee_percent_non_admin | ||
afk::tests::launchpad_tests::launchpad_tests::test_buy_coin_with_different_supply | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_integration | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_buy_all | ||
afk::tests::launchpad_tests::launchpad_tests::test_launchpad_end_to_end | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_end_to_end | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_test_calculation | ||
afk::tests::launchpad_tests::launchpad_tests::test_get_coin_amount_by_quote_amount_for_buy_steps | ||
afk::tests::launchpad_tests::launchpad_tests::test_get_coin_launch | ||
afk::tests::launchpad_tests::launchpad_tests::test_get_share_key_of_user | ||
afk::tests::launchpad_tests::launchpad_tests::test_launch_token | ||
afk::tests::launchpad_tests::launchpad_tests::test_launch_token_with_uncreated_token | ||
afk::tests::launchpad_tests::launchpad_tests::test_sell_coin_when_quote_amount_is_greater_than_liquidity_raised | ||
afk::tests::launchpad_tests::launchpad_tests::test_sell_coin_when_share_too_low | ||
afk::tests::launchpad_tests::launchpad_tests::test_set_protocol_fee_percent_non_admin | ||
afk::tests::launchpad_tests::launchpad_tests::test_buy_coin_with_different_supply | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_integration | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_buy_all | ||
afk::tests::launchpad_tests::launchpad_tests::test_launchpad_end_to_end | ||
afk::tests::launchpad_tests::launchpad_tests::launchpad_end_to_end |
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 @@ | ||
scarb 2.8.5 |
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,3 @@ | ||
pub mod staking; | ||
pub mod mocks; | ||
pub mod interfaces; |
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,46 @@ | ||
use starknet::ContractAddress; | ||
|
||
#[starknet::interface] | ||
pub trait IERC20<TContractState> { | ||
fn name(self: @TContractState) -> ByteArray; | ||
fn symbol(self: @TContractState) -> ByteArray; | ||
fn decimals(self: @TContractState) -> u8; | ||
|
||
fn total_supply(self: @TContractState) -> u256; | ||
fn balance_of(self: @TContractState, account: ContractAddress) -> u256; | ||
fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; | ||
|
||
fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool; | ||
fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool; | ||
fn transfer_from(ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; | ||
|
||
fn mint(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool; | ||
} | ||
|
||
#[starknet::interface] | ||
pub trait IStaking<TContractState> { | ||
fn set_rewards_duration(ref self: TContractState, duration: u256); | ||
fn notify_reward_amount(ref self: TContractState, amount: u256); | ||
fn stake(ref self: TContractState, amount: u256); | ||
fn withdraw(ref self: TContractState, amount: u256); | ||
fn claim_reward(ref self: TContractState); | ||
|
||
fn last_time_reward_applicable(self: @TContractState) -> u256; | ||
fn reward_per_token(self: @TContractState) -> u256; | ||
fn rewards_earned(self: @TContractState, account: ContractAddress) -> u256; | ||
|
||
fn staking_token(self: @TContractState) -> ContractAddress; | ||
fn rewards_token(self: @TContractState) -> ContractAddress; | ||
fn duration(self: @TContractState) -> u256; | ||
fn finish_at(self: @TContractState) -> u256; | ||
fn updated_at(self: @TContractState) -> u256; | ||
fn reward_rate(self: @TContractState) -> u256; | ||
fn reward_per_token_stored(self: @TContractState) -> u256; | ||
fn user_reward_per_token_paid(self: @TContractState, user: ContractAddress) -> u256; | ||
fn rewards(self: @TContractState, user: ContractAddress) -> u256; | ||
fn total_supply(self: @TContractState) -> u256; | ||
fn balance_of(self: @TContractState, user: ContractAddress) -> u256; | ||
fn owner(self: @TContractState) -> ContractAddress; | ||
|
||
fn return_block_timestamp(self: @TContractState) -> u256; | ||
} |
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,2 @@ | ||
pub mod staking_rewards; | ||
pub mod mock_erc20; |
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,144 @@ | ||
#[starknet::contract] | ||
pub mod MockToken { | ||
use starknet::event::EventEmitter; | ||
use starknet::{ContractAddress, get_caller_address}; | ||
use core::starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess, Map, StoragePathEntry}; | ||
use crate::staking::interfaces::IERC20; | ||
use core::num::traits::Zero; | ||
|
||
#[storage] | ||
pub struct Storage { | ||
balances: Map<ContractAddress, u256>, | ||
allowances: Map<(ContractAddress, ContractAddress), u256>, // Mapping<(owner, spender), amount> | ||
token_name: ByteArray, | ||
symbol: ByteArray, | ||
decimal: u8, | ||
total_supply: u256, | ||
owner: ContractAddress, | ||
} | ||
|
||
#[event] | ||
#[derive(Drop, starknet::Event)] | ||
pub enum Event { | ||
Transfer: Transfer, | ||
Approval: Approval, | ||
} | ||
|
||
#[derive(Drop, starknet::Event)] | ||
pub struct Transfer { | ||
#[key] | ||
from: ContractAddress, | ||
#[key] | ||
to: ContractAddress, | ||
amount: u256, | ||
} | ||
|
||
#[derive(Drop, starknet::Event)] | ||
pub struct Approval { | ||
#[key] | ||
owner: ContractAddress, | ||
#[key] | ||
spender: ContractAddress, | ||
value: u256 | ||
} | ||
|
||
#[constructor] | ||
fn constructor(ref self: ContractState) { | ||
self.token_name.write("Staking Token"); | ||
self.symbol.write("SKT"); | ||
self.decimal.write(18); | ||
self.owner.write(get_caller_address()); | ||
} | ||
|
||
#[abi(embed_v0)] | ||
impl MockTokenImpl of IERC20<ContractState> { | ||
fn total_supply(self: @ContractState) -> u256 { | ||
self.total_supply.read() | ||
} | ||
|
||
fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { | ||
let balance = self.balances.entry(account).read(); | ||
|
||
balance | ||
} | ||
|
||
fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { | ||
let allowance = self.allowances.entry((owner, spender)).read(); | ||
|
||
allowance | ||
} | ||
|
||
fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { | ||
let sender = get_caller_address(); | ||
|
||
let sender_prev_balance = self.balances.entry(sender).read(); | ||
let recipient_prev_balance = self.balances.entry(recipient).read(); | ||
|
||
assert(sender_prev_balance >= amount, 'Insufficient amount'); | ||
|
||
self.balances.entry(sender).write(sender_prev_balance - amount); | ||
self.balances.entry(recipient).write(recipient_prev_balance + amount); | ||
|
||
assert(self.balances.entry(recipient).read() > recipient_prev_balance, 'Transaction failed'); | ||
|
||
self.emit(Transfer { from: sender, to: recipient, amount }); | ||
|
||
true | ||
} | ||
|
||
fn transfer_from(ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool { | ||
let spender = get_caller_address(); | ||
|
||
let spender_allowance = self.allowances.entry((sender, spender)).read(); | ||
let sender_balance = self.balances.entry(sender).read(); | ||
let recipient_balance = self.balances.entry(recipient).read(); | ||
|
||
assert(amount <= spender_allowance, 'amount exceeds allowance'); | ||
assert(amount <= sender_balance, 'amount exceeds balance'); | ||
|
||
self.allowances.entry((sender, spender)).write(spender_allowance - amount); | ||
self.balances.entry(sender).write(sender_balance - amount); | ||
self.balances.entry(recipient).write(recipient_balance + amount); | ||
|
||
self.emit(Transfer { from: sender, to: recipient, amount }); | ||
|
||
true | ||
} | ||
|
||
fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool { | ||
let caller = get_caller_address(); | ||
|
||
self.allowances.entry((caller, spender)).write(amount); | ||
|
||
self.emit(Approval { owner: caller, spender, value: amount }); | ||
|
||
true | ||
} | ||
|
||
fn name(self: @ContractState) -> ByteArray { | ||
self.token_name.read() | ||
} | ||
|
||
fn symbol(self: @ContractState) -> ByteArray { | ||
self.symbol.read() | ||
} | ||
|
||
fn decimals(self: @ContractState) -> u8 { | ||
self.decimal.read() | ||
} | ||
|
||
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { | ||
let previous_total_supply = self.total_supply.read(); | ||
let previous_balance = self.balances.entry(recipient).read(); | ||
|
||
self.total_supply.write(previous_total_supply + amount); | ||
self.balances.entry(recipient).write(previous_balance + amount); | ||
|
||
let zero_address = Zero::zero(); | ||
|
||
self.emit(Transfer { from: zero_address, to: recipient, amount }); | ||
|
||
true | ||
} | ||
} | ||
} |
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,34 @@ | ||
#[starknet::contract] | ||
mod StakingRewards { | ||
use crate::staking::staking::StakingComponent; | ||
use starknet::ContractAddress; | ||
|
||
component!(path: StakingComponent, storage: staking, event: StakingEvent); | ||
|
||
#[storage] | ||
struct Storage { | ||
#[substorage(v0)] | ||
staking: StakingComponent::Storage, | ||
} | ||
|
||
#[event] | ||
#[derive(Drop, starknet::Event)] | ||
enum Event { | ||
#[flat] | ||
StakingEvent: StakingComponent::Event, | ||
} | ||
|
||
#[constructor] | ||
fn constructor( | ||
ref self: ContractState, | ||
owner: ContractAddress, | ||
staking_token: ContractAddress, | ||
reward_token: ContractAddress | ||
) { | ||
self.staking._initializer(owner, staking_token, reward_token); | ||
} | ||
|
||
#[abi(embed_v0)] | ||
impl StakingImpl = StakingComponent::StakingImpl<ContractState>; | ||
impl StakingInternalImpl = StakingComponent::InternalImpl<ContractState>; | ||
} |
Oops, something went wrong.