Contract Events
Complete reference for all events emitted by DogWithCapStaking contract.
Overview
Events are emitted for all significant state changes. They enable:
- Off-chain indexing and tracking
- User notification systems
- Analytics and monitoring
- Transaction history
Core Staking Events
PositionCreated
event PositionCreated(
address indexed user,
uint256 indexed positionId,
uint256 amount,
address indexed referrer,
uint256 timestamp
)Emitted when: A new staking position is created.
Parameters:
user- Address that created the positionpositionId- Unique identifier for the positionamount- Amount of tokens stakedreferrer- Referrer address (0x0 if none)timestamp- Block timestamp
Indexed Fields: user, positionId, referrer
Example Usage:
contract.on("PositionCreated", (user, positionId, amount, referrer, timestamp) => {
console.log(`User ${user} staked ${amount} tokens`);
console.log(`Position ID: ${positionId}`);
});PositionClaimed
event PositionClaimed(
address indexed user,
uint256 indexed positionId,
uint256 interestClaimed,
uint256 totalClaimed,
uint256 paidDays,
uint256 timestamp
)Emitted when: Interest is claimed from a position.
Parameters:
user- Address claiming interestpositionId- Position being claimed frominterestClaimed- Amount claimed in this transactiontotalClaimed- Cumulative total claimed from this positionpaidDays- Number of days paid fortimestamp- Block timestamp
Indexed Fields: user, positionId
Use Case: Track claiming patterns and earnings.
Referral Events
ReferralReward
event ReferralReward(
address indexed referrer,
address indexed referee,
uint256 stakeAmount,
uint256 rewardAmount,
uint256 newTotalVolume,
uint256 timestamp
)Emitted when: A referral reward is earned.
Parameters:
referrer- Address earning the commissionreferee- Address who was referredstakeAmount- Amount referee stakedrewardAmount- Commission earned (5% of stake)newTotalVolume- Referrer's updated total volumetimestamp- Block timestamp
Indexed Fields: referrer, referee
Example Query:
// Get all referrals for an address
const filter = contract.filters.ReferralReward(referrerAddress);
const events = await contract.queryFilter(filter);ReferralRewardsClaimed
event ReferralRewardsClaimed(
address indexed user,
uint256 claimedAmount,
uint256 remainingRewards,
uint256 timestamp
)Emitted when: User claims accumulated referral rewards.
Parameters:
user- Address claiming rewardsclaimedAmount- Amount claimedremainingRewards- Unclaimed amount still availabletimestamp- Block timestamp
Indexed Fields: user
Milestone Events
MilestoneAchieved
event MilestoneAchieved(
address indexed user,
MilestoneLevel indexed newLevel,
uint256 totalBonus,
uint256 vestingDuration,
uint256 timestamp
)Emitted when: User reaches a new milestone level.
Parameters:
user- Address achieving milestonenewLevel- Milestone level achieved (1-4)totalBonus- Bonus amount awardedvestingDuration- Vesting period in secondstimestamp- Block timestamp
Indexed Fields: user, newLevel
Milestone Levels:
enum MilestoneLevel {
NONE, // 0
BRONZE, // 1
SILVER, // 2
GOLD, // 3
DIAMOND // 4
}MilestoneVestingClaimed
event MilestoneVestingClaimed(
address indexed user,
uint8 indexed milestoneLevel,
uint256 claimedAmount,
uint256 remainingAmount,
uint256 timestamp
)Emitted when: Vested milestone bonus is claimed.
Parameters:
user- Address claiming vested tokensmilestoneLevel- Milestone level (1-4)claimedAmount- Amount claimedremainingAmount- Amount still vestingtimestamp- Block timestamp
Indexed Fields: user, milestoneLevel
User Stats Event
UserStatsUpdate
event UserStatsUpdate(
address indexed user,
uint256 totalStaked,
uint256 totalPositions,
MilestoneLevel milestone,
uint256 timestamp
)Emitted when: User's overall stats change.
Parameters:
user- User addresstotalStaked- Total amount stakedtotalPositions- Number of active positionsmilestone- Current milestone leveltimestamp- Block timestamp
Indexed Fields: user
Triggers:
- Creating new position
- Achieving milestone
- Any major state change
Cash Out Events
CashOutRequested
event CashOutRequested(
uint256 indexed requestId,
address indexed user,
uint256 amount,
uint256 fee,
string solanaAddress,
uint256 timestamp
)Emitted when: User requests cross-chain cash out.
Parameters:
requestId- Unique request identifieruser- User requesting cash outamount- Net amount (after fee)fee- Fee chargedsolanaAddress- Destination Solana addresstimestamp- Block timestamp
Indexed Fields: requestId, user
CashOutProcessed
event CashOutProcessed(
uint256 indexed requestId,
address indexed user,
uint256 amount,
string solanaAddress,
address processedBy,
uint256 timestamp
)Emitted when: Cash out is processed by admin.
Parameters:
requestId- Request identifieruser- User addressamount- Amount sent to SolanasolanaAddress- Destination addressprocessedBy- Admin who processedtimestamp- Block timestamp
Indexed Fields: requestId, user
CashOutRefunded
event CashOutRefunded(
uint256 indexed requestId,
address indexed user,
uint256 amount,
address refundedBy,
string reason,
uint256 timestamp
)Emitted when: Cash out is refunded.
Parameters:
requestId- Request identifieruser- User receiving refundamount- Refunded amountrefundedBy- Admin who refundedreason- Reason for refundtimestamp- Block timestamp
Indexed Fields: requestId, user
Admin Events
DailyInterestRateChanged
event DailyInterestRateChanged(
uint256 indexed oldRate,
uint256 indexed newRate,
address indexed changedBy,
string reason,
uint256 timestamp
)Emitted when: Admin changes the daily interest rate.
Parameters:
oldRate- Previous rate (basis points)newRate- New rate (basis points)changedBy- Admin addressreason- Explanationtimestamp- Block timestamp
Indexed Fields: oldRate, newRate, changedBy
AdminAction
event AdminAction(
string indexed action,
address indexed target,
uint256 value,
uint256 timestamp
)Emitted when: Admin performs significant action.
Parameters:
action- Action type (e.g., "DEPOSIT_REWARDS")target- Target address (if applicable)value- Associated valuetimestamp- Block timestamp
Indexed Fields: action, target
Action Types:
- "DEPOSIT_REWARDS"
- "SET_DAILY_INTEREST_RATE"
- "UPDATE_MILESTONE"
- "PAUSE"
- "UNPAUSE"
- "WITHDRAW_EXCESS"
- "MARK_CASH_OUT_PROCESSED"
- "REFUND_CASH_OUT"
Event Indexing
Using Web3.js
// Get all events for a user
const events = await contract.getPastEvents('allEvents', {
filter: { user: userAddress },
fromBlock: 0,
toBlock: 'latest'
});Using ethers.js
// Listen to PositionCreated events
contract.on("PositionCreated", (user, positionId, amount, referrer, timestamp) => {
console.log(`Position ${positionId} created by ${user}`);
});
// Query historical events
const filter = contract.filters.PositionCreated(userAddress);
const events = await contract.queryFilter(filter, startBlock, endBlock);Using viem
import { parseAbiItem } from 'viem';
const logs = await publicClient.getLogs({
address: contractAddress,
event: parseAbiItem('event PositionCreated(address indexed user, uint256 indexed positionId, uint256 amount, address indexed referrer, uint256 timestamp)'),
args: {
user: userAddress
},
fromBlock: startBlock,
toBlock: endBlock
});Event Monitoring
Backend Listener Example
// Listen to all important events
const startListening = () => {
// Position events
contract.on("PositionCreated", handlePositionCreated);
contract.on("PositionClaimed", handlePositionClaimed);
// Referral events
contract.on("ReferralReward", handleReferralReward);
contract.on("ReferralRewardsClaimed", handleReferralClaimed);
// Milestone events
contract.on("MilestoneAchieved", handleMilestoneAchieved);
contract.on("MilestoneVestingClaimed", handleVestingClaimed);
// Admin events
contract.on("DailyInterestRateChanged", handleRateChange);
};
const handlePositionCreated = async (
user,
positionId,
amount,
referrer,
timestamp,
event
) => {
// Save to database
await db.positions.create({
user,
positionId: positionId.toString(),
amount: amount.toString(),
referrer,
timestamp: timestamp.toNumber(),
txHash: event.transactionHash
});
// Notify user
await notifyUser(user, 'Position created successfully');
};Analytics Queries
Total Volume by User
const getUserVolume = async (userAddress: string) => {
const filter = contract.filters.PositionCreated(userAddress);
const events = await contract.queryFilter(filter);
const totalVolume = events.reduce((sum, event) => {
return sum + parseFloat(formatUnits(event.args.amount, 18));
}, 0);
return totalVolume;
};Referral Network
const getReferralTree = async (referrerAddress: string) => {
const filter = contract.filters.ReferralReward(referrerAddress);
const events = await contract.queryFilter(filter);
const referees = events.map(event => ({
address: event.args.referee,
stakeAmount: formatUnits(event.args.stakeAmount, 18),
rewardAmount: formatUnits(event.args.rewardAmount, 18),
timestamp: event.args.timestamp.toNumber()
}));
return referees;
};Daily Claims
const getDailyClaims = async (days: number) => {
const blocksPerDay = 28800; // Approximate
const currentBlock = await provider.getBlockNumber();
const startBlock = currentBlock - (blocksPerDay * days);
const filter = contract.filters.PositionClaimed();
const events = await contract.queryFilter(filter, startBlock);
// Group by day
const dailyData = events.reduce((acc, event) => {
const day = Math.floor(event.args.timestamp.toNumber() / 86400);
acc[day] = (acc[day] || 0) + parseFloat(formatUnits(event.args.interestClaimed, 18));
return acc;
}, {});
return dailyData;
};Best Practices
Event Handling
Best Practices:
- Always handle event listener errors
- Implement reconnection logic
- Store events in database for reliability
- Use block confirmations before processing
- Implement idempotency for event handlers
Error Handling
const safeEventListener = (handler: Function) => {
return async (...args: any[]) => {
try {
await handler(...args);
} catch (error) {
console.error('Event handler error:', error);
// Log to monitoring service
await logError(error);
}
};
};
contract.on("PositionCreated", safeEventListener(handlePositionCreated));Reconnection
const setupWithReconnection = () => {
let reconnectAttempts = 0;
const maxReconnects = 5;
provider.on('error', async (error) => {
console.error('Provider error:', error);
if (reconnectAttempts < maxReconnects) {
reconnectAttempts++;
await new Promise(resolve => setTimeout(resolve, 5000 * reconnectAttempts));
setupEventListeners();
}
});
provider.on('network', (newNetwork, oldNetwork) => {
if (oldNetwork) {
console.log('Network changed, reconnecting...');
setupEventListeners();
}
});
};