Skip to content

Commit

Permalink
Feature: Update validation functions so they receive actions instead …
Browse files Browse the repository at this point in the history
…of proposalId (#290)

* update validation functions so they receive actions instead of proposalId

* rename findAction function

* add package and changelog
  • Loading branch information
josemarinas committed Oct 18, 2023
1 parent bf3e275 commit 697caff
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 288 deletions.
6 changes: 6 additions & 0 deletions modules/client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ TEMPLATE:

- Helper for `daoUpdateAction` in `Client`

### Changed

- Input params for `isDaoUpdateValid` and `isPluginUpdateValid`
- Rename `isDaoUpdateProposalValid` to `isDaoUpdateValid`
- Rename `isPluginUpdateProposalValid` to `isPluginUpdateValid`

## [1.15.0]
### Added

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ Goes though the actions of an `IProposal` compatible proposal and checks that th

import { Client } from "@aragon/sdk-client";
import { context } from "../index";
import { DaoAction } from "@aragon/sdk-client-common";

// Instantiate the general purpose client from the Aragon OSx SDK context.
const client: Client = new Client(context);

const proposalId =
"0x1234567890123456789012345678901234567890123456789012345678901234";
const actions: DaoAction[] = [
// your actions
];

// check if a plugin update proposal is valid
const isValid = client.methods.isPluginUpdateProposalValid(proposalId);
const isValid = client.methods.isPluginUpdateValid({
daoAddress: "0x1234567890123456789012345678901234567890",
actions,
});

console.log(isValid);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ Goes though the actions of an `IProposal` compatible proposal and checks that th

import { Client } from "@aragon/sdk-client";
import { context } from "../index";
import { DaoAction } from "@aragon/sdk-client-common";

// Instantiate the general purpose client from the Aragon OSx SDK context.
const client: Client = new Client(context);

const proposalId =
"0x1234567890123456789012345678901234567890123456789012345678901234";
const actions: DaoAction[] = [
// your actions
];

// check if a dap update proposal is valid
const isValid = client.methods.isDaoUpdateProposalValid({ proposalId });
const isValid = client.methods.isDaoUpdateValid({
daoAddress: "0x1234567890123456789012345678901234567890",
actions,
});

console.log(isValid);

Expand Down
2 changes: 1 addition & 1 deletion modules/client/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@aragon/sdk-client",
"author": "Aragon Association",
"version": "1.15.0",
"version": "1.16.0",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/sdk-client.esm.js",
Expand Down
96 changes: 41 additions & 55 deletions modules/client/src/internal/client/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
QueryDao,
QueryDaos,
QueryIPlugin,
QueryIProposal,
QueryPlugin,
QueryPluginPreparations,
QueryPlugins,
Expand Down Expand Up @@ -53,7 +52,8 @@ import {
DepositParams,
GrantPermissionDecodedParams,
HasPermissionParams,
IsDaoUpdateProposalValidParams,
IsDaoUpdateValidParams,
IsPluginUpdateValidParams,
PluginQueryParams,
PluginRepo,
PluginRepoBuildMetadata,
Expand All @@ -74,7 +74,6 @@ import {
SubgraphBalance,
SubgraphDao,
SubgraphDaoListItem,
SubgraphIProposal,
SubgraphPluginInstallation,
SubgraphPluginRepo,
SubgraphPluginRepoListItem,
Expand All @@ -89,10 +88,9 @@ import {
decodeInitializeFromAction,
decodeRevokeAction,
decodeUpgradeToAndCallAction,
findAction,
findActionIndex,
getPreparedSetupId,
toAssetBalance,
toDaoActions,
toDaoDetails,
toDaoListItem,
toPluginRepo,
Expand Down Expand Up @@ -152,7 +150,6 @@ import {
PrepareUpdateParams,
PrepareUpdateStepValue,
promiseWithTimeout,
ProposalNotFoundError,
resolveIpfsCid,
SortDirection,
SupportedVersion,
Expand All @@ -169,6 +166,8 @@ import {
DepositErc721Schema,
DepositEthSchema,
HasPermissionSchema,
IsDaoUpdateValidSchema,
IsPluginUpdateValidSchema,
PluginQuerySchema,
} from "../schemas";

Expand Down Expand Up @@ -1110,12 +1109,12 @@ export class ClientMethods extends ClientCore implements IClientMethods {
return version;
}

public isDaoUpdateProposal(
public isDaoUpdate(
actions: DaoAction[],
): boolean {
const initializeFromInterface = DAO__factory.createInterface()
.getFunction("initializeFrom").format("minimal");
return findAction(actions, initializeFromInterface) !== -1;
return findActionIndex(actions, initializeFromInterface) !== -1;
}
/**
* Check if the specified actions try to update a plugin
Expand All @@ -1124,12 +1123,12 @@ export class ClientMethods extends ClientCore implements IClientMethods {
* @return {*} {boolean}
* @memberof ClientMethods
*/
public isPluginUpdateProposal(
public isPluginUpdate(
actions: DaoAction[],
): boolean {
const applyUpdateInterface = PluginSetupProcessor__factory.createInterface()
.getFunction("applyUpdate").format("minimal");
return findAction(actions, applyUpdateInterface) !== -1;
return findActionIndex(actions, applyUpdateInterface) !== -1;
}

/**
Expand Down Expand Up @@ -1297,29 +1296,17 @@ export class ClientMethods extends ClientCore implements IClientMethods {

/**
* Check if the specified proposal id is valid for updating a plugin
* The failure map should be checked before calling this method
*
* @param {string} proposalId
* @param {DaoAction[]} actions
* @return {*} {Promise<PluginUpdateProposalValidity>}
* @memberof ClientMethods
*/
public async isPluginUpdateProposalValid(
proposalId: string,
public async isPluginUpdateValid(
params: IsPluginUpdateValidParams,
): Promise<PluginUpdateProposalValidity> {
type T = { iproposal: SubgraphIProposal };
const { iproposal } = await this.graphql.request<T>({
query: QueryIProposal,
params: { id: proposalId },
name: "iproposal",
});
if (!iproposal) {
throw new ProposalNotFoundError();
}
await IsPluginUpdateValidSchema.strict().validate(params);
const causes: PluginUpdateProposalInValidityCause[] = [];
if (iproposal.allowFailureMap !== "0") {
causes.push(
PluginUpdateProposalInValidityCause.INVALID_ALLOW_FAILURE_MAP,
);
}
// get expected actions signatures
const grantSignature = DAO__factory.createInterface().getFunction("grant")
.format("minimal");
Expand All @@ -1329,10 +1316,12 @@ export class ClientMethods extends ClientCore implements IClientMethods {
.getFunction("applyUpdate").format("minimal");

// find signatures in the actions specified in the proposal
const daoActions = toDaoActions(iproposal.actions);
const grantIndex = findAction(daoActions, grantSignature);
const applyUpdateIndex = findAction(daoActions, applyUpdateSignature);
const revokeIndex = findAction(daoActions, revokeSignature);
const grantIndex = findActionIndex(params.actions, grantSignature);
const applyUpdateIndex = findActionIndex(
params.actions,
applyUpdateSignature,
);
const revokeIndex = findActionIndex(params.actions, revokeSignature);

// check that all actions are present and in the correct order
if (
Expand All @@ -1350,8 +1339,8 @@ export class ClientMethods extends ClientCore implements IClientMethods {
// check grant action
if (
!this.isPluginUpdatePermissionValid(
decodeGrantAction(daoActions[grantIndex].data),
iproposal.dao.id,
decodeGrantAction(params.actions[grantIndex].data),
params.daoAddress,
)
) {
causes.push(PluginUpdateProposalInValidityCause.INVALID_GRANT_PERMISSION);
Expand All @@ -1360,8 +1349,8 @@ export class ClientMethods extends ClientCore implements IClientMethods {
// check revoke action
if (
!this.isPluginUpdatePermissionValid(
decodeRevokeAction(daoActions[revokeIndex].data),
iproposal.dao.id,
decodeRevokeAction(params.actions[revokeIndex].data),
params.daoAddress,
)
) {
causes.push(
Expand All @@ -1371,10 +1360,10 @@ export class ClientMethods extends ClientCore implements IClientMethods {

// check apply update action
const decodedApplyUpdateActionParams = decodeApplyUpdateAction(
daoActions[applyUpdateIndex].data,
params.actions[applyUpdateIndex].data,
);
const applyUpdateCauses = await this.checkApplyUpdateActionInvalidityCauses(
iproposal.dao.id,
params.daoAddress,
decodedApplyUpdateActionParams,
);
causes.push(...applyUpdateCauses);
Expand All @@ -1383,29 +1372,26 @@ export class ClientMethods extends ClientCore implements IClientMethods {
causes,
};
}

public async isDaoUpdateProposalValid(
params: IsDaoUpdateProposalValidParams,
/**
* Check if the specified actions are valid for updating a dao
* The failure map should be checked before calling this method
*
* @param {IsDaoUpdateValidParams} params
* @return {*} {Promise<DaoUpdateProposalValidity>}
* @memberof ClientMethods
*/
public async isDaoUpdateValid(
params: IsDaoUpdateValidParams,
): Promise<DaoUpdateProposalValidity> {
type T = { iproposal: SubgraphIProposal };
const { iproposal } = await this.graphql.request<T>({
query: QueryIProposal,
params: { id: params.proposalId },
name: "iproposal",
});
if (!iproposal) {
throw new ProposalNotFoundError();
}
await IsDaoUpdateValidSchema.strict().validate(params);
const causes: DaoUpdateProposalInvalidityCause[] = [];
// get initialize from signature
const upgradeToAndCallSignature = DAO__factory.createInterface()
.getFunction(
"upgradeToAndCall",
).format("minimal");
// find initialize from signature in the actions specified in the proposal
const daoActions = toDaoActions(iproposal.actions);
const upgradeToAndCallIndex = findAction(
daoActions,
const upgradeToAndCallIndex = findActionIndex(
params.actions,
upgradeToAndCallSignature,
);
// check that initialize from action is present
Expand All @@ -1417,7 +1403,7 @@ export class ClientMethods extends ClientCore implements IClientMethods {
};
}
const decodedUpgradeToAndCallParams = decodeUpgradeToAndCallAction(
daoActions[upgradeToAndCallIndex].data,
params.actions[upgradeToAndCallIndex].data,
);
let decodedInitializeFromParams: DecodedInitializeFromParams;
try {
Expand All @@ -1432,7 +1418,7 @@ export class ClientMethods extends ClientCore implements IClientMethods {
// check version
if (
!await this.isDaoUpdateVersionValid(
iproposal.dao.id,
params.daoAddress,
decodedInitializeFromParams.previousVersion,
)
) {
Expand Down
18 changes: 9 additions & 9 deletions modules/client/src/internal/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
GrantPermissionWithConditionParams,
HasPermissionParams,
InitializeFromParams,
IsDaoUpdateProposalValidParams,
IsDaoUpdateValidParams,
PluginQueryParams,
PluginRepo,
PluginRepoListItem,
Expand Down Expand Up @@ -95,20 +95,20 @@ export interface IClientMethods {
contractAddress: string,
) => Promise<[number, number, number]>;

isPluginUpdateProposalValid: (
proposalId: string,
) => Promise<PluginUpdateProposalValidity>;

isPluginUpdateProposal: (
isPluginUpdate: (
actions: DaoAction[],
) => boolean;

isDaoUpdateProposal: (
isPluginUpdateValid: (
params: IsDaoUpdateValidParams,
) => Promise<PluginUpdateProposalValidity>;

isDaoUpdate: (
actions: DaoAction[],
) => boolean;

isDaoUpdateProposalValid: (
params: IsDaoUpdateProposalValidParams,
isDaoUpdateValid: (
params: IsDaoUpdateValidParams,
) => Promise<DaoUpdateProposalValidity>;

getDaoImplementation: (
Expand Down
18 changes: 18 additions & 0 deletions modules/client/src/internal/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,21 @@ export const DaoUpdateSchema = object({
initData: Uint8ArraySchema.notRequired(),
daoFactoryAddress: AddressOrEnsSchema.notRequired(),
});

export const IsPluginUpdateValidSchema = object({
actions: array().of(object({
to: AddressOrEnsSchema.required(),
value: BigintSchema.required(),
data: Uint8ArraySchema.required(),
})).required().min(1),
daoAddress: AddressOrEnsSchema.required(),
});
export const IsDaoUpdateValidSchema = object({
actions: array().of(object({
to: AddressOrEnsSchema.required(),
value: BigintSchema.required(),
data: Uint8ArraySchema.required(),
})).required().min(1),
daoAddress: AddressOrEnsSchema.required(),
version: array().of(number()).length(3).notRequired(),
});
2 changes: 1 addition & 1 deletion modules/client/src/internal/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ export function findInterface(
}
}

export function findAction(
export function findActionIndex(
actions: DaoAction[],
functionSignature: string,
): number {
Expand Down
10 changes: 8 additions & 2 deletions modules/client/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
DaoAction,
MetadataAbiInput,
Pagination,
PluginInstallItem,
Expand Down Expand Up @@ -455,8 +456,12 @@ export type DaoUpdateProposalValidity = {
causes: DaoUpdateProposalInvalidityCause[];
};

export type IsDaoUpdateProposalValidParams = {
proposalId: string;
type IsUpdateParamsBase = {
actions: DaoAction[];
daoAddress: string;
};

export type IsDaoUpdateValidParams = IsUpdateParamsBase & {
version?: [number, number, number];
};

Expand All @@ -467,3 +472,4 @@ export type DaoUpdateParams = InitializeFromParams & {
export type DaoUpdateDecodedParams = InitializeFromParams & {
implementationAddress: string;
};
export type IsPluginUpdateValidParams = IsUpdateParamsBase;
Loading

0 comments on commit 697caff

Please sign in to comment.