diff --git a/contracts/staking_rewards/src/lib.rs b/contracts/staking_rewards/src/lib.rs index 9daa544..483c1db 100644 --- a/contracts/staking_rewards/src/lib.rs +++ b/contracts/staking_rewards/src/lib.rs @@ -13,6 +13,7 @@ pub const SCALE: i128 = 1_000_000_000_000_000_000; // 18 decimals pub enum DataKey { Config, UserState(Address), + TotalStaked, } // ── Configuration Struct ────────────────────────────────────── @@ -242,10 +243,18 @@ impl StakingRewards { start_block, is_paused: false, }; - + + // Update total staked + let mut total_staked = e.storage().instance().get(&DataKey::TotalStaked).unwrap_or(0); + total_staked = total_staked + .checked_add(amount) + .ok_or(ContractError::Overflow)?; + e.storage().instance().set(&DataKey::TotalStaked, &total_staked); + e.storage().instance().set(&DataKey::Config, &config); + e.storage().instance().set(&DataKey::TotalStaked, &0i128); e.storage().instance().extend_ttl(10000, 10000); - + Ok(()) } @@ -315,6 +324,12 @@ impl StakingRewards { .staked_amount .checked_sub(amount) .ok_or(ContractError::Overflow)?; + + // Update total staked + let mut total_staked = e.storage().instance().get(&DataKey::TotalStaked).unwrap_or(0); + total_staked = total_staked + .checked_sub(amount) + .ok_or(ContractError::Overflow)?; if state.staked_amount == 0 && state.accrued_rewards == 0 { e.storage() @@ -409,6 +424,13 @@ impl StakingRewards { let state: UserStakingState = e.storage().persistent().get(&state_key).unwrap(); let staked_amount = state.staked_amount; + + // Update total staked + let mut total_staked = e.storage().instance().get(&DataKey::TotalStaked).unwrap_or(0); + total_staked = total_staked + .checked_sub(staked_amount) + .ok_or(ContractError::Overflow)?; + e.storage().instance().set(&DataKey::TotalStaked, &total_staked); if staked_amount <= 0 { return Ok(0); @@ -494,6 +516,9 @@ impl StakingRewards { let t_curr = e.ledger().sequence(); if state.staked_amount > 0 && t_curr > state.last_update_block { + // Time-based reward calculation: V_new = V_old * multiplier, where + // multiplier = exp(integral of reward rate over time). Rewards are + // computed as R_new = V_new - staked_amount to avoid rounding errors. let multiplier_res = calculate_multiplier(&config, state.last_update_block, t_curr); if let Ok(multiplier) = multiplier_res { let v_old_res = state.staked_amount.checked_add(state.accrued_rewards); @@ -541,6 +566,9 @@ impl StakingRewards { let t_curr = e.ledger().sequence(); if state.staked_amount > 0 && t_curr > state.last_update_block { + // Time-based reward calculation: V_new = V_old * multiplier, where + // multiplier = exp(integral of reward rate over time). Rewards are + // computed as R_new = V_new - staked_amount to avoid rounding errors. let multiplier = calculate_multiplier(config, state.last_update_block, t_curr)?; // Virtual Balance V = S + R diff --git a/web/pages/index.tsx b/web/pages/index.tsx index 780012b..60911db 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -74,7 +74,60 @@ export default function Home() { } }; - return ( + const handleFileAnalysis = async (file: File) => { + setLoading(true); + let errorType: string | undefined; + try { + // Convert file to ArrayBuffer + const arrayBuffer = await file.arrayBuffer(); + const response = await fetch('http://localhost:8080/analyze', { + method: 'POST', + headers: { 'Content-Type': 'application/octet-stream' }, + body: arrayBuffer, + }); + + if (!response.ok) { + // Parse error response from backend + const errorResponse = await extractErrorDetails(response); + errorType = errorResponse.error; + const userMessage = createUserFriendlyMessage(errorResponse); + throw new Error(userMessage); + } + + const report = await response.json(); + + const result: InvocationResult = { + id: Math.random().toString(36).substring(7), + functionName: 'WASM Analysis', + inputs: {}, + result: null, + resourceCost: report, + timestamp: Date.now(), + success: true, + }; + + setCurrentResult(result); + addToHistory(result); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'An unexpected error occurred during analysis'; + + const errorResult: InvocationResult = { + id: Math.random().toString(36).substring(7), + functionName: 'WASM Analysis', + inputs: {}, + error: errorMessage, + errorType: errorType || 'UNKNOWN_ERROR', + timestamp: Date.now(), + success: false, + }; + setCurrentResult(errorResult); + addToHistory(errorResult); + } finally { + setLoading(false); + } + }; + + return (
{/* Header */}
)} > - { - console.log('[UploadZone] Contract ready for analysis:', file.name, file.size, 'bytes'); - // TODO: wire into your analysis flow, e.g. POST file bytes to /analyze - }} + { + console.log('[UploadZone] Contract ready for analysis:', file.name, file.size, 'bytes'); + handleFileAnalysis(file); + }} />