Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audit fixing #68

Merged
merged 10 commits into from
May 26, 2021
5 changes: 5 additions & 0 deletions dex/elrond_dex_farm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]
#![allow(non_snake_case)]
#![allow(clippy::too_many_arguments)]

elrond_wasm::imports!();
elrond_wasm::derive_imports!();
Expand Down Expand Up @@ -233,6 +234,7 @@ pub trait Farm: rewards::RewardsModule + config::ConfigModule {
&mut reward,
&caller,
farm_attributes.with_locked_rewards,
farm_attributes.entering_epoch,
&opt_accept_funds_func,
)?;

Expand Down Expand Up @@ -305,6 +307,7 @@ pub trait Farm: rewards::RewardsModule + config::ConfigModule {
&mut reward,
&caller,
farm_attributes.with_locked_rewards,
farm_attributes.entering_epoch,
&opt_accept_funds_func,
)?;

Expand Down Expand Up @@ -355,6 +358,7 @@ pub trait Farm: rewards::RewardsModule + config::ConfigModule {
reward_amount: &mut Self::BigUint,
destination: &Address,
with_locked_rewards: bool,
entering_epoch: Epoch,
opt_accept_funds_func: &OptionalArg<BoxedBytes>,
) -> SCResult<()> {
if reward_amount > &mut 0 {
Expand All @@ -370,6 +374,7 @@ pub trait Farm: rewards::RewardsModule + config::ConfigModule {
.create_and_forward(
reward_amount.clone(),
destination.clone(),
entering_epoch,
opt_accept_funds_func.clone(),
)
.execute_on_dest_context_custom_range(
Expand Down
1 change: 0 additions & 1 deletion dex/elrond_dex_router/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ pub trait Router: factory::FactoryModule {
#[payment] returned_tokens: Self::BigUint,
#[call_result] result: AsyncCallResult<()>,
) {
// let (returned_tokens, token_id) = self.call_value().payment_token_pair();
match result {
AsyncCallResult::Ok(()) => {
self.pair_temporary_owner().remove(&address);
Expand Down
2 changes: 1 addition & 1 deletion distribution/distrib-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct CommunityDistribution<BigUint: BigUintApi> {
pub unlock_milestones: Vec<UnlockMilestone>,
}

#[derive(TopEncode, TopDecode, TypeAbi)]
#[derive(TopEncode, TopDecode, Clone, TypeAbi)]
pub struct LockedTokenAttributes {
pub unlock_milestones: Vec<UnlockMilestone>,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
"from": "address:owner",
"to": "sc:locked_asset_factory",
"value": "0",
"function": "cleanupUnusedTokens",
"arguments": [],
"function": "invalidateCache",
"arguments": [
"0",
"100"
],
"gasLimit": "100,000,000",
"gasPrice": "0"
},
Expand Down

This file was deleted.

43 changes: 33 additions & 10 deletions distribution/sc-proxy-dex/src/proxy_farm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,40 @@ pub trait ProxyFarmModule: proxy_common::ProxyCommonModule + proxy_pair::ProxyPa

#[payable("*")]
#[endpoint(enterFarmProxy)]
fn enter_farm_proxy_endpoint(&self, farm_address: Address) -> SCResult<()> {
self.enter_farm_proxy(farm_address, false)
fn enter_farm_proxy_endpoint(
&self,
#[payment_token] token_id: TokenIdentifier,
#[payment] amount: Self::BigUint,
farm_address: Address,
) -> SCResult<()> {
self.enter_farm_proxy(token_id, amount, farm_address, false)
}

#[payable("*")]
#[endpoint(enterFarmAndLockRewardsProxy)]
fn enter_farm_and_lock_rewards_proxy_endpoint(&self, farm_address: Address) -> SCResult<()> {
self.enter_farm_proxy(farm_address, true)
fn enter_farm_and_lock_rewards_proxy_endpoint(
&self,
#[payment_token] token_id: TokenIdentifier,
#[payment] amount: Self::BigUint,
farm_address: Address,
) -> SCResult<()> {
self.enter_farm_proxy(token_id, amount, farm_address, true)
}

fn enter_farm_proxy(&self, farm_address: Address, with_lock_rewards: bool) -> SCResult<()> {
fn enter_farm_proxy(
&self,
token_id: TokenIdentifier,
amount: Self::BigUint,
farm_address: Address,
with_lock_rewards: bool,
) -> SCResult<()> {
self.require_is_intermediated_farm(&farm_address)?;
self.require_proxy_farm_params_not_empty()?;
self.require_wrapped_farm_token_id_not_empty()?;
self.require_wrapped_lp_token_id_not_empty()?;
let proxy_params = self.proxy_farm_params().get();

let token_nonce = self.call_value().esdt_token_nonce();
let (amount, token_id) = self.call_value().payment_token_pair();
require!(amount != 0, "Payment amount cannot be zero");

let to_farm_token_id: TokenIdentifier;
Expand Down Expand Up @@ -131,15 +146,19 @@ pub trait ProxyFarmModule: proxy_common::ProxyCommonModule + proxy_pair::ProxyPa

#[payable("*")]
#[endpoint(exitFarmProxy)]
fn exit_farm_proxy(&self, farm_address: &Address) -> SCResult<()> {
fn exit_farm_proxy(
&self,
#[payment_token] token_id: TokenIdentifier,
#[payment] amount: Self::BigUint,
farm_address: &Address,
) -> SCResult<()> {
self.require_is_intermediated_farm(&farm_address)?;
self.require_proxy_farm_params_not_empty()?;
self.require_wrapped_farm_token_id_not_empty()?;
self.require_wrapped_lp_token_id_not_empty()?;
let proxy_params = self.proxy_farm_params().get();

let token_nonce = self.call_value().esdt_token_nonce();
let (amount, token_id) = self.call_value().payment_token_pair();
require!(amount != 0, "Payment amount cannot be zero");
require!(
token_id == self.wrapped_farm_token_id().get(),
Expand Down Expand Up @@ -212,15 +231,19 @@ pub trait ProxyFarmModule: proxy_common::ProxyCommonModule + proxy_pair::ProxyPa

#[payable("*")]
#[endpoint(claimRewardsProxy)]
fn claim_rewards_proxy(&self, farm_address: Address) -> SCResult<()> {
fn claim_rewards_proxy(
&self,
#[payment_token] token_id: TokenIdentifier,
#[payment] amount: Self::BigUint,
farm_address: Address,
) -> SCResult<()> {
self.require_is_intermediated_farm(&farm_address)?;
self.require_proxy_farm_params_not_empty()?;
self.require_wrapped_farm_token_id_not_empty()?;
self.require_wrapped_lp_token_id_not_empty()?;
let proxy_params = self.proxy_farm_params().get();

let token_nonce = self.call_value().esdt_token_nonce();
let (amount, token_id) = self.call_value().payment_token_pair();
require!(amount != 0, "Payment amount cannot be zero");
require!(
token_id == self.wrapped_farm_token_id().get(),
Expand Down
11 changes: 8 additions & 3 deletions distribution/sc-proxy-dex/src/proxy_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,15 @@ pub trait ProxyPairModule: proxy_common::ProxyCommonModule {

#[payable("*")]
#[endpoint(acceptEsdtPaymentProxy)]
fn accept_esdt_payment_proxy(&self, pair_address: Address) -> SCResult<()> {
fn accept_esdt_payment_proxy(
&self,
#[payment_token] token_id: TokenIdentifier,
#[payment] amount: Self::BigUint,
pair_address: Address,
) -> SCResult<()> {
self.require_is_intermediated_pair(&pair_address)?;

let token_nonce = self.call_value().esdt_token_nonce();
let (amount, token_id) = self.call_value().payment_token_pair();
require!(amount != 0, "Payment amount cannot be zero");

let caller = self.blockchain().get_caller();
Expand Down Expand Up @@ -277,6 +281,8 @@ pub trait ProxyPairModule: proxy_common::ProxyCommonModule {
#[endpoint(removeLiquidityProxy)]
fn remove_liquidity_proxy(
&self,
#[payment_token] token_id: TokenIdentifier,
#[payment] amount: Self::BigUint,
pair_address: Address,
first_token_amount_min: Self::BigUint,
second_token_amount_min: Self::BigUint,
Expand All @@ -288,7 +294,6 @@ pub trait ProxyPairModule: proxy_common::ProxyCommonModule {

let token_nonce = self.call_value().esdt_token_nonce();
require!(token_nonce != 0, "Can only be called with an SFT");
let (amount, token_id) = self.call_value().payment_token_pair();
require!(amount != 0, "Payment amount cannot be zero");

let wrapped_lp_token_id = self.wrapped_lp_token_id().get();
Expand Down
81 changes: 35 additions & 46 deletions sc-locked-asset-factory/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ elrond_wasm::imports!();
elrond_wasm::derive_imports!();

type Nonce = u64;
type Epoch = u64;

use super::locked_asset;
use distrib_common::*;
Expand All @@ -13,75 +12,65 @@ const GAS_LEFT_THRESHOLD: u64 = 5000000;

#[elrond_wasm_derive::module]
pub trait CacheModule: asset::AssetModule + locked_asset::LockedAssetModule {
#[inline(always)]
fn get_cached_sft_nonce_for_attributes(
&self,
attributes: &LockedTokenAttributes,
) -> Option<Nonce> {
let current_epoch = self.blockchain().get_block_epoch();
let cache_epoch = self.cache_epoch().get();

if current_epoch != cache_epoch {
self.cache_epoch().set(&current_epoch);
self.cached_attributes_to_sft_nonce_map().clear();
None
} else {
self.cached_attributes_to_sft_nonce_map().get(attributes)
}
self.cached_attributes_to_sft_nonce_map().get(attributes)
}

#[inline(always)]
fn cache_attributes_and_nonce(&self, attributes: LockedTokenAttributes, nonce: Nonce) {
if self.cached_attributes_to_sft_nonce_map().is_empty() {
self.first_cached_sft_nonce().set(&nonce);
}

self.cached_attributes_to_sft_nonce_map()
.insert(attributes, nonce);
}

#[endpoint(cleanupUnusedTokens)]
fn cleanup_unused_tokens(&self) -> SCResult<u64> {
#[endpoint(invalidateCache)]
fn invalidate_cache(&self, min_nonce: Nonce, max_nonce: Nonce) -> SCResult<u64> {
only_owner!(self, "Permission denied");
let last_burned_sft_nonce_initial = self.last_burned_sft_nonce().get();
let locked_asset_token_id = self.locked_asset_token_id().get();
let mut last_burned_sft_nonce = last_burned_sft_nonce_initial;
let amount_to_burn = Self::BigUint::from(AMOUNT_TO_BURN);
let current_epoch = self.blockchain().get_block_epoch();
let cache_epoch = self.cache_epoch().get();
require!(min_nonce <= max_nonce, "Bad arguments");
let gas_reserved_for_search = self.blockchain().get_gas_left() / 3;

let limit_nonce_to_burn = if cache_epoch == current_epoch {
self.first_cached_sft_nonce().get()
} else {
self.locked_asset_token_nonce().get() + 1
};
let mut to_invalidate = Vec::new();
for attr in self.cached_attributes_to_sft_nonce_map().keys() {
if self.blockchain().get_gas_left() < gas_reserved_for_search {
break;
}

for nonce in last_burned_sft_nonce + 1..limit_nonce_to_burn {
let gas_left = self.blockchain().get_gas_left();
let nonce = self
.cached_attributes_to_sft_nonce_map()
.get(&attr)
.unwrap();
if nonce <= max_nonce && nonce >= min_nonce {
to_invalidate.push((attr.clone(), nonce));
}
}

if gas_left < GAS_LEFT_THRESHOLD {
let amount_to_burn = Self::BigUint::from(AMOUNT_TO_BURN);
let token_id = self.locked_asset_token_id().get();

let mut invalidated_entries = 0;
for entry in to_invalidate.iter() {
if self.blockchain().get_gas_left() < GAS_LEFT_THRESHOLD {
break;
}
self.burn_locked_assets(&locked_asset_token_id, &amount_to_burn, nonce);
last_burned_sft_nonce = nonce;
}

if last_burned_sft_nonce != last_burned_sft_nonce_initial {
self.last_burned_sft_nonce().set(&last_burned_sft_nonce);
invalidated_entries += 1;
self.cached_attributes_to_sft_nonce_map().remove(&entry.0);
self.burn_locked_assets(&token_id, &&amount_to_burn, entry.1)
}

Ok(last_burned_sft_nonce - last_burned_sft_nonce_initial)
Ok(invalidated_entries)
}

#[view(getCacheSize)]
fn get_cache_size(&self) -> usize {
self.cached_attributes_to_sft_nonce_map().len()
}

#[storage_mapper("cached_attributes_to_sft_nonce_map")]
fn cached_attributes_to_sft_nonce_map(
&self,
) -> MapMapper<Self::Storage, LockedTokenAttributes, Nonce>;

#[storage_mapper("cache_epoch")]
fn cache_epoch(&self) -> SingleValueMapper<Self::Storage, Epoch>;

#[storage_mapper("last_burned_sft_nonce")]
fn last_burned_sft_nonce(&self) -> SingleValueMapper<Self::Storage, Nonce>;

#[storage_mapper("first_cached_sft_nonce")]
fn first_cached_sft_nonce(&self) -> SingleValueMapper<Self::Storage, Nonce>;
}
Loading