Skip to content

Commit

Permalink
Merge pull request #112 from scobi7/master
Browse files Browse the repository at this point in the history
Add streaming vesting (#112)
  • Loading branch information
scobi7 authored Jul 22, 2024
2 parents 93b975f + 0413624 commit 11fe55a
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 40 deletions.
9 changes: 9 additions & 0 deletions src/contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mod Governance {
use konoha::proposals::proposals as proposals_component;
use konoha::staking::staking as staking_component;
use konoha::staking::{IStakingDispatcher, IStakingDispatcherTrait};
use konoha::streaming::streaming as streaming_component;
use konoha::types::BlockNumber;
use konoha::types::ContractType;
use konoha::types::PropDetails;
Expand All @@ -53,6 +54,8 @@ mod Governance {
component!(path: upgrades_component, storage: upgrades, event: UpgradesEvent);
component!(path: discussion_component, storage: discussions, event: DiscussionEvent);
component!(path: staking_component, storage: staking, event: StakingEvent);
component!(path: streaming_component, storage: streaming, event: StreamingEvent);


#[abi(embed_v0)]
impl Airdrop = airdrop_component::AirdropImpl<ContractState>;
Expand All @@ -71,6 +74,9 @@ mod Governance {
#[abi(embed_v0)]
impl Staking = staking_component::StakingImpl<ContractState>;

#[abi(embed_v0)]
impl Streaming = streaming_component::StreamingImpl<ContractState>;

#[storage]
struct Storage {
proposal_initializer_run: LegacyMap::<u64, bool>,
Expand All @@ -87,6 +93,8 @@ mod Governance {
discussions: discussion_component::Storage,
#[substorage(v0)]
staking: staking_component::Storage,
#[substorage(v0)]
streaming: streaming_component::Storage,
}

// PROPOSALS
Expand Down Expand Up @@ -116,6 +124,7 @@ mod Governance {
UpgradesEvent: upgrades_component::Event,
DiscussionEvent: discussion_component::Event,
StakingEvent: staking_component::Event,
StreamingEvent: streaming_component::Event,
}

#[constructor]
Expand Down
1 change: 1 addition & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod discussion;
mod merkle_tree;
mod proposals;
mod staking;
mod streaming;
mod token;
mod traits;
mod treasury;
Expand Down
167 changes: 167 additions & 0 deletions src/streaming.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use starknet::ContractAddress;

#[starknet::interface]
trait IStreaming<TContractState> {
fn add_new_stream(
ref self: TContractState,
recipient: ContractAddress,
start_time: u64,
end_time: u64,
total_amount: u128,
);

fn claim_stream(
ref self: TContractState, recipient: ContractAddress, start_time: u64, end_time: u64,
);

fn cancel_stream(
ref self: TContractState, recipient: ContractAddress, start_time: u64, end_time: u64,
);

fn get_stream_info(
ref self: TContractState, recipient: ContractAddress, start_time: u64, end_time: u64,
) -> (u128, u128);
}

#[starknet::component]
mod streaming {
use konoha::contract::Governance;
use konoha::contract::{IGovernanceDispatcher, IGovernanceDispatcherTrait};
use konoha::traits::{IGovernanceTokenDispatcher, IGovernanceTokenDispatcherTrait};
use starknet::ContractAddress;
use starknet::{get_block_timestamp, get_caller_address, get_contract_address};

#[storage]
struct Storage {
streams: LegacyMap::<
(ContractAddress, u64, u64), (u128, u128)
> // (already_claimed, total_amount)
}

#[derive(starknet::Event, Drop, Serde)]
#[event]
enum Event {
StreamCreated: StreamCreated,
StreamClaimed: StreamClaimed,
StreamCanceled: StreamCanceled
}

#[derive(starknet::Event, Drop, Serde)]
struct StreamCreated {
recipient: ContractAddress,
start_time: u64,
end_time: u64,
total_amount: u128,
}

#[derive(starknet::Event, Drop, Serde)]
struct StreamClaimed {
recipient: ContractAddress,
start_time: u64,
end_time: u64,
total_amount: u128,
}

#[derive(starknet::Event, Drop, Serde)]
struct StreamCanceled {
recipient: ContractAddress,
start_time: u64,
end_time: u64,
reclaimed_amount: u256,
}

#[embeddable_as(StreamingImpl)]
impl Streaming<
TContractState, +HasComponent<TContractState>
> of super::IStreaming<ComponentState<TContractState>> {
fn add_new_stream(
ref self: ComponentState<TContractState>,
recipient: ContractAddress,
start_time: u64,
end_time: u64,
total_amount: u128,
) {
let key = (recipient, start_time, end_time);

assert(get_caller_address() == get_contract_address(), 'not self-call');
assert(start_time < end_time, 'starts first');

let mut claimable_amount = 0;
self.streams.write(key, (claimable_amount, total_amount));

self.emit(StreamCreated { recipient, start_time, end_time, total_amount, });
}

fn claim_stream(
ref self: ComponentState<TContractState>,
recipient: ContractAddress,
start_time: u64,
end_time: u64,
) {
let current_time = get_block_timestamp();

let key = (recipient, start_time, end_time);
let (already_claimed, total_amount): (u128, u128) = self.streams.read(key);
assert(current_time > start_time, 'stream has not started');

let elapsed_time = if current_time > end_time {
end_time - start_time
} else {
current_time - start_time
};
let stream_duration = end_time - start_time;

let currently_claimable = (total_amount * elapsed_time.into() / stream_duration.into());
let amount_to_claim = currently_claimable - already_claimed;

assert(amount_to_claim > 0, 'nothing to claim');

// Update the storage with the new claimed amount
self.streams.write(key, (currently_claimable, total_amount));

let self_dsp = IGovernanceDispatcher { contract_address: get_contract_address() };
IGovernanceTokenDispatcher { contract_address: self_dsp.get_governance_token_address() }
.mint(recipient, amount_to_claim.into());

self.emit(StreamClaimed { recipient, start_time, end_time, total_amount, });
}

fn cancel_stream(
ref self: ComponentState<TContractState>,
recipient: ContractAddress,
start_time: u64,
end_time: u64,
) {
let key: (ContractAddress, u64, u64) = (recipient, start_time, end_time);

// Read from the streams LegacyMap
let (already_claimed, total_amount): (u128, u128) = self.streams.read(key);
let to_distribute: u256 = total_amount.into() - already_claimed.into();

// Cancel stream
self.streams.write(key, (0, 0));

let self_dsp = IGovernanceDispatcher { contract_address: get_contract_address() };
IGovernanceTokenDispatcher { contract_address: self_dsp.get_governance_token_address() }
.mint(get_caller_address(), to_distribute.into());

self
.emit(
StreamCanceled {
recipient, start_time, end_time, reclaimed_amount: to_distribute,
}
);
}

fn get_stream_info(
ref self: ComponentState<TContractState>,
recipient: ContractAddress,
start_time: u64,
end_time: u64,
) -> (u128, u128) {
let key: (ContractAddress, u64, u64) = (recipient, start_time, end_time);
let (currently_claimable, total_amount): (u128, u128) = self.streams.read(key);
(currently_claimable, total_amount)
}
}
}
2 changes: 2 additions & 0 deletions tests/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ mod proposals_tests;
mod setup;
mod staking_tests;
mod test_storage_pack;
mod test_streaming;
mod test_treasury;
mod upgrades_tests;
mod vesting;
Loading

0 comments on commit 11fe55a

Please sign in to comment.