Skip to content

Instantly share code, notes, and snippets.

@Enigo
Last active April 29, 2023 13:58
Show Gist options
  • Save Enigo/35d4fdaccc71b3a951d75e0970d320a1 to your computer and use it in GitHub Desktop.
Save Enigo/35d4fdaccc71b3a951d75e0970d320a1 to your computer and use it in GitHub Desktop.
const LAND_CONTRACT: &str = "0x7a47f7707c4b2f2b1def04a47cd8681d48eadeb8";
const LAND_CONTRACT_CREATION_BLOCK: &str = "14846665";
const LAND_FUNCTION_NAME: &str = "buyL2";
pub async fn read_transactions() {
let api_key = String::from("ETHERSCAN_API_KEY_VALUE");
match mints_reader::read_mints().await {
Some(mints) => {
let mut futures = futures::stream::iter(mints.result)
.map(|res| process_wallet(res.wallet, &api_key))
.buffer_unordered(3);
// waiting for all to complete
while let Some(_) = futures.next().await {}
}
_ => {}
}
}
async fn process_wallet(wallet: String, api_key: &String) {
let mut page = 1;
loop {
let transactions = fetch_transactions(wallet.clone(), api_key, page).await;
if transactions.is_empty() {
break;
}
for res in transactions {
if res.is_error == "1" || res.to != LAND_CONTRACT || !res.function_name.contains(LAND_FUNCTION_NAME) {
continue;
}
let input_to_decode = res.input.replace(res.method_id.as_str(), "");
match decode_input_and_get_token_id(input_to_decode.as_str()) {
Ok(token_id) => {
if res.value == "0" {
// land was bought with sILV2
} else {
// The value returned by the Etherscan API endpoint is in Wei, which is the smallest unit of ether
let wei_value = Decimal::from_str(res.value.as_str()).unwrap();
let ether_value = wei_value / Decimal::new(10i64.pow(18), 0);
// match token_ids and persist ether_value
}
}
Err(e) => { error!("Error decoding input {e}") }
};
}
page += 1;
}
}
async fn fetch_transactions(
wallet: String,
api_key: &String,
page: i8,
) -> Vec<transaction::TheResult> {
let endpoint = format!("https://api.etherscan.io/api?module=account&action=txlist&address={}&page={}&offset=10000&startblock={}&endblock=99999999&sort=asc&apikey={}",
wallet, page, LAND_CONTRACT_CREATION_BLOCK, api_key);
return match api_utils::fetch_single_api_response::<transaction::Transaction>(endpoint.as_str()).await {
Ok(transaction) => {
if transaction.status == "1" {
return transaction.result.unwrap();
}
return vec![];
}
_ => vec![]
};
}
fn decode_input_and_get_token_id(input_to_decode: &str) -> Result<i32, Box<dyn std::error::Error>> {
fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
.collect()
}
let input_decoded = decode_hex(input_to_decode)?;
let input_params = vec![ParamType::Tuple(vec![ParamType::Uint(32), ParamType::Uint(32), ParamType::Uint(8), ParamType::Uint(16), ParamType::Uint(16), ParamType::Uint(8), ParamType::Uint(16)]), ParamType::FixedBytes(32)];
let decoded_input = decode(&input_params, &input_decoded[..])?;
let token_id = decoded_input[0]
.clone()
.into_tuple()
.ok_or("Error: could not convert decoded input into tuple")?[0]
.clone()
.into_uint()
.ok_or("Error: could not convert tuple element into uint")?
.as_u32();
Ok(token_id as i32)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment