// Copyright 2023-, Semiotic AI, Inc. // SPDX-License-Identifier: Apache-2.0 use std::{ collections::HashMap, str::FromStr, sync::{Arc, RwLock}, }; use alloy::{dyn_abi::Eip712Domain, primitives::Address, signers::local::PrivateKeySigner}; use rstest::*; use tap_core::{ manager::context::memory::{ checks::get_full_list_of_checks, EscrowStorage, InMemoryContext, QueryAppraisals, }, receipt::{ checks::{ReceiptCheck, StatefulTimestampCheck}, Context, Receipt, ReceiptWithState, }, signed_message::EIP712SignedMessage, tap_eip712_domain, }; #[fixture] fn signer() -> PrivateKeySigner { PrivateKeySigner::random() } #[fixture] fn allocation_ids() -> Vec
{ vec![ Address::from_str("0xabababababababababababababababababababab").unwrap(), Address::from_str("0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead").unwrap(), Address::from_str("0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef").unwrap(), Address::from_str("0x1234567890abcdef1234567890abcdef12345678").unwrap(), ] } #[fixture] fn sender_ids(signer: PrivateKeySigner) -> (PrivateKeySigner, Vec
) { let address = signer.address(); ( signer, vec![ Address::from_str("0xfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb").unwrap(), Address::from_str("0xfafafafafafafafafafafafafafafafafafafafa").unwrap(), Address::from_str("0xadadadadadadadadadadadadadadadadadadadad").unwrap(), address, ], ) } #[fixture] fn domain_separator() -> Eip712Domain { tap_eip712_domain(1, Address::from([0x11u8; 20])) } struct ContextFixture { context: InMemoryContext, escrow_storage: EscrowStorage, query_appraisals: QueryAppraisals, checks: Vec, signer: PrivateKeySigner, } #[fixture] fn context( domain_separator: Eip712Domain, allocation_ids: Vec
, sender_ids: (PrivateKeySigner, Vec
), ) -> ContextFixture { let (signer, sender_ids) = sender_ids; let escrow_storage = Arc::new(RwLock::new(HashMap::new())); let rav_storage = Arc::new(RwLock::new(None)); let receipt_storage = Arc::new(RwLock::new(HashMap::new())); let query_appraisals = Arc::new(RwLock::new(HashMap::new())); let timestamp_check = Arc::new(StatefulTimestampCheck::new(0)); let context = InMemoryContext::new( rav_storage, receipt_storage.clone(), escrow_storage.clone(), timestamp_check.clone(), ) .with_sender_address(signer.address()); let mut checks = get_full_list_of_checks( domain_separator, sender_ids.iter().cloned().collect(), Arc::new(RwLock::new(allocation_ids.iter().cloned().collect())), query_appraisals.clone(), ); checks.push(timestamp_check); ContextFixture { signer, context, escrow_storage, query_appraisals, checks, } } #[rstest] #[tokio::test] async fn partial_then_full_check_valid_receipt( domain_separator: Eip712Domain, allocation_ids: Vec
, context: ContextFixture, ) { let ContextFixture { checks, escrow_storage, query_appraisals, signer, .. } = context; let query_value = 20u128; let signed_receipt = EIP712SignedMessage::new( &domain_separator, Receipt::new(allocation_ids[0], query_value).unwrap(), &signer, ) .unwrap(); let query_id = signed_receipt.unique_hash(); // add escrow for sender escrow_storage .write() .unwrap() .insert(signer.address(), query_value + 500); // appraise query query_appraisals .write() .unwrap() .insert(query_id, query_value); let mut received_receipt = ReceiptWithState::new(signed_receipt); let result = received_receipt .perform_checks(&Context::new(), &checks) .await; assert!(result.is_ok()); } #[rstest] #[tokio::test] async fn partial_then_finalize_valid_receipt( allocation_ids: Vec
, domain_separator: Eip712Domain, context: ContextFixture, ) { let ContextFixture { checks, context, escrow_storage, query_appraisals, signer, .. } = context; let query_value = 20u128; let signed_receipt = EIP712SignedMessage::new( &domain_separator, Receipt::new(allocation_ids[0], query_value).unwrap(), &signer, ) .unwrap(); let query_id = signed_receipt.unique_hash(); // add escrow for sender escrow_storage .write() .unwrap() .insert(signer.address(), query_value + 500); // appraise query query_appraisals .write() .unwrap() .insert(query_id, query_value); let received_receipt = ReceiptWithState::new(signed_receipt); let awaiting_escrow_receipt = received_receipt .finalize_receipt_checks(&Context::new(), &checks) .await; assert!(awaiting_escrow_receipt.is_ok()); let awaiting_escrow_receipt = awaiting_escrow_receipt.unwrap(); let receipt = awaiting_escrow_receipt .unwrap() .check_and_reserve_escrow(&context, &domain_separator) .await; assert!(receipt.is_ok()); } #[rstest] #[tokio::test] async fn standard_lifetime_valid_receipt( allocation_ids: Vec
, domain_separator: Eip712Domain, context: ContextFixture, ) { let ContextFixture { checks, context, escrow_storage, query_appraisals, signer, .. } = context; let query_value = 20u128; let signed_receipt = EIP712SignedMessage::new( &domain_separator, Receipt::new(allocation_ids[0], query_value).unwrap(), &signer, ) .unwrap(); let query_id = signed_receipt.unique_hash(); // add escrow for sender escrow_storage .write() .unwrap() .insert(signer.address(), query_value + 500); // appraise query query_appraisals .write() .unwrap() .insert(query_id, query_value); let received_receipt = ReceiptWithState::new(signed_receipt); let awaiting_escrow_receipt = received_receipt .finalize_receipt_checks(&Context::new(), &checks) .await; assert!(awaiting_escrow_receipt.is_ok()); let awaiting_escrow_receipt = awaiting_escrow_receipt.unwrap(); let receipt = awaiting_escrow_receipt .unwrap() .check_and_reserve_escrow(&context, &domain_separator) .await; assert!(receipt.is_ok()); }