Smart Contracts
Contract Events

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 position
  • positionId - Unique identifier for the position
  • amount - Amount of tokens staked
  • referrer - 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 interest
  • positionId - Position being claimed from
  • interestClaimed - Amount claimed in this transaction
  • totalClaimed - Cumulative total claimed from this position
  • paidDays - Number of days paid for
  • timestamp - 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 commission
  • referee - Address who was referred
  • stakeAmount - Amount referee staked
  • rewardAmount - Commission earned (5% of stake)
  • newTotalVolume - Referrer's updated total volume
  • timestamp - 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 rewards
  • claimedAmount - Amount claimed
  • remainingRewards - Unclaimed amount still available
  • timestamp - 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 milestone
  • newLevel - Milestone level achieved (1-4)
  • totalBonus - Bonus amount awarded
  • vestingDuration - Vesting period in seconds
  • timestamp - 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 tokens
  • milestoneLevel - Milestone level (1-4)
  • claimedAmount - Amount claimed
  • remainingAmount - Amount still vesting
  • timestamp - 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 address
  • totalStaked - Total amount staked
  • totalPositions - Number of active positions
  • milestone - Current milestone level
  • timestamp - 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 identifier
  • user - User requesting cash out
  • amount - Net amount (after fee)
  • fee - Fee charged
  • solanaAddress - Destination Solana address
  • timestamp - 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 identifier
  • user - User address
  • amount - Amount sent to Solana
  • solanaAddress - Destination address
  • processedBy - Admin who processed
  • timestamp - 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 identifier
  • user - User receiving refund
  • amount - Refunded amount
  • refundedBy - Admin who refunded
  • reason - Reason for refund
  • timestamp - 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 address
  • reason - Explanation
  • timestamp - 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 value
  • timestamp - 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:

  1. Always handle event listener errors
  2. Implement reconnection logic
  3. Store events in database for reliability
  4. Use block confirmations before processing
  5. 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();
    }
  });
};

Next Steps

Resources