use crate::{
api::{
BlockchainApi, ManagedTypeApi, SendApi, StorageReadApi, CHANGE_OWNER_BUILTIN_FUNC_NAME,
DCT_LOCAL_BURN_FUNC_NAME, DCT_LOCAL_MINT_FUNC_NAME, DCT_MULTI_TRANSFER_FUNC_NAME,
DCT_NFT_ADD_QUANTITY_FUNC_NAME, DCT_NFT_BURN_FUNC_NAME, DCT_NFT_CREATE_FUNC_NAME,
DCT_NFT_TRANSFER_FUNC_NAME, DCT_TRANSFER_FUNC_NAME,
},
dct::DCTSystemSmartContractProxy,
types::{
AsManagedRef, BigUint, ContractCall, DctTokenPayment, ManagedAddress, ManagedArgBuffer,
ManagedBuffer, ManagedInto, ManagedVec, TokenIdentifier,
},
};
use dharitri_codec::TopDecode;
const PERCENTAGE_TOTAL: u64 = 10_000;
pub struct SendWrapper<A>
where
A: SendApi + ManagedTypeApi + StorageReadApi + BlockchainApi,
{
pub(crate) api: A,
}
impl<A> SendWrapper<A>
where
A: SendApi + ManagedTypeApi + StorageReadApi + BlockchainApi,
{
fn type_manager(&self) -> A {
self.api.clone()
}
pub(crate) fn new(api: A) -> Self {
SendWrapper { api }
}
pub fn dct_system_sc_proxy(&self) -> DCTSystemSmartContractProxy<A> {
DCTSystemSmartContractProxy::new_proxy_obj(self.api.clone())
}
pub fn contract_call<R>(
&self,
to: ManagedAddress<A>,
endpoint_name: ManagedBuffer<A>,
) -> ContractCall<A, R> {
ContractCall::new(self.api.clone(), to, endpoint_name)
}
pub fn direct_moax<D>(&self, to: &ManagedAddress<A>, amount: &BigUint<A>, data: D)
where
D: ManagedInto<A, ManagedBuffer<A>>,
{
self.api.direct_moax(to, amount, data)
}
pub fn direct<D>(
&self,
to: &ManagedAddress<A>,
token: &TokenIdentifier<A>,
nonce: u64,
amount: &BigUint<A>,
data: D,
) where
D: ManagedInto<A, ManagedBuffer<A>>,
{
self.direct_with_gas_limit(to, token, nonce, amount, 0, data, &[]);
}
#[allow(clippy::too_many_arguments)]
fn direct_with_gas_limit<D>(
&self,
to: &ManagedAddress<A>,
token: &TokenIdentifier<A>,
nonce: u64,
amount: &BigUint<A>,
gas: u64,
endpoint_name: D,
arguments: &[ManagedBuffer<A>],
) where
D: ManagedInto<A, ManagedBuffer<A>>,
{
let endpoint_name_managed = endpoint_name.managed_into(self.type_manager());
let mut arg_buffer = ManagedArgBuffer::new_empty(self.type_manager());
for arg in arguments {
arg_buffer.push_arg(arg);
}
if token.is_moax() {
let _ =
self.api
.direct_moax_execute(to, amount, gas, &endpoint_name_managed, &arg_buffer);
} else if nonce == 0 {
let _ = self.api.direct_dct_execute(
to,
token,
amount,
gas,
&endpoint_name_managed,
&arg_buffer,
);
} else {
let _ = self.api.direct_dct_nft_execute(
to,
token,
nonce,
amount,
gas,
&endpoint_name_managed,
&arg_buffer,
);
}
}
pub fn transfer_dct_via_async_call<D>(
&self,
to: &ManagedAddress<A>,
token: &TokenIdentifier<A>,
nonce: u64,
amount: &BigUint<A>,
data: D,
) -> !
where
D: ManagedInto<A, ManagedBuffer<A>>,
{
let data_buf: ManagedBuffer<A> = data.managed_into(self.type_manager());
let mut arg_buffer = ManagedArgBuffer::new_empty(self.type_manager());
arg_buffer.push_arg(token);
if nonce == 0 {
arg_buffer.push_arg(amount);
if !data_buf.is_empty() {
arg_buffer.push_arg_raw(data_buf);
}
self.api.async_call_raw(
to,
&BigUint::zero(self.type_manager()),
&ManagedBuffer::new_from_bytes(self.type_manager(), DCT_TRANSFER_FUNC_NAME),
&arg_buffer,
)
} else {
arg_buffer.push_arg(nonce);
arg_buffer.push_arg(amount);
arg_buffer.push_arg(to);
if !data_buf.is_empty() {
arg_buffer.push_arg_raw(data_buf);
}
self.api.async_call_raw(
&self.api.get_sc_address(),
&BigUint::zero(self.type_manager()),
&ManagedBuffer::new_from_bytes(self.type_manager(), DCT_NFT_TRANSFER_FUNC_NAME),
&arg_buffer,
)
}
}
pub fn transfer_multiple_dct_via_async_call<D>(
&self,
to: &ManagedAddress<A>,
payments: &ManagedVec<A, DctTokenPayment<A>>,
data: D,
) -> !
where
D: ManagedInto<A, ManagedBuffer<A>>,
{
let mut arg_buffer = ManagedArgBuffer::new_empty(self.type_manager());
arg_buffer.push_arg(to);
arg_buffer.push_arg(payments.len());
for payment in payments.into_iter() {
arg_buffer.push_arg(payment.token_identifier);
arg_buffer.push_arg(payment.token_nonce);
arg_buffer.push_arg(payment.amount);
}
let data_buf: ManagedBuffer<A> = data.managed_into(self.type_manager());
if !data_buf.is_empty() {
arg_buffer.push_arg_raw(data_buf);
}
self.api.async_call_raw(
&self.api.get_sc_address(),
&BigUint::zero(self.type_manager()),
&ManagedBuffer::new_from_bytes(self.type_manager(), DCT_MULTI_TRANSFER_FUNC_NAME),
&arg_buffer,
);
}
pub fn change_owner_address(
&self,
child_sc_address: ManagedAddress<A>,
new_owner: &ManagedAddress<A>,
) -> ContractCall<A, ()> {
let mut contract_call = ContractCall::new(
self.api.clone(),
child_sc_address,
ManagedBuffer::new_from_bytes(self.type_manager(), CHANGE_OWNER_BUILTIN_FUNC_NAME),
);
contract_call.push_endpoint_arg(&new_owner);
contract_call
}
pub fn call_local_dct_built_in_function(
&self,
gas: u64,
endpoint_name: &ManagedBuffer<A>,
arg_buffer: &ManagedArgBuffer<A>,
) -> ManagedVec<A, ManagedBuffer<A>> {
self.api
.call_local_dct_built_in_function(gas, endpoint_name, arg_buffer)
}
pub fn dct_local_mint(&self, token: &TokenIdentifier<A>, nonce: u64, amount: &BigUint<A>) {
let mut arg_buffer = ManagedArgBuffer::new_empty(self.type_manager());
let func_name: &[u8];
arg_buffer.push_arg(token);
if nonce == 0 {
func_name = DCT_LOCAL_MINT_FUNC_NAME;
} else {
func_name = DCT_NFT_ADD_QUANTITY_FUNC_NAME;
arg_buffer.push_arg(nonce);
}
arg_buffer.push_arg(amount);
let _ = self.call_local_dct_built_in_function(
self.api.get_gas_left(),
&ManagedBuffer::new_from_bytes(self.type_manager(), func_name),
&arg_buffer,
);
}
pub fn dct_local_burn(&self, token: &TokenIdentifier<A>, nonce: u64, amount: &BigUint<A>) {
let mut arg_buffer = ManagedArgBuffer::new_empty(self.type_manager());
let func_name: &[u8];
arg_buffer.push_arg(token);
if nonce == 0 {
func_name = DCT_LOCAL_BURN_FUNC_NAME;
} else {
func_name = DCT_NFT_BURN_FUNC_NAME;
arg_buffer.push_arg(&nonce);
}
arg_buffer.push_arg(amount);
let _ = self.call_local_dct_built_in_function(
self.api.get_gas_left(),
&ManagedBuffer::new_from_bytes(self.type_manager(), func_name),
&arg_buffer,
);
}
#[allow(clippy::too_many_arguments)]
pub fn dct_nft_create<T: dharitri_codec::TopEncode>(
&self,
token: &TokenIdentifier<A>,
amount: &BigUint<A>,
name: &ManagedBuffer<A>,
royalties: &BigUint<A>,
hash: &ManagedBuffer<A>,
attributes: &T,
uris: &ManagedVec<A, ManagedBuffer<A>>,
) -> u64 {
let mut arg_buffer = ManagedArgBuffer::new_empty(self.type_manager());
arg_buffer.push_arg(token);
arg_buffer.push_arg(amount);
arg_buffer.push_arg(name);
arg_buffer.push_arg(royalties);
arg_buffer.push_arg(hash);
arg_buffer.push_arg(attributes);
if uris.is_empty() {
arg_buffer.push_arg(ManagedBuffer::new(self.api.clone()));
} else {
for uri in uris {
arg_buffer.push_arg(uri);
}
}
let output = self.call_local_dct_built_in_function(
self.api.get_gas_left(),
&ManagedBuffer::new_from_bytes(self.type_manager(), DCT_NFT_CREATE_FUNC_NAME),
&arg_buffer,
);
if let Some(first_result_bytes) = output.get(0) {
u64::top_decode(first_result_bytes.as_managed_ref()).unwrap_or_default()
} else {
0
}
}
#[allow(clippy::too_many_arguments)]
pub fn sell_nft(
&self,
nft_id: &TokenIdentifier<A>,
nft_nonce: u64,
nft_amount: &BigUint<A>,
buyer: &ManagedAddress<A>,
payment_token: &TokenIdentifier<A>,
payment_nonce: u64,
payment_amount: &BigUint<A>,
) -> BigUint<A> {
let nft_token_data =
self.api
.get_dct_token_data(&self.api.get_sc_address(), nft_id, nft_nonce);
let royalties_amount = payment_amount.clone() * nft_token_data.royalties / PERCENTAGE_TOTAL;
self.direct(buyer, nft_id, nft_nonce, nft_amount, &[]);
if royalties_amount > 0u32 {
self.direct(
&nft_token_data.creator,
payment_token,
payment_nonce,
&royalties_amount,
&[],
);
payment_amount.clone() - royalties_amount
} else {
payment_amount.clone()
}
}
}