curve_casper_erc20/
detail.rs

1//! Implementation details.
2use core::convert::TryInto;
3
4use casper_contract::{
5    contract_api::{runtime, storage},
6    unwrap_or_revert::UnwrapOrRevert,
7};
8use casper_types::{
9    bytesrepr::{FromBytes, ToBytes},
10    system::CallStackElement,
11    ApiError, CLTyped, URef,
12};
13
14use crate::{error::Error, Address};
15
16/// Gets [`URef`] under a name.
17pub(crate) fn get_uref(name: &str) -> URef {
18    let key = runtime::get_key(name)
19        .ok_or(ApiError::MissingKey)
20        .unwrap_or_revert();
21    key.try_into().unwrap_or_revert()
22}
23
24/// Reads value from a named key.
25pub(crate) fn read_from<T>(name: &str) -> T
26where
27    T: FromBytes + CLTyped,
28{
29    let uref = get_uref(name);
30    let value: T = storage::read(uref).unwrap_or_revert().unwrap_or_revert();
31    value
32}
33
34/// Reads value from a named key.
35pub(crate) fn write_to<T>(name: &str, value: T)
36where
37    T: ToBytes + CLTyped,
38{
39    let uref = get_uref(name);
40    storage::write(uref, value);
41}
42
43/// Gets the immediate call stack element of the current execution.
44fn get_immediate_call_stack_item() -> Option<CallStackElement> {
45    let call_stack = runtime::get_call_stack();
46    call_stack.into_iter().rev().nth(1)
47}
48
49/// Returns address based on a [`CallStackElement`].
50///
51/// For `Session` and `StoredSession` variants it will return account hash, and for `StoredContract`
52/// case it will use contract hash as the address.
53fn call_stack_element_to_address(call_stack_element: CallStackElement) -> Address {
54    match call_stack_element {
55        CallStackElement::Session { account_hash } => Address::from(account_hash),
56        CallStackElement::StoredSession { account_hash, .. } => {
57            // Stored session code acts in account's context, so if stored session wants to interact
58            // with an ERC20 token caller's address will be used.
59            Address::from(account_hash)
60        }
61        CallStackElement::StoredContract {
62            contract_package_hash,
63            ..
64        } => Address::from(contract_package_hash),
65    }
66}
67
68/// Gets the immediate session caller of the current execution.
69///
70/// This function ensures that only session code can execute this function, and disallows stored
71/// session/stored contracts.
72pub(crate) fn get_immediate_caller_address() -> Result<Address, Error> {
73    get_immediate_call_stack_item()
74        .map(call_stack_element_to_address)
75        .ok_or(Error::InvalidContext)
76}
77
78/// Gets the caller address which is stored on the top of the call stack.
79///
80/// This is similar to what [`runtime::get_caller`] does but it also supports stored contracts.
81pub(crate) fn get_caller_address() -> Result<Address, Error> {
82    let call_stack = runtime::get_call_stack();
83    let top_of_the_stack = call_stack
84        .into_iter()
85        .rev()
86        .next()
87        .ok_or(Error::InvalidContext)?;
88    let address = call_stack_element_to_address(top_of_the_stack);
89    Ok(address)
90}