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

Added custom proxy for Builtin Function Calls #50

Open
wants to merge 1 commit into
base: feat/enshrine-esdt
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions enshrine-esdt-safe/src/custom_builtin_func_proxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
use multiversx_sc::{codec::Empty, proxy_imports::TopEncode, types::{BigUint, ManagedAddress, ManagedBuffer, ManagedVec, NotPayable, ProxyArg, TokenIdentifier, Tx, TxEnv, TxFrom, TxGas, TxTo, TxTypedCall, TxProxyTrait}};

use super::builtin_func_names::{
CHANGE_OWNER_BUILTIN_FUNC_NAME, CLAIM_DEVELOPER_REWARDS_FUNC_NAME, DELETE_USERNAME_FUNC_NAME,
ESDT_LOCAL_BURN_FUNC_NAME, ESDT_LOCAL_MINT_FUNC_NAME, ESDT_NFT_ADD_QUANTITY_FUNC_NAME,
ESDT_NFT_ADD_URI_FUNC_NAME, ESDT_NFT_BURN_FUNC_NAME, ESDT_NFT_CREATE_FUNC_NAME,
ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME, SET_USERNAME_FUNC_NAME,
};

/// Proxy describing the user builtin function signatures.
pub struct UserBuiltinProxy;

impl<Env, From, To, Gas> TxProxyTrait<Env, From, To, Gas> for UserBuiltinProxy
where
Env: TxEnv,
From: TxFrom<Env>,
To: TxTo<Env>,
Gas: TxGas<Env>,
{
type TxProxyMethods = UserBuiltinProxyMethods<Env, From, To, Gas>;

fn proxy_methods(self, tx: Tx<Env, From, To, (), Gas, (), ()>) -> Self::TxProxyMethods {
UserBuiltinProxyMethods { wrapped_tx: tx }
}
}

pub struct UserBuiltinProxyMethods<Env, From, To, Gas>
where
Env: TxEnv,
From: TxFrom<Env>,
To: TxTo<Env>,
Gas: TxGas<Env>,
{
wrapped_tx: Tx<Env, From, To, (), Gas, (), ()>,
}

impl<Env, From, To, Gas> UserBuiltinProxyMethods<Env, From, To, Gas>
where
Env: TxEnv,
From: TxFrom<Env>,
To: TxTo<Env>,
Gas: TxGas<Env>,
{
pub fn set_user_name<Arg0: ProxyArg<ManagedBuffer<Env::Api>>>(
self,
name: Arg0,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call(SET_USERNAME_FUNC_NAME)
.argument(&name)
.original_result()
}

pub fn delete_user_name(self) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call(DELETE_USERNAME_FUNC_NAME)
.original_result()
}

pub fn claim_developer_rewards(self) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call(CLAIM_DEVELOPER_REWARDS_FUNC_NAME)
.original_result()
}

pub fn change_owner_address(
self,
new_owner: &ManagedAddress<Env::Api>,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call(CHANGE_OWNER_BUILTIN_FUNC_NAME)
.argument(new_owner)
.original_result()
}

pub fn esdt_local_burn(
self,
token: &TokenIdentifier<Env::Api>,
nonce: u64,
amount: &BigUint<Env::Api>
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
if nonce == 0 {
return self
.wrapped_tx
.payment(NotPayable)
.raw_call(ESDT_LOCAL_BURN_FUNC_NAME)
.argument(token)
.argument(amount)
.original_result();
}

self.wrapped_tx
.payment(NotPayable)
.raw_call(ESDT_NFT_BURN_FUNC_NAME)
.argument(token)
.argument(&nonce)
.argument(amount)
.original_result()
}

pub fn esdt_local_mint(
self,
token: &TokenIdentifier<Env::Api>,
nonce: u64,
amount: &BigUint<Env::Api>,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
if nonce == 0 {
return self
.wrapped_tx
.payment(NotPayable)
.raw_call(ESDT_LOCAL_MINT_FUNC_NAME)
.argument(token)
.argument(amount)
.original_result();
}
self.wrapped_tx
.payment(NotPayable)
.raw_call(ESDT_NFT_ADD_QUANTITY_FUNC_NAME)
.argument(token)
.argument(&nonce)
.argument(amount)
.original_result()
}

pub fn nft_add_multiple_uri(
self,
token_id: &TokenIdentifier<Env::Api>,
nft_nonce: u64,
new_uris: &ManagedVec<Env::Api, ManagedBuffer<Env::Api>>,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
let mut tx = self
.wrapped_tx
.payment(NotPayable)
.raw_call(ESDT_NFT_ADD_URI_FUNC_NAME)
.argument(token_id)
.argument(&nft_nonce);

for uri in new_uris {
tx = tx.argument(&uri);
}

tx.original_result()
}

pub fn nft_update_attributes<T: TopEncode>(
self,
token_id: &TokenIdentifier<Env::Api>,
nft_nonce: u64,
new_attributes: &T,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call(ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME)
.argument(token_id)
.argument(&nft_nonce)
.argument(new_attributes)
.original_result()
}

#[allow(clippy::too_many_arguments)]
pub fn esdt_nft_create<T: TopEncode>(
self,
token: &TokenIdentifier<Env::Api>,
amount: &BigUint<Env::Api>,
name: &ManagedBuffer<Env::Api>,
royalties: &BigUint<Env::Api>,
hash: &ManagedBuffer<Env::Api>,
attributes: &T,
uris: &ManagedVec<Env::Api, ManagedBuffer<Env::Api>>,
nonce: &u64,
creator: &ManagedAddress<Env::Api>
) -> TxTypedCall<Env, From, To, NotPayable, Gas, u64> {
let mut tx = self
.wrapped_tx
.payment(NotPayable)
.raw_call(ESDT_NFT_CREATE_FUNC_NAME)
.argument(token)
.argument(amount)
.argument(name)
.argument(royalties)
.argument(hash)
.argument(attributes)
.argument(nonce)
.argument(creator);

if uris.is_empty() {
// at least one URI is required, so we push an empty one
tx = tx.argument(&Empty);
} else {
// The API function has the last argument as variadic,
// so we top-encode each and send as separate argument
for uri in uris {
tx = tx.argument(&uri);
}
}

tx.original_result()
}
}
49 changes: 38 additions & 11 deletions enshrine-esdt-safe/src/from_sovereign/transfer_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ use transaction::{
BatchId, GasLimit, Operation, OperationData, OperationEsdtPayment, OperationTuple,
};

use crate::to_sovereign;
use crate::{
custom_builtin_func_proxy,
to_sovereign::{self, create_tx::ESDT_SYSTEM_SC_ADDRESS},
};

use super::token_mapping::EsdtTokenInfo;

pub const ESDT_NFT_CREATE_FUNC_NAME: &str = "ESDTNFTCreate";

multiversx_sc::imports!();

const CALLBACK_GAS: GasLimit = 10_000_000; // Increase if not enough
Expand Down Expand Up @@ -51,6 +56,25 @@ pub trait TransferTokensModule:
self.distribute_payments(hash_of_hashes, operation_tuple, minted_operation_tokens);
}

fn call_system_sc_nft_create(&self, operation_token: &OperationEsdtPayment<Self::Api>) -> u64 {
self.tx()
.to(ManagedAddress::from(ESDT_SYSTEM_SC_ADDRESS))
.typed(custom_builtin_func_proxy::UserBuiltinProxy)
.esdt_nft_create(
&operation_token.token_identifier,
&operation_token.token_data.amount,
&operation_token.token_data.name,
&operation_token.token_data.royalties,
&operation_token.token_data.hash,
&operation_token.token_data.attributes,
&operation_token.token_data.uris,
&operation_token.token_nonce,
&operation_token.token_data.creator,
)
.returns(ReturnsResult)
.sync_call()
}

fn mint_tokens(
&self,
operation_tokens: &ManagedVec<OperationEsdtPayment<Self::Api>>,
Expand All @@ -71,15 +95,17 @@ pub trait TransferTokensModule:
&operation_token.token_data.amount,
);
} else {
nonce = self.send().esdt_nft_create(
&operation_token.token_identifier,
&operation_token.token_data.amount,
&operation_token.token_data.name,
&operation_token.token_data.royalties,
&operation_token.token_data.hash,
&operation_token.token_data.attributes,
&operation_token.token_data.uris,
);
nonce = self.call_system_sc_nft_create(&operation_token);

// nonce = self.send().esdt_nft_create(
// &operation_token.token_identifier,
// &operation_token.token_data.amount,
// &operation_token.token_data.name,
// &operation_token.token_data.royalties,
// &operation_token.token_data.hash,
// &operation_token.token_data.attributes,
// &operation_token.token_data.uris,
// );

// let token_data = operation_token.token_data.clone();
// let mut arg_buffer = ManagedArgBuffer::new();
Expand Down Expand Up @@ -245,7 +271,8 @@ pub trait TransferTokensModule:
let caller = self.blockchain().get_caller();
let header_verifier_address = self.header_verifier_address().get();

let _ = self.tx()
let _ = self
.tx()
.from(caller)
.to(header_verifier_address)
.typed(header_verifier_proxy::HeaderverifierProxy)
Expand Down
1 change: 1 addition & 0 deletions enshrine-esdt-safe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const DEFAULT_MAX_USER_TX_GAS_LIMIT: GasLimit = 300_000_000;
pub mod from_sovereign;
pub mod to_sovereign;
pub mod enshrine_esdt_safe_proxy;
pub mod custom_builtin_func_proxy;

#[multiversx_sc::contract]
pub trait EnshrineEsdtSafe:
Expand Down
Loading