1use std::str::FromStr;
2
3use base58::ToBase58;
4use blake2::{Blake2b512, Digest};
5use parity_scale_codec::{Compact, Decode, Encode, Error, Input};
6use serde::{Deserialize, Serialize};
7pub use sp_core::crypto::{AccountId32, Ss58AddressFormat, Ss58AddressFormatRegistry};
8pub use sp_core::ecdsa::{Public as EcdsaPublic, Signature as EcdsaSignature};
9pub use sp_core::ed25519::{Public as Ed25519Public, Signature as Ed25519Signature};
10pub use sp_core::{blake2_256, H256};
11
12use crate::pallets::timestamp::decode_timestamp;
13use crate::ss58::Ss58Codec;
14use crate::utils::deser_number_or_hex;
15
16pub mod client;
17pub mod network;
18pub mod pallets;
19pub mod rpc;
20pub mod ss58;
21mod utils;
22
23pub type GenericAddress = MultiAddress<AccountId32, ()>;
24
25pub type Balance = u128;
26
27#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
28pub enum MultiAddress<AccountId, AccountIndex> {
29 Id(AccountId),
31 Index(#[codec(compact)] AccountIndex),
33 Raw(Vec<u8>),
35 Address32([u8; 32]),
37 Address20([u8; 20]),
39}
40
41impl From<AccountId32> for GenericAddress {
42 fn from(a: AccountId32) -> Self {
43 MultiAddress::Id(a)
44 }
45}
46
47impl From<EcdsaPublic> for GenericAddress {
48 fn from(p: EcdsaPublic) -> Self {
49 let acct = public_into_account(p);
50 MultiAddress::Id(acct)
51 }
52}
53
54impl FromStr for GenericAddress {
55 type Err = &'static str;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 Ok(AccountId32::from_ss58check(s)
59 .map_err(|_| "Expected ss58 address")?
60 .into())
61 }
62}
63
64pub fn public_into_account(p: EcdsaPublic) -> AccountId32 {
65 let hash = blake2_256(&p.0);
66 hash.into()
67}
68
69pub fn pub_to_account_string(
70 p: [u8; 32],
71 prefix: u16,
72) -> Result<String, Box<dyn std::error::Error>> {
73 let raw_key = p;
74 let mut hasher = Blake2b512::new();
75 hasher.update(b"SS58PRE");
76 let simple_prefix: u8 = (prefix & 0x3F) as _;
77 let full_prefix = 0x4000 | ((prefix >> 8) & 0x3F) | ((prefix & 0xFF) << 6);
78 let prefix_hi: u8 = (full_prefix >> 8) as _;
79 let prefix_low: u8 = (full_prefix & 0xFF) as _;
80 if prefix == simple_prefix as u16 {
81 hasher.update([simple_prefix]);
82 } else {
83 hasher.update([prefix_hi]);
84 hasher.update([prefix_low]);
85 }
86 hasher.update(raw_key);
87 let checksum = hasher.finalize();
88
89 let mut raw_address: Vec<u8> = Vec::with_capacity(64);
90 if prefix == simple_prefix as u16 {
91 raw_address.push(simple_prefix);
92 } else {
93 raw_address.push(prefix_hi);
94 raw_address.push(prefix_low);
95 }
96 raw_address.append(&mut raw_key.to_vec());
97 raw_address.extend_from_slice(&checksum[0..2]);
98 Ok(raw_address[..].to_base58())
99}
100
101#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
102pub enum MultiSignature {
103 #[codec(index = 0)]
105 Ed25519(Ed25519Signature),
106 #[codec(index = 2)]
108 Ecdsa(EcdsaSignature),
109}
110
111impl From<EcdsaSignature> for MultiSignature {
112 fn from(value: EcdsaSignature) -> Self {
113 MultiSignature::Ecdsa(value)
114 }
115}
116
117impl From<Ed25519Signature> for MultiSignature {
118 fn from(value: Ed25519Signature) -> Self {
119 MultiSignature::Ed25519(value)
120 }
121}
122
123pub type SignedExtra = (u32, u32, H256, H256, (), (), ());
126
127#[derive(Clone, Copy, Debug, Decode, Encode, PartialEq, Eq)]
128pub struct GenericExtra(Era, Compact<u32>, Compact<Balance>);
129
130impl GenericExtra {
131 pub fn new(era: Era, nonce: u32) -> GenericExtra {
132 GenericExtra(era, Compact(nonce), Compact(0u128))
133 }
134}
135
136#[derive(Clone, Copy, Debug, Decode, Encode, PartialEq, Eq)]
137pub enum Era {
138 Immortal,
139}
140
141#[derive(Clone, Debug, PartialEq, Eq)]
142pub struct UncheckedExtrinsic<Call> {
143 pub signature: Option<(GenericAddress, MultiSignature, GenericExtra)>,
145 pub function: Call,
146}
147
148impl<Call: Encode> UncheckedExtrinsic<Call> {
149 pub fn as_hex(&self) -> String {
150 format!("0x{}", hex::encode(self.encode()))
151 }
152
153 pub fn call_as_hex(&self) -> String {
154 format!("0x{}", hex::encode(self.function.encode()))
155 }
156}
157
158impl<Call> Encode for UncheckedExtrinsic<Call>
159where
160 Call: Encode,
161{
162 fn encode(&self) -> Vec<u8> {
163 encode_with_vec_prefix::<Self, _>(|v| {
164 match self.signature.as_ref() {
165 Some(s) => {
166 v.push(4 | 0b1000_0000);
167 s.encode_to(v);
168 }
169 None => {
170 v.push(4 & 0b0111_1111);
171 }
172 }
173 self.function.encode_to(v);
174 })
175 }
176}
177
178impl<Call> Decode for UncheckedExtrinsic<Call>
179where
180 Call: Decode + Encode,
181{
182 fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
183 let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?;
188
189 let version = input.read_byte()?;
190
191 let is_signed = version & 0b1000_0000 != 0;
192 let version = version & 0b0111_1111;
193 if version != 4 {
194 return Err("Invalid transaction version".into());
195 }
196
197 Ok(UncheckedExtrinsic {
198 signature: if is_signed {
199 Some(Decode::decode(input)?)
200 } else {
201 None
202 },
203 function: Decode::decode(input)?,
204 })
205 }
206}
207
208fn encode_with_vec_prefix<T: Encode, F: Fn(&mut Vec<u8>)>(encoder: F) -> Vec<u8> {
211 let size = core::mem::size_of::<T>();
212 let reserve = match size {
213 0..=0b0011_1111 => 1,
214 0b0100_0000..=0b0011_1111_1111_1111 => 2,
215 _ => 4,
216 };
217 let mut v = Vec::with_capacity(reserve + size);
218 v.resize(reserve, 0);
219 encoder(&mut v);
220
221 let mut length: Vec<()> = Vec::new();
224 length.resize(v.len() - reserve, ());
225 length.using_encoded(|s| {
226 v.splice(0..reserve, s.iter().cloned());
227 });
228
229 v
230}
231
232#[derive(Clone, Copy, Debug, Encode)]
233pub struct SignedPayload<Call>((Call, GenericExtra, SignedExtra));
234
235impl<Call: Encode> SignedPayload<Call> {
236 pub fn new(call: Call, extra: GenericExtra, s_extra: SignedExtra) -> SignedPayload<Call> {
237 SignedPayload((call, extra, s_extra))
238 }
239
240 pub fn encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
244 self.0.using_encoded(|payload| {
245 if payload.len() > 256 {
246 f(&blake2_256(payload))
247 } else {
248 f(payload)
249 }
250 })
251 }
252}
253
254#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)]
255#[serde(rename_all = "camelCase")]
256pub struct RuntimeVersion {
257 pub spec_version: u32,
258 pub transaction_version: u32,
259}
260
261#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, Deserialize)]
263pub struct AccountDataGen<Balance> {
264 pub free: Balance,
272 pub reserved: Balance,
280 pub frozen: Balance,
284 pub flags: ExtraFlags,
287}
288
289const IS_NEW_LOGIC: u128 = 0x80000000_00000000_00000000_00000000u128;
290
291#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Deserialize)]
292pub struct ExtraFlags(u128);
293
294impl Default for ExtraFlags {
295 fn default() -> Self {
296 Self(IS_NEW_LOGIC)
297 }
298}
299impl ExtraFlags {
300 pub fn old_logic() -> Self {
301 Self(0)
302 }
303 pub fn set_new_logic(&mut self) {
304 self.0 |= IS_NEW_LOGIC
305 }
306 pub fn is_new_logic(&self) -> bool {
307 (self.0 & IS_NEW_LOGIC) == IS_NEW_LOGIC
308 }
309}
310
311pub type RefCount = u32;
313pub type Index = u32;
315
316#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, Deserialize)]
318pub struct AccountInfoGen<Index, AccountData> {
319 pub nonce: Index,
321 pub consumers: RefCount,
324 pub providers: RefCount,
328 pub sufficients: RefCount,
332 pub data: AccountData,
335}
336
337pub type AccountData = AccountDataGen<Balance>;
338pub type AccountInfo = AccountInfoGen<Index, AccountData>;
339
340#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
341#[serde(rename_all = "camelCase")]
342pub struct FeeDetails {
343 pub inclusion_fee: Option<InclusionFee>,
345 #[serde(skip)]
347 #[serde(deserialize_with = "deser_number_or_hex")]
348 pub tip: Balance,
349}
350
351impl FeeDetails {
352 pub fn final_fee(&self) -> Balance {
356 self.inclusion_fee
357 .as_ref()
358 .map(|i| i.inclusion_fee())
359 .unwrap_or_default()
360 .saturating_add(self.tip)
361 }
362}
363
364#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
365#[serde(rename_all = "camelCase")]
366pub struct InclusionFee {
367 #[serde(deserialize_with = "deser_number_or_hex")]
371 pub base_fee: Balance,
372 #[serde(deserialize_with = "deser_number_or_hex")]
375 pub len_fee: Balance,
376 #[serde(deserialize_with = "deser_number_or_hex")]
384 pub adjusted_weight_fee: Balance,
385}
386
387impl InclusionFee {
388 pub fn inclusion_fee(&self) -> Balance {
389 self.base_fee
390 .saturating_add(self.len_fee)
391 .saturating_add(self.adjusted_weight_fee)
392 }
393}
394
395#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
396#[serde(rename_all = "camelCase")]
397pub struct SignedBlock {
398 pub block: Block,
399}
400
401#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
402#[serde(rename_all = "camelCase")]
403pub struct Block {
404 pub header: Header,
405 pub extrinsics: Vec<String>,
406}
407
408impl Block {
409 pub fn timestamp(&self) -> Option<u64> {
411 self.extrinsics.iter().find_map(|e| decode_timestamp(e))
412 }
413}
414
415#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
416#[serde(rename_all = "camelCase")]
417pub struct Header {
418 pub parent_hash: H256,
419 #[serde(deserialize_with = "deser_number_or_hex")]
420 pub number: u128,
421}