Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wire Manage Tokens / Edit Colony motion #74

Merged
merged 2 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions src/amplifyClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,27 @@ export const mutations = {
}
}
`,
updateColonyMetadata: /* GraphQL */ `
mutation UpdateColonyMetadata($input: UpdateColonyMetadataInput!) {
updateColonyMetadata(input: $input) {
id
}
}
`,
createColonyTokens: /* GraphQL */ `
mutation CreateColonyTokens($input: CreateColonyTokensInput!) {
createColonyTokens(input: $input) {
id
}
}
`,
deleteColonyTokens: /* GraphQL */ `
mutation DeleteColonyTokens($input: DeleteColonyTokensInput!) {
deleteColonyTokens(input: $input) {
id
}
}
`,
};

/*
Expand Down Expand Up @@ -283,6 +304,26 @@ export const queries = {
newDescription
}
}
pendingColonyMetadata {
id
displayName
avatar
thumbnail
changelog {
transactionHash
oldDisplayName
newDisplayName
hasAvatarChanged
hasWhitelistChanged
haveTokensChanged
}
isWhitelistActivated
whitelistedAddresses
modifiedTokenAddresses {
added
removed
}
}
}
}
}
Expand All @@ -302,6 +343,52 @@ export const queries = {
}
}
`,
getColonyMetadata: /* GraphQL */ `
query GetColonyMetadata($id: ID!) {
getColonyMetadata(id: $id) {
id
displayName
avatar
thumbnail
changelog {
transactionHash
oldDisplayName
newDisplayName
hasAvatarChanged
hasWhitelistChanged
haveTokensChanged
}
isWhitelistActivated
whitelistedAddresses
modifiedTokenAddresses {
added
removed
}
}
}
`,
getTokenFromEverywhere: /* GraphQL */ `
query GetTokenFromEverywhere($input: TokenFromEverywhereArguments!) {
getTokenFromEverywhere(input: $input) {
items {
id
}
}
}
`,
getColony: /* GraphQL */ `
query GetColony($id: ID!) {
getColony(id: $id) {
colonyAddress: id
tokens {
items {
id
tokenAddress: tokenID
}
}
}
}
`,
};

export default (): void => {
Expand Down
19 changes: 19 additions & 0 deletions src/handlers/motions/motionCreated/handlers/editColony.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { TransactionDescription } from 'ethers/lib/utils';
import { ContractEvent, motionNameMapping } from '~types';
import { getPendingMetadataDatabaseId } from '~utils';
import { createMotionInDB } from '../helpers';

export const handleEditColonyMotion = async (
event: ContractEvent,
{ name }: TransactionDescription,
): Promise<void> => {
const { transactionHash, contractAddress: colonyAddress } = event;
const pendingColonyMetadataId = getPendingMetadataDatabaseId(
colonyAddress,
transactionHash,
);
await createMotionInDB(event, {
type: motionNameMapping[name],
pendingColonyMetadataId,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we're following the same pattern as with Domains. We attach the "pending" metadata to the action, so it can be retreived when the motion is finalized.

});
};
1 change: 1 addition & 0 deletions src/handlers/motions/motionCreated/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { handleUnlockTokenMotion } from './unlockToken';
export { handlePaymentMotion } from './payment';
export { handleMoveFundsMotion } from './moveFunds';
export { handleDomainEditReputationMotion } from './reputation';
export { handleEditColonyMotion } from './editColony';
4 changes: 2 additions & 2 deletions src/handlers/motions/motionCreated/handlers/manageDomain.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TransactionDescription } from 'ethers/lib/utils';
import { ContractEvent, motionNameMapping } from '~types';
import { getPendingMotionDomainDatabaseId } from '~utils';
import { getPendingMetadataDatabaseId } from '~utils';
import { createMotionInDB } from '../helpers';

export const handleManageDomainMotion = async (
Expand All @@ -9,7 +9,7 @@ export const handleManageDomainMotion = async (
): Promise<void> => {
const { transactionHash, contractAddress: colonyAddress } = event;
const { name } = parsedAction;
const pendingDomainMetadataId = getPendingMotionDomainDatabaseId(
const pendingDomainMetadataId = getPendingMetadataDatabaseId(
colonyAddress,
transactionHash,
);
Expand Down
6 changes: 6 additions & 0 deletions src/handlers/motions/motionCreated/motionCreated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
handlePaymentMotion,
handleMoveFundsMotion,
handleDomainEditReputationMotion,
handleEditColonyMotion,
} from './handlers';

export default async (event: ContractEvent): Promise<void> => {
Expand Down Expand Up @@ -70,6 +71,11 @@ export default async (event: ContractEvent): Promise<void> => {
break;
}

case ColonyOperations.EditColony: {
await handleEditColonyMotion(event, parsedAction);
break;
}

default: {
break;
}
Expand Down
111 changes: 106 additions & 5 deletions src/handlers/motions/motionFinalized/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { BigNumber } from 'ethers';
import { TransactionDescription } from 'ethers/lib/utils';

import { ColonyOperations, MotionQuery, MotionVote, StakerReward } from '~types';
import { getDomainDatabaseId, getVotingClient, verbose } from '~utils';
import {
ColonyMetadata,
ColonyOperations,
MotionQuery,
MotionVote,
StakerReward,
} from '~types';
import {
getColonyFromDB,
getDomainDatabaseId,
getExistingTokenAddresses,
getVotingClient,
updateColonyTokens,
verbose,
} from '~utils';
import networkClient from '~networkClient';
import { mutate } from '~amplifyClient';
import { query, mutate } from '~amplifyClient';

export const getStakerReward = async (
motionId: string,
Expand Down Expand Up @@ -70,8 +83,15 @@ const getParsedActionFromDomainMotion = async (
}
};

export const linkPendingDomainMetadataWithDomain = async (action: string, colonyAddress: string, finalizedMotion: MotionQuery): Promise<void> => {
const parsedDomainAction = await getParsedActionFromDomainMotion(action, colonyAddress);
export const linkPendingDomainMetadataWithDomain = async (
action: string,
colonyAddress: string,
finalizedMotion: MotionQuery,
): Promise<void> => {
const parsedDomainAction = await getParsedActionFromDomainMotion(
action,
colonyAddress,
);
if (parsedDomainAction?.name === ColonyOperations.AddDomain) {
const colonyClient = await networkClient.getColonyClient(colonyAddress);
const domainCount = await colonyClient.getDomainCount();
Expand All @@ -96,3 +116,84 @@ export const linkPendingDomainMetadataWithDomain = async (action: string, colony
});
}
};

export const linkPendingColonyMetadataWithColony = async (
pendingColonyMetadata: ColonyMetadata,
colonyAddress: string,
): Promise<void> => {
const currentColonyMetadata = await query<ColonyMetadata>(
'getColonyMetadata',
{
id: colonyAddress,
},
);

if (!currentColonyMetadata) {
console.error(
`Could not find the current metadata for the colony: ${colonyAddress}. This is a bug and should be investigated.`,
);
return;
}

const {
haveTokensChanged,
hasAvatarChanged,
hasWhitelistChanged,
newDisplayName,
oldDisplayName,
} = pendingColonyMetadata.changelog?.[0] ?? {};

const updatedMetadata = {
...currentColonyMetadata,
};

/*
* Here, we update metadata as granularly as possible so that we don't overwrite state changes that occured
* after this motion was created.
*/
Copy link
Contributor Author

@willm30 willm30 May 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the comment suggests, this should fix the problem of one motion overwriting the state changes of another motion that was created after it, but finalized before it is finalized. To be tested in JoinColony/colonyCDapp#433

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this works as I imagine, we can refactor how we store Domain metadata to follow the same pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#76


if (hasAvatarChanged) {
// If avatar has changed, update avatar and thumbnail
updatedMetadata.avatar = pendingColonyMetadata.avatar;
updatedMetadata.thumbnail = pendingColonyMetadata.thumbnail;
}

if (hasWhitelistChanged) {
// If whitelist has changed, update whitelistedAddresses and isWhitelistActivated
updatedMetadata.isWhitelistActivated =
pendingColonyMetadata.isWhitelistActivated;

updatedMetadata.whitelistedAddresses =
pendingColonyMetadata.whitelistedAddresses;
}

if (newDisplayName !== oldDisplayName) {
// If displayName has changed, update displayName
updatedMetadata.displayName = pendingColonyMetadata.displayName;
}

if (haveTokensChanged && pendingColonyMetadata.modifiedTokenAddresses) {
// If tokens have changed, update colony tokens
const colony = await getColonyFromDB(colonyAddress);

if (colony) {
const existingTokenAddresses = getExistingTokenAddresses(colony);

await updateColonyTokens(
colony,
existingTokenAddresses,
pendingColonyMetadata.modifiedTokenAddresses,
);
}
}

await mutate('updateColonyMetadata', {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, we update the metadata changelog with the changes the motion introduced.

input: {
...updatedMetadata,
changelog: [
...(currentColonyMetadata.changelog ?? []),
pendingColonyMetadata.changelog?.[0],
],
},
});
};
24 changes: 21 additions & 3 deletions src/handlers/motions/motionFinalized/motionFinalized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import {
updateMotionInDB,
getMessageKey,
} from '../helpers';
import { getStakerReward, linkPendingDomainMetadataWithDomain } from './helpers';

import {
getStakerReward,
linkPendingColonyMetadataWithColony,
linkPendingDomainMetadataWithDomain,
} from './helpers';

export default async (event: ContractEvent): Promise<void> => {
const {
Expand Down Expand Up @@ -45,7 +50,9 @@ export default async (event: ContractEvent): Promise<void> => {
motionData,
} = finalizedMotion;

const yayWon = BigNumber.from(yayVotes).gt(nayVotes) || (Number(yayPercentage) > Number(nayPercentage));
const yayWon =
BigNumber.from(yayVotes).gt(nayVotes) ||
Number(yayPercentage) > Number(nayPercentage);

/*
* pendingDomainMetadata is a motion data prop that we use to store the metadata of a Domain that COULD be created/edited
Expand All @@ -54,7 +61,18 @@ export default async (event: ContractEvent): Promise<void> => {
* a new DomainMetadata with the corresponding Domain item id.
*/
if (finalizedMotion.pendingDomainMetadata && yayWon) {
await linkPendingDomainMetadataWithDomain(action, colonyAddress, finalizedMotion);
await linkPendingDomainMetadataWithDomain(
action,
colonyAddress,
finalizedMotion,
);
}

if (finalizedMotion.pendingColonyMetadata && yayWon) {
await linkPendingColonyMetadataWithColony(
finalizedMotion.pendingColonyMetadata,
colonyAddress,
);
}

const updatedStakerRewards = await Promise.all(
Expand Down
14 changes: 14 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export enum ColonyActionType {
MoveFundsMotion = 'MOVE_FUNDS_MOTION',
EmitDomainReputationPenaltyMotion = 'EMIT_DOMAIN_REPUTATION_PENALTY_MOTION',
EmitDomainReputationRewardMotion = 'EMIT_DOMAIN_REPUTATION_REWARD_MOTION',
ColonyEditMotion = 'COLONY_EDIT_MOTION',
}

export type ColonyActionHandler = (event: ContractEvent) => Promise<void>;
Expand Down Expand Up @@ -136,3 +137,16 @@ interface VotingReputationParams {
revealPeriod: string;
escalationPeriod: string;
}

export interface ColonyQuery {
colonyAddress: string;
tokens:
| {
items: Array<{
id: string;
tokenAddress: string;
} | null>;
}
| null
| undefined;
}
Loading