Track SAC Events

Note: this program relies on the previous SAC tracker program.

This program tracks all events of the SACs registered from the previous program.

Currently deployed version

This program is already live on Zephyr and is tracking events for SACs wrapped in and after ledger 177442 and its data can be accessed as follows:

query SACEvents {
  allZephyr86882807C5E507349D54F6F33Fc8229As {
    edges {
      node {
        sequence
        contract
        topic1
        topic2
        topic3
        topic4
        data
      }
    }
  }
}
{
  "data": {
    "allZephyr86882807C5E507349D54F6F33Fc8229As": {
      "edges": [
        {
          "node": {
            "sequence": "\\x0002b522",
            "contract": "\\xc184ad97f64befba0907b3cef6b570155c16658fcef92df221147d1592faa3e0",
            "topic1": "\\x0000000f000000046d696e74",
            "topic2": "\\x000000120000000000000000d08a167b577b96595971d6884e6a3097affb238ca5947585ead11660fa23676f",
            "topic3": "\\x00000012000000000000000047447cded9fa966bd551e683c1d39d5e9b32361f1a6483c15382f7684751bea0",
            "topic4": "\\x0000000e0000003c54454d3a47444949554654334b35355a4d574b5a4f484c495154544b47434c3237365a445253535a49354d46354c49524d594832454e545737374248",
            "data": "\\x0000000a00000000000000000000000000000190"
          }
        }
      ]
    }
  }
}

Remember that all this data is hex encoded bytes. topicn and data should be parsed as ScVals (ScVal::from_xdr(...)), contract is the inner Hash(<this is contract>) so you can easily build the corresponding string using the stellar-strkey libs. sequence is the big endian bytes repr for an i64. For example you can parse it in js as follows

const hex = "\\x0002b522";
const cleanHex = hex.replace(/\\x/g, '');
const result = parseInt(cleanHex, 16);

console.log(result);

Code

#![allow(unused)]
fn main() {
use rs_zephyr_sdk::{
    stellar_xdr::next::{ContractEventBody, Limits, TransactionMeta, WriteXdr},
    EnvClient,
};

#[no_mangle]
pub extern "C" fn on_close() {
    let mut env = EnvClient::default();
    let reader = env.reader();

    let sequence = reader.ledger_sequence();
    let processing = reader.tx_processing();

    let sacs = env.db_read("sacs", &["contract"]).unwrap();
    let tracked_deployed_sacs: Vec<&Vec<u8>> = sacs.rows.iter().map(|row| &row.row[0].0).collect();

    for tx_processing in processing {
        if let TransactionMeta::V3(meta) = &tx_processing.tx_apply_processing {
            if let Some(soroban) = &meta.soroban_meta {
                if !soroban.events.is_empty() {
                    for event in soroban.events.iter() {
                        let contract_id = event.contract_id.as_ref().unwrap().0;
                        if tracked_deployed_sacs.contains(&contract_id.to_vec().as_ref()) {
                            let (topics, data) = match &event.body {
                                ContractEventBody::V0(v0) => (
                                    v0.topics
                                        .iter()
                                        .map(|topic| topic.to_xdr(Limits::none()).unwrap())
                                        .collect::<Vec<Vec<u8>>>(),
                                    v0.data.to_xdr(Limits::none()).unwrap(),
                                ),
                            };
                            env.db_write(
                                "sac_event",
                                &[
                                    "sequence", "contract", "topic1", "topic2", "topic3", "topic4",
                                    "data",
                                ],
                                &[
                                    &sequence.to_be_bytes(),
                                    &contract_id,
                                    &topics.get(0).unwrap_or(&vec![]),
                                    &topics.get(1).unwrap_or(&vec![]),
                                    &topics.get(2).unwrap_or(&vec![]),
                                    &topics.get(3).unwrap_or(&vec![]),
                                    &data,
                                ],
                            )
                            .unwrap()
                        }
                    }
                }
            }
        }
    }
}
}