-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcall.rs
More file actions
153 lines (137 loc) · 4.52 KB
/
Copy pathcall.rs
File metadata and controls
153 lines (137 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use mlua::{Error as LuaError, Lua, Result as LuaResult, Table};
use regex::Regex;
use starknet::{
core::types::{BlockId, BlockTag, FieldElement, FunctionCall},
core::utils::get_selector_from_name,
providers::{AnyProvider, Provider},
};
use crate::account;
use crate::error::{Error, ErrorExtLua, KiptResult};
use crate::lua::{self, LuaOutput, LuaTableSetable, RT};
/// Call output.
struct CallOutput {
pub data: Vec<String>,
}
impl LuaTableSetable for CallOutput {
fn set_all(&self, table: &Table) {
table.set("data", self.data.clone()).unwrap();
}
}
/// Defines a lua function that make a function call to a contract.
///
/// # Arguments
///
/// * `lua` - Lua VM instance.
/// * `contract_address` - The contract deployed contract address to call.
/// * `function_name` - The function name to convert into a selector.
/// * `calldata` - The function call arguments.
/// * `options` - Options for the call.
pub fn lua_call<'lua>(
lua: &'lua Lua,
contract_address: String,
function_name: String,
calldata: Vec<String>,
options: Table<'lua>,
) -> LuaResult<Table<'lua>> {
let url_network = lua::get_provider(lua)?;
let block_id: Option<String> = options.get("block_id")?;
let data = futures::executor::block_on(async move {
RT.spawn(async move {
let provider = match account::setup_provider(&url_network).await {
Ok(a) => a,
Err(e) => {
return LuaOutput {
is_success: false,
data: None,
error: format!("{:?}", e),
}
}
};
match function_call(
&provider,
&contract_address,
&function_name,
calldata,
&block_id.unwrap_or("pending".to_string()),
)
.await
{
Ok(call_res) => LuaOutput {
is_success: false,
data: Some(CallOutput { data: call_res }),
error: "".to_string(),
},
Err(e) => LuaOutput {
is_success: false,
data: None,
error: format!("{:?}", e),
},
}
})
.await
.unwrap()
});
if data.error.is_empty() {
let t = lua.create_table()?;
if let Some(d) = data.data {
// Lua idx starts to 1, sadly.
let mut idx = 1;
for v in d.data {
t.set(idx, v)?;
idx += 1;
}
}
Ok(t)
} else {
Err(LuaError::ExternalError(std::sync::Arc::new(
ErrorExtLua::new(&data.error),
)))
}
}
/// Sends an invoke transaction to a contract.
///
/// # Arguments
///
/// * `provider` - The provider to make the function call.
/// * `contract_address` - The deployed contract address.
/// * `function_name` - Name of the function to be executed.
/// * `calldata` - The call data felts to pass as argument to the function.
/// * `block_id` - The block id against which the function call is made.
async fn function_call(
provider: &AnyProvider,
contract_address: &str,
function_name: &str,
calldata: Vec<String>,
block_id: &str,
) -> KiptResult<Vec<String>> {
let mut sn_calldata = vec![];
for c in calldata {
sn_calldata.push(FieldElement::from_hex_be(&c)?);
}
let r = provider
.call(
FunctionCall {
contract_address: FieldElement::from_hex_be(contract_address)?,
entry_point_selector: get_selector_from_name(function_name)?,
calldata: sn_calldata,
},
parse_block_id(block_id)?,
)
.await?;
Ok(r.into_iter().map(|f| format!("0x{:064x}", f)).collect())
}
/// Function from starkli: https://github.com/xJonathanLEI/starkli/blob/3fd85cf58f7adf757f3a62a86ae4e1fe487b4c8a/src/utils.rs#L59C1-L71C2
pub fn parse_block_id(id: &str) -> KiptResult<BlockId> {
let regex_block_number = Regex::new("^[0-9]{1,}$").unwrap();
if id == "latest" {
Ok(BlockId::Tag(BlockTag::Latest))
} else if id == "pending" {
Ok(BlockId::Tag(BlockTag::Pending))
} else if regex_block_number.is_match(id) {
Ok(BlockId::Number(id.parse::<u64>().map_err(|_e| {
Error::Other(format!("Can't convert block_id as u64: {}", id))
})?))
} else {
Ok(BlockId::Hash(FieldElement::from_hex_be(id)?))
}
}