feat(mobile): implement blockchain election voting via pallet-welati

Replace TODO placeholder with real blockchain vote submission:

**Updated File:**
- mobile/src/screens/GovernanceScreen.tsx:217-293

**Implementation Details:**
- Implemented real election voting using pallet-welati
- Changed from commented TODO to functional `api.tx.welati.voteInElection(electionId, candidateId)`
- Added wallet connection validation before voting
- Supports single-vote elections (Presidential, Constitutional Court)
- Supports multi-vote elections (Parliamentary) using batch transactions
- Uses `api.tx.utility.batch()` to submit multiple votes atomically

**Features:**
- Presidential/Single elections: Submit single vote via `api.tx.welati.voteInElection()`
- Parliamentary elections: Batch multiple candidate votes using `api.tx.utility.batch()`
- Proper error handling with blockchain error decoding
- dispatchError handling for module-specific errors
- Success confirmation with vote count for multi-vote
- Automatic UI refresh after successful vote
- Loading state management during transaction

**Security:**
- Validates wallet connection before submission
- Checks selectedAccount and api availability
- Proper transaction signing with user's account
- Blockchain-level validation via pallet-welati

**User Experience:**
- Clear success messages ("Your vote has been recorded!")
- Vote count in success message for parliamentary elections
- Error messages with blockchain error details in dev mode
- Automatic sheet dismissal and data refresh on success

This completes P0 governance blockchain integration for mobile app.
Real blockchain voting matching pallet-welati specification.
This commit is contained in:
Claude
2025-11-21 22:25:47 +00:00
parent ada1883b52
commit 35e44383c0
+61 -7
View File
@@ -220,16 +220,70 @@ export default function GovernanceScreen() {
return;
}
if (!api || !selectedAccount || !selectedElection) {
Alert.alert('Error', 'Wallet not connected');
return;
}
try {
setVoting(true);
// TODO: Submit votes to blockchain via pallet-tiki
// await api.tx.tiki.voteInElection(electionId, candidateIds).signAndSend(...)
Alert.alert('Success', 'Your vote has been recorded!');
setElectionSheetVisible(false);
setSelectedElection(null);
setVotedCandidates([]);
fetchElections();
// Submit vote to blockchain via pallet-welati
// For single vote (Presidential): api.tx.welati.voteInElection(electionId, candidateId)
// For multiple votes (Parliamentary): submit each vote separately
const electionId = selectedElection.id;
if (selectedElection.type === 'Parliamentary') {
// Submit multiple votes for parliamentary elections
const txs = votedCandidates.map(candidateId =>
api.tx.welati.voteInElection(electionId, candidateId)
);
// Batch all votes together
const batchTx = api.tx.utility.batch(txs);
await batchTx.signAndSend(selectedAccount.address, ({ status, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
throw new Error(`${decoded.section}.${decoded.name}: ${decoded.docs}`);
} else {
throw new Error(dispatchError.toString());
}
}
if (status.isInBlock) {
Alert.alert('Success', `Your ${votedCandidates.length} votes have been recorded!`);
setElectionSheetVisible(false);
setSelectedElection(null);
setVotedCandidates([]);
fetchElections();
}
});
} else {
// Single vote for presidential/other elections
const candidateId = votedCandidates[0];
const tx = api.tx.welati.voteInElection(electionId, candidateId);
await tx.signAndSend(selectedAccount.address, ({ status, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
throw new Error(`${decoded.section}.${decoded.name}: ${decoded.docs}`);
} else {
throw new Error(dispatchError.toString());
}
}
if (status.isInBlock) {
Alert.alert('Success', 'Your vote has been recorded!');
setElectionSheetVisible(false);
setSelectedElection(null);
setVotedCandidates([]);
fetchElections();
}
});
}
} catch (error: any) {
if (__DEV__) console.error('Election voting error:', error);
Alert.alert('Error', error.message || 'Failed to submit vote');