#![doc = include_str!("../README.md")]
use std::time::{SystemTime, UNIX_EPOCH};
use thegraph_core::alloy::{dyn_abi::Eip712Domain, primitives::Address, sol_types::eip712_domain};
use thiserror::Error;
mod error;
pub mod manager;
pub mod rav_request;
pub mod receipt;
pub mod signed_message;
pub use error::Error;
use error::Result;
fn get_current_timestamp_u64_ns() -> Result<u64> {
Ok(SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|err| Error::InvalidSystemTime {
source_error_message: err.to_string(),
})?
.as_nanos() as u64)
}
#[derive(Debug, Clone, Copy)]
pub enum TapVersion {
V1,
V2,
}
impl TapVersion {
pub fn as_str(&self) -> &'static str {
match self {
TapVersion::V1 => "1",
TapVersion::V2 => "2",
}
}
}
pub fn tap_eip712_domain(
chain_id: u64,
verifying_contract_address: Address,
version: TapVersion,
) -> Eip712Domain {
let name = match version {
TapVersion::V1 => "TAP",
TapVersion::V2 => "GraphTallyCollector",
};
eip712_domain! {
name: name,
version: "1",
chain_id: chain_id,
verifying_contract: verifying_contract_address,
}
}
#[cfg(test)]
mod tap_tests {
use std::str::FromStr;
use rstest::*;
use tap_graph::{Receipt, ReceiptAggregateVoucher};
use thegraph_core::alloy::{
dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner,
};
use crate::{signed_message::Eip712SignedMessage, tap_eip712_domain, TapVersion};
#[fixture]
fn keys() -> (PrivateKeySigner, Address) {
let wallet = PrivateKeySigner::random();
let address = wallet.address();
(wallet, address)
}
#[fixture]
fn allocation_ids() -> Vec<Address> {
vec![
Address::from_str("0xabababababababababababababababababababab").unwrap(),
Address::from_str("0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead").unwrap(),
Address::from_str("0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef").unwrap(),
Address::from_str("0x1234567890abcdef1234567890abcdef12345678").unwrap(),
]
}
#[fixture]
fn domain_separator() -> Eip712Domain {
tap_eip712_domain(1, Address::from([0x11u8; 20]), TapVersion::V1)
}
#[rstest]
#[case::basic_rav_test (vec![45,56,34,23])]
#[case::rav_from_zero_valued_receipts (vec![0,0,0,0])]
#[test]
fn signed_rav_is_valid_with_no_previous_rav(
keys: (PrivateKeySigner, Address),
allocation_ids: Vec<Address>,
domain_separator: Eip712Domain,
#[case] values: Vec<u128>,
) {
let mut receipts = Vec::new();
for value in values {
receipts.push(
Eip712SignedMessage::new(
&domain_separator,
Receipt::new(allocation_ids[0], value).unwrap(),
&keys.0,
)
.unwrap(),
);
}
let rav = ReceiptAggregateVoucher::aggregate_receipts(allocation_ids[0], &receipts, None)
.unwrap();
let signed_rav = Eip712SignedMessage::new(&domain_separator, rav, &keys.0).unwrap();
assert!(signed_rav.recover_signer(&domain_separator).unwrap() == keys.1);
}
#[rstest]
#[case::basic_rav_test(vec![45,56,34,23])]
#[case::rav_from_zero_valued_receipts(vec![0,0,0,0])]
#[test]
fn signed_rav_is_valid_with_previous_rav(
keys: (PrivateKeySigner, Address),
allocation_ids: Vec<Address>,
domain_separator: Eip712Domain,
#[case] values: Vec<u128>,
) {
let mut receipts = Vec::new();
for value in values {
receipts.push(
Eip712SignedMessage::new(
&domain_separator,
Receipt::new(allocation_ids[0], value).unwrap(),
&keys.0,
)
.unwrap(),
);
}
let prev_rav = ReceiptAggregateVoucher::aggregate_receipts(
allocation_ids[0],
&receipts[0..receipts.len() / 2],
None,
)
.unwrap();
let signed_prev_rav =
Eip712SignedMessage::new(&domain_separator, prev_rav, &keys.0).unwrap();
let rav = ReceiptAggregateVoucher::aggregate_receipts(
allocation_ids[0],
&receipts[receipts.len() / 2..receipts.len()],
Some(signed_prev_rav),
)
.unwrap();
let signed_rav = Eip712SignedMessage::new(&domain_separator, rav, &keys.0).unwrap();
assert!(signed_rav.recover_signer(&domain_separator).unwrap() == keys.1);
}
}