use crate::{
call::{
common::{
ReturnType,
Set,
Unset,
},
execution::EmptyArgumentList,
CallBuilder,
CallParams,
CallV1,
ExecutionInput,
},
Environment,
Error,
Gas,
};
use num_traits::Zero;
use pallet_contracts_uapi::CallFlags;
#[derive(Clone)]
pub struct Call<E: Environment> {
callee: E::AccountId,
ref_time_limit: u64,
proof_size_limit: u64,
storage_deposit_limit: Option<E::Balance>,
transferred_value: E::Balance,
call_flags: CallFlags,
}
impl<E: Environment> Call<E> {
pub fn new(callee: E::AccountId) -> Self {
Self {
callee,
ref_time_limit: Default::default(),
proof_size_limit: Default::default(),
storage_deposit_limit: None,
transferred_value: E::Balance::zero(),
call_flags: CallFlags::empty(),
}
}
}
impl<E, Args, RetType> CallBuilder<E, Set<Call<E>>, Args, RetType>
where
E: Environment,
{
pub fn call_v1(self) -> CallBuilder<E, Set<CallV1<E>>, Args, RetType> {
let call_type = self.call_type.value();
CallBuilder {
call_type: Set(CallV1 {
callee: call_type.callee,
gas_limit: call_type.ref_time_limit,
transferred_value: call_type.transferred_value,
call_flags: call_type.call_flags,
}),
exec_input: self.exec_input,
return_type: self.return_type,
_phantom: Default::default(),
}
}
pub fn ref_time_limit(self, ref_time_limit: Gas) -> Self {
let call_type = self.call_type.value();
CallBuilder {
call_type: Set(Call {
ref_time_limit,
..call_type
}),
..self
}
}
pub fn proof_size_limit(self, proof_size_limit: Gas) -> Self {
let call_type = self.call_type.value();
CallBuilder {
call_type: Set(Call {
proof_size_limit,
..call_type
}),
..self
}
}
pub fn storage_deposit_limit(self, storage_deposit_limit: E::Balance) -> Self {
let call_type = self.call_type.value();
CallBuilder {
call_type: Set(Call {
storage_deposit_limit: Some(storage_deposit_limit),
..call_type
}),
..self
}
}
pub fn transferred_value(self, transferred_value: E::Balance) -> Self {
let call_type = self.call_type.value();
CallBuilder {
call_type: Set(Call {
transferred_value,
..call_type
}),
..self
}
}
pub fn call_flags(self, call_flags: CallFlags) -> Self {
let call_type = self.call_type.value();
CallBuilder {
call_type: Set(Call {
call_flags,
..call_type
}),
..self
}
}
}
impl<E, Args, RetType>
CallBuilder<E, Set<Call<E>>, Set<ExecutionInput<Args>>, Set<ReturnType<RetType>>>
where
E: Environment,
{
pub fn params(self) -> CallParams<E, Call<E>, Args, RetType> {
CallParams {
call_type: self.call_type.value(),
_return_type: Default::default(),
exec_input: self.exec_input.value(),
_phantom: self._phantom,
}
}
}
impl<E, RetType>
CallBuilder<E, Set<Call<E>>, Unset<ExecutionInput<EmptyArgumentList>>, Unset<RetType>>
where
E: Environment,
{
pub fn params(self) -> CallParams<E, Call<E>, EmptyArgumentList, ()> {
CallParams {
call_type: self.call_type.value(),
_return_type: Default::default(),
exec_input: Default::default(),
_phantom: self._phantom,
}
}
}
impl<E>
CallBuilder<
E,
Set<Call<E>>,
Unset<ExecutionInput<EmptyArgumentList>>,
Unset<ReturnType<()>>,
>
where
E: Environment,
{
pub fn invoke(self) {
self.params().invoke()
}
pub fn try_invoke(self) -> Result<ink_primitives::MessageResult<()>, Error> {
self.params().try_invoke()
}
}
impl<E, Args, R>
CallBuilder<E, Set<Call<E>>, Set<ExecutionInput<Args>>, Set<ReturnType<R>>>
where
E: Environment,
Args: scale::Encode,
R: scale::Decode,
{
pub fn invoke(self) -> R {
self.params().invoke()
}
pub fn try_invoke(self) -> Result<ink_primitives::MessageResult<R>, Error> {
self.params().try_invoke()
}
}
impl<E, Args, R> CallParams<E, Call<E>, Args, R>
where
E: Environment,
{
#[inline]
pub fn callee(&self) -> &E::AccountId {
&self.call_type.callee
}
#[inline]
pub fn ref_time_limit(&self) -> u64 {
self.call_type.ref_time_limit
}
#[inline]
pub fn proof_size_limit(&self) -> u64 {
self.call_type.proof_size_limit
}
#[inline]
pub fn storage_deposit_limit(&self) -> Option<&E::Balance> {
self.call_type.storage_deposit_limit.as_ref()
}
#[inline]
pub fn transferred_value(&self) -> &E::Balance {
&self.call_type.transferred_value
}
#[inline]
pub fn call_flags(&self) -> &CallFlags {
&self.call_type.call_flags
}
}
impl<E, Args, R> CallParams<E, Call<E>, Args, R>
where
E: Environment,
Args: scale::Encode,
R: scale::Decode,
{
pub fn invoke(&self) -> R {
crate::invoke_contract(self)
.unwrap_or_else(|env_error| {
panic!("Cross-contract call failed with {env_error:?}")
})
.unwrap_or_else(|lang_error| {
panic!("Cross-contract call failed with {lang_error:?}")
})
}
pub fn try_invoke(&self) -> Result<ink_primitives::MessageResult<R>, crate::Error> {
crate::invoke_contract(self)
}
}