Skip to content

Commit 2dbc910

Browse files
authored
Prevent submitting new proposals of a proposal type already pending enactment (#1762)
* [proposePage] disallow sending extrinsics if there is already the same type in the enactment queue * [proposePage] localize message about a proposal pending enactment * fmt * add localizations for removing locations
1 parent d99501d commit 2dbc910

File tree

10 files changed

+87
-3
lines changed

10 files changed

+87
-3
lines changed

app/lib/l10n/arb/app_de.arb

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
"proposalNew": "Neuer Vorschlag",
210210
"proposalType": "Vorschlagstyp",
211211
"proposalTypeAddLocation": "Standort hinzufügen",
212+
"proposalTypeRemoveLocation": "Standort entfernen",
212213
"proposalTypeUpdateDemurrage": "Demurrage aktualisieren",
213214
"proposalTypeUpdateNominalIncome": "Grundeinkommen aktualisieren",
214215
"proposalTypeSetInactivityTimeout": "Inaktivitätszeitlimit festlegen",
@@ -246,6 +247,7 @@
246247
"proposalUpdateState": "Aktualisieren",
247248
"proposalUpdateExplanation": "Dies wird den Status des Vorschlags aktualisieren. Wenn er zu alt ist und nicht genügend Aye-Stimmen hat, wird er abgelehnt. Wenn er lange genug bestätigt wurde, wird er angenommen.",
248249
"proposalOnlyBootstrappersOrReputablesCanSubmit": "Nur Bootstrappers oder Reputables können einen Vorschlag einreichen.",
250+
"proposalCannotSubmitProposalTypePendingEnactment": "Ein Vorschlag dieses Typs kann nicht eingereicht werden, da bereits einer auf die Umsetzung wartet.",
249251
"proposalSubmit": "Vorschlag einreichen",
250252
"proposalSuperseded": "Verdrängt",
251253
"proposalRejected": "Abgelehnt",

app/lib/l10n/arb/app_en.arb

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
"proposalNew": "New Proposal",
210210
"proposalType": "Proposal Type",
211211
"proposalTypeAddLocation": "Add location",
212+
"proposalTypeRemoveLocation": "Remove location",
212213
"proposalTypeUpdateDemurrage": "Update Demurrage",
213214
"proposalTypeUpdateNominalIncome": "Update Nominal Income",
214215
"proposalTypeSetInactivityTimeout": "Set Inactivity Timeout",
@@ -243,6 +244,7 @@
243244
"proposalFieldErrorEnterInactivityTimeout": "Enter inactivity timeout",
244245
"proposalFieldErrorPositiveIntegerRange": "Must be a positive integer",
245246
"proposalOnlyBootstrappersOrReputablesCanSubmit": "Only bootstrappers or reputables can submit a proposal.",
247+
"proposalCannotSubmitProposalTypePendingEnactment": "Cannot submit a proposal of this type, as there is already one pending enactment.",
246248
"proposalClose": "Close",
247249
"proposalUpdateState": "Update",
248250
"proposalUpdateExplanation": "This will update the proposal state. If it is too old and does not have enough Aye votes, it will be rejected. If it has been confirming long enough, it will pass.",

app/lib/l10n/arb/app_fr.arb

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
"proposalNew": "Nouvelle Proposition",
210210
"proposalType": "Type de proposition",
211211
"proposalTypeAddLocation": "Ajouter un lieu",
212+
"proposalTypeRemoveLocation": "Retrancher un lieu",
212213
"proposalTypeUpdateDemurrage": "Mettre à jour la démurrage",
213214
"proposalTypeUpdateNominalIncome": "Mettre à jour le revenu nominal",
214215
"proposalTypeSetInactivityTimeout": "Définir le délai d'inactivité",
@@ -243,6 +244,7 @@
243244
"proposalFieldErrorEnterInactivityTimeout": "Entrez le délai d'inactivité",
244245
"proposalFieldErrorPositiveIntegerRange": "Doit être un entier positif",
245246
"proposalOnlyBootstrappersOrReputablesCanSubmit": "Seuls les bootstrappers ou les Reputables peuvent soumettre une proposition.",
247+
"proposalCannotSubmitProposalTypePendingEnactment": "Impossible de soumettre une proposition de ce type, car une autre est déjà en attente d'adoption.",
246248
"proposalClose": "Fermer",
247249
"proposalUpdateState": "Mettre à jour",
248250
"proposalUpdateExplanation": "Cela mettra à jour l'état de la proposition. Si elle est trop ancienne et n'a pas suffisamment de votes Aye, elle sera rejetée. Si elle a été confirmée assez longtemps, elle sera acceptée.",

app/lib/l10n/arb/app_ru.arb

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
"proposalNew": "новое предложение",
210210
"proposalType": "Тип предложения",
211211
"proposalTypeAddLocation": "Добавить местоположение",
212+
"proposalTypeRemoveLocation": "Удалить местоположение",
212213
"proposalTypeUpdateDemurrage": "Обновить демерредж",
213214
"proposalTypeUpdateNominalIncome": "Обновить номинальный доход",
214215
"proposalTypeSetInactivityTimeout": "Установить тайм-аут неактивности",
@@ -243,6 +244,7 @@
243244
"proposalFieldErrorEnterInactivityTimeout": "Введите тайм-аут неактивности",
244245
"proposalFieldErrorPositiveIntegerRange": "Должно быть положительное целое число",
245246
"proposalOnlyBootstrappersOrReputablesCanSubmit": "Только бутстраперы или уважаемые участники могут подать предложение.",
247+
"proposalCannotSubmitProposalTypePendingEnactment": "Невозможно подать предложение этого типа, так как уже есть одно ожидающее принятия.",
246248
"proposalClose": "Закрыть",
247249
"proposalUpdateState": "Обновить",
248250
"proposalUpdateExplanation": "Это обновит статус предложения. Если оно слишком старое и не имеет достаточного количества голосов 'За', оно будет отклонено. Если оно подтверждается достаточно долго, оно будет принято.",

app/lib/l10n/arb/app_sw.arb

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
"proposalNew": "Mapendekezo mapya",
210210
"proposalType": "Aina ya pendekezo",
211211
"proposalTypeAddLocation": "Ongeza eneo",
212+
"proposalTypeRemoveLocation": "Ondoa eneo",
212213
"proposalTypeUpdateDemurrage": "Sasisha ada ya kuchelewesha",
213214
"proposalTypeUpdateNominalIncome": "Sasisha mapato ya kawaida",
214215
"proposalTypeSetInactivityTimeout": "Weka muda wa kutokufanya kazi",
@@ -243,6 +244,7 @@
243244
"proposalFieldErrorEnterInactivityTimeout": "Weka muda wa kutokufanya kazi",
244245
"proposalFieldErrorPositiveIntegerRange": "Lazima iwe namba kamili chanya",
245246
"proposalOnlyBootstrappersOrReputablesCanSubmit": "Ni bootstrappers au waheshimika pekee wanaoweza kuwasilisha pendekezo.",
247+
"proposalCannotSubmitProposalTypePendingEnactment": "Haiwezi kuwasilisha pendekezo la aina hii kwa sababu tayari kuna moja linalosubiri kutekelezwa.",
246248
"proposalClose": "Funga",
247249
"proposalUpdateState": "Sasisha",
248250
"proposalUpdateExplanation": "Hii itasasisha hali ya pendekezo. Ikiwa ni la zamani sana na halina kura za kutosha za 'Ndio', litakataliwa. Ikiwa limekuwa likithibitishwa kwa muda wa kutosha, litakubaliwa.",

app/lib/page-encointer/democracy/proposal_page/helpers.dart

+19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import 'dart:math';
22

33
import 'package:encointer_wallet/l10n/l10.dart';
44

5+
import 'package:ew_polkadart/encointer_types.dart' as et;
6+
57
/// Enum for Scope selection
68
enum ProposalScope { global, local }
79

@@ -21,6 +23,7 @@ extension ProposalScopeExt on ProposalScope {
2123
/// Enum representing different proposal actions
2224
enum ProposalActionIdentifier {
2325
addLocation,
26+
removeLocation,
2427
updateDemurrage,
2528
updateNominalIncome,
2629
setInactivityTimeout,
@@ -29,6 +32,20 @@ enum ProposalActionIdentifier {
2932
issueSwapNativeOption
3033
}
3134

35+
ProposalActionIdentifier proposalActionIdentifierFromPolkadartAction(et.ProposalAction action) {
36+
return switch (action.runtimeType) {
37+
et.AddLocation => ProposalActionIdentifier.addLocation,
38+
et.RemoveLocation => ProposalActionIdentifier.removeLocation,
39+
et.UpdateDemurrage => ProposalActionIdentifier.updateDemurrage,
40+
et.UpdateNominalIncome => ProposalActionIdentifier.updateNominalIncome,
41+
et.SetInactivityTimeout => ProposalActionIdentifier.setInactivityTimeout,
42+
et.Petition => ProposalActionIdentifier.petition,
43+
et.SpendNative => ProposalActionIdentifier.spendNative,
44+
et.IssueSwapNativeOption => ProposalActionIdentifier.issueSwapNativeOption,
45+
_ => throw UnimplementedError('Invalid Proposal Id Type'),
46+
};
47+
}
48+
3249
/// We still have to implement support for:
3350
/// * issueSwapOption: It does not exist yet in the generated types
3451
List<ProposalActionIdentifier> supportedProposalIds() {
@@ -53,6 +70,7 @@ extension PropsalActionExt on ProposalActionIdentifier {
5370

5471
// Only local proposals allowed
5572
ProposalActionIdentifier.addLocation => [ProposalScope.local],
73+
ProposalActionIdentifier.removeLocation => [ProposalScope.local],
5674
ProposalActionIdentifier.updateDemurrage => [ProposalScope.local],
5775
ProposalActionIdentifier.updateNominalIncome => [ProposalScope.local],
5876
ProposalActionIdentifier.issueSwapNativeOption => [ProposalScope.local],
@@ -66,6 +84,7 @@ extension PropsalActionExt on ProposalActionIdentifier {
6684
String localizedStr(AppLocalizations l10n) {
6785
return switch (this) {
6886
ProposalActionIdentifier.addLocation => l10n.proposalTypeAddLocation,
87+
ProposalActionIdentifier.removeLocation => l10n.proposalTypeRemoveLocation,
6988
ProposalActionIdentifier.updateDemurrage => l10n.proposalTypeUpdateDemurrage,
7089
ProposalActionIdentifier.updateNominalIncome => l10n.proposalTypeUpdateNominalIncome,
7190
ProposalActionIdentifier.setInactivityTimeout => l10n.proposalTypeSetInactivityTimeout,

app/lib/page-encointer/democracy/proposal_page/propose_page.dart

+19-1
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@ class _ProposePageState extends State<ProposePage> {
6969
// Beneficiary in for the spendNative/issueSwapNativeOption
7070
AccountData? beneficiary;
7171

72+
List<ProposalActionIdentifier> enactmentQueue = [];
73+
7274
@override
7375
void initState() {
7476
super.initState();
7577
_updateAllowedScopes();
78+
_updateEnactmentQueue();
7679

7780
beneficiary = context.read<AppStore>().account.currentAccount;
7881
}
@@ -85,6 +88,13 @@ class _ProposePageState extends State<ProposePage> {
8588
});
8689
}
8790

91+
Future<void> _updateEnactmentQueue() async {
92+
final queue = await webApi.encointer.getProposalEnactmentQueue();
93+
setState(() {
94+
enactmentQueue = queue.map(proposalActionIdentifierFromPolkadartAction).toList();
95+
});
96+
}
97+
8898
@override
8999
void dispose() {
90100
super.dispose();
@@ -160,8 +170,12 @@ class _ProposePageState extends State<ProposePage> {
160170
const Spacer(),
161171
if (!isBootstrapperOrReputable(store, store.account.currentAddress))
162172
Text(l10n.proposalOnlyBootstrappersOrReputablesCanSubmit, textAlign: TextAlign.center),
173+
if (enactmentQueue.contains(selectedAction))
174+
Text(l10n.proposalCannotSubmitProposalTypePendingEnactment, textAlign: TextAlign.center),
175+
const SizedBox(height: 5),
163176
SubmitButton(
164-
onPressed: isBootstrapperOrReputable(store, store.account.currentAddress)
177+
onPressed: isBootstrapperOrReputable(store, store.account.currentAddress) &&
178+
!enactmentQueue.contains(selectedAction)
165179
? (context) async {
166180
_formKey.currentState!.validate();
167181
await _submitProposal();
@@ -201,6 +215,8 @@ class _ProposePageState extends State<ProposePage> {
201215

202216
case ProposalActionIdentifier.issueSwapNativeOption:
203217
return issueSwapNativeOptionInput();
218+
case ProposalActionIdentifier.removeLocation:
219+
throw UnimplementedError('remove location is unsupported');
204220
}
205221
}
206222

@@ -603,6 +619,8 @@ class _ProposePageState extends State<ProposePage> {
603619
);
604620

605621
return IssueSwapNativeOption(maybeCid!, hex.decode(ben.replaceFirst('0x', '')), issueOption);
622+
case ProposalActionIdentifier.removeLocation:
623+
throw UnimplementedError('removeLocation is unsupported');
606624
}
607625
}
608626
}

app/lib/service/substrate_api/encointer/encointer_api.dart

+18
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,24 @@ class EncointerApi {
733733
}
734734
}
735735

736+
Future<List<et.ProposalAction>> getProposalEnactmentQueue({BlockHash? at}) async {
737+
try {
738+
final prefix = encointerKusama.query.encointerDemocracy.enactmentQueueMapPrefix();
739+
final pairs = await encointerKusama.rpc.state.getPairs(prefix);
740+
741+
// Keys including storage prefix.
742+
Log.d("[getProposalEnactmentQueue] storageKeys: ${pairs.map((pair) => '0x${hex.encode(pair.key)}')}");
743+
Log.d("[getProposalEnactmentQueue] storageValues: ${pairs.map((pair) => '0x${hex.encode(pair.value!)}')}");
744+
745+
final proposalActions = pairs.map((pair) => et.ProposalAction.decode(ByteInput(pair.value!)));
746+
747+
return proposalActions.toList();
748+
} catch (e, s) {
749+
Log.e('[getProposalEnactmentQueue]', '$e', s);
750+
return List.of([]);
751+
}
752+
}
753+
736754
Future<Map<BigInt, Proposal>> getProposals(List<BigInt> proposalIds, {BlockHash? at}) async {
737755
try {
738756
Log.d('[getProposals] ProposalIds: $proposalIds');

app/lib/service/tx/lib/src/submit_to_inner.dart

-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,6 @@ void _showErrorDialog(BuildContext context, ErrorNotificationMsg message) {
8787
final l10n = context.l10n;
8888
final languageCode = Localizations.localeOf(context).languageCode;
8989

90-
print('Should show error dialog');
91-
9290
AppAlert.showDialog<void>(
9391
context,
9492
title: Text(message.title),

packages/ew_polkadart/lib/encointer_types.dart

+21
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ export 'generated/encointer_kusama/types/encointer_primitives/communities/commun
3434
export 'generated/encointer_kusama/types/encointer_primitives/communities/community_rules.dart' show CommunityRules;
3535
export 'generated/encointer_kusama/types/encointer_primitives/communities/location.dart' show Location;
3636

37+
// export types from democracy
38+
export 'generated/encointer_kusama/types/encointer_primitives/democracy/proposal.dart' show Proposal;
39+
export 'generated/encointer_kusama/types/encointer_primitives/democracy/proposal_action.dart'
40+
show
41+
ProposalAction,
42+
AddLocation,
43+
RemoveLocation,
44+
UpdateDemurrage,
45+
UpdateNominalIncome,
46+
SetInactivityTimeout,
47+
Petition,
48+
SpendNative,
49+
IssueSwapNativeOption;
50+
export 'generated/encointer_kusama/types/encointer_primitives/democracy/proposal_action_identifier.dart'
51+
show ProposalActionIdentifier;
52+
export 'generated/encointer_kusama/types/encointer_primitives/democracy/proposal_state.dart'
53+
show ProposalState, Ongoing, Rejected, SupersededBy, Approved, Confirming, Enacted;
54+
export 'generated/encointer_kusama/types/encointer_primitives/democracy/tally.dart' show Tally;
55+
export 'generated/encointer_kusama/types/encointer_primitives/democracy/vote.dart' show Vote;
56+
export 'generated/encointer_kusama/types/encointer_primitives/treasuries/swap_native_option.dart' show SwapNativeOption;
57+
3758
// export types from faucet
3859
export 'generated/encointer_kusama/types/encointer_primitives/faucet/faucet.dart' show Faucet;
3960

0 commit comments

Comments
 (0)