useCallAnyContract()
Casts a vote in a DAO or governance contract using the generic contract interaction hook. Requires voting rights in the specified contract.
Parameters
- encryptKey (string): User’s decryption PIN
- wallet (WalletData): Wallet credentials
- contractAddress (string): Governance contract address
- entrypoint (string): “vote” (contract method name)
- calldata (any[]): [proposalId, voteChoice]
Example Implementation
'use client'
import { useCallAnyContract } from "@chipi-pay/chipi-sdk";
import { useState } from "react";
const GOVERNANCE_CONTRACT = "0xYourGovernanceContractAddress";
// Sample wallet data - replace with your wallet in production
const sampleWallet = {
publicKey: "0x123...yourPublicKeyHere",
privateKey: "encrypted:key:data" // This would be encrypted data in production
};
export function VoteForm() {
const { callAsync, callData, isLoading, error } = useCallAnyContract();
const [form, setForm] = useState({
pin: '',
proposalId: '',
choice: 'for'
});
const handleVote = async (e: React.FormEvent) => {
e.preventDefault();
try {
await callAsync({
encryptKey: form.pin,
wallet: {
publicKey: sampleWallet.publicKey,
encryptedPrivateKey: sampleWallet.privateKey
},
contractAddress: GOVERNANCE_CONTRACT,
entrypoint: "vote",
calldata: [form.proposalId, form.choice]
});
} catch (err) {
console.error('Voting failed:', err);
}
};
return (
<div className="bg-white rounded-xl shadow-lg p-6">
<h2 className="text-2xl font-bold mb-4">Cast Vote</h2>
<form onSubmit={handleVote} className="space-y-4">
<div>
<label className="block text-sm font-medium mb-1">Security PIN</label>
<input
type="password"
value={form.pin}
onChange={(e) => setForm({...form, pin: e.target.value})}
className="w-full p-2 border rounded-md"
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Proposal ID</label>
<input
type="number"
value={form.proposalId}
onChange={(e) => setForm({...form, proposalId: e.target.value})}
className="w-full p-2 border rounded-md"
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Vote Choice</label>
<select
value={form.choice}
onChange={(e) => setForm({...form, choice: e.target.value})}
className="w-full p-2 border rounded-md"
>
<option value="for">For</option>
<option value="against">Against</option>
<option value="abstain">Abstain</option>
</select>
</div>
<button
type="submit"
disabled={isLoading}
className="w-full bg-purple-600 text-white py-2 px-4 rounded-md hover:bg-purple-700 disabled:bg-gray-400"
>
{isLoading ? 'Submitting...' : 'Cast Vote'}
</button>
</form>
{callData && (
<div className="mt-4 p-3 bg-gray-50 rounded-md">
<p className="text-sm font-mono break-all">
Vote TX: {callData}
</p>
</div>
)}
{error && (
<div className="mt-4 p-3 bg-red-50 text-red-700 rounded-md">
Error: {error.message}
</div>
)}
</div>
);
}
:::info
Voting power is calculated based on your token balance at the snapshot block.
:::