diff --git a/modules/client/CHANGELOG.md b/modules/client/CHANGELOG.md index a4e255c5c..30bf900ee 100644 --- a/modules/client/CHANGELOG.md +++ b/modules/client/CHANGELOG.md @@ -17,6 +17,8 @@ TEMPLATE: --> ## [UPCOMING] +### Added +- Added `initializeFrom` encoders and decoders ### Fixes - Fix status calculation for token voting proposals - Make the `network` parameter required on `getPluginInstallItem` diff --git a/modules/client/examples/01-client/01-create-dao.ts b/modules/client/examples/01-client/01-create-dao.ts index 3fa5463da..21cd87ff7 100644 --- a/modules/client/examples/01-client/01-create-dao.ts +++ b/modules/client/examples/01-client/01-create-dao.ts @@ -13,8 +13,8 @@ import { CreateDaoParams, DaoCreationSteps, DaoMetadata, - TokenVotingPluginInstall, TokenVotingClient, + TokenVotingPluginInstall, VotingMode, } from "@aragon/sdk-client"; import { GasFeeEstimation } from "@aragon/sdk-client-common"; diff --git a/modules/client/examples/01-client/05-get-daos.ts b/modules/client/examples/01-client/05-get-daos.ts index 1e41ba29e..07613f7e6 100644 --- a/modules/client/examples/01-client/05-get-daos.ts +++ b/modules/client/examples/01-client/05-get-daos.ts @@ -11,8 +11,8 @@ Gets a list of DAOs from the Aragon OSx DAO registry. import { Client, DaoListItem, - DaoSortBy, DaoQueryParams, + DaoSortBy, } from "@aragon/sdk-client"; import { SortDirection } from "@aragon/sdk-client-common"; import { context } from "../index"; diff --git a/modules/client/examples/01-client/07-get-transfers.ts b/modules/client/examples/01-client/07-get-transfers.ts index 174046178..8db34a6e3 100644 --- a/modules/client/examples/01-client/07-get-transfers.ts +++ b/modules/client/examples/01-client/07-get-transfers.ts @@ -13,8 +13,8 @@ By default, retrieves ETH, DAI, USDC and USDT, on Mainnet). import { Client, - TransferQueryParams, Transfer, + TransferQueryParams, TransferSortBy, TransferType, } from "@aragon/sdk-client"; diff --git a/modules/client/examples/01-client/11-prepare-uninstallation.ts b/modules/client/examples/01-client/11-prepare-uninstallation.ts index 1159b8b4a..0afab33f4 100644 --- a/modules/client/examples/01-client/11-prepare-uninstallation.ts +++ b/modules/client/examples/01-client/11-prepare-uninstallation.ts @@ -5,8 +5,8 @@ title: Prepare Uninstallation ### Prepare the uninstallation of a plugin -The `prepareUninstallation` method performs the prior steps so that a DAO proposal can eventually apply the removal of a Plugin. -The proposal will need an Action calling the `applyUninstallation` function. +The `prepareUninstallation` method performs the prior steps so that a DAO proposal can eventually apply the removal of a Plugin. +The proposal will need an Action calling the `applyUninstallation` function. For more details see https://devs.aragon.org/docs/sdk/examples/encoders-decoders/apply-uninstallation#encoding diff --git a/modules/client/examples/03-tokenVoting-client/index.ts b/modules/client/examples/03-tokenVoting-client/index.ts index ebf9a399f..75e210255 100644 --- a/modules/client/examples/03-tokenVoting-client/index.ts +++ b/modules/client/examples/03-tokenVoting-client/index.ts @@ -17,7 +17,6 @@ import { context } from "../index"; // Instantiate the ContextPlugin from the Aragon OSx SDK context. - // Create a TokenVoting client. const tokenVotingClient = new TokenVotingClient(context); console.log(tokenVotingClient); diff --git a/modules/client/examples/05-encoders-decoders/04-revoke-permissions.ts b/modules/client/examples/05-encoders-decoders/04-revoke-permissions.ts index 01013c427..b5b0b0ae2 100644 --- a/modules/client/examples/05-encoders-decoders/04-revoke-permissions.ts +++ b/modules/client/examples/05-encoders-decoders/04-revoke-permissions.ts @@ -12,9 +12,9 @@ Revokes a permission to a given address (`who`) to perform an action on a contra import { Client, + Permissions, RevokePermissionDecodedParams, RevokePermissionParams, - Permissions, } from "@aragon/sdk-client"; import { DaoAction } from "@aragon/sdk-client-common"; import { context } from "../index"; diff --git a/modules/client/examples/05-encoders-decoders/05-register-standard-callback.ts b/modules/client/examples/05-encoders-decoders/05-register-standard-callback.ts index 92cb27fa1..da0558929 100644 --- a/modules/client/examples/05-encoders-decoders/05-register-standard-callback.ts +++ b/modules/client/examples/05-encoders-decoders/05-register-standard-callback.ts @@ -10,10 +10,7 @@ Register a new standard callback for the DAO. ### Encoding */ -import { - Client, - RegisterStandardCallbackParams, -} from "@aragon/sdk-client"; +import { Client, RegisterStandardCallbackParams } from "@aragon/sdk-client"; import { DaoAction } from "@aragon/sdk-client-common"; import { context } from "../index"; diff --git a/modules/client/examples/05-encoders-decoders/06-withdraw.ts b/modules/client/examples/05-encoders-decoders/06-withdraw.ts index beb92673c..73eeab19d 100644 --- a/modules/client/examples/05-encoders-decoders/06-withdraw.ts +++ b/modules/client/examples/05-encoders-decoders/06-withdraw.ts @@ -17,10 +17,7 @@ In order for a withdrawal to be successful, the address executing it must have ` #### Encoding */ -import { - Client, - WithdrawParams, -} from "@aragon/sdk-client"; +import { Client, WithdrawParams } from "@aragon/sdk-client"; import { DaoAction, TokenType } from "@aragon/sdk-client-common"; import { context } from "../index"; diff --git a/modules/client/examples/05-encoders-decoders/07-update-metadata.ts b/modules/client/examples/05-encoders-decoders/07-update-metadata.ts index 7b3da30d1..ed553b6b3 100644 --- a/modules/client/examples/05-encoders-decoders/07-update-metadata.ts +++ b/modules/client/examples/05-encoders-decoders/07-update-metadata.ts @@ -24,13 +24,13 @@ const metadataParams: DaoMetadata = { links: [ { url: "https://discord.com/...", - name: "Discord" + name: "Discord", }, { url: "https://twitter.com/...", - name: "Twitter" - } - ] + name: "Twitter", + }, + ], }; const daoAddressOrEns: string = "0x123458235832745982839878932332423"; // or my-dao.dao.eth @@ -41,7 +41,7 @@ const ipfsUri: string = await client.methods.pinMetadata(metadataParams); // Update the metadata of a given DAO. const action: DaoAction = await client.encoding.updateDaoMetadataAction( daoAddressOrEns, - ipfsUri + ipfsUri, ); console.log({ action }); @@ -62,9 +62,10 @@ Returns: */ // Decodes the update metadata action. -const decodedParams: DaoMetadata = await client.decoding.updateDaoMetadataAction( - action.data -); +const decodedParams: DaoMetadata = await client.decoding + .updateDaoMetadataAction( + action.data, + ); console.log({ decodedParams }); /* MARKDOWN @@ -97,7 +98,7 @@ Decode an update metadata action and expect an IPFS URI containing the CID of th // Decodes the parameters of an update metadata raw action. const decodedParamsRaw: string = client.decoding.updateDaoMetadataRawAction( - action.data + action.data, ); console.log({ decodedParamsRaw }); diff --git a/modules/client/examples/05-encoders-decoders/12-apply-uninstallation.ts b/modules/client/examples/05-encoders-decoders/13-apply-uninstallation.ts similarity index 100% rename from modules/client/examples/05-encoders-decoders/12-apply-uninstallation.ts rename to modules/client/examples/05-encoders-decoders/13-apply-uninstallation.ts diff --git a/modules/client/examples/05-encoders-decoders/14-initialize-from.ts b/modules/client/examples/05-encoders-decoders/14-initialize-from.ts new file mode 100644 index 000000000..57d2cc7e4 --- /dev/null +++ b/modules/client/examples/05-encoders-decoders/14-initialize-from.ts @@ -0,0 +1,60 @@ +/* MARKDOWN +--- +title: Initialize From +--- + +## Upgrade a DAO to a new version + +Encodes the action for upgrading the dao to a new version and passing initialization data of the new version. + +### Encoding +*/ + +import { Client, InitializeFromParams } from "@aragon/sdk-client"; +import { DaoAction } from "@aragon/sdk-client-common"; +import { context } from "../index"; + +// Instantiates an Aragon OSx SDK client. +const client: Client = new Client(context); + +// This variable contains the values received on the ininitializeFrom() method +const initializeFromParams: InitializeFromParams = { + previousVersion: [1, 0, 0], + initData: new Uint8Array([12, 34, 45, 85, 95, 45, 73]), // initialization data for the new version to be pased to upgradeToAndCall() +}; + +const daoAddressOrEns: string = "0x123123123123123123123123123123123123"; // "my-dao.eth" + +const action: DaoAction = client.encoding.initializeFromAction( + daoAddressOrEns, + initializeFromParams, +); +console.log(action); + +/* MARKDOWN + ```json + { + to: "0x123123123...", + value: 0n, + data: Uint8Array[12,34,45...] + } + ``` + + ### Decoding + */ + +// Decodes the initialize from action. +const decodedParams: InitializeFromParams = client.decoding + .initializeFromAction(action.data); +console.log({ decodedParams }); + +/* MARKDOWN + Returns: + + ```json + { + previousVersion: [1, 0, 0], + initData: Uint8Array[12,34,45...] + } + ``` + */ diff --git a/modules/client/src/addresslistVoting/client.ts b/modules/client/src/addresslistVoting/client.ts index 8a80255c4..de70d1d30 100644 --- a/modules/client/src/addresslistVoting/client.ts +++ b/modules/client/src/addresslistVoting/client.ts @@ -11,7 +11,11 @@ import { AddresslistVotingClientDecoding } from "./internal/client/decoding"; import { AddresslistVotingClientEstimation } from "./internal/client/estimation"; import { Networkish } from "@ethersproject/providers"; import { AddresslistVotingPluginInstall } from "./types"; -import { ClientCore, Context, PluginInstallItem } from "@aragon/sdk-client-common"; +import { + ClientCore, + Context, + PluginInstallItem, +} from "@aragon/sdk-client-common"; /** * Provider a generic client with high level methods to manage and interact an Address List Voting plugin installed in a DAO diff --git a/modules/client/src/client-common/types/common.ts b/modules/client/src/client-common/types/common.ts index 0278fe56f..8305c5460 100644 --- a/modules/client/src/client-common/types/common.ts +++ b/modules/client/src/client-common/types/common.ts @@ -1,4 +1,3 @@ - // This file contains common types, interfaces, and enumerations export enum DaoRole { @@ -9,7 +8,6 @@ export enum DaoRole { SET_SIGNATURE_VALIDATOR_ROLE = "SET_SIGNATURE_VALIDATOR_ROLE", } - /** * Contains the general human readable information about the DAO */ @@ -17,4 +15,3 @@ export type DaoConfig = { name: string; metadataUri: string; }; - diff --git a/modules/client/src/client.ts b/modules/client/src/client.ts index 23989cade..b235a3373 100644 --- a/modules/client/src/client.ts +++ b/modules/client/src/client.ts @@ -9,7 +9,7 @@ import { IClientEstimation, IClientMethods, } from "./internal/interfaces"; -import { Context, ClientCore } from "@aragon/sdk-client-common"; +import { ClientCore, Context } from "@aragon/sdk-client-common"; /** * Provider a generic client with high level methods to manage and interact with DAO's diff --git a/modules/client/src/internal/client/decoding.ts b/modules/client/src/internal/client/decoding.ts index 840df21ab..3e9542099 100644 --- a/modules/client/src/internal/client/decoding.ts +++ b/modules/client/src/internal/client/decoding.ts @@ -3,6 +3,7 @@ import { DecodedApplyUninstallationParams, GrantPermissionDecodedParams, GrantPermissionWithConditionParams, + InitializeFromParams, RegisterStandardCallbackParams, RevokePermissionDecodedParams, UpgradeToAndCallParams, @@ -278,6 +279,26 @@ export class ClientDecoding extends ClientCore implements IClientDecoding { }; } + /** + * Decodes the initializeFrom params from an initializeFromAction + * + * @param {Uint8Array} data + * @return {*} {InitializeFromParams} + * @memberof ClientDecoding + */ + public initializeFromAction(data: Uint8Array): InitializeFromParams { + const daoInterface = DAO__factory.createInterface(); + const hexBytes = bytesToHex(data); + const expectedFunction = daoInterface.getFunction( + "initializeFrom", + ); + const result = daoInterface.decodeFunctionData(expectedFunction, hexBytes); + return { + previousVersion: result[0], + initData: hexToBytes(result[1]), + }; + } + /** * Returns the decoded function info given the encoded data of an action * diff --git a/modules/client/src/internal/client/encoding.ts b/modules/client/src/internal/client/encoding.ts index 809d10f1d..25a44ae4e 100644 --- a/modules/client/src/internal/client/encoding.ts +++ b/modules/client/src/internal/client/encoding.ts @@ -2,6 +2,7 @@ import { ApplyUninstallationParams, GrantPermissionParams, GrantPermissionWithConditionParams, + InitializeFromParams, RegisterStandardCallbackParams, RevokePermissionParams, UpgradeToAndCallParams, @@ -414,4 +415,28 @@ export class ClientEncoding extends ClientCore implements IClientEncoding { data: hexToBytes(hexBytes), }; } + + /** + * Computes an action to be passed to the upgradeToAndCallAction method when upgrading a DAO to a new version. + * + * @param {string} daoAddressOrEns + * @param {InitializeFromParams} params + * @return {*} + * @memberof ClientEncoding + */ + public initializeFromAction( + daoAddressOrEns: string, + params: InitializeFromParams, + ) { + const daoInterface = DAO__factory.createInterface(); + const hexBytes = daoInterface.encodeFunctionData("initializeFrom", [ + params.previousVersion, + params.initData ?? new Uint8Array(), + ]); + return { + to: daoAddressOrEns, + value: BigInt(0), + data: hexToBytes(hexBytes), + }; + } } diff --git a/modules/client/src/internal/interfaces.ts b/modules/client/src/internal/interfaces.ts index 719348fce..a3329118e 100644 --- a/modules/client/src/internal/interfaces.ts +++ b/modules/client/src/internal/interfaces.ts @@ -25,6 +25,7 @@ import { GrantPermissionParams, GrantPermissionWithConditionParams, HasPermissionParams, + InitializeFromParams, PluginQueryParams, PluginRepo, PluginRepoListItem, @@ -127,6 +128,10 @@ export interface IClientEncoding { daoAddressOrEns: string, params: ApplyUninstallationParams, ) => DaoAction[]; + initializeFromAction: ( + daoAddressOrEns: string, + params: InitializeFromParams, + ) => DaoAction; } export interface IClientDecoding { @@ -156,6 +161,9 @@ export interface IClientDecoding { applyUninstallationAction: ( data: Uint8Array, ) => DecodedApplyUninstallationParams; + initializeFromAction: ( + data: Uint8Array, + ) => InitializeFromParams; } export interface IClientEstimation { diff --git a/modules/client/src/tokenVoting/internal/utils.ts b/modules/client/src/tokenVoting/internal/utils.ts index a1ac2f420..6a8de5f58 100644 --- a/modules/client/src/tokenVoting/internal/utils.ts +++ b/modules/client/src/tokenVoting/internal/utils.ts @@ -222,7 +222,11 @@ export function parseToken( | SubgraphErc721Token | SubgraphErc20WrapperToken, ): Erc20TokenDetails | Erc721TokenDetails | null { - let token: Erc721TokenDetails | Erc20TokenDetails| Erc20WrapperTokenDetails | null = null; + let token: + | Erc721TokenDetails + | Erc20TokenDetails + | Erc20WrapperTokenDetails + | null = null; if (subgraphToken.__typename === SubgraphContractType.ERC20) { token = { address: subgraphToken.id, diff --git a/modules/client/src/types.ts b/modules/client/src/types.ts index d43f9d331..05ae196bf 100644 --- a/modules/client/src/types.ts +++ b/modules/client/src/types.ts @@ -345,3 +345,8 @@ export type UpgradeToAndCallParams = { implementationAddress: string; data: Uint8Array; }; + +export type InitializeFromParams = { + previousVersion: [number, number, number]; + initData?: Uint8Array; +}; diff --git a/modules/client/test/abi/ERC1967.ts b/modules/client/test/abi/ERC1967.ts index cb4af01e4..e426b5849 100644 --- a/modules/client/test/abi/ERC1967.ts +++ b/modules/client/test/abi/ERC1967.ts @@ -70,4 +70,4 @@ export const ERC1967ABI = [ "stateMutability": "payable", "type": "receive", }, -]; \ No newline at end of file +]; diff --git a/modules/client/test/abi/index.ts b/modules/client/test/abi/index.ts index 3f4e3a26b..7a9137556 100644 --- a/modules/client/test/abi/index.ts +++ b/modules/client/test/abi/index.ts @@ -1 +1 @@ -export * from './ERC1967' \ No newline at end of file +export * from "./ERC1967"; diff --git a/modules/client/test/helpers/build-daos.ts b/modules/client/test/helpers/build-daos.ts index e1911a963..33f030c09 100644 --- a/modules/client/test/helpers/build-daos.ts +++ b/modules/client/test/helpers/build-daos.ts @@ -4,9 +4,9 @@ import { Client, CreateDaoParams, DaoCreationSteps, - TokenVotingPluginInstall, MultisigClient, TokenVotingClient, + TokenVotingPluginInstall, VotingMode, } from "../../src"; import { @@ -112,7 +112,7 @@ export async function buildTokenVotingDAO( plugin, signer, ); - const tokenAddress = await tokenVotingContract.getVotingToken() + const tokenAddress = await tokenVotingContract.getVotingToken(); return { dao, diff --git a/modules/client/test/integration/client/decoding.test.ts b/modules/client/test/integration/client/decoding.test.ts index 349d67057..587ba2fec 100644 --- a/modules/client/test/integration/client/decoding.test.ts +++ b/modules/client/test/integration/client/decoding.test.ts @@ -11,6 +11,7 @@ import { GrantPermissionDecodedParams, GrantPermissionParams, GrantPermissionWithConditionParams, + InitializeFromParams, PermissionIds, Permissions, RegisterStandardCallbackParams, @@ -661,5 +662,26 @@ describe("Client", () => { ); } }); + it("Should decode an initialize from action", async () => { + const context = new Context(contextParamsLocalChain); + const client = new Client(context); + const params: InitializeFromParams = { + previousVersion: [1, 0, 0], + initData: new Uint8Array([0, 1, 2, 3]), + }; + const action = await client.encoding.initializeFromAction( + "0x1234567890123456789012345678901234567890", + params, + ); + const decodedParams = client.decoding.initializeFromAction(action.data); + for (const index in params.previousVersion) { + expect(params.previousVersion[index]).toBe( + decodedParams.previousVersion[index], + ); + } + expect(bytesToHex(params.initData as Uint8Array)).toBe( + bytesToHex(decodedParams.initData as Uint8Array), + ); + }); }); }); diff --git a/modules/client/test/integration/client/encoding.test.ts b/modules/client/test/integration/client/encoding.test.ts index 7cb8ce16a..5272345ab 100644 --- a/modules/client/test/integration/client/encoding.test.ts +++ b/modules/client/test/integration/client/encoding.test.ts @@ -13,6 +13,7 @@ import { Client, DaoMetadata, GrantPermissionParams, + InitializeFromParams, PermissionIds, Permissions, RegisterStandardCallbackParams, @@ -538,5 +539,35 @@ describe("Client", () => { ); } }); + it("Should encode an initializeFrom action", async () => { + const context = new Context(contextParamsLocalChain); + const client = new Client(context); + const params: InitializeFromParams = { + previousVersion: [1, 0, 0], + initData: new Uint8Array([0, 1, 2, 3]), + }; + const action = client.encoding.initializeFromAction( + "0x1234567890123456789012345678901234567890", + params, + ); + expect(typeof action).toBe("object"); + expect(action.data).toBeInstanceOf(Uint8Array); + + const daoInterface = DAO__factory.createInterface(); + const hexString = bytesToHex(action.data); + const argsDecoded = daoInterface.decodeFunctionData( + "initializeFrom", + hexString, + ); + expect(argsDecoded.length).toBe(2); + for (const index in argsDecoded[0]) { + expect(argsDecoded[0][parseInt(index)]).toBe( + params.previousVersion[parseInt(index)], + ); + } + expect(argsDecoded[1]).toBe( + bytesToHex(params.initData as Uint8Array), + ); + }); }); }); diff --git a/modules/client/test/integration/client/methods.test.ts b/modules/client/test/integration/client/methods.test.ts index fef852f5a..4a1bf3aef 100644 --- a/modules/client/test/integration/client/methods.test.ts +++ b/modules/client/test/integration/client/methods.test.ts @@ -417,7 +417,10 @@ describe("Client", () => { daoAddressOrEns: dao, pluginRepo: deployment.multisigRepo.address, installationAbi: INSTALLATION_ABI, - installationParams: [["0x1234567890123456789012345678901234567890"], [true, 1]], + installationParams: [ + ["0x1234567890123456789012345678901234567890"], + [true, 1], + ], }, ); diff --git a/modules/client/test/integration/multisig-client/methods.test.ts b/modules/client/test/integration/multisig-client/methods.test.ts index d596ead7b..c9405ed46 100644 --- a/modules/client/test/integration/multisig-client/methods.test.ts +++ b/modules/client/test/integration/multisig-client/methods.test.ts @@ -417,7 +417,7 @@ describe("Client Multisig", () => { expect(wallets).toMatchObject(members); expect(mockedClient.request).toHaveBeenCalledWith(QueryMultisigMembers, { address: ADDRESS_ONE, - block: { number: 123456 } + block: { number: 123456 }, }); }); diff --git "a/modules/client/test/unit/tokenVoting-client\302\240 /utils.test.ts" "b/modules/client/test/unit/tokenVoting-client\302\240 /utils.test.ts" index 94d378e9c..17f75f006 100644 --- "a/modules/client/test/unit/tokenVoting-client\302\240 /utils.test.ts" +++ "b/modules/client/test/unit/tokenVoting-client\302\240 /utils.test.ts" @@ -65,14 +65,14 @@ describe("tokenVoting-client utils", () => { }); }); it("should return null", () => { - const token = parseToken({ - // @ts-ignore - __typename: "Other", - id: "0x1234567890123456789012345678901234567890", - name: "TestToken", - symbol: "TT", - }); - expect(token).toEqual(null); + const token = parseToken({ + // @ts-ignore + __typename: "Other", + id: "0x1234567890123456789012345678901234567890", + name: "TestToken", + symbol: "TT", + }); + expect(token).toEqual(null); }); }); describe("computeProposalStatus", () => {