use k256::ecdsa::SigningKey;
use super::*;
pub async fn claim_daily_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
fee_token: &str,
) -> Result<String, String> {
sponsored_diamond_call(sender, fee_payer, selector("claimDaily()").to_vec(), fee_token, 600_000)
.await
}
pub async fn can_claim_credits(account_hex: &str) -> Result<bool, String> {
let account_bytes = hex_to_bytes(account_hex)?;
if account_bytes.len() != 20 {
return Err(format!("account must be 20 bytes, got {}", account_bytes.len()));
}
let mut padded = [0u8; 32];
padded[12..].copy_from_slice(&account_bytes);
let result_hex = read_view(selector("canClaim(address)"), &[padded]).await?;
let trimmed = result_hex.trim().trim_start_matches("0x");
Ok(trimmed.chars().last().map(|c| c == '1').unwrap_or(false))
}
pub async fn daily_allowance() -> Result<u128, String> {
let result = read_view(selector("dailyAllowance()"), &[]).await?;
decode_u256_as_u128(&result)
}
pub async fn last_claim_day(account_hex: &str) -> Result<u64, String> {
let account_bytes = hex_to_bytes(account_hex)?;
if account_bytes.len() != 20 {
return Err(format!("account must be 20 bytes, got {}", account_bytes.len()));
}
let mut padded = [0u8; 32];
padded[12..].copy_from_slice(&account_bytes);
let result_hex = read_view(selector("lastClaimDay(address)"), &[padded]).await?;
let val = decode_u256_as_u128(&result_hex)?;
Ok(val as u64)
}
pub(crate) fn encode_redeem(code: &str) -> Vec<u8> {
let sel = selector("redeem(string)");
let bytes = code.as_bytes();
let len = bytes.len();
let padded_len = len.div_ceil(32) * 32;
let mut buf = Vec::with_capacity(4 + 32 + 32 + padded_len);
buf.extend_from_slice(&sel);
buf.extend_from_slice(&u256_be(0x20));
buf.extend_from_slice(&u256_be(len as u128));
buf.extend_from_slice(bytes);
buf.resize(4 + 32 + 32 + padded_len, 0);
buf
}
pub async fn redeem_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
code: &str,
fee_token: &str,
) -> Result<String, String> {
sponsored_diamond_call(sender, fee_payer, encode_redeem(code), fee_token, 2_000_000).await
}
pub async fn session_expiry_of(account_hex: &str) -> Result<u64, String> {
let account = parse_eth_address(account_hex)?;
let result = read_view(selector("sessionExpiryOf(address)"), &[addr_word(&account)]).await?;
decode_u256_as_u64(&result)
}
pub async fn session_price() -> Result<u128, String> {
let result = read_view(selector("sessionPrice()"), &[]).await?;
decode_u256_as_u128(&result)
}
pub async fn open_session_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
fee_token: &str,
) -> Result<String, String> {
let price = session_price().await.unwrap_or(0);
let input = selector("openSession()").to_vec();
if price > 0 {
sponsored_escrow_diamond_call(sender, fee_payer, price, input, fee_token, 600_000).await
} else {
sponsored_diamond_call(sender, fee_payer, input, fee_token, 600_000).await
}
}
pub(crate) fn encode_deposit_credits(amount_wei: u128) -> Vec<u8> {
let mut out = Vec::with_capacity(4 + 32);
out.extend_from_slice(&selector("depositCredits(uint256)"));
out.extend_from_slice(&u256_be(amount_wei));
out
}
pub async fn credit_balance_of(account_hex: &str) -> Result<u128, String> {
let account = parse_eth_address(account_hex)?;
let result = read_view(selector("creditOf(address)"), &[addr_word(&account)]).await?;
decode_u256_as_u128(&result)
}
pub async fn deposit_credits_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
amount_wei: u128,
fee_token: &str,
) -> Result<String, String> {
sponsored_escrow_diamond_call(
sender,
fee_payer,
amount_wei,
encode_deposit_credits(amount_wei),
fee_token,
1_500_000,
)
.await
}
pub async fn withdraw_credits_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
amount_wei: u128,
fee_token: &str,
) -> Result<String, String> {
sponsored_diamond_call(
sender,
fee_payer,
encode_withdraw_credits(amount_wei),
fee_token,
1_000_000,
)
.await
}
pub(crate) fn encode_withdraw_credits(amount_wei: u128) -> Vec<u8> {
let mut out = Vec::with_capacity(4 + 32);
out.extend_from_slice(&selector("withdrawCredits(uint256)"));
out.extend_from_slice(&u256_be(amount_wei));
out
}
pub async fn lh_allowance(owner_hex: &str, spender_hex: &str) -> Result<u128, String> {
let owner = parse_eth_address(owner_hex)?;
let spender = parse_eth_address(spender_hex)?;
let calldata_hex = encode_call_hex(
selector("allowance(address,address)"),
&[addr_word(&owner), addr_word(&spender)],
);
let result = eth_call(LOCALHARNESS_TOKEN_ADDRESS, &calldata_hex).await?;
decode_u256_as_u128(&result)
}
pub async fn approve_lh_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
spender_hex: &str,
amount_wei: u128,
fee_token: &str,
) -> Result<String, String> {
let spender = parse_eth_address(spender_hex)?;
sponsored_call_to(
sender,
fee_payer,
LOCALHARNESS_TOKEN_ADDRESS,
encode_approve(&spender, amount_wei),
fee_token,
300_000,
)
.await
}
pub async fn transfer_lh_sponsored(
sender: &SigningKey,
fee_payer: &SigningKey,
to_hex: &str,
amount_wei: u128,
fee_token: &str,
) -> Result<String, String> {
let to = parse_eth_address(to_hex)?;
sponsored_call_to(
sender,
fee_payer,
LOCALHARNESS_TOKEN_ADDRESS,
encode_transfer(&to, amount_wei),
fee_token,
300_000,
)
.await
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deposit_credits_calldata_layout() {
let cd = encode_deposit_credits(1_000_000_000_000_000_000);
assert_eq!(&cd[0..4], &selector("depositCredits(uint256)"));
assert_eq!(cd.len(), 36);
}
}