@@ -192,6 +192,36 @@ async function trySubmittingVote() {
192192 }
193193}
194194
195+ /**
196+ * Calculate the available balance of an account, which is the balance that can actually be used for voting.
197+ *
198+ * For basic accounts, this is just the balance. For vesting contracts, it is calculated how much of the balance is still locked.
199+ */
200+ function availableBalance(account : Nimiq .PlainAccount , voteEndTime : number ): number {
201+ if (account .type === ' basic' ) {
202+ return account .balance ;
203+ } else if (account .type === ' vesting' ) {
204+ const now = Math .min (new Date ().getTime (), voteEndTime );
205+ let unlocked = 0 ;
206+ let start = account .startTime ; // All times on the account are in milliseconds
207+ while ((start += account .timeStep ) <= now ) {
208+ unlocked += account .stepAmount ;
209+ if (unlocked >= account .totalAmount ) {
210+ unlocked = account .totalAmount ;
211+ break ;
212+ }
213+ }
214+ const stillLocked = account .totalAmount - unlocked ;
215+ // If the contract had balance still locked, but all balance has been withdrawn since the end of the vote,
216+ // the returned "available balance" is negative.
217+ // That still works, because then through the tx history the outgoing tx will be re-added to the balance,
218+ // bringing it to what was actually available at the end of the vote (which can be 0).
219+ return account .balance - stillLocked ;
220+ } else {
221+ return 0 ;
222+ }
223+ }
224+
195225async function submitVote() {
196226 const config = votingConfig .value ;
197227 const voteData: BaseVote = { name: config ! .name , choices: serializeChoices () };
@@ -210,8 +240,8 @@ async function submitVote() {
210240 disableDisclaimer: true ,
211241 });
212242
213- if (signedTransaction . raw . senderType !== Nimiq .AccountType .Basic ) {
214- throw new Error (' You can only vote with basic accounts. Vesting and HTLC contracts are not allowed.' );
243+ if (! [ Nimiq . AccountType . Basic , Nimiq .AccountType .Vesting ]. includes ( signedTransaction . raw . senderType ) ) {
244+ throw new Error (' You can only vote with basic and vesting accounts. HTLC contracts are not allowed.' );
215245 }
216246
217247 const { sender, value : txValue } = signedTransaction .raw ;
@@ -230,7 +260,7 @@ async function submitVote() {
230260 client .value ?.getStaker (sender ),
231261 ]);
232262
233- const accountBalance = account ?. balance || 0 ;
263+ const accountBalance = account ? availableBalance ( account , Infinity ) : 0 ;
234264 const stakerBalance = staker ? staker .balance + staker .inactiveBalance + staker .retiredBalance : 0 ;
235265
236266 vote .value .value = accountBalance + stakerBalance ;
@@ -289,13 +319,14 @@ async function countVotes(config = votingConfig.value!): Promise<ElectionResults
289319 // Get accounts details in parallel for all chunks
290320 const balancesByAddress = new Map <string , number >();
291321 try {
322+ const votingEndTime = blockDateUtil (config .end , height .value ).getTime ();
292323 await Promise .all (addressChunk .map (async (chunk ) => {
293324 const accounts = await nimiqClient .getAccounts (chunk );
294325 accounts .forEach ((account , i ) => {
295326 const address = chunk [i ];
296- // Only keep BASIC accounts
297- if (account . type === ' basic ' ) {
298- balancesByAddress .set (address , account . balance );
327+ const balance = availableBalance ( account , votingEndTime );
328+ if (balance ) {
329+ balancesByAddress .set (address , balance );
299330 } else {
300331 balancesByAddress .delete (address );
301332 }
@@ -329,7 +360,7 @@ async function countVotes(config = votingConfig.value!): Promise<ElectionResults
329360 error (' Failed to get account balances when counting votes' , e as Error , ' Try reloading.' );
330361 }
331362
332- // Remove votes from non-basic accounts, it's not allowed to vote with vesting or HTLC contracts
363+ // Remove votes from unallowed accounts - it's not allowed to vote with HTLC contracts
333364 votes = votes .filter ((v ) => balancesByAddress .has (v .tx .sender ));
334365
335366 stats .votes = votes .length ;
0 commit comments