Corporate action entity reference (Dividends, Voting)
Dividends, voting proposals, and other corporate actions for token holders
Corporate action entities track dividends, voting proposals, and other events that affect token holders. These entities are indexed by TheGraph from addon contract events.
Schema location:
kit/subgraph/schema.graphql
DividendDistribution
Dividend payment scheduled for token holders.
Fields
type DividendDistribution @entity {
id: Bytes! # Distribution contract + distribution ID
token: Token! # Token receiving dividend
distributionToken: Token! # Token used for payment
totalAmount: BigDecimal! # Total dividend amount
amountPerToken: BigDecimal! # Amount per token unit
snapshotId: BigInt! # Balance snapshot ID
snapshotTimestamp: BigInt! # When snapshot was taken
claimDeadline: BigInt! # Last claim timestamp
createdAt: BigInt! # Creation timestamp
claimedAmount: BigDecimal! # Total claimed so far
claimCount: BigInt! # Number of claims
isActive: Boolean! # Currently claimable
claims: [DividendClaim!]! # Individual claims
}Relationships
- Many-to-one:
token→ Security tokendistributionToken→ Payment token (can be same astokenor different)
- One-to-many:
claims→ Individual holder claims
Distribution lifecycle
- Created - Dividend announced with snapshot
- Active - Holders can claim proportional amounts
- Expired - After
claimDeadline, unclaimed funds returned - Withdrawn - Admin withdraws unclaimed after deadline
Usage example
query GetDividends($tokenAddress: Bytes!) {
dividendDistributions(
where: { token: $tokenAddress, isActive: true }
orderBy: createdAt
orderDirection: desc
) {
id
totalAmount
amountPerToken
distributionToken {
symbol
decimals
}
claimDeadline
claimedAmount
claimCount
}
}
# Get unclaimed dividends for holder
query GetUnclaimedDividends($tokenAddress: Bytes!, $holderAddress: Bytes!) {
dividendDistributions(where: { token: $tokenAddress, isActive: true }) {
id
totalAmount
amountPerToken
claimDeadline
claims(where: { holder: $holderAddress }) {
id
claimed
}
}
}DividendClaim
Individual holder's claim on a dividend distribution.
Fields
type DividendClaim @entity {
id: Bytes! # distribution + holder address
distribution: DividendDistribution! # Parent distribution
holder: Account! # Token holder
amount: BigDecimal! # Claimable amount
claimed: Boolean! # Claim status
claimedAt: BigInt # Claim timestamp
claimTx: Bytes # Claim transaction hash
}Relationships
- Many-to-one:
distribution→ Parent distributionholder→ Token holder account (see Investor entities)
Claim calculation
// Amount holder can claim
claimableAmount = (holderBalance at snapshotId) * amountPerToken
// Example:
// Holder has 1000 tokens at snapshot
// amountPerToken = 0.05 USDC
// claimableAmount = 1000 * 0.05 = 50 USDCUsage example
query GetHolderClaims($holderAddress: Bytes!) {
dividendClaims(where: { holder: $holderAddress, claimed: false }) {
distribution {
token {
name
symbol
}
distributionToken {
symbol
}
claimDeadline
}
amount
}
}
# Claim history
query GetClaimHistory($holderAddress: Bytes!) {
dividendClaims(
where: { holder: $holderAddress, claimed: true }
orderBy: claimedAt
orderDirection: desc
) {
distribution {
token {
symbol
}
}
amount
claimedAt
claimTx
}
}VotingProposal
Shareholder voting proposal for governance decisions.
Fields
type VotingProposal @entity {
id: Bytes! # Governance contract + proposal ID
token: Token! # Token for voting rights
proposalId: BigInt! # Proposal number
title: String! # Proposal title
description: String! # Full description
proposer: Account! # Proposal creator
snapshotId: BigInt! # Voting power snapshot
startTime: BigInt! # Voting start timestamp
endTime: BigInt! # Voting end timestamp
quorumRequired: BigDecimal! # Minimum votes for validity
votesFor: BigDecimal! # Total votes in favor
votesAgainst: BigDecimal! # Total votes against
votesAbstain: BigDecimal! # Total abstentions
voteCount: BigInt! # Number of voters
status: String! # 'active' | 'passed' | 'rejected' | 'cancelled' | 'executed'
executedAt: BigInt # Execution timestamp
executedTx: Bytes # Execution transaction
votes: [Vote!]! # Individual votes
}Proposal status
active- Currently accepting votespassed- Voting ended, quorum met, majority approvedrejected- Voting ended, quorum not met or majority rejectedcancelled- Proposal cancelled before voting endedexecuted- Passed proposal executed on-chain
Quorum calculation
// Check if proposal passes
hasQuorum = votesFor + votesAgainst + votesAbstain >= quorumRequired;
passes = hasQuorum && votesFor > votesAgainst;Usage example
query GetProposals($tokenAddress: Bytes!) {
votingProposals(
where: { token: $tokenAddress }
orderBy: startTime
orderDirection: desc
) {
id
title
status
startTime
endTime
votesFor
votesAgainst
votesAbstain
quorumRequired
voteCount
}
}
# Active proposals
query GetActiveProposals($tokenAddress: Bytes!, $now: BigInt!) {
votingProposals(
where: {
token: $tokenAddress
status: "active"
startTime_lte: $now
endTime_gte: $now
}
) {
id
title
description
endTime
votesFor
votesAgainst
}
}Vote
Individual holder's vote on a proposal.
Fields
type Vote @entity {
id: Bytes! # proposal + voter address
proposal: VotingProposal! # Proposal voted on
voter: Account! # Voter
support: String! # 'for' | 'against' | 'abstain'
votingPower: BigDecimal! # Votes cast (based on balance)
votedAt: BigInt! # Vote timestamp
voteTx: Bytes! # Vote transaction hash
}Relationships
- Many-to-one:
proposal→ Parent proposalvoter→ Voting account
Voting power
Voting power is determined by token balance at proposal.snapshotId:
votingPower = tokenBalance(voter, snapshotId);Usage example
query GetProposalVotes($proposalId: Bytes!) {
votingProposal(id: $proposalId) {
title
votesFor
votesAgainst
votesAbstain
votes(orderBy: votingPower, orderDirection: desc) {
voter {
id
}
support
votingPower
votedAt
}
}
}
# Check if holder voted
query GetHolderVote($proposalId: Bytes!, $holderAddress: Bytes!) {
vote(id: $proposalId_$holderAddress) {
support
votingPower
votedAt
}
}
# Holder's voting history
query GetVotingHistory($holderAddress: Bytes!) {
votes(
where: { voter: $holderAddress }
orderBy: votedAt
orderDirection: desc
) {
proposal {
title
status
}
support
votingPower
votedAt
}
}CorporateAction
Generic corporate action event (mergers, splits, name changes, etc.).
Fields
type CorporateAction @entity {
id: Bytes! # Action contract + action ID
token: Token! # Affected token
actionType: String! # 'split' | 'merge' | 'rename' | 'dividend' | 'other'
title: String! # Action title
description: String! # Details
effectiveDate: BigInt! # When action takes effect
executedAt: BigInt # Execution timestamp
status: String! # 'pending' | 'executed' | 'cancelled'
metadata: String # JSON metadata
}Action types
split- Stock split (1 share becomes N)merge- Reverse split (N shares become 1)rename- Token name/symbol changedividend- Dividend distribution (links to DividendDistribution)redemption- Bond maturity redemptionconversion- Convertible security conversionother- Custom action
Usage example
query GetCorporateActions($tokenAddress: Bytes!) {
corporateActions(
where: { token: $tokenAddress }
orderBy: effectiveDate
orderDirection: desc
) {
id
actionType
title
description
effectiveDate
status
executedAt
}
}
# Upcoming actions
query GetUpcomingActions($tokenAddress: Bytes!, $now: BigInt!) {
corporateActions(
where: { token: $tokenAddress, status: "pending", effectiveDate_gte: $now }
orderBy: effectiveDate
orderDirection: asc
) {
actionType
title
effectiveDate
}
}Yield tracking
For bonds and yield-bearing tokens, track interest payments and redemptions.
BondInterestPayment
type BondInterestPayment @entity {
id: Bytes! # Bond + payment ID
bond: Token! # Bond token
paymentToken: Token! # Payment token
totalAmount: BigDecimal! # Total interest paid
amountPerToken: BigDecimal! # Interest per bond unit
paymentDate: BigInt! # Payment timestamp
periodStart: BigInt! # Interest period start
periodEnd: BigInt! # Interest period end
claims: [InterestClaim!]! # Holder claims
}Usage example
query GetBondPayments($bondAddress: Bytes!) {
bondInterestPayments(
where: { bond: $bondAddress }
orderBy: paymentDate
orderDirection: desc
) {
totalAmount
amountPerToken
paymentToken {
symbol
}
paymentDate
periodStart
periodEnd
}
}Cross-entity queries
Get holder's total claimable
query GetHolderClaimables($holderAddress: Bytes!) {
# Unclaimed dividends
dividendClaims(where: { holder: $holderAddress, claimed: false }) {
distribution {
token {
symbol
}
distributionToken {
symbol
}
}
amount
}
# Active votes
votingProposals(
where: { status: "active", votes_: { voter: $holderAddress } }
) {
title
endTime
}
}See also
- Token entities - Security tokens affected by corporate actions
- Investor entities - Token holders eligible for dividends/voting
- Data model overview - Complete data architecture
- Contract reference - Addon contract methods