Skip to content

Commit

Permalink
Serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsosf committed Mar 14, 2024
1 parent 8c0f659 commit 646da2f
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 0 deletions.
81 changes: 81 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ serde = { version = "1.0.197", features = ["derive"] }
num-bigint = "0.4.4"
num-traits = "0.2.18"
rust_decimal = "1.34.3"
sha3 = "0.10.8"
hex = "0.4.3"
17 changes: 17 additions & 0 deletions src/icon_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,20 @@ pub async fn get_balance(address: &str) -> Result<Value, Box<dyn Error>> {

Ok(response)
}

pub async fn send_transaction(from: &str, to: &str, value: &str, version: &str, nid: &str, nonce: &str, step_limit: &str) -> Result<String, Box<dyn Error>> {
let transaction_builder = TransactionBuilder::new()
.method("icx_sendTransaction")
.from(from)
.to(to)
.value(value)
.version(version)
.nid(nid)
.nonce(nonce)
.step_limit(step_limit)
.serialize(true);
Ok(transaction_builder)
// let response: Value = transaction_builder.map_err(|e| Box::new(e) as Box<dyn Error>)?;
//
// Ok(response)
}
107 changes: 107 additions & 0 deletions src/transaction_builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use reqwest::{Client, Error};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value, Map};
use sha3::{Digest, Sha3_256};
use std::collections::BTreeMap;

#[derive(Default, Serialize, Deserialize)]
pub struct TransactionBuilder {
Expand Down Expand Up @@ -68,6 +70,111 @@ impl TransactionBuilder {
self.set_params(&params)
}

pub fn from(self, from: &str) -> Self {
let mut params = Map::new();
params.insert("from".to_string(), json!(from));

self.set_params(&params)
}

pub fn to(self, to: &str) -> Self {
let mut params = Map::new();
params.insert("to".to_string(), json!(to));

self.set_params(&params)
}

pub fn value(self, value: &str) -> Self {
let mut params = Map::new();
params.insert("value".to_string(), json!(value));

self.set_params(&params)
}

pub fn version(self, version: &str) -> Self {
let mut params = Map::new();
params.insert("version".to_string(), json!(version));

self.set_params(&params)
}

pub fn nid(self, nid: &str) -> Self {
let mut params = Map::new();
params.insert("nid".to_string(), json!(nid));

self.set_params(&params)
}

pub fn nonce(self, nonce: &str) -> Self {
let mut params = Map::new();
params.insert("nonce".to_string(), json!(nonce));

self.set_params(&params)
}

pub fn step_limit(self, step_limit: &str) -> Self {
let mut params = Map::new();
params.insert("stepLimit".to_string(), json!(step_limit));

self.set_params(&params)
}

pub fn serialize(&self, hashed: bool) -> String {
let result_str = Self::value_traverse(&self.data["params"]);
let result_string_replaced = &result_str[1..result_str.len() - 1];
let result = format!("icx_sendTransaction.{}", result_string_replaced);

if hashed {
format!("{}", hex::encode(sha3::Sha3_256::digest(result.as_bytes())))
} else {
result
}
}

fn value_traverse(value: &Value) -> String {
match value {
Value::Object(obj) => {
let mut result = "{".to_string();
let sorted: BTreeMap<_, _> = obj.iter().collect();
for (key, val) in &sorted {
result.push_str(&format!("{}.", key));
result.push_str(&Self::value_traverse(val));
result.push('.');
}
if result.ends_with('.') {
result.pop();
}
result.push('}');
result
},
Value::Array(arr) => {
let mut result = "[".to_string();
for val in arr {
result.push_str(&Self::value_traverse(val));
result.push('.');
}
if result.ends_with('.') {
result.pop();
}
result.push(']');
result
},
Value::String(s) => Self::escape_string(s),
Value::Number(n) => n.to_string(),
Value::Bool(b) => b.to_string(),
Value::Null => "\\0".to_string(),
}
}

fn escape_string(value: &str) -> String {
value.replace("\\", "\\\\")
.replace(".", "\\.")
.replace("{", "\\{")
.replace("}", "\\}")
.replace("[", "\\[")
.replace("]", "\\]")
}

pub async fn send(self) -> Result<Value, Error> {
let client = Client::new();
let url = self.icon_service_url.unwrap_or_else(|| "https://api.icon.community/api/v3".to_string());
Expand Down
24 changes: 24 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,27 @@ async fn test_icx_to_hex() -> Result<(), ()> {

Ok(())
}

#[tokio::test]
async fn test_serialize_transaction() -> Result<(), ()> {
let res = icon_service::send_transaction(
"hx8dc6ae3d93e60a2dddf80bfc5fb1cd16a2bf6160",
"hxf8689d6c4c8f333651469fdea2ac59a18f6c242d",
"0x2386f26fc10000",
"0x2",
"0x1",
"0x1",
"0x186a0"
).await;

match res {
Ok(response) => {
assert_eq!(response, "308167c8113b6e6f3f9e7ba28f495af468ed636a72e411d99823a78c61d104b3")
// assert_eq!(response["jsonrpc"], "2.0");
// assert!(!response.as_object().unwrap().contains_key("error"));
},
Err(e) => println!("Error: {:?}", e),
}

Ok(())
}

0 comments on commit 646da2f

Please sign in to comment.