1use crate::errors::DecimalNumberParsingError;
4
5pub const fn near_data_to_near_token(data: crate::Data<u128>) -> crate::NearToken {
7 crate::NearToken::from_yoctonear(data.data)
8}
9
10pub fn parse_decimal_number(s: &str, pref_const: u128) -> Result<u128, DecimalNumberParsingError> {
20 let (int, fraction) = if let Some((whole, fractional)) = s.trim().split_once('.') {
21 let int: u128 = whole
22 .parse()
23 .map_err(|_| DecimalNumberParsingError::InvalidNumber(s.to_owned()))?;
24 let mut fraction: u128 = fractional
25 .parse()
26 .map_err(|_| DecimalNumberParsingError::InvalidNumber(s.to_owned()))?;
27 let len = u32::try_from(fractional.len())
28 .map_err(|_| DecimalNumberParsingError::InvalidNumber(s.to_owned()))?;
29 fraction = fraction
30 .checked_mul(
31 pref_const
32 .checked_div(10u128.checked_pow(len).ok_or_else(|| {
33 DecimalNumberParsingError::LongFractional(fractional.to_owned())
34 })?)
35 .filter(|n| *n != 0u128)
36 .ok_or_else(|| {
37 DecimalNumberParsingError::LongFractional(fractional.to_owned())
38 })?,
39 )
40 .ok_or_else(|| DecimalNumberParsingError::LongFractional(fractional.to_owned()))?;
41 (int, fraction)
42 } else {
43 let int: u128 = s
44 .parse()
45 .map_err(|_| DecimalNumberParsingError::InvalidNumber(s.to_owned()))?;
46 (int, 0)
47 };
48 let result = fraction
49 .checked_add(
50 int.checked_mul(pref_const)
51 .ok_or_else(|| DecimalNumberParsingError::LongWhole(int.to_string()))?,
52 )
53 .ok_or_else(|| DecimalNumberParsingError::LongWhole(int.to_string()))?;
54 Ok(result)
55}
56
57pub fn is_critical_blocks_error(
58 err: &near_jsonrpc_client::errors::JsonRpcError<
59 near_jsonrpc_primitives::types::blocks::RpcBlockError,
60 >,
61) -> bool {
62 is_critical_json_rpc_error(err, |err| match err {
63 near_jsonrpc_client::methods::block::RpcBlockError::UnknownBlock { .. }
64 | near_jsonrpc_client::methods::block::RpcBlockError::NotSyncedYet
65 | near_jsonrpc_client::methods::block::RpcBlockError::InternalError { .. } => true,
66 })
67}
68
69pub fn is_critical_validator_error(
70 err: &near_jsonrpc_client::errors::JsonRpcError<
71 near_jsonrpc_primitives::types::validator::RpcValidatorError,
72 >,
73) -> bool {
74 is_critical_json_rpc_error(err, |err| match err {
75 near_jsonrpc_primitives::types::validator::RpcValidatorError::UnknownEpoch
76 | near_jsonrpc_primitives::types::validator::RpcValidatorError::ValidatorInfoUnavailable
77 | near_jsonrpc_primitives::types::validator::RpcValidatorError::InternalError { .. } => {
78 true
79 }
80 })
81}
82
83pub fn is_critical_query_error(
84 err: &near_jsonrpc_client::errors::JsonRpcError<
85 near_jsonrpc_primitives::types::query::RpcQueryError,
86 >,
87) -> bool {
88 is_critical_json_rpc_error(err, |err| match err {
89 near_jsonrpc_primitives::types::query::RpcQueryError::NoSyncedBlocks
90 | near_jsonrpc_primitives::types::query::RpcQueryError::UnavailableShard { .. }
91 | near_jsonrpc_primitives::types::query::RpcQueryError::GarbageCollectedBlock { .. }
92 | near_jsonrpc_primitives::types::query::RpcQueryError::UnknownBlock { .. }
93 | near_jsonrpc_primitives::types::query::RpcQueryError::InvalidAccount { .. }
94 | near_jsonrpc_primitives::types::query::RpcQueryError::UnknownAccount { .. }
95 | near_jsonrpc_primitives::types::query::RpcQueryError::NoContractCode { .. }
96 | near_jsonrpc_primitives::types::query::RpcQueryError::TooLargeContractState { .. }
97 | near_jsonrpc_primitives::types::query::RpcQueryError::UnknownAccessKey { .. }
98 | near_jsonrpc_primitives::types::query::RpcQueryError::ContractExecutionError { .. }
99 | near_jsonrpc_primitives::types::query::RpcQueryError::InternalError { .. } => true,
100 })
101}
102
103pub fn is_critical_transaction_error(
104 err: &near_jsonrpc_client::errors::JsonRpcError<
105 near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError,
106 >,
107) -> bool {
108 is_critical_json_rpc_error(err, |err| {
109 match err {
110 near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError::TimeoutError => {
111 false
112 }
113 near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError::InvalidTransaction { .. } |
114 near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError::DoesNotTrackShard |
115 near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError::RequestRouted{..} |
116 near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError::UnknownTransaction{..} |
117 near_jsonrpc_client::methods::broadcast_tx_commit::RpcTransactionError::InternalError{..} => {
118 true
119 }
120 }
121 })
122}
123
124fn is_critical_json_rpc_error<T>(
125 err: &near_jsonrpc_client::errors::JsonRpcError<T>,
126 is_critical_t: impl Fn(&T) -> bool,
127) -> bool {
128 match err {
129 near_jsonrpc_client::errors::JsonRpcError::TransportError(_rpc_transport_error) => {
130 false
131 }
132 near_jsonrpc_client::errors::JsonRpcError::ServerError(rpc_server_error) => match rpc_server_error {
133 near_jsonrpc_client::errors::JsonRpcServerError::HandlerError(rpc_transaction_error) => is_critical_t(rpc_transaction_error),
134 near_jsonrpc_client::errors::JsonRpcServerError::RequestValidationError(..) |
135 near_jsonrpc_client::errors::JsonRpcServerError::NonContextualError(..) => {
136 true
137 }
138 near_jsonrpc_client::errors::JsonRpcServerError::InternalError{ .. } => {
139 false
140 }
141 near_jsonrpc_client::errors::JsonRpcServerError::ResponseStatusError(json_rpc_server_response_status_error) => match json_rpc_server_response_status_error {
142 near_jsonrpc_client::errors::JsonRpcServerResponseStatusError::Unauthorized |
143 near_jsonrpc_client::errors::JsonRpcServerResponseStatusError::Unexpected{..} |
144 near_jsonrpc_client::errors::JsonRpcServerResponseStatusError::BadRequest => {
145 true
146 }
147 near_jsonrpc_client::errors::JsonRpcServerResponseStatusError::TimeoutError |
148 near_jsonrpc_client::errors::JsonRpcServerResponseStatusError::ServiceUnavailable |
149 near_jsonrpc_client::errors::JsonRpcServerResponseStatusError::TooManyRequests => {
150 false
151 }
152 }
153 }
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 const TEST: [(u128, &str, u128); 6] = [
162 (129_380_000_001_u128, "129.380000001", 10u128.pow(9)),
163 (
164 12_938_000_000_100_000_000_u128,
165 "12938000000.1",
166 10u128.pow(9),
167 ),
168 (129_380_000_001_u128, "0.129380000001", 10u128.pow(12)),
169 (129_380_000_001_000_u128, "129.380000001000", 10u128.pow(12)),
170 (
171 9_488_129_380_000_001_u128,
172 "9488.129380000001",
173 10u128.pow(12),
174 ),
175 (129_380_000_001_u128, "00.129380000001", 10u128.pow(12)),
176 ];
177
178 #[test]
179 fn parse_test() {
180 for (expected_value, str_value, precision) in TEST {
181 let parsed_value = parse_decimal_number(str_value, precision).unwrap();
182 assert_eq!(parsed_value, expected_value)
183 }
184 }
185
186 #[test]
187 fn test_long_fraction() {
188 let data = "1.23456";
189 let prefix = 10000u128;
190 assert_eq!(
191 parse_decimal_number(data, prefix),
192 Err(DecimalNumberParsingError::LongFractional(23456.to_string()))
193 );
194 }
195
196 #[test]
197 fn invalid_number_whole() {
198 let num = "1h4.7859";
199 let prefix: u128 = 10000;
200 assert_eq!(
201 parse_decimal_number(num, prefix),
202 Err(DecimalNumberParsingError::InvalidNumber(
203 "1h4.7859".to_owned()
204 ))
205 );
206 }
207 #[test]
208 fn invalid_number_fraction() {
209 let num = "14.785h9";
210 let prefix: u128 = 10000;
211 assert_eq!(
212 parse_decimal_number(num, prefix),
213 Err(DecimalNumberParsingError::InvalidNumber(
214 "14.785h9".to_owned()
215 ))
216 );
217 }
218
219 #[test]
220 fn max_long_fraction() {
221 let max_data = 10u128.pow(17) + 1;
222 let data = "1.".to_string() + max_data.to_string().as_str();
223 let prefix = 10u128.pow(17);
224 assert_eq!(
225 parse_decimal_number(data.as_str(), prefix),
226 Err(DecimalNumberParsingError::LongFractional(
227 max_data.to_string()
228 ))
229 );
230 }
231
232 #[test]
233 fn parse_u128_error_test() {
234 let test_data = u128::MAX.to_string();
235 let gas = parse_decimal_number(&test_data, 10u128.pow(9));
236 assert_eq!(
237 gas,
238 Err(DecimalNumberParsingError::LongWhole(u128::MAX.to_string()))
239 );
240 }
241
242 #[test]
243 fn test() {
244 let data = "1.000000000000000000000000000000000000001";
245 let prefix = 100u128;
246 assert_eq!(
247 parse_decimal_number(data, prefix),
248 Err(DecimalNumberParsingError::LongFractional(
249 "000000000000000000000000000000000000001".to_string()
250 ))
251 );
252 }
253}