Skip to content

Commit

Permalink
Proxy dex legacy contract
Browse files Browse the repository at this point in the history
  • Loading branch information
psorinionut committed Jul 16, 2024
1 parent c061a85 commit d291936
Show file tree
Hide file tree
Showing 22 changed files with 1,712 additions and 1 deletion.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ members = [
"legacy-contracts/farm-staking-proxy-v-13/meta",
"legacy-contracts/farm-v-13",
"legacy-contracts/farm-v-13/meta",
"legacy-contracts/proxy-dex-legacy",
"legacy-contracts/proxy-dex-legacy/meta",

"locked-asset/",
"locked-asset/distribution",
Expand Down
7 changes: 7 additions & 0 deletions legacy-contracts/proxy-dex-legacy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
*/target/

# The erdpy output
output
24 changes: 24 additions & 0 deletions legacy-contracts/proxy-dex-legacy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "proxy-dex-legacy"
version = "0.0.0"
edition = "2018"
publish = false

[lib]
path = "src/lib.rs"

[dependencies.multiversx-sc]
version = "=0.50.5"
features = ["esdt-token-payment-legacy-decode"]

[dev-dependencies.multiversx-sc-scenario]
version = "=0.50.5"

[dependencies.common_structs]
path = "../../common/common_structs"

[dependencies.token_merge_helper]
path = "../../common/modules/token_merge_helper"

[dependencies.factory]
path = "../../locked-asset/factory"
24 changes: 24 additions & 0 deletions legacy-contracts/proxy-dex-legacy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# DEX Proxy Smart Contract

This document presents how one can deploy and configure a DEX Proxy Contract.
The bigger picture about what a DEX Proxy Contract can do can be found in the Repository's Root Readme.

## Deployment

The DEX Proxy contract can be deployed using `erdpy` and using the interraction snippets.

The init parameters are:

- asset_token_id. The TokenId of the asset that a locked asset represents. In case of Maiar Exchange it will be MEX.

- locked_asset_token_id. The TokenId of the locked asset represents. In case of Maiar Exchange it will be Locked MEX.

## Configuration workflow

1. In order to complete the setup of the dex proxy contracts, Wrapped LP Token and Wrapped Farm token must be issued via `issueSftProxyPair` and `issueSftProxyFarm`. After this, setLocalRoles has to be called once for each of the two tokens, using for address the Proxy Address itself.

2. In order to add a pair to intermediate, meaning a pair that is eligible to function with MEX, the admin should use `addPairToIntermediate` and `removeIntermediatedPair`.

3. In order to add a farm to intermediate, meaning a farm that is eligible to function with MEX or with Wrapped LP Tokens, the admin should use `addFarmToIntermediate` and `removeIntermediatedFarm`.

4. In order for the Setup to be complete, LocalMint + LocalBurn roles for MEX and NftBurn role for Locked MEX should be granted to the Proxy Contract.
14 changes: 14 additions & 0 deletions legacy-contracts/proxy-dex-legacy/meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "proxy-dex-legacy-meta"

version = "0.0.0"
authors = [ "you",]
edition = "2018"
publish = false

[dependencies.proxy-dex-legacy]
path = ".."

[dependencies.multiversx-sc-meta]
version = "0.50.5"
default-features = false
3 changes: 3 additions & 0 deletions legacy-contracts/proxy-dex-legacy/meta/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
multiversx_sc_meta::cli_main::<proxy_dex_legacy::AbiProvider>();
}
4 changes: 4 additions & 0 deletions legacy-contracts/proxy-dex-legacy/multiversx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"language": "rust"
}

109 changes: 109 additions & 0 deletions legacy-contracts/proxy-dex-legacy/src/energy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

use common_structs::Epoch;

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, PartialEq, Debug)]
pub struct Energy<M: ManagedTypeApi> {
amount: BigInt<M>,
last_update_epoch: Epoch,
total_locked_tokens: BigUint<M>,
}

impl<M: ManagedTypeApi> Default for Energy<M> {
fn default() -> Self {
Self {
amount: BigInt::zero(),
last_update_epoch: 0,
total_locked_tokens: BigUint::zero(),
}
}
}

impl<M: ManagedTypeApi> Energy<M> {
#[inline]
pub fn new(
amount: BigInt<M>,
last_update_epoch: Epoch,
total_locked_tokens: BigUint<M>,
) -> Self {
Energy {
amount,
last_update_epoch,
total_locked_tokens,
}
}

pub fn new_zero_energy(current_epoch: Epoch) -> Self {
Self::new(BigInt::zero(), current_epoch, BigUint::zero())
}

fn add(&mut self, future_epoch: Epoch, current_epoch: Epoch, amount_per_epoch: &BigUint<M>) {
if current_epoch >= future_epoch {
return;
}

let epochs_diff = future_epoch - current_epoch;
let energy_added = amount_per_epoch * epochs_diff;
self.amount += BigInt::from(energy_added);
}

fn subtract(&mut self, past_epoch: Epoch, current_epoch: Epoch, amount_per_epoch: &BigUint<M>) {
if past_epoch >= current_epoch {
return;
}

let epoch_diff = current_epoch - past_epoch;
let energy_decrease = amount_per_epoch * epoch_diff;
self.amount -= BigInt::from(energy_decrease);
}

pub fn deplete(&mut self, current_epoch: Epoch) {
if self.last_update_epoch == current_epoch {
return;
}

if self.total_locked_tokens > 0 {
self.subtract(
self.last_update_epoch,
current_epoch,
&self.total_locked_tokens.clone(),
);
}

self.last_update_epoch = current_epoch;
}

pub fn refund_after_token_unlock(
&mut self,
unlock_amount: &BigUint<M>,
unlock_epoch: Epoch,
current_epoch: Epoch,
) {
self.add(current_epoch, unlock_epoch, unlock_amount);
self.total_locked_tokens -= unlock_amount;
}

pub fn deplete_after_early_unlock(
&mut self,
unlock_amount: &BigUint<M>,
unlock_epoch: Epoch,
current_epoch: Epoch,
) {
self.subtract(current_epoch, unlock_epoch, unlock_amount);
self.total_locked_tokens -= unlock_amount;
}

pub fn update_after_unlock_any(
&mut self,
unlock_amount: &BigUint<M>,
unlock_epoch: Epoch,
current_epoch: Epoch,
) {
if unlock_epoch < current_epoch {
self.refund_after_token_unlock(unlock_amount, unlock_epoch, current_epoch);
} else {
self.deplete_after_early_unlock(unlock_amount, unlock_epoch, current_epoch);
}
}
}
135 changes: 135 additions & 0 deletions legacy-contracts/proxy-dex-legacy/src/energy_update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

use common_structs::LockedAssetTokenAttributesEx;
use factory::attr_ex_helper;

use crate::{energy::Energy, proxy_common};

static LEGACY_LOCKED_TOKEN_ID_STORAGE_KEY: &[u8] = b"legacyLockedTokenId";
static USER_ENERGY_STORAGE_KEY: &[u8] = b"userEnergy";
static EXTENDED_ATTRIBUTES_ACTIVATION_NONCE_KEY: &[u8] = b"extended_attributes_activation_nonce";

mod energy_factory_proxy {
multiversx_sc::imports!();
use crate::energy_update::Energy;

#[multiversx_sc::proxy]
pub trait LockedTokenTransferModule {
#[endpoint(setUserEnergyAfterLockedTokenTransfer)]
fn set_user_energy_after_locked_token_transfer(
&self,
user: ManagedAddress,
energy: Energy<Self::Api>,
);
}
}

#[multiversx_sc::module]
pub trait EnergyUpdateModule:
proxy_common::ProxyCommonModule + attr_ex_helper::AttrExHelper
{
#[only_owner]
#[endpoint(setEnergyFactoryAddress)]
fn set_energy_factory_address(&self, sc_address: ManagedAddress) {
require!(
self.blockchain().is_smart_contract(&sc_address),
"Invalid address"
);

self.energy_factory_address().set(&sc_address);
}

fn deduct_energy_from_user(
&self,
user: &ManagedAddress,
token_id: &TokenIdentifier,
token_nonce: u64,
token_amount: &BigUint,
) {
let energy_factory_addr = self.energy_factory_address().get();
let legacy_locked_token_id = self.get_legacy_locked_token_id(&energy_factory_addr);
if token_id != &legacy_locked_token_id {
return;
}

let mut energy = self.get_energy_entry(user);
let current_epoch = self.blockchain().get_block_epoch();
let attributes: LockedAssetTokenAttributesEx<Self::Api> =
self.get_attributes_ex(token_id, token_nonce);
let amounts_per_epoch = attributes.get_unlock_amounts_per_epoch(token_amount);
for epoch_amount_pair in &amounts_per_epoch.pairs {
energy.update_after_unlock_any(
&epoch_amount_pair.amount,
epoch_amount_pair.epoch,
current_epoch,
);
}

self.set_energy_in_factory(user.clone(), energy, energy_factory_addr);
}

fn set_energy_in_factory(
&self,
user: ManagedAddress,
energy: Energy<Self::Api>,
energy_factory_addr: ManagedAddress,
) {
let _: () = self
.energy_factory_proxy(energy_factory_addr)
.set_user_energy_after_locked_token_transfer(user, energy)
.execute_on_dest_context();
}

fn get_energy_entry(&self, user: &ManagedAddress) -> Energy<Self::Api> {
let current_epoch = self.blockchain().get_block_epoch();
if self.energy_factory_address().is_empty() {
return Energy::new_zero_energy(current_epoch);
}

let energy_buffer: ManagedBuffer = self.read_storage_from_energy_factory(user);
if !energy_buffer.is_empty() {
let mut user_energy: Energy<Self::Api> = Energy::top_decode(energy_buffer)
.unwrap_or_else(|_| sc_panic!("Failed decoding result from energy factory"));
user_energy.deplete(current_epoch);

user_energy
} else {
Energy::new_zero_energy(current_epoch)
}
}

fn read_storage_from_energy_factory<T: TopDecode>(&self, user: &ManagedAddress) -> T {
let energy_factory_address = self.energy_factory_address().get();
let mut key_buffer = ManagedBuffer::new_from_bytes(USER_ENERGY_STORAGE_KEY);
key_buffer.append(user.as_managed_buffer());

self.storage_raw()
.read_from_address(&energy_factory_address, key_buffer)
}

fn get_legacy_locked_token_id(&self, energy_factory_addr: &ManagedAddress) -> TokenIdentifier {
self.storage_raw().read_from_address(
energy_factory_addr,
ManagedBuffer::new_from_bytes(LEGACY_LOCKED_TOKEN_ID_STORAGE_KEY),
)
}

fn get_extended_attributes_activation_nonce(&self) -> u64 {
let sc_address = self.locked_asset_factory_address().get();
self.storage_raw().read_from_address(
&sc_address,
ManagedBuffer::new_from_bytes(EXTENDED_ATTRIBUTES_ACTIVATION_NONCE_KEY),
)
}

#[proxy]
fn energy_factory_proxy(
&self,
sc_address: ManagedAddress,
) -> energy_factory_proxy::Proxy<Self::Api>;

#[view(getEnergyFactoryAddress)]
#[storage_mapper("energyFactoryAddress")]
fn energy_factory_address(&self) -> SingleValueMapper<ManagedAddress>;
}
Loading

0 comments on commit d291936

Please sign in to comment.