diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..35a90142 Binary files /dev/null and b/.DS_Store differ diff --git a/ink-awesome-defi/.DS_Store b/ink-awesome-defi/.DS_Store new file mode 100644 index 00000000..c9dfd3cb Binary files /dev/null and b/ink-awesome-defi/.DS_Store differ diff --git a/ink-awesome-defi/README.md b/ink-awesome-defi/README.md new file mode 100644 index 00000000..3e833b1a --- /dev/null +++ b/ink-awesome-defi/README.md @@ -0,0 +1,15 @@ +# Ink! Awesome DeFi + + +This is a Repo of Notable Smart contracts re-writen in Ink! domain (pallet-smart-contract) specific lanaguage. it outlines how production worthy smart contract should be built and structured. Smart contracts within this repo utilizes the awesome [Openbrush](https://openbrush.brushfam.io/) library of smart contract and utilities. This repo contains; + +1. Uniswap V2 Ink! Implementation. +2. Synthetix staking reward contract +3. Uniswap V3 still in the works (it complicated math libs got me lazy. Ticks 😒) + + +My hopes for this Repo is for it to be a good resource for engineers/teams looking to build production worth smart contracts and wish other awesome developers would build into this repo other more complicated smart contracts making this Repo more useful to a wider range of teams in the polkaDeFI space. + + +## Want to contribute? +My buddy [Ayo](https://github.com/Adebara123), built a [template](https://github.com/Adebara123/Ink-Contract-Template) which I used to build these smart contracts and I would be employing you contributor to use that also. diff --git a/ink-awesome-defi/synthetix-staking-reward/.DS_Store b/ink-awesome-defi/synthetix-staking-reward/.DS_Store new file mode 100644 index 00000000..330dd194 Binary files /dev/null and b/ink-awesome-defi/synthetix-staking-reward/.DS_Store differ diff --git a/ink-awesome-defi/synthetix-staking-reward/.gitignore b/ink-awesome-defi/synthetix-staking-reward/.gitignore new file mode 100644 index 00000000..c41cc9e3 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/Cargo.toml b/ink-awesome-defi/synthetix-staking-reward/Cargo.toml new file mode 100644 index 00000000..9b92544b --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "contracts" +version = "0.1.0" +authors = ["developreuche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.1", default-features = false } + +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false, features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"] } +psp22_lp = { path = "contracts/modules/psp22_lp", default-features = false } +staking_reward = { path = "contracts/modules/staking_reward", default-features = false } +global = {path = "contracts", default-features = false} +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "contracts.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts.rs b/ink-awesome-defi/synthetix-staking-reward/contracts.rs new file mode 100644 index 00000000..58233ec9 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts.rs @@ -0,0 +1,3 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use global; \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/.DS_Store b/ink-awesome-defi/synthetix-staking-reward/contracts/.DS_Store new file mode 100644 index 00000000..78e19c68 Binary files /dev/null and b/ink-awesome-defi/synthetix-staking-reward/contracts/.DS_Store differ diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/Cargo.toml b/ink-awesome-defi/synthetix-staking-reward/contracts/Cargo.toml new file mode 100644 index 00000000..46c815ce --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "global" +version = "0.1.0" +authors = ["developeruche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } + +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false, features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"]} + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } +sp-arithmetic = { version = "15", default-features = false } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "global.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", + "sp-arithmetic/std", +] +ink-as-dependency = [] +e2e-tests = [] + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/controllers/mod.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/controllers/mod.rs new file mode 100644 index 00000000..3b1d20f9 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/controllers/mod.rs @@ -0,0 +1 @@ +pub mod staking_reward; \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/controllers/staking_reward.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/controllers/staking_reward.rs new file mode 100644 index 00000000..6206f39b --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/controllers/staking_reward.rs @@ -0,0 +1,80 @@ + +use openbrush::traits::AccountId; +use openbrush::traits::Balance; +use crate::providers::common::errors::StakingRewardsErrors; + + + +#[openbrush::wrapper] +pub type StakingRewardRef = dyn StakingRewardController; + +#[openbrush::trait_definition] +pub trait StakingRewardController { + #[ink(message)] + fn get_reward_token(&self) -> AccountId; + + #[ink(message)] + fn get_staked_token(&self) -> AccountId; + + #[ink(message)] + fn get_reward_rate(&self) -> Balance; + + #[ink(message)] + fn get_period_finish(&self) -> Balance; + + #[ink(message)] + fn get_reward_duration(&self) -> Balance; + + #[ink(message)] + fn get_last_update_time(&self) -> Balance; + + #[ink(message)] + fn get_reward_per_token_stored(&self) -> Balance; + + #[ink(message)] + fn get_user_reward_per_token_paid(&self, _account: AccountId) -> Balance; + + #[ink(message)] + fn get_rewards(&self, _account: AccountId) -> Balance; + + #[ink(message)] + fn total_supply(&self) -> Balance; + + #[ink(message)] + fn balance_of(&self, _account: AccountId) -> Balance; + + #[ink(message)] + fn last_time_reward_applicable(&self) -> Balance; + + #[ink(message)] + fn reward_per_token(&self) -> Balance; + + #[ink(message)] + fn earned(&self, _account: AccountId) -> Balance; + + #[ink(message)] + fn get_reward_for_duration(&self) -> Balance; + + + + #[ink(message)] + fn stake(&mut self, _amount: Balance) -> Result<(), StakingRewardsErrors>; + + #[ink(message)] + fn withdraw(&mut self, _amount: Balance) -> Result<(), StakingRewardsErrors>; + + #[ink(message)] + fn get_reward(&mut self) -> Result<(), StakingRewardsErrors>; + + #[ink(message)] + fn exit(&mut self) -> Result<(), StakingRewardsErrors>; + + #[ink(message)] + fn notify_reward_amount(&mut self, _reward: Balance) -> Result<(), StakingRewardsErrors>; + + #[ink(message)] + fn recover_erc20(&mut self, _token: AccountId, _amount: Balance) -> Result<(), StakingRewardsErrors>; + + #[ink(message)] + fn set_reward_duration(&mut self, _duration: Balance) -> Result<(), StakingRewardsErrors>; +} \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/global.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/global.rs new file mode 100644 index 00000000..26a14f59 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/global.rs @@ -0,0 +1,4 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub mod controllers; +pub mod providers; \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/.DS_Store b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/.DS_Store new file mode 100644 index 00000000..4378fcb3 Binary files /dev/null and b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/.DS_Store differ diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/.DS_Store b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/.DS_Store new file mode 100644 index 00000000..ee9c024f Binary files /dev/null and b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/.DS_Store differ diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/.gitignore b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/.gitignore new file mode 100755 index 00000000..8de8f877 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/Cargo.toml b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/Cargo.toml new file mode 100755 index 00000000..672d68fb --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "psp22_lp" +version = "0.1.0" +authors = ["developeruche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false, features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"] } +global = {path = "./../../", default-features = false} + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "psp22_lp.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/psp22_lp.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/psp22_lp.rs new file mode 100755 index 00000000..d44e567c --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/psp22_lp/psp22_lp.rs @@ -0,0 +1,64 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + + + + + +#[openbrush::implementation(PSP22, PSP22Permit, Nonces, PSP22Mintable, Ownable, PSP22Metadata)] +#[openbrush::contract] +pub mod psp22_permit { + use openbrush::{traits::Storage, modifiers}; + + + #[ink(storage)] + #[derive(Default, Storage)] + pub struct PSP22Lp { + #[storage_field] + psp22: psp22::Data, + #[storage_field] + metadata: metadata::Data, + #[storage_field] + ownable: ownable::Data, + #[storage_field] + nonces: nonces::Data, + #[storage_field] + psp22_permit: psp22::extensions::permit::Data, + + } + + + #[default_impl(PSP22Mintable)] + #[modifiers(only_owner)] + fn mint(&mut self) {} + + + + + + + impl PSP22Lp { + #[ink(constructor)] + pub fn new(total_supply: Balance, name: Option, symbol: Option, decimal: u8) -> Self { + let mut instance = Self::default(); + let caller = instance.env().caller(); + + instance.metadata.name.set(&name); + instance.metadata.symbol.set(&symbol); + instance.metadata.decimals.set(&decimal); + + ownable::Internal::_init_with_owner(&mut instance, Self::env().caller()); + psp22::Internal::_mint_to(&mut instance, caller, total_supply).expect("Should mint total_supply"); + + + instance + } + + + + #[ink(message)] + pub fn burn(&mut self, _amount: Balance) -> Result<(), PSP22Error> { + let caller = self.env().caller(); + psp22::Internal::_burn_from(self, caller, _amount) + } + } +} diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/.DS_Store b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/.DS_Store new file mode 100644 index 00000000..a0ef4a6a Binary files /dev/null and b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/.DS_Store differ diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/.gitignore b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/.gitignore new file mode 100755 index 00000000..8de8f877 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/Cargo.toml b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/Cargo.toml new file mode 100755 index 00000000..9c88266d --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "staking_reward" +version = "0.1.0" +authors = ["developeruche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } + +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false , features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"]} +global = {path = "./../../", default-features = false} + + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "staking_reward.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", + "global/std" +] +ink-as-dependency = [] +e2e-tests = [] + + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/staking_reward.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/staking_reward.rs new file mode 100755 index 00000000..2594b131 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/modules/staking_reward/staking_reward.rs @@ -0,0 +1,216 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + + + +#[ink::contract] +mod staking_reward { + use ink::prelude::vec::Vec; + use global::providers::common::errors::StakingRewardsErrors; + use global::providers::data::staking_reward::StakingStorage; + use global::controllers::staking_reward::stakingrewardcontroller_external::StakingRewardController; + use global::providers::deployables::staking_reward::StakingRewardImpl; + use openbrush::contracts::ownable; + use openbrush::traits::Storage; + use global::controllers::staking_reward::stakingrewardcontroller_external; + + + + // ====================================== + // Storage + // ====================================== + #[ink(storage)] + #[derive(Default, Storage)] + pub struct StakingReward { + #[storage_field] + pub staking_state: StakingStorage, + #[storage_field] + ownable: ownable::Data, + } + + + + // ====================================== + // Events + // ====================================== + #[ink(event)] + pub struct Staked { + #[ink(topic)] + caller:AccountId, + amount: Balance, + } + + #[ink(event)] + pub struct Withdraw { + #[ink(topic)] + caller:AccountId, + amount: Balance, + } + + #[ink(event)] + pub struct RewardPaid { + #[ink(topic)] + caller:AccountId, + reward: Balance, + } + + #[ink(event)] + pub struct RewardNotified { + reward: Balance, + } + + #[ink(event)] + pub struct DurationUpdate { + duration: Balance, + } + + + + + impl StakingRewardImpl for StakingReward {} + + + impl StakingRewardController for StakingReward { + #[ink(message)] + fn total_supply(&self) -> Balance { + StakingRewardImpl::total_supply(self) + } + + #[ink(message)] + fn get_reward_token(&self) -> AccountId { + StakingRewardImpl::get_reward_token(self) + } + + #[ink(message)] + fn get_staked_token(&self) -> AccountId { + StakingRewardImpl::get_staked_token(self) + } + + #[ink(message)] + fn get_reward_rate(&self) -> Balance { + StakingRewardImpl::get_reward_rate(self) + } + + #[ink(message)] + fn get_period_finish(&self) -> Balance { + StakingRewardImpl::get_period_finish(self) + } + + #[ink(message)] + fn get_reward_duration(&self) -> Balance { + StakingRewardImpl::get_reward_duration(self) + } + + #[ink(message)] + fn get_last_update_time(&self) -> Balance { + StakingRewardImpl::get_last_update_time(self) + } + + #[ink(message)] + fn get_reward_per_token_stored(&self) -> Balance { + StakingRewardImpl::get_reward_per_token_stored(self) + } + + #[ink(message)] + fn get_user_reward_per_token_paid(&self, _account: AccountId) -> Balance { + StakingRewardImpl::get_user_reward_per_token_paid(self, _account) + } + + #[ink(message)] + fn get_rewards(&self, _account: AccountId) -> Balance { + StakingRewardImpl::get_rewards(self, _account) + } + + #[ink(message)] + fn balance_of(&self, _account: AccountId) -> Balance { + StakingRewardImpl::balance_of(self, _account) + } + + #[ink(message)] + fn last_time_reward_applicable(&self) -> Balance { + StakingRewardImpl::last_time_reward_applicable(self) + } + + #[ink(message)] + fn reward_per_token(&self) -> Balance { + StakingRewardImpl::reward_per_token(self) + } + + #[ink(message)] + fn earned(&self, _account: AccountId) -> Balance { + StakingRewardImpl::earned(self, _account) + } + + #[ink(message)] + fn get_reward_for_duration(&self) -> Balance { + StakingRewardImpl::get_reward_for_duration(self) + } + + + + + + #[ink(message)] + fn stake(&mut self, _amount: Balance) -> Result<(), StakingRewardsErrors> { + StakingRewardImpl::stake(self, _amount) + } + + #[ink(message)] + fn withdraw(&mut self, _amount: Balance) -> Result<(), StakingRewardsErrors> { + StakingRewardImpl::withdraw(self, _amount) + } + + #[ink(message)] + fn get_reward(&mut self) -> Result<(), StakingRewardsErrors> { + StakingRewardImpl::get_reward(self) + } + + #[ink(message)] + fn exit(&mut self) -> Result<(), StakingRewardsErrors> { + StakingRewardImpl::exit(self) + } + + #[ink(message)] + fn notify_reward_amount(&mut self, _reward: Balance) -> Result<(), StakingRewardsErrors> { + StakingRewardImpl::notify_reward_amount(self, _reward) + } + + #[ink(message)] + fn recover_erc20(&mut self, _token: AccountId, _amount: Balance) -> Result<(), StakingRewardsErrors> { + StakingRewardImpl::recover_erc20(self, _token, _amount) + } + + #[ink(message)] + fn set_reward_duration(&mut self, _duration: Balance) -> Result<(), StakingRewardsErrors> { + StakingRewardImpl::set_reward_duration(self, _duration) + } + } + + + + + + + + + + + + + impl StakingReward { + + #[ink(constructor)] + pub fn new(_owner: AccountId, _reward_token: AccountId, _staked_token: AccountId) -> Self { + let mut instance = Self::default(); + + + instance.staking_state.admin = _owner; + instance.staking_state.staked_token = _staked_token; + instance.staking_state.reward_token = _reward_token; + + + instance + } + + } + +} \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/.DS_Store b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/.DS_Store new file mode 100644 index 00000000..482eb7c2 Binary files /dev/null and b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/.DS_Store differ diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/database.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/database.rs new file mode 100644 index 00000000..8f84ed21 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/database.rs @@ -0,0 +1,2 @@ +pub const CONTRACT_1_STATE: u32 = openbrush::storage_unique_key!(contract_1_state); +pub const FACTORY_STORAGE_LOCATION: u32 = openbrush::storage_unique_key!(factory_storage_location); \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/errors.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/errors.rs new file mode 100644 index 00000000..3298eaf8 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/errors.rs @@ -0,0 +1,45 @@ +use openbrush:: + contracts::traits::{ + ownable::*, + psp22::PSP22Error, + errors::ReentrancyGuardError, + }; + + + + + + +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum StakingRewardsErrors { + OwnableError(OwnableError), + ReentrancyGuardError(ReentrancyGuardError), + NotAdmin, + AmountShouldBeGreaterThanZero, + InsufficientFunds, + NotEnoughAllowance, + TokenTransferFailed, + Overflow, + StakingStillInProgress, + InvalidAmount, + ProviderRewardIsToLarge, + CannotWithdrawRewardToken, + CannotWithdrawStakedToken, +} + + + + + +impl From for StakingRewardsErrors { + fn from(error: OwnableError) -> Self { + StakingRewardsErrors::OwnableError(error) + } +} + +impl From for StakingRewardsErrors { + fn from(error: ReentrancyGuardError) -> Self { + StakingRewardsErrors::ReentrancyGuardError(error) + } +} \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/mod.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/mod.rs new file mode 100644 index 00000000..51412cb8 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/common/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod errors; \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/data/mod.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/data/mod.rs new file mode 100644 index 00000000..3b1d20f9 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/data/mod.rs @@ -0,0 +1 @@ +pub mod staking_reward; \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/data/staking_reward.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/data/staking_reward.rs new file mode 100644 index 00000000..b8e5bd3c --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/data/staking_reward.rs @@ -0,0 +1,46 @@ +use ink::storage::Mapping; +use openbrush::traits::AccountId; +use ink::prelude::vec::Vec; +use openbrush::traits::Balance; + + + +#[derive(Debug)] +#[openbrush::storage_item(STAKING_REWARD_STORAGE_LOCATION)] +pub struct StakingStorage { + pub admin: AccountId, + pub staked_token: AccountId, + pub reward_token: AccountId, + pub period_to_finish: Balance, + pub reward_rate: Balance, + pub reward_duration: Balance, + pub last_updated_time: Balance, + pub reward_per_token_stored: Balance, + pub user_reward_per_token: Mapping, + pub rewards: Mapping, + pub total_supply: Balance, + pub balances: Mapping, +} + + + +impl Default for StakingStorage { + fn default() -> Self { + Self { + admin: AccountId::from([0x0; 32]), + staked_token: AccountId::from([0x0; 32]), + reward_token: AccountId::from([0x0; 32]), + period_to_finish: Default::default(), + reward_rate: Default::default(), + reward_duration: Default::default(), + last_updated_time: Default::default(), + reward_per_token_stored: Default::default(), + user_reward_per_token: Default::default(), + rewards: Default::default(), + total_supply: Default::default(), + balances: Default::default(), + } + } +} + + diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/deployables/mod.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/deployables/mod.rs new file mode 100644 index 00000000..3b1d20f9 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/deployables/mod.rs @@ -0,0 +1 @@ +pub mod staking_reward; \ No newline at end of file diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/deployables/staking_reward.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/deployables/staking_reward.rs new file mode 100644 index 00000000..02e7ec1d --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/deployables/staking_reward.rs @@ -0,0 +1,277 @@ +use core::cell::RefCell; +use openbrush::{traits::{Storage, AccountId}, contracts::ownable::OwnableError}; +use crate::providers::{data::staking_reward::StakingStorage, common::errors::StakingRewardsErrors}; +use openbrush::traits::Balance; +use openbrush::{contracts::{psp22::{psp22, extensions::metadata::PSP22MetadataImpl}, traits::psp22::PSP22Ref}}; +use ink::prelude::vec::Vec; +use openbrush::modifier_definition; + + + + + +pub trait StakingRewardImpl: + Storage +{ + // ====================================== + // Mutating functions + // ====================================== + fn stake(&mut self, _amount: Balance) -> Result<(), StakingRewardsErrors> { + let state = self.data::(); + let caller = Self::env().caller(); + if _amount <= 0 { + return Err(StakingRewardsErrors::InvalidAmount); + } + + state.total_supply += _amount; + let current_balance = state.balances.get(&caller).unwrap_or(0u128); + state.balances.insert(caller, &(current_balance + _amount)); + + PSP22Ref::transfer_from(&state.staked_token, caller, Self::env().account_id(), _amount, Vec::::new()).map_err(|_| StakingRewardsErrors::TokenTransferFailed)?; + Ok(()) + } + + fn withdraw(&mut self, _amount: Balance) -> Result<(), StakingRewardsErrors> { + let state = self.data::(); + let caller = Self::env().caller(); + if _amount <= 0 { + return Err(StakingRewardsErrors::InvalidAmount); + } + + state.total_supply -= _amount; + let current_balance = state.balances.get(&caller).unwrap_or(0u128); + state.balances.insert(caller, &(current_balance - _amount)); + + PSP22Ref::transfer(&state.staked_token, caller, _amount, Vec::::new()).map_err(|_| StakingRewardsErrors::TokenTransferFailed)?; + Ok(()) + } + + fn get_reward(&mut self) -> Result<(), StakingRewardsErrors> { + let state = self.data::(); + let caller = Self::env().caller(); + + + let reward = state.rewards.get(&caller).unwrap_or(0u128); + + if reward <= 0 { + return Err(StakingRewardsErrors::InvalidAmount); + } + + state.rewards.insert(caller, &0u128); + PSP22Ref::transfer(&state.reward_token, caller, reward, Vec::::new()).map_err(|_| StakingRewardsErrors::TokenTransferFailed)?; + Ok(()) + } + + fn exit(&mut self) -> Result<(), StakingRewardsErrors> { + let state = self.data::(); + let caller = Self::env().caller(); + + let amount = state.balances.get(&caller).unwrap_or(0u128); + self.withdraw(amount)?; + self.get_reward()?; + Ok(()) + } + + + + + + + fn notify_reward_amount(&mut self, _reward: Balance) -> Result<(), StakingRewardsErrors> { + let state = self.data::(); + let caller = Self::env().caller(); + + // remove this whe you plug in the modifer + if caller != state.admin { + return Err(StakingRewardsErrors::NotAdmin); + } + + if _reward <= 0 { + return Err(StakingRewardsErrors::InvalidAmount); + } + + let block_timestamp = Self::env().block_timestamp() as u128; + if block_timestamp >= state.period_to_finish { + state.reward_rate = _reward / state.reward_duration; + } else { + let remaining = state.period_to_finish - block_timestamp; + let leftover = remaining * state.reward_rate; + state.reward_rate = (_reward + leftover) / state.reward_duration; + } + + + let balance = PSP22Ref::balance_of(&state.reward_token, Self::env().account_id()); + + if state.reward_rate > balance / state.reward_duration { + return Err(StakingRewardsErrors::ProviderRewardIsToLarge); + } + state.last_updated_time = block_timestamp; + state.period_to_finish = block_timestamp + state.reward_duration; + + Ok(()) + } + + + fn recover_erc20(&mut self, _token: AccountId, _amount: Balance) -> Result<(), StakingRewardsErrors> { + let state = self.data::(); + let caller = Self::env().caller(); + + // remove this whe you plug in the modifer + if caller != state.admin { + return Err(StakingRewardsErrors::NotAdmin); + } + + if state.reward_token == _token { + return Err(StakingRewardsErrors::CannotWithdrawRewardToken); + } + + if state.staked_token == _token { + return Err(StakingRewardsErrors::CannotWithdrawStakedToken); + } + + if _amount <= 0 { + return Err(StakingRewardsErrors::InvalidAmount); + } + + PSP22Ref::transfer(&state.reward_token, caller, _amount, Vec::::new()).map_err(|_| StakingRewardsErrors::TokenTransferFailed)?; + Ok(()) + } + + fn set_reward_duration(&mut self, _duration: Balance) -> Result<(), StakingRewardsErrors> { + let state = self.data::(); + let caller = Self::env().caller(); + + // remove this whe you plug in the modifer + if caller != state.admin { + return Err(StakingRewardsErrors::NotAdmin); + } + + if _duration <= 0 { + return Err(StakingRewardsErrors::InvalidAmount); + } + + if (Self::env().block_timestamp() as u128) < state.period_to_finish { + return Err(StakingRewardsErrors::StakingStillInProgress); + } + + state.reward_duration = _duration; + Ok(()) + } + + + + + + + + + + // ====================================== + // View functions + // ====================================== + fn get_reward_token(&self) -> AccountId { + self.data::().reward_token + } + + fn get_staked_token(&self) -> AccountId { + self.data::().staked_token + } + + fn get_reward_rate(&self) -> Balance { + self.data::().reward_rate + } + + fn get_period_finish(&self) -> Balance { + self.data::().period_to_finish + } + + fn get_reward_duration(&self) -> Balance { + self.data::().reward_duration + } + + fn get_last_update_time(&self) -> Balance { + self.data::().last_updated_time + } + + fn get_reward_per_token_stored(&self) -> Balance { + self.data::().reward_per_token_stored + } + + fn get_user_reward_per_token_paid(&self, _account: AccountId) -> Balance { + self.data::().user_reward_per_token.get(&_account).unwrap_or(0u128).clone() + } + + fn get_rewards(&self, _account: AccountId) -> Balance { + self.data::().rewards.get(&_account).unwrap_or(0u128).clone() + } + + fn total_supply(&self) -> Balance { + self.data::().total_supply + } + + fn balance_of(&self, _account: AccountId) -> Balance { + self.data::().balances.get(&_account).unwrap_or(0u128).clone() + } + + fn last_time_reward_applicable(&self) -> Balance { + let state = self.data::(); + let block_timestamp = Self::env().block_timestamp() as u128; + block_timestamp.min(state.period_to_finish) + } + + fn reward_per_token(&self) -> Balance { + let state = self.data::(); + if state.total_supply == 0 { + state.reward_per_token_stored + } else { + state.reward_per_token_stored + (self.last_time_reward_applicable() - state.last_updated_time) * state.reward_rate * 10u128.pow(18) / state.total_supply + } + } + + fn earned(&self, _account: AccountId) -> Balance { + let state = self.data::(); + let user_reward_per_token_paid = state.user_reward_per_token.get(&_account).unwrap_or(0u128).clone(); + let reward_per_token = self.reward_per_token(); + let balance_of = self.balance_of(_account); + let earned = balance_of * (reward_per_token - user_reward_per_token_paid) / 10u128.pow(18) + state.rewards.get(&_account).unwrap_or(0u128); + + earned + } + + fn get_reward_for_duration(&self) -> Balance { + let state = self.data::(); + state.reward_rate * state.reward_duration + } + + fn get_caller(&self) -> AccountId { + Self::env().caller() + } +} + + + + + +// ====================================== +// Modifers +// ====================================== +//TODO: move this logic into the trait... modifer_definition! macro does not accept abr data +// #[modifier_definition] +// pub fn update_reward(instance: &mut T, body: F, is_address_zero: bool) -> Result +// where T: Storage + StakingRewardImpl, F: FnOnce(&mut T) -> Result, E: From +// { + +// let instance_ = RefCell::new(instance); +// let mut instance_1 = instance_.borrow_mut(); +// let state = instance_1.data::(); +// let reward_per_token = StakingRewardImpl::reward_per_token(instance); +// let last_updated_time = StakingRewardImpl::last_time_reward_applicable(instance); + +// if is_address_zero { +// let current_earned = StakingRewardImpl::earned(instance, instance.get_caller()); +// state.rewards.insert(instance.get_caller(), ¤t_earned); +// state.user_reward_per_token.insert(instance.get_caller(), &reward_per_token); +// } + +// body(instance) +// } diff --git a/ink-awesome-defi/synthetix-staking-reward/contracts/providers/mod.rs b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/mod.rs new file mode 100644 index 00000000..770cc004 --- /dev/null +++ b/ink-awesome-defi/synthetix-staking-reward/contracts/providers/mod.rs @@ -0,0 +1,3 @@ +pub mod data; +pub mod deployables; +pub mod common; \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/.DS_Store b/ink-awesome-defi/uniswap-v2-core-ink/.DS_Store new file mode 100644 index 00000000..61bfbbbf Binary files /dev/null and b/ink-awesome-defi/uniswap-v2-core-ink/.DS_Store differ diff --git a/ink-awesome-defi/uniswap-v2-core-ink/.gitignore b/ink-awesome-defi/uniswap-v2-core-ink/.gitignore new file mode 100644 index 00000000..c41cc9e3 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/Cargo.toml b/ink-awesome-defi/uniswap-v2-core-ink/Cargo.toml new file mode 100644 index 00000000..6a5a8f79 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "contracts" +version = "0.1.0" +authors = ["[your_name] <[your_email]>"] +edition = "2021" + +[dependencies] +ink = { version = "4.2.1", default-features = false } + +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false, features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"] } +psp22_lp = { path = "contracts/modules/psp22_lp", default-features = false } +pair = { path = "contracts/modules/pair", default-features = false } +factory = { path = "contracts/modules/factory", default-features = false } +global = {path = "contracts", default-features = false} +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "contracts.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts.rs new file mode 100644 index 00000000..58233ec9 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts.rs @@ -0,0 +1,3 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use global; \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/.DS_Store b/ink-awesome-defi/uniswap-v2-core-ink/contracts/.DS_Store new file mode 100644 index 00000000..cb6234f1 Binary files /dev/null and b/ink-awesome-defi/uniswap-v2-core-ink/contracts/.DS_Store differ diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/Cargo.toml b/ink-awesome-defi/uniswap-v2-core-ink/contracts/Cargo.toml new file mode 100644 index 00000000..46c815ce --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "global" +version = "0.1.0" +authors = ["developeruche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } + +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false, features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"]} + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } +sp-arithmetic = { version = "15", default-features = false } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "global.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", + "sp-arithmetic/std", +] +ink-as-dependency = [] +e2e-tests = [] + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/factory.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/factory.rs new file mode 100644 index 00000000..42c6f377 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/factory.rs @@ -0,0 +1,25 @@ + +use openbrush::traits::AccountId; + +use crate::providers::common::errors::UniswapV2Errors; + + + +#[openbrush::wrapper] +pub type FactoryRef = dyn FactoryController; + +#[openbrush::trait_definition] +pub trait FactoryController { + // this function would set the address that receives the protocol fee + #[ink(message)] + fn set_fee_to(&mut self, _fee_to: AccountId) -> Result<(), UniswapV2Errors>; + + // this function is used the updated the address that can call the set_fee_to function + #[ink(message)] + fn set_fee_to_setter(&mut self, _fee_to_setter: AccountId) -> Result<(), UniswapV2Errors>; + + // this function is used to set the pair code hash (this is handy for upgrades) + #[ink(message)] + fn set_pair_code_hash(&mut self, _pair_code_hash: [u8; 32]) -> Result<(), UniswapV2Errors>; + +} \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/mod.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/mod.rs new file mode 100644 index 00000000..67469793 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/mod.rs @@ -0,0 +1,2 @@ +pub mod pair; +pub mod factory; \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/pair.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/pair.rs new file mode 100644 index 00000000..f932a004 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/controllers/pair.rs @@ -0,0 +1,51 @@ +use ink::primitives::AccountId; +use openbrush::traits::Balance; + +use crate::providers::common::errors::UniswapV2Errors; +use openbrush::contracts::traits::psp22::*; + + +#[openbrush::wrapper] +pub type PairRef = dyn PairController + PSP22; + +#[openbrush::trait_definition] +pub trait PairController { + + #[ink(message)] + fn initialize(&mut self, _token0: AccountId, _token1: AccountId); + + #[ink(message)] + fn mint(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors>; + + #[ink(message)] + fn burn(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors>; + + #[ink(message)] + fn swap(&mut self, _amount0: Balance, _amount1: Balance, _to: AccountId) -> Result<(), UniswapV2Errors>; + + #[ink(message)] + fn skim(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors>; + + #[ink(message)] + fn sync(&mut self) -> Result<(), UniswapV2Errors>; + + + + #[ink(message)] + fn token_0(&self) -> AccountId; + + #[ink(message)] + fn token_1(&self) -> AccountId; + + #[ink(message)] + fn factory(&self) -> AccountId; + + #[ink(message)] + fn price0_cumulative_last(&self) -> u128; + + #[ink(message)] + fn price1_cumulative_last(&self) -> u128; + + #[ink(message)] + fn get_reserves(&self) -> (u128, u128, u128); +} \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/global.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/global.rs new file mode 100644 index 00000000..26a14f59 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/global.rs @@ -0,0 +1,4 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub mod controllers; +pub mod providers; \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/.DS_Store b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/.DS_Store new file mode 100644 index 00000000..4de4b072 Binary files /dev/null and b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/.DS_Store differ diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/.DS_Store b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/.DS_Store new file mode 100644 index 00000000..49bf1f8b Binary files /dev/null and b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/.DS_Store differ diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/.gitignore b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/.gitignore new file mode 100755 index 00000000..8de8f877 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/Cargo.toml b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/Cargo.toml new file mode 100755 index 00000000..38e13334 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "factory" +version = "0.1.0" +authors = ["developeruche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } + +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false , features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"]} +global = {path = "./../../", default-features = false} +pair ={ path = "../pair" , default-features = false, features = ["ink-as-dependency"]} + + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "factory.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", + "global/std" +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/factory.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/factory.rs new file mode 100755 index 00000000..e2751774 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/factory/factory.rs @@ -0,0 +1,97 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + + + +#[ink::contract] +mod factory { + use ink::prelude::vec::Vec; + use global::providers::common::errors::UniswapV2Errors; + use global::providers::data::factory::FactoryStorage; + // use global::controllers::factory::factorycontroller_external; + // use global::controllers::factory::FactoryController; + use global::controllers::factory::factorycontroller_external::FactoryController; + use global::providers::deployables::factory::FactoryImpl; + use openbrush::traits::Storage; + use pair::pair::PairRef; + use ink::ToAccountId; + + + + #[ink(storage)] + #[derive(Default, Storage)] + pub struct Factory { + #[storage_field] + pub factory_state: FactoryStorage, + + } + + impl FactoryImpl for Factory {} + + + impl FactoryController for Factory { + #[ink(message)] + fn set_fee_to(&mut self, _fee_to: AccountId) -> Result<(), UniswapV2Errors> { + FactoryImpl::set_fee_to(self, _fee_to) + } + + #[ink(message)] + fn set_fee_to_setter(&mut self, _fee_to_setter: AccountId) -> Result<(), UniswapV2Errors> { + FactoryImpl::set_fee_to_setter(self, _fee_to_setter) + } + + #[ink(message)] + fn set_pair_code_hash(&mut self, _pair_code_hash: [u8; 32]) -> Result<(), UniswapV2Errors> { + FactoryImpl::set_pair_code_hash(self, _pair_code_hash) + } + } + + impl Factory { + + #[ink(constructor)] + pub fn new(pair_code_hash: [u8; 32]) -> Self { + let mut instance = Self::default(); + + instance.factory_state.fee_to_setter = Some(Self::env().caller()); + instance.factory_state.pair_code_hash = pair_code_hash; + + + instance + } + + + + + #[ink(message)] + pub fn create_pair(&mut self, token_a: AccountId, token_b: AccountId, salt_bytes: Vec) -> Result { + let pair = self.factory_state.get_pair.get(&(token_a, token_b)); + if pair.is_some() { + return Err(UniswapV2Errors::PairAlreadyExists); + } + + let pair = self.factory_state.get_pair.get(&(token_b, token_a)); + if pair.is_some() { + return Err(UniswapV2Errors::PairAlreadyExists); + } + + let hash = self.factory_state.pair_code_hash; + + let pair = PairRef::new(token_a, token_b) + .endowment(0) + .code_hash(hash.into()) + .salt_bytes(&salt_bytes) + .instantiate(); + + let pair_addr = pair.to_account_id(); + + self.factory_state.get_pair.insert(&(token_a, token_b), &pair_addr); + self.factory_state.get_pair.insert(&(token_b, token_a), &pair_addr); + + self.factory_state.all_pairs.push(pair_addr); + + Ok(pair_addr) + } + + + } + +} \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/.DS_Store b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/.DS_Store new file mode 100644 index 00000000..2926f511 Binary files /dev/null and b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/.DS_Store differ diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/.gitignore b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/.gitignore new file mode 100755 index 00000000..8de8f877 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/Cargo.toml b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/Cargo.toml new file mode 100755 index 00000000..f1b6324b --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "pair" +version = "0.1.0" +authors = ["developeruche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } + +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false , features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"]} +global = {path = "./../../", default-features = false} + + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "pair.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", + "global/std" +] +ink-as-dependency = [] +e2e-tests = [] + + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/pair.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/pair.rs new file mode 100755 index 00000000..a65c1128 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/pair/pair.rs @@ -0,0 +1,200 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + + + +#[openbrush::implementation(PSP22, PSP22Permit, Nonces, Ownable, PSP22Metadata)] +#[openbrush::contract] +pub mod pair { + + use global::providers::common::errors::UniswapV2Errors; + use global::providers::data::pair::set_factory; + use global::providers::{data::pair::PairStorage, deployables::pair::PairImpl}; + use global::controllers::pair::PairController; + use openbrush::traits::{Hash as HashType, String}; + use openbrush::{traits::Storage, contracts::reentrancy_guard}; + use global::controllers::pair::paircontroller_external; + use openbrush::modifiers; + use crate::pair::reentrancy_guard::non_reentrant; + + + // ========================================= + // Storage + // ========================================= + #[ink(storage)] + #[derive(Default, Storage)] + pub struct Pair { + #[storage_field] + psp22: psp22::Data, + #[storage_field] + metadata: metadata::Data, + #[storage_field] + ownable: ownable::Data, + #[storage_field] + nonces: nonces::Data, + #[storage_field] + psp22_permit: psp22::extensions::permit::Data, + #[storage_field] + pub guard: reentrancy_guard::Data, + #[storage_field] + pub pool_state: PairStorage, + } + + + // ========================================= + // Overriding PSP22 Functions + // ========================================= + + + + + // ========================================= + // Events + // ========================================= + #[ink(event)] + pub struct Mint { + #[ink(topic)] + pub sender: AccountId, + pub amount1: Balance, + pub amount2: Balance, + } + + #[ink(event)] + pub struct Burn { + #[ink(topic)] + pub sender: AccountId, + pub amount1: Balance, + pub amount2: Balance, + #[ink(topic)] + pub to: AccountId, + } + + #[ink(event)] + pub struct Swap { + #[ink(topic)] + pub sender: AccountId, + pub amount0_in: Balance, + pub amount1_in: Balance, + pub amount0_out: Balance, + pub amount1_out: Balance, + #[ink(topic)] + pub to: AccountId, + } + + #[ink(event)] + pub struct Sync { + pub reserve0: Balance, + pub reserve1: Balance, + } + + + + + impl PairImpl for Pair {} + + + + + + impl PairController for Pair { + // ========================================= + // View Functions + // ========================================= + #[ink(message)] + fn token_0(&self) -> AccountId { + PairImpl::token_0(self) + } + + #[ink(message)] + fn token_1(&self) -> AccountId { + PairImpl::token_1(self) + } + + #[ink(message)] + fn factory(&self) -> AccountId { + PairImpl::factory(self) + } + + #[ink(message)] + fn price0_cumulative_last(&self) -> u128 { + PairImpl::price0_cumulative_last(self) + } + + #[ink(message)] + fn price1_cumulative_last(&self) -> u128 { + PairImpl::price1_cumulative_last(self) + } + + #[ink(message)] + fn get_reserves(&self) -> (u128, u128, u128) { + PairImpl::get_reserves(self) + } + + + + + // ========================================= + // Write Functions + // ========================================= + #[ink(message)] + fn initialize(&mut self, _token0: AccountId, _token1: AccountId) { + PairImpl::initialize(self, _token0, _token1); + } + + #[ink(message)] + #[modifiers(non_reentrant)] + fn mint(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors> { + PairImpl::mint(self, _to) + } + + #[ink(message)] + #[modifiers(non_reentrant)] + fn burn(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors> { + PairImpl::burn(self, _to) + } + + #[ink(message)] + #[modifiers(non_reentrant)] + fn swap(&mut self, _amount0: Balance, _amount1: Balance, _to: AccountId) -> Result<(), UniswapV2Errors> { + PairImpl::swap(self, _amount0, _amount1, _to) + } + + #[ink(message)] + #[modifiers(non_reentrant)] + fn skim(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors> { + PairImpl::skim(self, _to) + } + + #[ink(message)] + #[modifiers(non_reentrant)] + fn sync(&mut self) -> Result<(), UniswapV2Errors> { + PairImpl::sync(self) + } + } + + + impl Pair { + #[ink(constructor)] + pub fn new(token_a: AccountId, token_b: AccountId) -> Self { + let mut instance = Self::default(); + let caller = instance.env().caller(); + + instance.metadata.name.set(&Some(String::from("Uniswap V2"))); + instance.metadata.symbol.set(&Some(String::from("UNI-V2"))); + instance.metadata.decimals.set(&18); + + ownable::Internal::_init_with_owner(&mut instance, caller); + + set_factory(&mut instance, Self::env().account_id()); + + PairImpl::initialize(&mut instance, token_a, token_b); + instance + } + + + #[ink(message)] + pub fn get_code_hash(&mut self) -> HashType { + self.env().own_code_hash().unwrap() + } + } + +} \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/.DS_Store b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/.DS_Store new file mode 100644 index 00000000..ee9c024f Binary files /dev/null and b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/.DS_Store differ diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/.gitignore b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/.gitignore new file mode 100755 index 00000000..8de8f877 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/Cargo.toml b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/Cargo.toml new file mode 100755 index 00000000..672d68fb --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "psp22_lp" +version = "0.1.0" +authors = ["developeruche "] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "4.0.0-beta.1", default-features = false, features = ["psp22","ownable","access_control", "psp34", "reentrancy_guard", "pausable"] } +global = {path = "./../../", default-features = false} + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "psp22_lp.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + "openbrush/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/psp22_lp.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/psp22_lp.rs new file mode 100755 index 00000000..d44e567c --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/modules/psp22_lp/psp22_lp.rs @@ -0,0 +1,64 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + + + + + +#[openbrush::implementation(PSP22, PSP22Permit, Nonces, PSP22Mintable, Ownable, PSP22Metadata)] +#[openbrush::contract] +pub mod psp22_permit { + use openbrush::{traits::Storage, modifiers}; + + + #[ink(storage)] + #[derive(Default, Storage)] + pub struct PSP22Lp { + #[storage_field] + psp22: psp22::Data, + #[storage_field] + metadata: metadata::Data, + #[storage_field] + ownable: ownable::Data, + #[storage_field] + nonces: nonces::Data, + #[storage_field] + psp22_permit: psp22::extensions::permit::Data, + + } + + + #[default_impl(PSP22Mintable)] + #[modifiers(only_owner)] + fn mint(&mut self) {} + + + + + + + impl PSP22Lp { + #[ink(constructor)] + pub fn new(total_supply: Balance, name: Option, symbol: Option, decimal: u8) -> Self { + let mut instance = Self::default(); + let caller = instance.env().caller(); + + instance.metadata.name.set(&name); + instance.metadata.symbol.set(&symbol); + instance.metadata.decimals.set(&decimal); + + ownable::Internal::_init_with_owner(&mut instance, Self::env().caller()); + psp22::Internal::_mint_to(&mut instance, caller, total_supply).expect("Should mint total_supply"); + + + instance + } + + + + #[ink(message)] + pub fn burn(&mut self, _amount: Balance) -> Result<(), PSP22Error> { + let caller = self.env().caller(); + psp22::Internal::_burn_from(self, caller, _amount) + } + } +} diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/database.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/database.rs new file mode 100644 index 00000000..8f84ed21 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/database.rs @@ -0,0 +1,2 @@ +pub const CONTRACT_1_STATE: u32 = openbrush::storage_unique_key!(contract_1_state); +pub const FACTORY_STORAGE_LOCATION: u32 = openbrush::storage_unique_key!(factory_storage_location); \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/errors.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/errors.rs new file mode 100644 index 00000000..5eb5fde4 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/errors.rs @@ -0,0 +1,48 @@ +use openbrush:: + contracts::traits::{ + ownable::*, + psp22::PSP22Error, + errors::ReentrancyGuardError, + }; + + + + + + +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum UniswapV2Errors { + PSP22Error(PSP22Error), + OwnableError(OwnableError), + ReentrancyGuardError(ReentrancyGuardError), + InsufficientLiquidityMinted, + InsufficientLiquidityBurned, + InsufficientAmountOut, + InvalidToAddress, + ConstantProductError, + InvalidPairAddress, + PairAlreadyExists +} + + + + +// implementing error conversion utils +impl From for UniswapV2Errors { + fn from(error: PSP22Error) -> Self { + UniswapV2Errors::PSP22Error(error) + } +} + +impl From for UniswapV2Errors { + fn from(error: OwnableError) -> Self { + UniswapV2Errors::OwnableError(error) + } +} + +impl From for UniswapV2Errors { + fn from(error: ReentrancyGuardError) -> Self { + UniswapV2Errors::ReentrancyGuardError(error) + } +} \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/mod.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/mod.rs new file mode 100644 index 00000000..51412cb8 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/common/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod errors; \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/factory.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/factory.rs new file mode 100644 index 00000000..7fb2e226 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/factory.rs @@ -0,0 +1,31 @@ +use ink::storage::Mapping; +use openbrush::traits::AccountId; +use ink::prelude::vec::Vec; + + + +#[derive(Debug)] +#[openbrush::storage_item(FACTORY_STORAGE_LOCATION)] +pub struct FactoryStorage { + pub fee_to: Option, + pub fee_to_setter: Option, + pub get_pair: Mapping<(AccountId, AccountId), AccountId>, + pub all_pairs: Vec, + pub pair_code_hash: [u8; 32], +} + + + +impl Default for FactoryStorage { + fn default() -> Self { + Self { + fee_to: Default::default(), + fee_to_setter: Default::default(), + get_pair: Default::default(), + all_pairs: Default::default(), + pair_code_hash: Default::default(), + } + } +} + + diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/mod.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/mod.rs new file mode 100644 index 00000000..67469793 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/mod.rs @@ -0,0 +1,2 @@ +pub mod pair; +pub mod factory; \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/pair.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/pair.rs new file mode 100644 index 00000000..60bffc16 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/data/pair.rs @@ -0,0 +1,116 @@ +use openbrush::traits::{ AccountId, Balance, Storage }; + + +#[derive(Debug, Clone, Copy)] +#[openbrush::storage_item(PAIR_STORAGE_LOCATION)] +pub struct PairStorage { + pub minimum_liquidity: Balance, + pub factory: AccountId, + pub token_0: AccountId, + pub token_1: AccountId, + pub reserve_0: Balance, + pub reserve_1: Balance, + pub block_timestamp_last: Balance, + pub price0_cumulative_last: Balance, + pub price1_cumulative_last: Balance, + pub k_last: Balance, +} + + +impl Default for PairStorage { + fn default() -> Self { + Self { + minimum_liquidity: Balance::from(1000u32), + factory: AccountId::from([0u8; 32]), + token_0: AccountId::from([0u8; 32]), + token_1: AccountId::from([0u8; 32]), + reserve_0: Balance::default(), + reserve_1: Balance::default(), + block_timestamp_last: Balance::default(), + price0_cumulative_last: Balance::default(), + price1_cumulative_last: Balance::default(), + k_last: Balance::default(), + } + } +} + + + + +// implementing utils functions for accessing storage (this makes life abit easier) +pub fn get_minimum_liquidity(instance: &T) -> Balance where T: Storage { + instance.data::().minimum_liquidity +} + +pub fn get_factory(instance: &T) -> AccountId where T: Storage { + instance.data::().factory +} + +pub fn set_factory(instance: &mut T, factory: AccountId) where T: Storage { + instance.data::().factory = factory; +} + +pub fn get_token_0(instance: &T) -> AccountId where T: Storage { + instance.data::().token_0 +} + +pub fn set_token_0(instance: &mut T, token_0: AccountId) where T: Storage { + instance.data::().token_0 = token_0; +} + +pub fn get_token_1(instance: &T) -> AccountId where T: Storage { + instance.data::().token_1 +} + +pub fn set_token_1(instance: &mut T, token_1: AccountId) where T: Storage { + instance.data::().token_1 = token_1; +} + +pub fn get_reserve_0(instance: &T) -> Balance where T: Storage { + instance.data::().reserve_0 +} + +pub fn set_reserve_0(instance: &mut T, reserve_0: Balance) where T: Storage { + instance.data::().reserve_0 = reserve_0; +} + +pub fn get_reserve_1(instance: &T) -> Balance where T: Storage { + instance.data::().reserve_1 +} + +pub fn set_reserve_1(instance: &mut T, reserve_1: Balance) where T: Storage { + instance.data::().reserve_1 = reserve_1; +} + +pub fn get_block_timestamp_last(instance: &T) -> Balance where T: Storage { + instance.data::().block_timestamp_last +} + +pub fn set_block_timestamp_last(instance: &mut T, block_timestamp_last: Balance) where T: Storage { + instance.data::().block_timestamp_last = block_timestamp_last; +} + +pub fn get_price0_cumulative_last(instance: &T) -> Balance where T: Storage { + instance.data::().price0_cumulative_last +} + +pub fn set_price0_cumulative_last(instance: &mut T, price0_cumulative_last: Balance) where T: Storage { + instance.data::().price0_cumulative_last = price0_cumulative_last; +} + +pub fn get_price1_cumulative_last(instance: &T) -> Balance where T: Storage { + instance.data::().price1_cumulative_last +} + +pub fn set_price1_cumulative_last(instance: &mut T, price1_cumulative_last: Balance) where T: Storage { + instance.data::().price1_cumulative_last = price1_cumulative_last; +} + +pub fn get_k_last(instance: &T) -> Balance where T: Storage { + instance.data::().k_last +} + +pub fn set_k_last(instance: &mut T, k_last: Balance) where T: Storage { + instance.data::().k_last = k_last; +} + diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/factory.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/factory.rs new file mode 100644 index 00000000..5c01c58c --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/factory.rs @@ -0,0 +1,37 @@ +use openbrush::{traits::{Storage, AccountId}, contracts::ownable::OwnableError}; +use crate::providers::{data::factory::FactoryStorage, common::errors::UniswapV2Errors}; + + +pub trait FactoryImpl: + Storage +{ + fn set_fee_to(&mut self, _fee_to: AccountId) -> Result<(), UniswapV2Errors> { + let state = self.data::(); + + if state.fee_to_setter.unwrap() != Self::env().caller() { + return Err(UniswapV2Errors::OwnableError(OwnableError::CallerIsNotOwner)) + } + self.data::().fee_to_setter = Some(_fee_to); + Ok(()) + } + + fn set_fee_to_setter(&mut self, _fee_to_setter: AccountId) -> Result<(), UniswapV2Errors> { + let state = self.data::(); + + if state.fee_to_setter.unwrap() != Self::env().caller() { + return Err(UniswapV2Errors::OwnableError(OwnableError::CallerIsNotOwner)) + } + self.data::().fee_to_setter = Some(_fee_to_setter); + Ok(()) + } + + fn set_pair_code_hash(&mut self, _pair_code_hash: [u8; 32]) -> Result<(), UniswapV2Errors> { + let state = self.data::(); + + if state.fee_to_setter.unwrap() != Self::env().caller() { + return Err(UniswapV2Errors::OwnableError(OwnableError::CallerIsNotOwner)) + } + self.data::().pair_code_hash = _pair_code_hash; + Ok(()) + } +} \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/mod.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/mod.rs new file mode 100644 index 00000000..67469793 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/mod.rs @@ -0,0 +1,2 @@ +pub mod pair; +pub mod factory; \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/pair.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/pair.rs new file mode 100644 index 00000000..1add0e68 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/deployables/pair.rs @@ -0,0 +1,284 @@ + +use ink::prelude::vec::Vec; +use ink::primitives::AccountId; +use openbrush::{traits::{Storage, Balance}, contracts::{psp22::{psp22, extensions::metadata::PSP22MetadataImpl}, traits::psp22::PSP22Ref}}; +use crate::providers::{data::pair::{PairStorage, get_token_0, get_token_1, get_factory, get_price0_cumulative_last, get_price1_cumulative_last}, common::errors::UniswapV2Errors}; +use scale::CompactAs; +use sp_arithmetic::FixedU128; + + +pub trait PairImpl: + Storage + + Storage + + PSP22MetadataImpl + + psp22::Internal + +{ + // public varible get functions + fn token_0(&self) -> AccountId { + get_token_0(self) + } + + fn token_1(&self) -> AccountId { + get_token_1(self) + } + + fn factory(&self) -> AccountId { + get_factory(self) + } + + fn price0_cumulative_last(&self) -> u128 { + get_price0_cumulative_last(self) + } + + fn price1_cumulative_last(&self) -> u128 { + get_price1_cumulative_last(self) + } + + fn get_reserves(&self) -> (u128, u128, u128) { + let state = self.data::(); + (state.reserve_0, state.reserve_1, state.block_timestamp_last) + } + + + + + + + + + fn initialize(&mut self, _token0: AccountId, _token1: AccountId) { + let state = self.data::(); + state.token_0 = _token0; + state.token_1 = _token1; + } + + fn mint(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors> { + let state = *self.data::(); + let this = Self::env().account_id(); + let (reserve_0, reserve_1, minimum_liquidity) = (state.reserve_0, state.reserve_1, state.minimum_liquidity); + let balance0 = PSP22Ref::balance_of(&state.token_0, this); + let balance1 = PSP22Ref::balance_of(&state.token_1, this); + let amount0 = balance0 - reserve_0; + let amount1 = balance1 - reserve_1; + let liqudity: Balance; + + let fee_on = self.internal_mint_fee(); + + + if self._total_supply() == 0 { + // this is the first liquidity is been added to the pool + liqudity = internal_sqrt(amount0 * amount1) - minimum_liquidity; + self._mint_to(AccountId::from([0u8; 32]), minimum_liquidity)?; + } else { + liqudity = (amount0 * self._total_supply() / reserve_0).min(amount1 * self._total_supply() / reserve_1); + } + + if liqudity == 0 { + return Err(UniswapV2Errors::InsufficientLiquidityMinted); + } + + self._mint_to(_to, liqudity)?; + + self.internal_update(balance0, balance1)?; + + if fee_on.unwrap_or(false) { + self.data::().k_last = (self.data::().reserve_0 as u128) * (self.data::().reserve_1 as u128); + } + + Ok(()) + } + + + fn burn(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors> { + let state = *self.data::(); + let this = Self::env().account_id(); + let (token_0, token_1) = (state.token_0, state.token_1); + let mut balance0 = PSP22Ref::balance_of(&token_0, this); + let mut balance1 = PSP22Ref::balance_of(&token_1, this); + let liquidity = self._balance_of(&this); + + let fee_on = self.internal_mint_fee(); + let _total_supply = self._total_supply(); + + let amount0 = liquidity * balance0 / _total_supply; + let amount1 = liquidity * balance1 / _total_supply; + + if amount0 == 0 || amount1 == 0 { + return Err(UniswapV2Errors::InsufficientLiquidityBurned); + } + + self._burn_from(this, liquidity)?; + + PSP22Ref::transfer(&this, _to, amount0, Vec::::new())?; + PSP22Ref::transfer(&this, _to, amount1, Vec::::new())?; + + balance0 = PSP22Ref::balance_of(&token_0, this); + balance1 = PSP22Ref::balance_of(&token_1, this); + + if fee_on.unwrap_or(false) { + self.data::().k_last = (self.data::().reserve_0 as u128) * (self.data::().reserve_1 as u128); + } + + self.internal_update(balance0, balance1)?; + + Ok(()) + } + + + + fn swap(&mut self, _amount0: Balance, _amount1: Balance, _to: AccountId) -> Result<(), UniswapV2Errors> { + let state = *self.data::(); + let this = Self::env().account_id(); + + if _amount0 == 0 && _amount1 == 0 { + return Err(UniswapV2Errors::InsufficientAmountOut); + } + + let (reserve_0, reserve_1, token_0, token_1) = (state.reserve_0, state.reserve_1, state.token_0, state.token_1); + + if _to == token_0 || _to == token_1 { + return Err(UniswapV2Errors::InvalidToAddress); + } + + PSP22Ref::transfer(&token_0, _to, _amount0, Vec::::new())?; + PSP22Ref::transfer(&token_1, _to, _amount1, Vec::::new())?; + + let balance0 = PSP22Ref::balance_of(&token_0, this); + let balance1 = PSP22Ref::balance_of(&token_1, this); + + let amount0_in = if balance0 > reserve_0 - _amount0 { + balance0 - (reserve_0 - _amount0) + } else { + 0u128 + }; + + let amount1_in = if balance1 > reserve_1 - _amount1 { + balance1 - (reserve_1 - _amount1) + } else { + 0u128 + }; + + if amount0_in == 0 && amount1_in == 0 { + return Err(UniswapV2Errors::InsufficientAmountOut); + } + + let balance0adjusted = balance0 * 1000 - amount0_in * 3; + let balance1adjusted = balance1 * 1000 - amount1_in * 3; + + if (balance0adjusted * balance1adjusted) < (reserve_0 * reserve_1) * 1000u128.pow(2) { + return Err(UniswapV2Errors::ConstantProductError); + } + + self.internal_update(balance0, balance1)?; + Ok(()) + } + + + fn skim(&mut self, _to: AccountId) -> Result<(), UniswapV2Errors> { + let state = *self.data::(); + let this = Self::env().account_id(); + let (token_0, token_1) = (state.token_0, state.token_1); + let balance0 = PSP22Ref::balance_of(&token_0, this); + let balance1 = PSP22Ref::balance_of(&token_1, this); + let amount0 = balance0 - state.reserve_0; + let amount1 = balance1 - state.reserve_1; + + if amount0 > 0 { + PSP22Ref::transfer(&token_0, _to, amount0, Vec::::new())?; + } + + if amount1 > 0 { + PSP22Ref::transfer(&token_1, _to, amount1, Vec::::new())?; + } + + Ok(()) + } + + + fn sync(&mut self) -> Result<(), UniswapV2Errors> { + let state = *self.data::(); + let (token_0, token_1) = (state.token_0, state.token_1); + let balance0 = PSP22Ref::balance_of(&token_0, Self::env().account_id()); + let balance1 = PSP22Ref::balance_of(&token_1, Self::env().account_id()); + self.internal_update(balance0, balance1)?; + Ok(()) + } + + + + + + // ========================================= + // Internal Functions + // ========================================= + fn internal_transfer(&mut self, _token: AccountId, _to: AccountId, _value: u128) -> bool { + return PSP22Ref::transfer(&_token, _to, _value, Vec::::new()).is_ok(); + } + + fn internal_mint_fee(&mut self) -> Result { + let state = self.data::(); + let fee_to = Some(AccountId::from([1u8; 32])); // PSP22Ref::fee_to(&state.token_0); //TODO: fee_to + + let return_data = fee_to.is_some(); + + if return_data { + if state.k_last != 0 { + let root_k_pre = (state.reserve_0 as u128) * (state.reserve_1 as u128); + let root_k = internal_sqrt(root_k_pre); + let root_k_last = internal_sqrt(state.k_last); + + if root_k > root_k_last { + let numerator = self._total_supply() * (root_k - root_k_last); + let denominator = (root_k * 5) + root_k_last; + let liquidity = numerator / denominator; + if liquidity > 0 { + self._mint_to(fee_to.unwrap(), liquidity)?; + } + } + } + } + Ok(return_data) + } + + + + fn internal_update(&mut self, balance1: Balance, balance2: Balance) -> Result<(), UniswapV2Errors> { + let state = self.data::(); + let (reserve_0, reserve_1, block_timestamp_last) = (state.reserve_0, state.reserve_1, state.block_timestamp_last); + let time_elapsed = Self::env().block_timestamp() as u128 - block_timestamp_last; + + if time_elapsed > 0 && reserve_0 != 0 && reserve_1 != 0 { + state.price0_cumulative_last += (uq112x112decode(uq112x112encode(state.reserve_1), state.reserve_0)) * time_elapsed; + state.price1_cumulative_last += (uq112x112decode(uq112x112encode(state.reserve_0), state.reserve_1)) * time_elapsed; + } + + + state.reserve_0 = balance1; + state.reserve_1 = balance2; + state.block_timestamp_last = Self::env().block_timestamp() as u128; + + + // emit the sync event + Ok(()) + } + + +} + + + +fn internal_sqrt(_y: u128) -> u128 { + let d1 = FixedU128::from_inner(_y); + let d2 = FixedU128::sqrt(d1); + let d3 = *d2.encode_as(); + d3 +} + + +fn uq112x112encode(x: u128) -> u128 { + x * 2u128.pow(112) +} + +fn uq112x112decode(x: u128, y: u128) -> u128 { + x / y +} \ No newline at end of file diff --git a/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/mod.rs b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/mod.rs new file mode 100644 index 00000000..770cc004 --- /dev/null +++ b/ink-awesome-defi/uniswap-v2-core-ink/contracts/providers/mod.rs @@ -0,0 +1,3 @@ +pub mod data; +pub mod deployables; +pub mod common; \ No newline at end of file