SDK for interacting with the Rootstock Collective DAO protocol. This SDK provides a simple interface for backing builders, governance (proposals and voting), staking, and rewards management.
npm install @rsksmart/collective-sdk viemimport { CollectiveSDK } from '@rsksmart/collective-sdk'
import { parseEther } from 'viem'
// Initialize SDK
const sdk = new CollectiveSDK({ chainId: 31 }) // 31 = testnet, 30 = mainnet
// Get user balances
const balances = await sdk.holdings.getBalances('0x...')
console.log('RIF Balance:', balances.rif.formatted)
console.log('stRIF Balance:', balances.stRif.formatted)
// Get builders list
const builders = await sdk.backing.getBuilders()
console.log('Active builders:', builders.filter(b => b.isOperational).length)
// Get proposals
const { proposals } = await sdk.proposals.getProposals({ limit: 10 })
console.log('Latest proposals:', proposals.length)- Backing: View and manage builder backing allocations
- Holdings: Check token balances (RIF, stRIF, USDRIF, RBTC) and voting power
- Staking: Stake RIF to receive stRIF and manage staking positions
- Rewards: View and claim backer rewards
- Governance: View proposals, vote, and create new proposals
const sdk = new CollectiveSDK({
chainId: 31, // Required: 30 (mainnet) or 31 (testnet)
rpcUrl?: string, // Optional: Custom RPC URL
contractAddresses?: Partial<ContractAddresses>, // Optional: Override addresses
})Get available stRIF balance for backing builders.
const available = await sdk.backing.getAvailableForBacking('0x...')
// Returns:
{
balance: TokenAmount, // Total stRIF balance
totalAllocated: TokenAmount,// Already allocated to builders
available: TokenAmount // Available for new backing
}Get total backing amount for a user.
const backing = await sdk.backing.getTotalBacking('0x...')
// Returns:
{
amount: TokenAmount, // Total allocated amount
buildersCount: number // Number of backed builders
}Get global backers incentives statistics.
const incentives = await sdk.backing.getBackersIncentives()
// Returns:
{
annualPercentage: Percentage, // Estimated annual percentage
rewardsRif: TokenAmount, // Current cycle RIF rewards
rewardsNative: TokenAmount, // Current cycle RBTC rewards
rewardsUsdrif: TokenAmount, // Current cycle USDRIF rewards
totalPotentialReward: TokenAmount
}Get list of all builders in the protocol.
const builders = await sdk.backing.getBuilders()
// Each builder:
{
address: Address, // Builder wallet address
gauge: Address, // Builder's gauge contract
isOperational: boolean,// Active and not paused
totalAllocation: bigint,
stateFlags: {
initialized: boolean,
kycApproved: boolean,
communityApproved: boolean,
kycPaused: boolean,
selfPaused: boolean
}
}Get builders that a user is backing with their allocations.
const { backedBuilders, totalBacking } = await sdk.backing.getBackedBuilders('0x...')
// Each backed builder:
{
builder: Builder,
allocation: TokenAmount // Amount allocated to this builder
}Get token balances for a user.
const balances = await sdk.holdings.getBalances('0x...')
// Returns:
{
rif: TokenAmount, // RIF balance
stRif: TokenAmount, // stRIF balance
usdrif: TokenAmount, // USDRIF balance
rbtc: TokenAmount // Native RBTC balance
}Get voting power (stRIF balance) for governance.
const power = await sdk.holdings.getVotingPower('0x...')
// Returns:
{
votingPower: TokenAmount,
delegatedTo: Address | null
}Get aggregated unclaimed rewards for a backer.
const rewards = await sdk.holdings.getUnclaimedRewards('0x...')
// Returns:
{
rif: TokenAmount,
rbtc: TokenAmount,
usdrif: TokenAmount,
totalUsdValue: number // Estimated USD value
}Get detailed breakdown of rewards per gauge and token.
const detailed = await sdk.holdings.getDetailedRewardsList('0x...')
// Returns rewards grouped by gauge with per-token amountsClaim backer rewards.
// Claim all rewards
const result = await sdk.holdings.claimRewards(walletClient, '0x...', 'all')
// Claim specific token
const result = await sdk.holdings.claimRewards(walletClient, '0x...', 'rif')
// Options: 'rif', 'rbtc', 'usdrif', 'all'
// Wait for confirmation
const receipt = await result.wait(1)
console.log('Claimed in block:', receipt.blockNumber)Get staking information for a user.
const info = await sdk.staking.getStakingInfo('0x...')
// Returns:
{
rifBalance: TokenAmount, // RIF balance
stRifBalance: TokenAmount, // stRIF balance
allowance: TokenAmount, // RIF allowance for staking
hasAllowance: (amount: bigint) => boolean
}Approve RIF tokens for staking.
const tx = await sdk.staking.approveRIF(walletClient, parseEther('100'))
console.log('Approval tx:', tx.hash)
await tx.wait(1)Stake RIF to receive stRIF.
// First approve
await sdk.staking.approveRIF(walletClient, parseEther('100'))
// Then stake (delegate voting power to yourself)
const tx = await sdk.staking.stakeRIF(
walletClient,
parseEther('100'),
'0x...' // delegatee address (usually your own)
)
await tx.wait(1)Unstake stRIF to receive RIF back.
const tx = await sdk.staking.unstakeRIF(
walletClient,
parseEther('50'),
'0x...' // recipient address
)
await tx.wait(1)Get Governor contract statistics.
const stats = await sdk.proposals.getStats()
// Returns:
{
proposalCount: number,
proposalThreshold: TokenAmount, // Minimum stRIF to create proposal
quorumVotes: TokenAmount, // Minimum votes for quorum
votingDelay: number, // Blocks before voting starts
votingPeriod: number // Voting duration in blocks
}Get paginated list of proposals.
const { proposals, total, hasMore } = await sdk.proposals.getProposals({
offset: 0,
limit: 10
})
// Each proposal:
{
id: string,
proposer: Address,
state: ProposalState,
stateLabel: string,
votes: {
forVotes: TokenAmount,
againstVotes: TokenAmount,
abstainVotes: TokenAmount
},
startBlock: bigint,
endBlock: bigint
}Get basic proposal information (fast).
const proposal = await sdk.proposals.getProposal('123456...')Get full proposal details including description and actions.
const proposal = await sdk.proposals.getProposalDetails('123456...', {
fromBlock: 1000000n // Optional: start block for event search
})
// Includes:
{
...basicInfo,
description: string,
actions: ProposalAction[]
}Cast a vote on a proposal.
import { VoteSupport } from '@rsksmart/collective-sdk'
const result = await sdk.proposals.castVote(
walletClient,
'123456...',
VoteSupport.For, // For, Against, or Abstain
{ reason: 'Great proposal!' }
)
await result.wait(1)Check if user has already voted.
const voted = await sdk.proposals.hasVoted('123456...', '0x...')Check if user has enough voting power to create proposals.
const { canCreate, votingPower, threshold } = await sdk.proposals.canCreateProposal('0x...')Create a treasury transfer proposal.
const tx = await sdk.proposals.createTreasuryTransferProposal(walletClient, {
token: 'rif', // 'rif', 'rbtc', or 'usdrif'
recipient: '0x...',
amount: parseEther('1000'),
description: 'Fund development team'
})Create a proposal to whitelist a new builder.
const tx = await sdk.proposals.createBuilderWhitelistProposal(walletClient, {
builderAddress: '0x...',
description: 'Whitelist Builder XYZ'
})import { CollectiveSDK, VoteSupport } from '@rsksmart/collective-sdk'
import { createWalletClient, createPublicClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { rootstockTestnet } from 'viem/chains'
async function main() {
// Initialize SDK
const sdk = new CollectiveSDK({ chainId: 31 })
// Setup wallet
const account = privateKeyToAccount('0x...')
const walletClient = createWalletClient({
account,
chain: rootstockTestnet,
transport: http(),
})
const publicClient = createPublicClient({
chain: rootstockTestnet,
transport: http(),
})
// Check balances
const balances = await sdk.holdings.getBalances(account.address)
console.log('RIF:', balances.rif.formatted)
console.log('stRIF:', balances.stRif.formatted)
// Stake RIF
const stakeAmount = parseEther('100')
const stakingInfo = await sdk.staking.getStakingInfo(account.address)
if (!stakingInfo.hasAllowance(stakeAmount)) {
console.log('Approving RIF...')
const approveTx = await sdk.staking.approveRIF(walletClient, stakeAmount)
await approveTx.wait(1)
}
console.log('Staking RIF...')
const stakeTx = await sdk.staking.stakeRIF(walletClient, stakeAmount, account.address)
await stakeTx.wait(1)
console.log('Staked!')
// View proposals
const { proposals } = await sdk.proposals.getProposals({ limit: 5 })
console.log('Recent proposals:', proposals.length)
// Vote on a proposal
const activeProposal = proposals.find(p => p.stateLabel === 'Active')
if (activeProposal) {
const hasVoted = await sdk.proposals.hasVoted(activeProposal.id, account.address)
if (!hasVoted) {
console.log('Voting...')
const voteTx = await sdk.proposals.castVote(
walletClient,
activeProposal.id,
VoteSupport.For
)
await voteTx.wait(1)
console.log('Voted!')
}
}
// Check and claim rewards
const rewards = await sdk.holdings.getUnclaimedRewards(account.address)
if (rewards.rif.value > 0n || rewards.rbtc.value > 0n) {
console.log('Claiming rewards...')
const claimTx = await sdk.holdings.claimRewards(walletClient, account.address, 'all')
await claimTx.wait(1)
console.log('Rewards claimed!')
}
}
main().catch(console.error)| Network | Chain ID | Status |
|---|---|---|
| Rootstock Mainnet | 30 | ✅ Available |
| Rootstock Testnet | 31 | ✅ Available |
The SDK exports all TypeScript types:
import type {
CollectiveConfig,
TokenBalances,
VotingPower,
StakingInfo,
Builder,
BackersIncentives,
Proposal,
ProposalState,
VoteSupport,
// ... and more
} from '@rsksmart/collective-sdk'import { ProposalState, VoteSupport } from '@rsksmart/collective-sdk'
// Proposal states
ProposalState.Pending
ProposalState.Active
ProposalState.Canceled
ProposalState.Defeated
ProposalState.Succeeded
ProposalState.Queued
ProposalState.Expired
ProposalState.Executed
// Vote options
VoteSupport.Against // 0
VoteSupport.For // 1
VoteSupport.Abstain // 2