casperlabs_contract_utils/
data.rs

1use alloc::{
2    string::{String, ToString},
3    vec::Vec,
4};
5use casper_contract::{
6    contract_api::{runtime, storage},
7    unwrap_or_revert::UnwrapOrRevert,
8};
9use casper_types::{
10    bytesrepr::{FromBytes, ToBytes},
11    ApiError, CLTyped, Key, RuntimeArgs, URef, U128, U256,
12};
13use casper_types_derive::{CLTyped, FromBytes, ToBytes};
14use core::convert::TryInto;
15
16#[derive(Clone, Copy, CLTyped, ToBytes, FromBytes, Default)]
17pub struct Dict {
18    uref: URef,
19}
20
21impl Dict {
22    pub fn instance(name: &str) -> Dict {
23        let key = runtime::get_key(name).unwrap_or_revert();
24        let uref = *key.as_uref().unwrap_or_revert();
25        Dict { uref }
26    }
27
28    pub fn init(name: &str) {
29        storage::new_dictionary(name).unwrap_or_revert();
30    }
31
32    pub fn at(uref: URef) -> Dict {
33        Dict { uref }
34    }
35
36    pub fn get<T: CLTyped + FromBytes>(&self, key: &str) -> Option<T> {
37        storage::dictionary_get(self.uref, key)
38            .unwrap_or_revert()
39            .unwrap_or_default()
40    }
41
42    pub fn get_by_key<T: CLTyped + FromBytes>(&self, key: &Key) -> Option<T> {
43        self.get(&key_to_str(key))
44    }
45
46    pub fn get_by_keys<T: CLTyped + FromBytes, U: CLTyped + ToBytes>(
47        &self,
48        keys: (&U, &Key),
49    ) -> Option<T> {
50        self.get(&keys_to_str(keys.0, keys.1))
51    }
52
53    pub fn set<T: CLTyped + ToBytes>(&self, key: &str, value: T) {
54        storage::dictionary_put(self.uref, key, Some(value));
55    }
56
57    pub fn set_by_key<T: CLTyped + ToBytes>(&self, key: &Key, value: T) {
58        self.set(&key_to_str(key), value);
59    }
60
61    pub fn set_by_keys<T: CLTyped + ToBytes, U: CLTyped + ToBytes>(
62        &self,
63        keys: (&U, &Key),
64        value: T,
65    ) {
66        self.set(&keys_to_str(keys.0, keys.1), value)
67    }
68    pub fn set_by_values<T: CLTyped + ToBytes, U: CLTyped + ToBytes, V: CLTyped + ToBytes>(
69        &self,
70        keys: (&T, &U),
71        value: V,
72    ) {
73        self.set(&values_to_str(keys.0, keys.1), value);
74    }
75
76    pub fn get_by_values<T: CLTyped + ToBytes, U: CLTyped + ToBytes, R: CLTyped + FromBytes>(
77        &self,
78        keys: (&T, &U),
79    ) -> Option<R> {
80        self.get(&values_to_str(keys.0, keys.1))
81    }
82
83    pub fn remove<T: CLTyped + ToBytes>(&self, key: &str) {
84        storage::dictionary_put(self.uref, key, Option::<T>::None);
85    }
86
87    pub fn remove_by_key<T: CLTyped + ToBytes>(&self, key: &Key) {
88        self.remove::<T>(&key_to_str(key));
89    }
90
91    pub fn remove_by_vec_of_keys<T: CLTyped + ToBytes>(&self, keys: (&Key, &Key)) {
92        self.remove::<T>(&keys_to_str(keys.0, keys.1))
93    }
94}
95
96pub fn key_to_str(key: &Key) -> String {
97    match key {
98        Key::Account(account) => account.to_string(),
99        Key::Hash(package) => hex::encode(package),
100        _ => runtime::revert(ApiError::UnexpectedKeyVariant),
101    }
102}
103
104pub fn keys_to_str<U: CLTyped + ToBytes, V: CLTyped + ToBytes>(key_a: &U, key_b: &V) -> String {
105    let mut bytes_a = key_a.to_bytes().unwrap_or_revert();
106    let mut bytes_b = key_b.to_bytes().unwrap_or_revert();
107    bytes_a.append(&mut bytes_b);
108    let bytes = runtime::blake2b(bytes_a);
109    hex::encode(bytes)
110}
111
112pub fn values_to_str<T: CLTyped + ToBytes, U: CLTyped + ToBytes>(
113    value_a: &T,
114    value_b: &U,
115) -> String {
116    let mut bytes_a = value_a.to_bytes().unwrap_or_revert();
117    let mut bytes_b = value_b.to_bytes().unwrap_or_revert();
118
119    bytes_a.append(&mut bytes_b);
120
121    let bytes = runtime::blake2b(bytes_a);
122    hex::encode(bytes)
123}
124
125pub fn key_and_value_to_str<T: CLTyped + ToBytes>(key: &Key, value: &T) -> String {
126    let mut bytes_a = key.to_bytes().unwrap_or_revert();
127    let mut bytes_b = value.to_bytes().unwrap_or_revert();
128
129    bytes_a.append(&mut bytes_b);
130
131    let bytes = runtime::blake2b(bytes_a);
132    hex::encode(bytes)
133}
134
135pub fn get_key<T: FromBytes + CLTyped>(name: &str) -> Option<T> {
136    match runtime::get_key(name) {
137        None => None,
138        Some(value) => {
139            let key = value.try_into().unwrap_or_revert();
140            let value = storage::read(key).unwrap_or_revert().unwrap_or_revert();
141            Some(value)
142        }
143    }
144}
145
146pub fn set_key<T: ToBytes + CLTyped>(name: &str, value: T) {
147    match runtime::get_key(name) {
148        Some(key) => {
149            let key_ref = key.try_into().unwrap_or_revert();
150            storage::write(key_ref, value);
151        }
152        None => {
153            let key = storage::new_uref(value).into();
154            runtime::put_key(name, key);
155        }
156    }
157}
158
159pub fn call_function(target: Key, function_name: String, function_args: RuntimeArgs) -> String {
160    if function_name == "get_gauge_weight"
161        || function_name == "gauge_relative_weight"
162        || function_name == "inflation_rate"
163        || function_name == "working_supply"
164        || function_name == "balance_of"
165        || function_name == "duration"
166        || function_name == "reward_rate"
167        || function_name == "balances"
168        || function_name == "total_supply"
169        || function_name == "get_balance"
170        || function_name == "earned"
171        || function_name == "allowance"
172        || function_name == "locked_end"
173        || function_name == "vested_of"
174        || function_name == "locked_of"
175        || function_name == "initial_locked"
176        || function_name == "start_time"
177        || function_name == "end_time"
178        || function_name == "total_claimed"
179        || function_name == "working_balances"
180        || function_name == "vested_supply"
181        || function_name == "user_reward_per_token_paid"
182    {
183        let ret: U256 = runtime::call_versioned_contract(
184            target.into_hash().unwrap_or_revert().into(),
185            None,
186            &function_name,
187            function_args,
188        );
189        let data: String = ret.to_string() + ":U256";
190        return data;
191    }
192    if function_name == "gauges" || function_name == "lp_token" {
193        let ret: Key = runtime::call_versioned_contract(
194            target.into_hash().unwrap_or_revert().into(),
195            None,
196            &function_name,
197            function_args,
198        );
199        let data: String = ret.to_string() + ":Key";
200        return data;
201    }
202    if function_name == "gauge_type_names" {
203        let ret: String = runtime::call_versioned_contract(
204            target.into_hash().unwrap_or_revert().into(),
205            None,
206            &function_name,
207            function_args,
208        );
209        let data: String = ret.to_string() + ":String";
210        return data;
211    }
212    if function_name == "gauge_types"
213        || function_name == "n_gauge_types"
214        || function_name == "n_gauges"
215    {
216        let ret: (bool, U128) = runtime::call_versioned_contract(
217            target.into_hash().unwrap_or_revert().into(),
218            None,
219            &function_name,
220            function_args,
221        );
222        let data: String =
223            "(".to_string() + &ret.0.to_string() + "," + &ret.1.to_string() + ")" + ":(bool,U128)";
224        return data;
225    }
226    "".to_string()
227}