Skip to content

Commit

Permalink
Remove extra upvote weight + prevent stakeless upvotes in staked comm…
Browse files Browse the repository at this point in the history
…unity (#8768)

* remove extra upvote weight + prevent stakeless upvotes

* apply upvote check to comment reaction

* add UI toast on failed staked reaction

* fix test
  • Loading branch information
rbennettcw authored Aug 6, 2024
1 parent 75a883d commit 79c70a9
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 27 deletions.
3 changes: 1 addition & 2 deletions libs/shared/src/commonProtocol/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ export const calculateVoteWeight = (
stakeBalance: string,
voteWeight: number,
) => {
// all community members get 1 weight by default
return 1 + parseInt(stakeBalance, 10) * voteWeight;
return parseInt(stakeBalance, 10) * voteWeight;
};

export enum Denominations {
Expand Down
2 changes: 1 addition & 1 deletion packages/commonwealth/client/scripts/models/Reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Reaction {
this.author_chain = author_chain;
this.canvasSignedData = canvas_signed_data;
this.canvasHash = canvas_hash;
this.calculatedVotingWeight = calculated_voting_weight || 1;
this.calculatedVotingWeight = calculated_voting_weight || 0;
this.updatedAt = updated_at;

this.profile = addressToUserProfile(Address);
Expand Down
2 changes: 1 addition & 1 deletion packages/commonwealth/client/scripts/models/Thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ function processAssociatedReactions(
type: tempReactionType[i],
address: tempAddressesReacted[i],
updated_at: tempReactionTimestamps[i],
voting_weight: tempReactionWeights[i] || 1,
voting_weight: tempReactionWeights[i] || 0,
reactedProfileName: emptyStringToNull(reactedProfileName?.[i]),
reactedProfileAvatarUrl: emptyStringToNull(
reactedProfileAvatarUrl?.[i],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toCanvasSignedDataApiArgs } from '@hicommonwealth/shared';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';
import axios, { AxiosError } from 'axios';
import { notifyError } from 'client/scripts/controllers/app/notifications';
import { signCommentReaction } from 'controllers/server/sessions';
import Reaction from 'models/Reaction';
import app from 'state';
Expand Down Expand Up @@ -87,7 +88,14 @@ const useCreateCommentReactionMutation = ({

return reaction;
},
onError: (error) => checkForSessionKeyRevalidationErrors(error),
onError: (error) => {
if (error instanceof AxiosError) {
if (error.response?.data?.error?.toLowerCase().includes('stake')) {
notifyError('Buy stake in community to upvote comments');
}
}
return checkForSessionKeyRevalidationErrors(error);
},
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toCanvasSignedDataApiArgs } from '@hicommonwealth/shared';
import { useMutation } from '@tanstack/react-query';
import axios from 'axios';
import axios, { AxiosError } from 'axios';
import { notifyError } from 'client/scripts/controllers/app/notifications';
import { signThreadReaction } from 'controllers/server/sessions';
import app from 'state';
import useUserOnboardingSliderMutationStore from 'state/ui/userTrainingCards';
Expand Down Expand Up @@ -68,7 +69,7 @@ const useCreateThreadReactionMutation = ({
address: response.data.result.Address.address,
type: 'like',
updated_at: response.data.result.updated_at,
voting_weight: response.data.result.calculated_voting_weight || 1,
voting_weight: response.data.result.calculated_voting_weight || 0,
};
updateThreadInAllCaches(
communityId,
Expand All @@ -81,7 +82,14 @@ const useCreateThreadReactionMutation = ({
userId &&
markTrainingActionAsComplete(UserTrainingCardTypes.GiveUpvote, userId);
},
onError: (error) => checkForSessionKeyRevalidationErrors(error),
onError: (error) => {
if (error instanceof AxiosError) {
if (error.response?.data?.error?.toLowerCase().includes('stake')) {
notifyError('Buy stake in community to upvote threads');
}
}
return checkForSessionKeyRevalidationErrors(error);
},
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@hicommonwealth/model';
import { PermissionEnum } from '@hicommonwealth/schemas';
import { NotificationCategories, commonProtocol } from '@hicommonwealth/shared';
import { BigNumber } from 'ethers';
import { MixpanelCommunityInteractionEvent } from '../../../shared/analytics/types';
import { config } from '../../config';
import { validateTopicGroupsMembership } from '../../util/requirementsModule/validateTopicGroupsMembership';
Expand All @@ -23,6 +24,7 @@ const Errors = {
BalanceCheckFailed: 'Could not verify user token balance',
FailedCreateReaction: 'Failed to create reaction',
CommunityNotFound: 'Community not found',
MustHaveStake: 'Must have stake to upvote',
};

export type CreateCommentReactionOptions = {
Expand Down Expand Up @@ -133,8 +135,13 @@ export async function __createCommentReaction(
node.eth_chain_id,
[address.address],
);
const stakeBalance = stakeBalances[address.address];
if (BigNumber.from(stakeBalance).lte(0)) {
// stake is enabled but user has no stake
throw new AppError(Errors.MustHaveStake);
}
calculatedVotingWeight = commonProtocol.calculateVoteWeight(
stakeBalances[address.address],
stakeBalance,
voteWeight,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@hicommonwealth/model';
import { PermissionEnum } from '@hicommonwealth/schemas';
import { NotificationCategories, commonProtocol } from '@hicommonwealth/shared';
import { BigNumber } from 'ethers';
import { MixpanelCommunityInteractionEvent } from '../../../shared/analytics/types';
import { config } from '../../config';
import { validateTopicGroupsMembership } from '../../util/requirementsModule/validateTopicGroupsMembership';
Expand All @@ -23,6 +24,7 @@ export const Errors = {
ThreadArchived: 'Thread is archived',
FailedCreateReaction: 'Failed to create reaction',
CommunityNotFound: 'Community not found',
MustHaveStake: 'Must have stake to upvote',
};

export type CreateThreadReactionOptions = {
Expand Down Expand Up @@ -125,8 +127,13 @@ export async function __createThreadReaction(
node.eth_chain_id,
[address.address],
);
const stakeBalance = stakeBalances[address.address];
if (BigNumber.from(stakeBalance).lte(0)) {
// stake is enabled but user has no stake
throw new AppError(Errors.MustHaveStake);
}
calculatedVotingWeight = commonProtocol.calculateVoteWeight(
stakeBalances[address.address],
stakeBalance,
voteWeight,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe('Reaction vote weight', () => {
reaction: 'like',
threadId: thread.id,
});
const expectedWeight = 1 + 50 * 200;
const expectedWeight = 50 * 200;
expect(reaction.calculated_voting_weight).to.eq(expectedWeight);
const t = await server.models.Thread.findByPk(thread.id);
// @ts-expect-error StrictNullChecks
Expand All @@ -142,7 +142,7 @@ describe('Reaction vote weight', () => {
reaction: 'like',
commentId: comment.id,
});
const expectedWeight = 1 + 50 * 200;
const expectedWeight = 50 * 200;
expect(reaction.calculated_voting_weight).to.eq(expectedWeight);
const c = await server.models.Comment.findByPk(comment.id);
// @ts-expect-error StrictNullChecks
Expand All @@ -152,7 +152,7 @@ describe('Reaction vote weight', () => {
test('should set thread reaction vote weight to min 1', async () => {
Sinon.stub(commonProtocol.contractHelpers, 'getNamespaceBalance').resolves({
// @ts-expect-error StrictNullChecks
[address.address]: '0',
[address.address]: '17',
});
const thread = await createThread();
const [reaction] = await threadsController.createThreadReaction({
Expand All @@ -161,14 +161,14 @@ describe('Reaction vote weight', () => {
reaction: 'like',
threadId: thread.id,
});
const expectedWeight = 1;
const expectedWeight = 17 * 200;
expect(reaction.calculated_voting_weight).to.eq(expectedWeight);
});

test('should set comment reaction vote weight to min 1', async () => {
Sinon.stub(commonProtocol.contractHelpers, 'getNamespaceBalance').resolves({
// @ts-expect-error StrictNullChecks
[address.address]: '0',
[address.address]: '7',
});
const thread = await createThread();
const comment = await createComment(thread.id);
Expand All @@ -178,7 +178,7 @@ describe('Reaction vote weight', () => {
reaction: 'like',
commentId: comment.id,
});
const expectedWeight = 1;
const expectedWeight = 7 * 200;
expect(reaction.calculated_voting_weight).to.eq(expectedWeight);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ describe('ServerCommentsController', () => {
}),
},
CommunityStake: {
findOne: sandbox.stub().resolves({
id: 5,
stake_id: 1,
vote_weight: 1,
}),
findOne: sandbox.stub().resolves(null),
},
Community: {
findByPk: async () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ describe('ServerThreadsController', () => {
}),
},
CommunityStake: {
findOne: sandbox.stub().resolves({
id: 5,
stake_id: 1,
vote_weight: 1,
}),
findOne: sandbox.stub().resolves(null),
},

Community: {
Expand Down

0 comments on commit 79c70a9

Please sign in to comment.