Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions contracts/staking_rewards/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ──────────────────────────────────────
Expand Down Expand Up @@ -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(())
}

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
65 changes: 59 additions & 6 deletions web/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div style={{ minHeight: '100vh', backgroundColor: '#0f1117' }}>
{/* Header */}
<header
Expand Down Expand Up @@ -142,11 +195,11 @@ export default function Home() {
</div>
)}
>
<UploadZone
onFileReady={(file) => {
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
}}
<UploadZone
onFileReady={(file) => {
console.log('[UploadZone] Contract ready for analysis:', file.name, file.size, 'bytes');
handleFileAnalysis(file);
}}
/>
</ErrorBoundary>
</div>
Expand Down