Skip to content

Commit

Permalink
Merge pull request #65 from multiversx/wegld-fee
Browse files Browse the repository at this point in the history
Wegld fee
  • Loading branch information
andreiblt1304 committed Jul 12, 2024
2 parents 332b5f6 + 4b92c04 commit c02420b
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 27 deletions.
10 changes: 10 additions & 0 deletions common/transaction/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ impl<M: ManagedTypeApi> From<OperationEsdtPayment<M>> for EsdtTokenPayment<M> {
}
}

impl<M: ManagedTypeApi> Default for OperationEsdtPayment<M> {
fn default() -> Self {
OperationEsdtPayment {
token_identifier: TokenIdentifier::from(ManagedBuffer::new()),
token_nonce: 0,
token_data: StolenFromFrameworkEsdtTokenData::default(),
}
}
}

// Temporary until Clone is implemented for EsdtTokenData
#[derive(
TopDecode, TopEncode, NestedDecode, NestedEncode, TypeAbi, Debug, ManagedVecItem, Clone,
Expand Down
29 changes: 25 additions & 4 deletions common/utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ multiversx_sc::imports!();
pub type PaymentsVec<M> = ManagedVec<M, EsdtTokenPayment<M>>;

static ERR_EMPTY_PAYMENTS: &[u8] = b"No payments";
const DASH: u8 = b'-';
const MAX_TOKEN_ID_LEN: usize = 32;

#[multiversx_sc::module]
pub trait UtilsModule: bls_signature::BlsSignatureModule {
Expand Down Expand Up @@ -66,18 +68,37 @@ pub trait UtilsModule: bls_signature::BlsSignatureModule {
list
}

fn has_sov_token_prefix(&self, token_id: &TokenIdentifier) -> bool {
let dash = b'-';
fn has_prefix(&self, token_id: &TokenIdentifier) -> bool {
let buffer = token_id.as_managed_buffer();
let mut array_buffer = [0u8; 32];
let mut array_buffer = [0u8; MAX_TOKEN_ID_LEN];
let slice = buffer.load_to_byte_array(&mut array_buffer);

let counter = slice.iter().filter(|&&c| c == dash).count();
let counter = slice.iter().filter(|&&c| c == DASH).count();

if counter == 2 {
return true;
}

false
}

fn has_sov_prefix(&self, token_id: &TokenIdentifier, chain_prefix: ManagedBuffer) -> bool {
if !self.has_prefix(token_id) {
return false;
}

let buffer = token_id.as_managed_buffer();
let mut array_buffer = [0u8; MAX_TOKEN_ID_LEN];
let slice = buffer.load_to_byte_array(&mut array_buffer);

if let Some(index) = slice.iter().position(|&b| b == DASH) {
let prefix = ManagedBuffer::from(&slice[..index]);

if prefix == chain_prefix {
return true;
}
}

false
}
}
6 changes: 6 additions & 0 deletions enshrine-esdt-safe/src/common/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ use multiversx_sc::imports::*;
pub trait CommonStorage {
#[storage_mapper("isSovereignChain")]
fn is_sovereign_chain(&self) -> SingleValueMapper<bool>;

#[storage_mapper("wegldIdentifier")]
fn wegld_identifier(&self) -> SingleValueMapper<TokenIdentifier>;

#[storage_mapper("sovereignTokensPrefix")]
fn sovereign_tokens_prefix(&self) -> SingleValueMapper<ManagedBuffer>;
}
18 changes: 18 additions & 0 deletions enshrine-esdt-safe/src/enshrine_esdt_safe_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,20 @@ where
{
pub fn init<
Arg0: ProxyArg<bool>,
Arg1: ProxyArg<Option<TokenIdentifier<Env::Api>>>,
Arg2: ProxyArg<Option<ManagedBuffer<Env::Api>>>,
>(
self,
is_sovereign_chain: Arg0,
opt_wegld_identifier: Arg1,
opt_sov_token_prefix: Arg2,
) -> TxTypedDeploy<Env, From, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_deploy()
.argument(&is_sovereign_chain)
.argument(&opt_wegld_identifier)
.argument(&opt_sov_token_prefix)
.original_result()
}
}
Expand Down Expand Up @@ -181,6 +187,18 @@ where
.original_result()
}

pub fn register_new_token_id<
Arg0: ProxyArg<MultiValueEncoded<Env::Api, TokenIdentifier<Env::Api>>>,
>(
self,
tokens: Arg0,
) -> TxTypedCall<Env, From, To, (), Gas, ()> {
self.wrapped_tx
.raw_call("registerNewTokenID")
.argument(&tokens)
.original_result()
}

pub fn set_max_tx_batch_size<
Arg0: ProxyArg<usize>,
>(
Expand Down
114 changes: 100 additions & 14 deletions enshrine-esdt-safe/src/from_sovereign/transfer_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use transaction::{GasLimit, Operation, OperationData, OperationEsdtPayment, Oper

const CALLBACK_GAS: GasLimit = 10_000_000; // Increase if not enough
const TRANSACTION_GAS: GasLimit = 30_000_000;
const DEFAULT_ISSUE_COST: u64 = 50000000000000000;

#[multiversx_sc::module]
pub trait TransferTokensModule:
Expand All @@ -22,8 +23,10 @@ pub trait TransferTokensModule:
{
#[endpoint(executeBridgeOps)]
fn execute_operations(&self, hash_of_hashes: ManagedBuffer, operation: Operation<Self::Api>) {
let is_sovereign_chain = self.is_sovereign_chain().get();

require!(
!self.is_sovereign_chain().get(),
!is_sovereign_chain,
"Invalid method to call in current chain"
);

Expand All @@ -36,13 +39,70 @@ pub trait TransferTokensModule:
sc_panic!("Operation is not registered");
}

let are_tokens_registered =
self.verify_operation_tokens_issue_paid(operation.tokens.clone());

if !are_tokens_registered {
self.emit_transfer_failed_events(
&hash_of_hashes,
&OperationTuple {
op_hash: operation_hash.clone(),
operation: operation.clone(),
},
);

return;
}

let minted_operation_tokens = self.mint_tokens(&operation.tokens);
let operation_tuple = OperationTuple {
op_hash: operation_hash,
operation,
op_hash: operation_hash.clone(),
operation: operation.clone(),
};

self.distribute_payments(hash_of_hashes, operation_tuple, minted_operation_tokens);
self.distribute_payments(
hash_of_hashes.clone(),
operation_tuple,
minted_operation_tokens,
);
}

#[endpoint(registerNewTokenID)]
#[payable("*")]
fn register_new_token_id(&self, tokens: MultiValueEncoded<TokenIdentifier>) {
let call_payment = self.call_value().single_esdt().clone();
let wegld_identifier = self.wegld_identifier().get();

require!(
call_payment.token_identifier == wegld_identifier,
"WEGLD is the only token accepted as register fee"
);

require!(
call_payment.amount == DEFAULT_ISSUE_COST * tokens.len() as u64,
"WEGLD fee amount is not met"
);

for token_id in tokens {
self.register_token(token_id);
}
}

fn verify_operation_tokens_issue_paid(
&self,
tokens: ManagedVec<OperationEsdtPayment<Self::Api>>,
) -> bool {
for token in tokens.iter() {
if !self.has_sov_prefix(&token.token_identifier, self.get_sovereign_prefix()) {
continue;
}

if !self.paid_issued_tokens().contains(&token.token_identifier) {
return false;
}
}

true
}

fn mint_tokens(
Expand All @@ -52,7 +112,8 @@ pub trait TransferTokensModule:
let mut output_payments = ManagedVec::new();

for operation_token in operation_tokens.iter() {
if !self.has_sov_token_prefix(&operation_token.token_identifier) {
let sov_prefix = self.get_sovereign_prefix();
if !self.has_sov_prefix(&operation_token.token_identifier, sov_prefix) {
output_payments.push(operation_token.clone());
continue;
}
Expand Down Expand Up @@ -113,7 +174,6 @@ pub trait TransferTokensModule:

output_payments
}

fn distribute_payments(
&self,
hash_of_hashes: ManagedBuffer,
Expand Down Expand Up @@ -195,6 +255,7 @@ pub trait TransferTokensModule:
);
}
ManagedAsyncCallResult::Err(_) => {
self.burn_sovereign_tokens(&operation_tuple.operation);
self.emit_transfer_failed_events(hash_of_hashes, operation_tuple);
}
}
Expand All @@ -208,6 +269,21 @@ pub trait TransferTokensModule:
.sync_call();
}

fn burn_sovereign_tokens(&self, operation: &Operation<Self::Api>) {
for token in operation.tokens.iter() {
let sov_prefix = self.get_sovereign_prefix();
if !self.has_sov_prefix(&token.token_identifier, sov_prefix) {
continue;
}

self.send().esdt_local_burn(
&token.token_identifier,
token.token_nonce,
&token.token_data.amount,
);
}
}

fn emit_transfer_failed_events(
&self,
hash_of_hashes: &ManagedBuffer,
Expand All @@ -218,14 +294,6 @@ pub trait TransferTokensModule:
operation_tuple.op_hash.clone(),
);

for operation_token in &operation_tuple.operation.tokens {
self.send().esdt_local_burn(
&operation_token.token_identifier,
operation_token.token_nonce,
&operation_token.token_data.amount,
);
}

// deposit back mainchain tokens into user account
let sc_address = self.blockchain().get_sc_address();
let tx_nonce = self.get_and_save_next_tx_id();
Expand Down Expand Up @@ -268,9 +336,27 @@ pub trait TransferTokensModule:
}
}

#[inline]
fn get_sovereign_prefix(&self) -> ManagedBuffer {
self.sovereign_tokens_prefix().get()
}

#[inline]
fn register_token(&self, token_id: TokenIdentifier<Self::Api>) {
self.paid_issued_tokens().insert(token_id);
}

#[inline]
fn is_wegld(&self, token_id: &TokenIdentifier<Self::Api>) -> bool {
token_id.eq(&self.wegld_identifier().get())
}

#[storage_mapper("pending_hashes")]
fn pending_hashes(&self, hash_of_hashes: &ManagedBuffer) -> UnorderedSetMapper<ManagedBuffer>;

#[storage_mapper("header_verifier_address")]
fn header_verifier_address(&self) -> SingleValueMapper<ManagedAddress>;

#[storage_mapper("mintedTokens")]
fn paid_issued_tokens(&self) -> UnorderedSetMapper<TokenIdentifier<Self::Api>>;
}
29 changes: 28 additions & 1 deletion enshrine-esdt-safe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,36 @@ pub trait EnshrineEsdtSafe:
+ common::storage::CommonStorage
{
#[init]
fn init(&self, is_sovereign_chain: bool) {
fn init(
&self,
is_sovereign_chain: bool,
opt_wegld_identifier: Option<TokenIdentifier>,
opt_sov_token_prefix: Option<ManagedBuffer>,
) {
self.is_sovereign_chain().set(is_sovereign_chain);
self.set_paused(true);

if is_sovereign_chain {
return;
}

match opt_wegld_identifier {
Some(identifier) => {
require!(
identifier.is_valid_esdt_identifier(),
"Sent Identifier is not valid"
);

self.wegld_identifier().set(identifier);
}

None => sc_panic!("WEGLG identifier must be set in Mainchain"),
}

match opt_sov_token_prefix {
Some(prefix) => self.sovereign_tokens_prefix().set(prefix),
None => sc_panic!("Sovereign Token Prefix must be set in Mainchain"),
}
}

#[only_owner]
Expand Down
4 changes: 1 addition & 3 deletions enshrine-esdt-safe/src/to_sovereign/create_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ pub trait CreateTxModule:

current_token_data.amount = payment.amount.clone();

if self.is_sovereign_chain().get()
|| self.has_sov_token_prefix(&payment.token_identifier)
{
if self.is_sovereign_chain().get() || self.has_prefix(&payment.token_identifier) {
self.send().esdt_local_burn(
&payment.token_identifier,
payment.token_nonce,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const RECEIVER_ADDRESS: TestAddress = TestAddress::new("receiver");

const NFT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("NFT-123456");
const FUNGIBLE_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("CROWD-123456");
const PREFIX_NFT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("SOV-NFT-123456");
const PREFIX_NFT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("sov-NFT-123456");

fn world() -> ScenarioWorld {
let mut blockchain = ScenarioWorld::new();
Expand Down
5 changes: 3 additions & 2 deletions enshrine-esdt-safe/wasm-enshrine-esdt-safe-full/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

// Init: 1
// Upgrade: 1
// Endpoints: 27
// Endpoints: 28
// Async Callback: 1
// Promise callbacks: 1
// Total number of exported functions: 31
// Total number of exported functions: 32

#![no_std]

Expand All @@ -28,6 +28,7 @@ multiversx_sc_wasm_adapter::endpoints! {
addSigners => add_signers
removeSigners => remove_signers
executeBridgeOps => execute_operations
registerNewTokenID => register_new_token_id
setMaxTxBatchSize => set_max_tx_batch_size
setMaxTxBatchBlockDuration => set_max_tx_batch_block_duration
getCurrentTxBatch => get_current_tx_batch
Expand Down
Loading

0 comments on commit c02420b

Please sign in to comment.