use k256::ecdsa::SigningKey;
use super::*;
pub const TITHE_MAX_BPS: u64 = 10_000;
pub(crate) fn encode_set_tithe(guild_id: u64, bps: u64) -> Vec<u8> {
let mut out = Vec::with_capacity(4 + 64);
out.extend_from_slice(&selector("setTithe(uint256,uint256)"));
out.extend_from_slice(&u256_be(guild_id as u128));
out.extend_from_slice(&u256_be(bps as u128));
out
}
pub(crate) fn encode_revoke_tithe() -> Vec<u8> {
selector("revokeTithe()").to_vec()
}
pub(crate) fn encode_collect_tithe(account: &[u8; 20]) -> Vec<u8> {
let mut out = Vec::with_capacity(4 + 32);
out.extend_from_slice(&selector("collectTithe(address)"));
out.extend_from_slice(&addr_word(account));
out
}
pub fn set_tithe_call(guild_id: u64, bps: u64) -> Result<crate::tempo_tx::TempoCall, String> {
let diamond = parse_eth_address(REGISTRY_ADDRESS)?;
Ok(crate::tempo_tx::TempoCall {
to: diamond,
value_wei: 0,
input: encode_set_tithe(guild_id, bps),
})
}
pub async fn revoke_tithe_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
fee_token: &str,
) -> Result<String, String> {
sponsored_diamond_call(sender, fee_payer, encode_revoke_tithe(), fee_token, 400_000).await
}
pub async fn collect_tithe_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
account_hex: &str,
fee_token: &str,
) -> Result<String, String> {
let account = parse_eth_address(account_hex)?;
sponsored_diamond_call(
sender,
fee_payer,
encode_collect_tithe(&account),
fee_token,
1_000_000,
)
.await
}
pub async fn tithe_of(account_hex: &str) -> Result<(u64, u64), String> {
let account = parse_eth_address(account_hex)?;
let result = read_view(selector("titheOf(address)"), &[addr_word(&account)]).await?;
let bytes = hex_to_bytes(&result)?;
if bytes.len() < 64 {
return Ok((0, 0)); }
let guild_id = u64_low(&bytes[0..32]);
let bps = u64_low(&bytes[32..64]);
Ok((guild_id, bps))
}
#[cfg(test)]
mod tithe_tests {
use super::*;
#[test]
fn set_tithe_calldata_layout() {
let cd = encode_set_tithe(7, 500); assert_eq!(&cd[0..4], &selector("setTithe(uint256,uint256)"));
assert_eq!(cd.len(), 4 + 64);
assert_eq!(u64::from_be_bytes(cd[4 + 24..4 + 32].try_into().unwrap()), 7); assert_eq!(u64::from_be_bytes(cd[36 + 24..36 + 32].try_into().unwrap()), 500); }
#[test]
fn revoke_tithe_calldata_layout() {
let cd = encode_revoke_tithe();
assert_eq!(&cd[..], &selector("revokeTithe()"));
assert_eq!(cd.len(), 4);
}
#[test]
fn collect_tithe_calldata_layout() {
let account = [0xFFu8; 20];
let cd = encode_collect_tithe(&account);
assert_eq!(&cd[0..4], &selector("collectTithe(address)"));
assert_eq!(cd.len(), 4 + 32);
assert!(cd[4..4 + 12].iter().all(|&b| b == 0)); assert_eq!(&cd[4 + 12..4 + 32], &account); }
#[test]
fn set_tithe_call_targets_diamond() {
let call = set_tithe_call(9, 1000).unwrap();
assert_eq!(call.to, parse_eth_address(REGISTRY_ADDRESS).unwrap());
assert_eq!(call.value_wei, 0);
assert_eq!(call.input, encode_set_tithe(9, 1000));
}
#[test]
fn tithe_of_decode_and_short_response() {
let mut bytes = Vec::new();
bytes.extend_from_slice(&u256_be(42)); bytes.extend_from_slice(&u256_be(250)); assert_eq!(u64_low(&bytes[0..32]), 42);
assert_eq!(u64_low(&bytes[32..64]), 250);
assert!(bytes[0..32].len() < 64);
}
}