From 15ecee2d0695e93d89f50f79892fd6f6e5e87eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 16:48:53 +0200 Subject: [PATCH 01/25] add isTokenGovernanceCompatible function --- modules/client-common/src/utils.ts | 10 +++ modules/client/package.json | 3 +- .../tokenVoting/internal/client/methods.ts | 66 ++++++++++++++++++- .../src/tokenVoting/internal/constants.ts | 28 ++++++++ .../src/tokenVoting/internal/interfaces.ts | 1 + .../tokenVoting-client/methods.test.ts | 30 +++++++++ modules/common/package.json | 4 +- modules/common/src/utils.ts | 11 ++++ modules/common/test/unit/constants.ts | 21 ++++++ modules/common/test/unit/utils.test.ts | 13 ++++ yarn.lock | 13 ++-- 11 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 modules/common/test/unit/constants.ts create mode 100644 modules/common/test/unit/utils.test.ts diff --git a/modules/client-common/src/utils.ts b/modules/client-common/src/utils.ts index 5a0c9159e..b805c80f7 100644 --- a/modules/client-common/src/utils.ts +++ b/modules/client-common/src/utils.ts @@ -28,6 +28,7 @@ import { ADDITIONAL_NETWORKS, LIVE_CONTRACTS } from "./constants"; import { defaultAbiCoder } from "@ethersproject/abi"; import { isAddress } from "@ethersproject/address"; import { Network } from "@ethersproject/networks"; +import { Zero } from "@ethersproject/constants"; export function findLog( receipt: ContractReceipt, @@ -228,3 +229,12 @@ export function getNetwork(networkish: Networkish): Network { } return network; } + +export function getInterfaceId(iface: Interface): string { + let interfaceId = Zero; + const functions: string[] = Object.keys(iface.functions); + for (let i = 0; i < functions.length; i++) { + interfaceId = interfaceId.xor(iface.getSighash(functions[i])); + } + return interfaceId.toHexString(); +} diff --git a/modules/client/package.json b/modules/client/package.json index 788bdaf60..e30e897cf 100644 --- a/modules/client/package.json +++ b/modules/client/package.json @@ -71,7 +71,8 @@ "@ethersproject/contracts": "^5.5.0", "@ethersproject/providers": "^5.5.0", "@ethersproject/wallet": "^5.6.0", - "@openzeppelin/contracts": "^4.9.2", + "@openzeppelin/contracts": "^4.8.1", + "@openzeppelin/contracts-upgradeable": "^4.8.1", "graphql": "^16.5.0", "graphql-request": "^4.3.0" }, diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index 0919319ab..372cddc7d 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -97,7 +97,16 @@ import { UNAVAILABLE_PROPOSAL_METADATA, UNSUPPORTED_PROPOSAL_METADATA_LINK, } from "@aragon/sdk-client-common"; -import { INSTALLATION_ABI } from "../constants"; +import { + GOVERNANCE_INTERFACES_SUPPORTED, + INSTALLATION_ABI, + TOKEN_INTERFACES_REQUIRED, + // SUPPORTED_GOVERNANCE_TOKEN_INTERFACES, +} from "../constants"; +// import { abi as ERC20_VOTES_ABI } from "@openzeppelin/contracts/build/contracts/ERC20Votes.json"; +import { abi as ERC165_ABI } from "@openzeppelin/contracts/build/contracts/ERC165.json"; +import { Contract } from "@ethersproject/contracts"; + /** * Methods module the SDK TokenVoting Client */ @@ -740,4 +749,59 @@ export class TokenVotingClientMethods extends ClientCore } return null; } + + /** + *Check valid address + chck if its a contract, if not return message + if is contract, check if it supports ERC165 + if erc165 is true, + - check if ERC20 or ERCUpgradeable + CHECK: + IVotes or + IVotesUpgradeable or + GovernaceErc20 or + GovernaceWrappedErc20 or + * + * @param {string} tokenAddress + * @return {*} {Promise} + * @memberof TokenVotingClientMethods + */ + public async isTokenGovernanceCompatible( + tokenAddress: string, + ): Promise { + const signer = this.web3.getConnectedSigner(); + if(!isAddress(tokenAddress)) { + throw new InvalidAddressError(); + } + const provider = this.web3.getProvider(); + if (await provider.getCode(tokenAddress) === "0x") { + throw new Error("not a contract"); + } + const contract = new Contract( + tokenAddress, + ERC165_ABI, + signer, + ); + // TODO: check if is a contract + try { + for (const iface of TOKEN_INTERFACES_REQUIRED) { + const isSupported = await contract.supportsInterface(iface); + if (!isSupported) { + // TODO: throw a custom error + throw new Error(); + } + } + for (const iface of GOVERNANCE_INTERFACES_SUPPORTED) { + const isSupported = await contract.supportsInterface(iface); + if (isSupported) { + return true; + } + } + // TODO: throw a custom error + throw new Error(); + } catch { + // if it thorws, means it does not impolement The ERC165 interface + throw new Error(); + } + } } diff --git a/modules/client/src/tokenVoting/internal/constants.ts b/modules/client/src/tokenVoting/internal/constants.ts index 5ac68561a..ebff47ac2 100644 --- a/modules/client/src/tokenVoting/internal/constants.ts +++ b/modules/client/src/tokenVoting/internal/constants.ts @@ -1,8 +1,15 @@ import { IERC20MintableUpgradeable__factory, + IGovernanceWrappedERC20__factory, MajorityVotingBase__factory, } from "@aragon/osx-ethers"; +import { getInterfaceId } from "@aragon/sdk-common"; import { MetadataAbiInput } from "@aragon/sdk-client-common"; +import { abi as IVOTES_ABI } from "@openzeppelin/contracts/build/contracts/IVotes.json"; +import { abi as IVOTES_UPGRADEABLE_ABI } from "@openzeppelin/contracts-upgradeable/build/contracts/IVotesUpgradeable.json"; +import { abi as ERC165_ABI } from "@openzeppelin/contracts/build/contracts/ERC165.json"; +import { Interface } from "@ethersproject/abi"; + export const AVAILABLE_FUNCTION_SIGNATURES: string[] = [ MajorityVotingBase__factory.createInterface().getFunction( "updateVotingSettings", @@ -107,3 +114,24 @@ export const INSTALLATION_ABI: MetadataAbiInput[] = [ "The token mint settings struct containing the `receivers` and `amounts`.", }, ]; + +export const ERC20_FUNCTIONS = [ + "function totalSupply() public view returns (uint256)", + "function balanceOf(address _owner) public view returns (uint256 balance)", + "function transfer(address _to, uint256 _value) public returns (bool success)", + "function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)", + "function approve(address _spender, uint256 _value) public returns (bool success)", + "function allowance(address _owner, address _spender) public view returns (uint256 remaining)", +]; + +export const TOKEN_INTERFACES_REQUIRED = [ + getInterfaceId(new Interface(ERC165_ABI)), + getInterfaceId(new Interface(ERC20_FUNCTIONS)), +]; + +export const GOVERNANCE_INTERFACES_SUPPORTED = [ + getInterfaceId(new Interface(IVOTES_UPGRADEABLE_ABI)), + getInterfaceId(new Interface(IVOTES_ABI)), + getInterfaceId(IERC20MintableUpgradeable__factory.createInterface()), + getInterfaceId(IGovernanceWrappedERC20__factory.createInterface()), +]; diff --git a/modules/client/src/tokenVoting/internal/interfaces.ts b/modules/client/src/tokenVoting/internal/interfaces.ts index 4c8446629..dd3e52b16 100644 --- a/modules/client/src/tokenVoting/internal/interfaces.ts +++ b/modules/client/src/tokenVoting/internal/interfaces.ts @@ -80,6 +80,7 @@ export interface ITokenVotingClientMethods { tokenAddress: string, ) => AsyncGenerator; getDelegatee: (tokenAddress: string) => Promise; + isTokenGovernanceCompatible: (tokenAddress: string) => Promise; } export interface ITokenVotingClientEncoding { diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index d72a7c5ba..25dee3f43 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -1426,6 +1426,36 @@ describe("Token Voting Client", () => { const token = await client.methods.getToken(pluginAddress); expect(token).toBe(null); }); + + it("Should check if a ERC20 is compatible with governance and return false", async () => { + const ctx = new Context(contextParamsLocalChain); + const client = new TokenVotingClient(ctx); + const erc20Token = await deployErc20(); + expect(() => + client.methods.isTokenGovernanceCompatible( + erc20Token.address, + ) + ).rejects.toThrow(); + }); + it("Should check if ERC721 is compatible with governance and return false", async () => { + const ctx = new Context(contextParamsLocalChain); + const client = new TokenVotingClient(ctx); + const erc721Token = await deployErc721(); + expect(() => + client.methods.isTokenGovernanceCompatible( + erc721Token.address, + ) + ).rejects.toThrow(); + }); + it("Should check if GovernanceERC20 is compatible with governance and return true", async () => { + const ctx = new Context(contextParamsLocalChain); + const client = new TokenVotingClient(ctx); + const dao = await buildTokenVotingDAO(repoAddr, VotingMode.STANDARD); + const isCompatible = await client.methods.isTokenGovernanceCompatible( + dao.tokenAddress, + ); + expect(isCompatible).toBe(true); + }); }); }); }); diff --git a/modules/common/package.json b/modules/common/package.json index 616f101ad..5ed2ab0ba 100644 --- a/modules/common/package.json +++ b/modules/common/package.json @@ -52,7 +52,9 @@ "size-limit": "^7.0.8", "tsdx": "^0.14.1", "tslib": "^2.3.1", - "typescript": "^4.6.2" + "typescript": "^4.6.2", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/abi": "^5.7.0" }, "dependencies": {} } \ No newline at end of file diff --git a/modules/common/src/utils.ts b/modules/common/src/utils.ts index a2f4bca8f..db0f003e2 100644 --- a/modules/common/src/utils.ts +++ b/modules/common/src/utils.ts @@ -1,4 +1,15 @@ +import { Interface } from '@ethersproject/abi'; +import { Zero } from '@ethersproject/constants'; + export function isProposalId(propoosalId: string): boolean { const regex = new RegExp(/^0x[A-Fa-f0-9]{40}_0x[A-Fa-f0-9]{1,64}$/i); return regex.test(propoosalId); } +export function getInterfaceId(iface: Interface): string { + let interfaceId = Zero; + const functions: string[] = Object.keys(iface.functions); + for (let i = 0; i < functions.length; i++) { + interfaceId = interfaceId.xor(iface.getSighash(functions[i])); + } + return interfaceId.toHexString(); +} diff --git a/modules/common/test/unit/constants.ts b/modules/common/test/unit/constants.ts new file mode 100644 index 000000000..6bca6b4e6 --- /dev/null +++ b/modules/common/test/unit/constants.ts @@ -0,0 +1,21 @@ +export const ERC165_ABI = [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4", + }, + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool", + }, + ], + "stateMutability": "view", + "type": "function", + }, +]; diff --git a/modules/common/test/unit/utils.test.ts b/modules/common/test/unit/utils.test.ts new file mode 100644 index 000000000..c816c225d --- /dev/null +++ b/modules/common/test/unit/utils.test.ts @@ -0,0 +1,13 @@ +import { getInterfaceId } from "../../src/utils"; +import { ERC165_ABI } from "./constants"; +import { Interface } from "@ethersproject/abi"; + +describe("Utils", () => { + describe("getInterfaceId", () => { + it("should return the interface id for an ERC165 contract", () => { + const result = getInterfaceId(new Interface(ERC165_ABI)); + // defined here: https://eips.ethereum.org/EIPS/eip-165 + expect(result).toEqual("0x36372b07"); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 710b700e1..131e23b84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1731,15 +1731,20 @@ ethers "^4.0.0-beta.1" source-map-support "^0.5.19" +"@openzeppelin/contracts-upgradeable@^4.8.1": + version "4.9.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.3.tgz#ff17a80fb945f5102571f8efecb5ce5915cc4811" + integrity sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A== + "@openzeppelin/contracts@^4.1.0": version "4.8.1" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.8.1.tgz#709cfc4bbb3ca9f4460d60101f15dac6b7a2d5e4" integrity sha512-xQ6eUZl+RDyb/FiZe1h+U7qr/f4p/SrTSQcTPH2bjur3C5DbuW/zFgCU/b1P/xcIaEqJep+9ju4xDRi3rmChdQ== -"@openzeppelin/contracts@^4.9.2": - version "4.9.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.2.tgz#1cb2d5e4d3360141a17dbc45094a8cad6aac16c1" - integrity sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg== +"@openzeppelin/contracts@^4.8.1": + version "4.9.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364" + integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg== "@rollup/plugin-babel@^5.1.0": version "5.3.1" From 284b6a88fe74a76d64be9c24d54e7f6a65fd353c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 17:01:04 +0200 Subject: [PATCH 02/25] add custom errors --- modules/client/CHANGELOG.md | 5 ++- .../tokenVoting/internal/client/methods.ts | 40 ++++++++----------- .../src/tokenVoting/internal/constants.ts | 10 +++-- .../tokenVoting-client/methods.test.ts | 10 +++-- modules/common/CHANGELOG.md | 4 +- modules/common/src/errors.ts | 33 +++++++++++++++ 6 files changed, 68 insertions(+), 34 deletions(-) diff --git a/modules/client/CHANGELOG.md b/modules/client/CHANGELOG.md index 224aecd29..08812312f 100644 --- a/modules/client/CHANGELOG.md +++ b/modules/client/CHANGELOG.md @@ -21,10 +21,11 @@ TEMPLATE: - Block param on `getVotingSettings` and `getMembers` functions to allow for historical data - Support for local chains - Support for ERC1155 deposits and withdrawals -## 1.12.0-rc1 +- `isTokenGovernanceCompatible` function +## [1.12.0-rc1] ### Added - Support for baseMainnet network -## 1.11.0-rc1 +## [1.11.0-rc1] ### Added - Added `initializeFrom` encoders and decoders - Support for ERC721 deposits and withdrawals diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index 372cddc7d..8f71e7409 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -98,6 +98,8 @@ import { UNSUPPORTED_PROPOSAL_METADATA_LINK, } from "@aragon/sdk-client-common"; import { + ERC165_INTERFACE_ID, + ERC20_INTERFACE_ID, GOVERNANCE_INTERFACES_SUPPORTED, INSTALLATION_ABI, TOKEN_INTERFACES_REQUIRED, @@ -106,6 +108,10 @@ import { // import { abi as ERC20_VOTES_ABI } from "@openzeppelin/contracts/build/contracts/ERC20Votes.json"; import { abi as ERC165_ABI } from "@openzeppelin/contracts/build/contracts/ERC165.json"; import { Contract } from "@ethersproject/contracts"; +import { ERC165NotSupportedError } from "@aragon/sdk-common"; +import { ERC20NotSupportedError } from "@aragon/sdk-common"; +import { GoveranceNotSupportedError } from "@aragon/sdk-common"; +import { NotAContractError } from "@aragon/sdk-common"; /** * Methods module the SDK TokenVoting Client @@ -751,16 +757,7 @@ export class TokenVotingClientMethods extends ClientCore } /** - *Check valid address - chck if its a contract, if not return message - if is contract, check if it supports ERC165 - if erc165 is true, - - check if ERC20 or ERCUpgradeable - CHECK: - IVotes or - IVotesUpgradeable or - GovernaceErc20 or - GovernaceWrappedErc20 or + * Checks if the given token is compatible with the TokenVoting plugin * * @param {string} tokenAddress * @return {*} {Promise} @@ -770,26 +767,25 @@ export class TokenVotingClientMethods extends ClientCore tokenAddress: string, ): Promise { const signer = this.web3.getConnectedSigner(); - if(!isAddress(tokenAddress)) { + if (!isAddress(tokenAddress)) { throw new InvalidAddressError(); } const provider = this.web3.getProvider(); if (await provider.getCode(tokenAddress) === "0x") { - throw new Error("not a contract"); + throw new NotAContractError(); } const contract = new Contract( tokenAddress, ERC165_ABI, signer, ); - // TODO: check if is a contract + // TODO: check if is a contract try { - for (const iface of TOKEN_INTERFACES_REQUIRED) { - const isSupported = await contract.supportsInterface(iface); - if (!isSupported) { - // TODO: throw a custom error - throw new Error(); - } + if (!await contract.supportsInterface(ERC165_INTERFACE_ID)) { + throw new ERC165NotSupportedError(); + } + if (!await contract.supportsInterface(ERC20_INTERFACE_ID)) { + throw new ERC20NotSupportedError(); } for (const iface of GOVERNANCE_INTERFACES_SUPPORTED) { const isSupported = await contract.supportsInterface(iface); @@ -797,11 +793,9 @@ export class TokenVotingClientMethods extends ClientCore return true; } } - // TODO: throw a custom error - throw new Error(); + throw new GoveranceNotSupportedError(); } catch { - // if it thorws, means it does not impolement The ERC165 interface - throw new Error(); + throw new ERC165NotSupportedError(); } } } diff --git a/modules/client/src/tokenVoting/internal/constants.ts b/modules/client/src/tokenVoting/internal/constants.ts index ebff47ac2..921cd1e88 100644 --- a/modules/client/src/tokenVoting/internal/constants.ts +++ b/modules/client/src/tokenVoting/internal/constants.ts @@ -124,10 +124,12 @@ export const ERC20_FUNCTIONS = [ "function allowance(address _owner, address _spender) public view returns (uint256 remaining)", ]; -export const TOKEN_INTERFACES_REQUIRED = [ - getInterfaceId(new Interface(ERC165_ABI)), - getInterfaceId(new Interface(ERC20_FUNCTIONS)), -]; +export const ERC20_INTERFACE_ID = getInterfaceId( + new Interface(ERC20_FUNCTIONS), +); +export const ERC165_INTERFACE_ID = getInterfaceId( + new Interface(ERC165_ABI), +); export const GOVERNANCE_INTERFACES_SUPPORTED = [ getInterfaceId(new Interface(IVOTES_UPGRADEABLE_ABI)), diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index 25dee3f43..49ba1233c 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -31,6 +31,8 @@ import * as ganacheSetup from "../../helpers/ganache-setup"; import * as deployContracts from "../../helpers/deployContracts"; import { + ERC165NotSupportedError, + ERC20NotSupportedError, getExtendedProposalId, InvalidAddressOrEnsError, } from "@aragon/sdk-common"; @@ -1427,7 +1429,7 @@ describe("Token Voting Client", () => { expect(token).toBe(null); }); - it("Should check if a ERC20 is compatible with governance and return false", async () => { + it("Should check if a ERC20 is compatible with governance and throw", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const erc20Token = await deployErc20(); @@ -1435,9 +1437,9 @@ describe("Token Voting Client", () => { client.methods.isTokenGovernanceCompatible( erc20Token.address, ) - ).rejects.toThrow(); + ).rejects.toThrow(new ERC165NotSupportedError()); }); - it("Should check if ERC721 is compatible with governance and return false", async () => { + it("Should check if ERC721 is compatible with governance and throw", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const erc721Token = await deployErc721(); @@ -1445,7 +1447,7 @@ describe("Token Voting Client", () => { client.methods.isTokenGovernanceCompatible( erc721Token.address, ) - ).rejects.toThrow(); + ).rejects.toThrow(new ERC20NotSupportedError()); }); it("Should check if GovernanceERC20 is compatible with governance and return true", async () => { const ctx = new Context(contextParamsLocalChain); diff --git a/modules/common/CHANGELOG.md b/modules/common/CHANGELOG.md index 21844cf1e..7ac3ef77d 100644 --- a/modules/common/CHANGELOG.md +++ b/modules/common/CHANGELOG.md @@ -17,7 +17,9 @@ TEMPLATE: --> ## [UPCOMING] - +### Added +- New error classes +- `getInterfaceId` function ## 1.5.0 ### Added - New error classes `SizeMismatchError`, `InvalidProposalStatusError`, `NotImplementedError`, `InvalidActionError`, `InvalidSubdomainError`, `InvalidGasEstimationFactorError` and `UseTransferError` diff --git a/modules/common/src/errors.ts b/modules/common/src/errors.ts index 689b7f558..50d12fb0c 100644 --- a/modules/common/src/errors.ts +++ b/modules/common/src/errors.ts @@ -276,3 +276,36 @@ export class InvalidParameter extends SdkError { ); } } +export class NotAContractError extends SdkError { + constructor(cause?: Error) { + super( + "The provided address does not point to a contract or the contract is not deployed", + cause, + ); + } +} + +export class ERC165NotSupportedError extends SdkError { + constructor(cause?: Error) { + super( + "ERC165 is not supported by the contract at the provided address", + cause, + ); + } +} +export class ERC20NotSupportedError extends SdkError { + constructor(cause?: Error) { + super( + "ERC20 is not supported by the contract at the provided address", + cause, + ); + } +} +export class GoveranceNotSupportedError extends SdkError { + constructor(cause?: Error) { + super( + "The contract at the provided address does not support governance", + cause, + ); + } +} From 2fceb13f93a89820c7b420d83be6950fb4edc327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 17:03:38 +0200 Subject: [PATCH 03/25] update docs --- .../20-is-governance-token-compatible.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts diff --git a/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts b/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts new file mode 100644 index 000000000..68262df7e --- /dev/null +++ b/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts @@ -0,0 +1,32 @@ +/* MARKDOWN +--- +title: Is governance token compatible +--- + +## Check if a token is compatible with the TokenVoting Plugin as an underlying token + +Check if a token is compatible with the TokenVoting Plugin as an underlying token. This means that the token is ERC20 and ERC165 compliant and has the required methods for the TokenVoting Plugin to work. +*/ + +import { TokenVotingClient } from "@aragon/sdk-client"; +import { context } from "../index"; + +// Instantiate the general purpose client from the Aragon OSx SDK context. + +// Create a TokenVoting client. +const tokenVotingClient: TokenVotingClient = new TokenVotingClient( + context, +); + +const tokenAddress = "0x1234567890123456789012345678901234567890"; // token contract adddress + +const delegatee = tokenVotingClient.methods.isTokenGovernanceCompatible(tokenAddress); + +console.log(delegatee); + +/* MARKDOWN + Returns: + ```ts + true // throw if the token is not compatible + ``` + */ From fd3c89a27d6f38f060375b0d3bfabec935048309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 17:07:20 +0200 Subject: [PATCH 04/25] fix code smells --- modules/client-common/src/utils.ts | 10 ---------- .../client/src/tokenVoting/internal/client/methods.ts | 11 ++++------- modules/common/src/utils.ts | 4 ++-- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/modules/client-common/src/utils.ts b/modules/client-common/src/utils.ts index b805c80f7..5a0c9159e 100644 --- a/modules/client-common/src/utils.ts +++ b/modules/client-common/src/utils.ts @@ -28,7 +28,6 @@ import { ADDITIONAL_NETWORKS, LIVE_CONTRACTS } from "./constants"; import { defaultAbiCoder } from "@ethersproject/abi"; import { isAddress } from "@ethersproject/address"; import { Network } from "@ethersproject/networks"; -import { Zero } from "@ethersproject/constants"; export function findLog( receipt: ContractReceipt, @@ -229,12 +228,3 @@ export function getNetwork(networkish: Networkish): Network { } return network; } - -export function getInterfaceId(iface: Interface): string { - let interfaceId = Zero; - const functions: string[] = Object.keys(iface.functions); - for (let i = 0; i < functions.length; i++) { - interfaceId = interfaceId.xor(iface.getSighash(functions[i])); - } - return interfaceId.toHexString(); -} diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index 8f71e7409..600032117 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -4,7 +4,10 @@ import { decodeProposalId, decodeRatio, encodeProposalId, + ERC165NotSupportedError, + ERC20NotSupportedError, getExtendedProposalId, + GoveranceNotSupportedError, InvalidAddressError, InvalidAddressOrEnsError, InvalidCidError, @@ -12,6 +15,7 @@ import { IpfsPinError, isProposalId, NoProviderError, + NotAContractError, promiseWithTimeout, ProposalCreationError, resolveIpfsCid, @@ -102,16 +106,9 @@ import { ERC20_INTERFACE_ID, GOVERNANCE_INTERFACES_SUPPORTED, INSTALLATION_ABI, - TOKEN_INTERFACES_REQUIRED, - // SUPPORTED_GOVERNANCE_TOKEN_INTERFACES, } from "../constants"; -// import { abi as ERC20_VOTES_ABI } from "@openzeppelin/contracts/build/contracts/ERC20Votes.json"; import { abi as ERC165_ABI } from "@openzeppelin/contracts/build/contracts/ERC165.json"; import { Contract } from "@ethersproject/contracts"; -import { ERC165NotSupportedError } from "@aragon/sdk-common"; -import { ERC20NotSupportedError } from "@aragon/sdk-common"; -import { GoveranceNotSupportedError } from "@aragon/sdk-common"; -import { NotAContractError } from "@aragon/sdk-common"; /** * Methods module the SDK TokenVoting Client diff --git a/modules/common/src/utils.ts b/modules/common/src/utils.ts index db0f003e2..60a0c24a3 100644 --- a/modules/common/src/utils.ts +++ b/modules/common/src/utils.ts @@ -8,8 +8,8 @@ export function isProposalId(propoosalId: string): boolean { export function getInterfaceId(iface: Interface): string { let interfaceId = Zero; const functions: string[] = Object.keys(iface.functions); - for (let i = 0; i < functions.length; i++) { - interfaceId = interfaceId.xor(iface.getSighash(functions[i])); + for (const func of functions) { + interfaceId = interfaceId.xor(iface.getSighash(func)); } return interfaceId.toHexString(); } From 6a84475b13ad7d01195f5faa0d93ebe272de9b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 17:09:07 +0200 Subject: [PATCH 05/25] remove todo --- modules/client/src/tokenVoting/internal/client/methods.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index 600032117..fd9773835 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -776,7 +776,6 @@ export class TokenVotingClientMethods extends ClientCore ERC165_ABI, signer, ); - // TODO: check if is a contract try { if (!await contract.supportsInterface(ERC165_INTERFACE_ID)) { throw new ERC165NotSupportedError(); From f2f7fa399d69c55795eeb24705ca9c28886d02b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 21:23:14 +0200 Subject: [PATCH 06/25] add missing impoort in tests --- .../client/test/integration/tokenVoting-client/methods.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index 49ba1233c..5e318ecb7 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -76,6 +76,7 @@ import { SubgraphTokenVotingProposalListItem, } from "../../../src/tokenVoting/internal/types"; import { deployErc20 } from "../../helpers/deploy-erc20"; +import { deployErc721 } from "../../helpers/deploy-erc721"; import { GovernanceERC20__factory, GovernanceWrappedERC20__factory, From bfc47ab877535f13aa337b2f42e1240bcfdad0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 22:02:22 +0200 Subject: [PATCH 07/25] fix tests --- modules/client/src/tokenVoting/internal/client/methods.ts | 8 +++++++- .../test/integration/tokenVoting-client/methods.test.ts | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index fd9773835..808a71178 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -790,7 +790,13 @@ export class TokenVotingClientMethods extends ClientCore } } throw new GoveranceNotSupportedError(); - } catch { + } catch (e) { + if ( + e instanceof GoveranceNotSupportedError || + e instanceof ERC20NotSupportedError + ) { + throw e; + } throw new ERC165NotSupportedError(); } } diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index 5e318ecb7..91f54bc4e 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -1438,7 +1438,7 @@ describe("Token Voting Client", () => { client.methods.isTokenGovernanceCompatible( erc20Token.address, ) - ).rejects.toThrow(new ERC165NotSupportedError()); + ).rejects.toThrow(ERC165NotSupportedError) }); it("Should check if ERC721 is compatible with governance and throw", async () => { const ctx = new Context(contextParamsLocalChain); @@ -1448,7 +1448,7 @@ describe("Token Voting Client", () => { client.methods.isTokenGovernanceCompatible( erc721Token.address, ) - ).rejects.toThrow(new ERC20NotSupportedError()); + ).rejects.toThrow(ERC20NotSupportedError); }); it("Should check if GovernanceERC20 is compatible with governance and return true", async () => { const ctx = new Context(contextParamsLocalChain); From 6e1604614bbd57e0e5752af4b16b5169fecf2767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Mon, 14 Aug 2023 22:11:44 +0200 Subject: [PATCH 08/25] add tests --- .../tokenVoting/internal/client/methods.ts | 2 ++ .../tokenVoting-client/methods.test.ts | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index 808a71178..28e7ca5e7 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -764,10 +764,12 @@ export class TokenVotingClientMethods extends ClientCore tokenAddress: string, ): Promise { const signer = this.web3.getConnectedSigner(); + // check if is address if (!isAddress(tokenAddress)) { throw new InvalidAddressError(); } const provider = this.web3.getProvider(); + // check if is a contract if (await provider.getCode(tokenAddress) === "0x") { throw new NotAContractError(); } diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index 91f54bc4e..9304678fe 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -34,7 +34,9 @@ import { ERC165NotSupportedError, ERC20NotSupportedError, getExtendedProposalId, + InvalidAddressError, InvalidAddressOrEnsError, + NotAContractError, } from "@aragon/sdk-common"; import { ADDRESS_FOUR, @@ -1450,6 +1452,24 @@ describe("Token Voting Client", () => { ) ).rejects.toThrow(ERC20NotSupportedError); }); + it("Should be called with an invalid address and throw", async () => { + const ctx = new Context(contextParamsLocalChain); + const client = new TokenVotingClient(ctx); + expect(() => + client.methods.isTokenGovernanceCompatible( + "0x123", + ) + ).rejects.toThrow(InvalidAddressError); + }); + it("Should be called with wallet invalid address and throw", async () => { + const ctx = new Context(contextParamsLocalChain); + const client = new TokenVotingClient(ctx); + expect(() => + client.methods.isTokenGovernanceCompatible( + TEST_WALLET_ADDRESS, + ) + ).rejects.toThrow(NotAContractError); + }); it("Should check if GovernanceERC20 is compatible with governance and return true", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); From e3f30b36d709bc4abc5b7a9128f0a803f8ae5b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Tue, 15 Aug 2023 01:17:31 +0200 Subject: [PATCH 09/25] fix tests --- modules/common/test/unit/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/common/test/unit/utils.test.ts b/modules/common/test/unit/utils.test.ts index c816c225d..0c3f41c16 100644 --- a/modules/common/test/unit/utils.test.ts +++ b/modules/common/test/unit/utils.test.ts @@ -7,7 +7,7 @@ describe("Utils", () => { it("should return the interface id for an ERC165 contract", () => { const result = getInterfaceId(new Interface(ERC165_ABI)); // defined here: https://eips.ethereum.org/EIPS/eip-165 - expect(result).toEqual("0x36372b07"); + expect(result).toEqual("0x01ffc9a7"); }); }); }); From 39c16e59f5ed12fa44e882592fc405985c204d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Wed, 16 Aug 2023 16:26:29 +0200 Subject: [PATCH 10/25] fix comments --- .../tokenVoting/internal/client/methods.ts | 36 ++++++++----------- .../src/tokenVoting/internal/interfaces.ts | 3 +- .../client/src/tokenVoting/internal/types.ts | 6 ++++ .../client/src/tokenVoting/internal/utils.ts | 29 +++++++++++++-- modules/common/src/errors.ts | 24 ------------- 5 files changed, 50 insertions(+), 48 deletions(-) diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index 28e7ca5e7..ecf1488ac 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -4,10 +4,7 @@ import { decodeProposalId, decodeRatio, encodeProposalId, - ERC165NotSupportedError, - ERC20NotSupportedError, getExtendedProposalId, - GoveranceNotSupportedError, InvalidAddressError, InvalidAddressOrEnsError, InvalidCidError, @@ -64,6 +61,7 @@ import { SubgraphTokenVotingMember, SubgraphTokenVotingProposal, SubgraphTokenVotingProposalListItem, + TokenVotingTokenCompatibility, } from "../types"; import { QueryTokenVotingMembers, @@ -74,6 +72,7 @@ import { } from "../graphql-queries"; import { computeProposalStatusFilter, + isERC20Token, tokenVotingInitParamsToContract, toTokenVotingMember, toTokenVotingProposal, @@ -103,12 +102,12 @@ import { } from "@aragon/sdk-client-common"; import { ERC165_INTERFACE_ID, - ERC20_INTERFACE_ID, GOVERNANCE_INTERFACES_SUPPORTED, INSTALLATION_ABI, } from "../constants"; import { abi as ERC165_ABI } from "@openzeppelin/contracts/build/contracts/ERC165.json"; import { Contract } from "@ethersproject/contracts"; +import { AddressZero } from "@ethersproject/constants"; /** * Methods module the SDK TokenVoting Client @@ -757,15 +756,15 @@ export class TokenVotingClientMethods extends ClientCore * Checks if the given token is compatible with the TokenVoting plugin * * @param {string} tokenAddress - * @return {*} {Promise} + * @return {*} {Promise} * @memberof TokenVotingClientMethods */ - public async isTokenGovernanceCompatible( + public async isTokenVotingCompatibleToken( tokenAddress: string, - ): Promise { + ): Promise { const signer = this.web3.getConnectedSigner(); // check if is address - if (!isAddress(tokenAddress)) { + if (!isAddress(tokenAddress) || tokenAddress === AddressZero) { throw new InvalidAddressError(); } const provider = this.web3.getProvider(); @@ -778,28 +777,23 @@ export class TokenVotingClientMethods extends ClientCore ERC165_ABI, signer, ); + + if (!isERC20Token(tokenAddress, signer)) { + return TokenVotingTokenCompatibility.INCOMPATIBLE; + } try { if (!await contract.supportsInterface(ERC165_INTERFACE_ID)) { - throw new ERC165NotSupportedError(); - } - if (!await contract.supportsInterface(ERC20_INTERFACE_ID)) { - throw new ERC20NotSupportedError(); + return TokenVotingTokenCompatibility.NEEDS_WRAP; } for (const iface of GOVERNANCE_INTERFACES_SUPPORTED) { const isSupported = await contract.supportsInterface(iface); if (isSupported) { - return true; + return TokenVotingTokenCompatibility.COMPATIBLE; } } - throw new GoveranceNotSupportedError(); + return TokenVotingTokenCompatibility.NEEDS_WRAP; } catch (e) { - if ( - e instanceof GoveranceNotSupportedError || - e instanceof ERC20NotSupportedError - ) { - throw e; - } - throw new ERC165NotSupportedError(); + return TokenVotingTokenCompatibility.NEEDS_WRAP; } } } diff --git a/modules/client/src/tokenVoting/internal/interfaces.ts b/modules/client/src/tokenVoting/internal/interfaces.ts index dd3e52b16..367b6a28c 100644 --- a/modules/client/src/tokenVoting/internal/interfaces.ts +++ b/modules/client/src/tokenVoting/internal/interfaces.ts @@ -33,6 +33,7 @@ import { WrapTokensParams, WrapTokensStepValue, } from "../types"; +import { TokenVotingTokenCompatibility } from "./types"; // TokenVoting @@ -80,7 +81,7 @@ export interface ITokenVotingClientMethods { tokenAddress: string, ) => AsyncGenerator; getDelegatee: (tokenAddress: string) => Promise; - isTokenGovernanceCompatible: (tokenAddress: string) => Promise; + isTokenVotingCompatibleToken: (tokenAddress: string) => Promise; } export interface ITokenVotingClientEncoding { diff --git a/modules/client/src/tokenVoting/internal/types.ts b/modules/client/src/tokenVoting/internal/types.ts index 6fd760eb7..4ababf6f3 100644 --- a/modules/client/src/tokenVoting/internal/types.ts +++ b/modules/client/src/tokenVoting/internal/types.ts @@ -90,3 +90,9 @@ export type SubgraphTokenVotingMember = { balance: string; }[]; }; + +export enum TokenVotingTokenCompatibility { + COMPATIBLE = "compatible", + NEEDS_WRAP = "needsWrap", + INCOMPATIBLE = "incompatible", +} diff --git a/modules/client/src/tokenVoting/internal/utils.ts b/modules/client/src/tokenVoting/internal/utils.ts index 6a8de5f58..557690a6e 100644 --- a/modules/client/src/tokenVoting/internal/utils.ts +++ b/modules/client/src/tokenVoting/internal/utils.ts @@ -41,6 +41,9 @@ import { ProposalStatus, TokenType, } from "@aragon/sdk-client-common"; +import { Signer } from "@ethersproject/abstract-signer"; +import { Contract } from "@ethersproject/contracts"; +import { abi as ERC_20_ABI } from "@openzeppelin/contracts/build/contracts/ERC20.json"; export function toTokenVotingProposal( proposal: SubgraphTokenVotingProposal, @@ -282,8 +285,6 @@ export function toTokenVotingMember( }; } - - export function computeProposalStatus( proposal: SubgraphTokenVotingProposal | SubgraphTokenVotingProposalListItem, ): ProposalStatus { @@ -335,3 +336,27 @@ export function computeProposalStatusFilter(status: ProposalStatus) { } return where; } + +export async function isERC20Token( + tokenAddress: string, + signer: Signer, +): Promise { + const contract = new Contract( + tokenAddress, + ERC_20_ABI, + signer, + ); + // Check that it has the balanceOf function + try { + await contract.balanceOf(signer.getAddress()); + try { + await contract.metadata.tokenURI(0); + return false; + } catch { + return true; + } + } catch { + return false; + } + // check that is not an ERC721 +} diff --git a/modules/common/src/errors.ts b/modules/common/src/errors.ts index 50d12fb0c..3604e735e 100644 --- a/modules/common/src/errors.ts +++ b/modules/common/src/errors.ts @@ -285,27 +285,3 @@ export class NotAContractError extends SdkError { } } -export class ERC165NotSupportedError extends SdkError { - constructor(cause?: Error) { - super( - "ERC165 is not supported by the contract at the provided address", - cause, - ); - } -} -export class ERC20NotSupportedError extends SdkError { - constructor(cause?: Error) { - super( - "ERC20 is not supported by the contract at the provided address", - cause, - ); - } -} -export class GoveranceNotSupportedError extends SdkError { - constructor(cause?: Error) { - super( - "The contract at the provided address does not support governance", - cause, - ); - } -} From 8718977716543f53b44b540ef58e96da59352764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Wed, 16 Aug 2023 16:31:11 +0200 Subject: [PATCH 11/25] fix example --- .../20-is-governance-token-compatible.ts | 9 ++++++--- modules/client/src/tokenVoting/internal/constants.ts | 12 ------------ 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts b/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts index 68262df7e..8cd1716e2 100644 --- a/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts +++ b/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts @@ -20,13 +20,16 @@ const tokenVotingClient: TokenVotingClient = new TokenVotingClient( const tokenAddress = "0x1234567890123456789012345678901234567890"; // token contract adddress -const delegatee = tokenVotingClient.methods.isTokenGovernanceCompatible(tokenAddress); +const compatibility = tokenVotingClient.methods.isTokenVotingCompatibleToken(tokenAddress); -console.log(delegatee); +console.log(compatibility); /* MARKDOWN Returns: ```ts - true // throw if the token is not compatible + // "compatible" if is erc20 and erc165 + // "needsWrap" if is erc20 and not erc165 or compatible with voting + // "incompatible" if is not erc20 + compatible ``` */ diff --git a/modules/client/src/tokenVoting/internal/constants.ts b/modules/client/src/tokenVoting/internal/constants.ts index 921cd1e88..537db0008 100644 --- a/modules/client/src/tokenVoting/internal/constants.ts +++ b/modules/client/src/tokenVoting/internal/constants.ts @@ -115,18 +115,7 @@ export const INSTALLATION_ABI: MetadataAbiInput[] = [ }, ]; -export const ERC20_FUNCTIONS = [ - "function totalSupply() public view returns (uint256)", - "function balanceOf(address _owner) public view returns (uint256 balance)", - "function transfer(address _to, uint256 _value) public returns (bool success)", - "function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)", - "function approve(address _spender, uint256 _value) public returns (bool success)", - "function allowance(address _owner, address _spender) public view returns (uint256 remaining)", -]; -export const ERC20_INTERFACE_ID = getInterfaceId( - new Interface(ERC20_FUNCTIONS), -); export const ERC165_INTERFACE_ID = getInterfaceId( new Interface(ERC165_ABI), ); @@ -134,6 +123,5 @@ export const ERC165_INTERFACE_ID = getInterfaceId( export const GOVERNANCE_INTERFACES_SUPPORTED = [ getInterfaceId(new Interface(IVOTES_UPGRADEABLE_ABI)), getInterfaceId(new Interface(IVOTES_ABI)), - getInterfaceId(IERC20MintableUpgradeable__factory.createInterface()), getInterfaceId(IGovernanceWrappedERC20__factory.createInterface()), ]; From bc511618864ea437ff17927f5740dee4c582afdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Wed, 16 Aug 2023 16:50:43 +0200 Subject: [PATCH 12/25] update package and subgraph versions --- modules/client-common/package.json | 2 +- modules/client-common/src/constants.ts | 2 +- modules/client/package.json | 6 +++--- modules/common/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/client-common/package.json b/modules/client-common/package.json index b6e9c3bda..9f87689cf 100644 --- a/modules/client-common/package.json +++ b/modules/client-common/package.json @@ -1,7 +1,7 @@ { "name": "@aragon/sdk-client-common", "author": "Aragon Association", - "version": "1.4.0-rc0", + "version": "1.5.0-rc0", "license": "MIT", "main": "dist/index.js", "module": "dist/sdk-client-common.esm.js", diff --git a/modules/client-common/src/constants.ts b/modules/client-common/src/constants.ts index b567302e5..cad707c04 100644 --- a/modules/client-common/src/constants.ts +++ b/modules/client-common/src/constants.ts @@ -50,7 +50,7 @@ export const UNAVAILABLE_PROPOSAL_METADATA: ProposalMetadata = { const getGraphqlNode = (netowrk: SupportedNetwork): string => { return `https://subgraph.satsuma-prod.com/qHR2wGfc5RLi6/aragon/osx-${ SupportedNetworksToGraphqlNetworks[netowrk] - }/version/v1.2.2/api`; + }/version/v1.3.0/api`; }; export const GRAPHQL_NODES: { [K in SupportedNetwork]: { url: string }[] } = { diff --git a/modules/client/package.json b/modules/client/package.json index e30e897cf..937ef01b9 100644 --- a/modules/client/package.json +++ b/modules/client/package.json @@ -1,7 +1,7 @@ { "name": "@aragon/sdk-client", "author": "Aragon Association", - "version": "1.12.0-rc1", + "version": "1.13.0-rc1", "license": "MIT", "main": "dist/index.js", "module": "dist/sdk-client.esm.js", @@ -62,8 +62,8 @@ }, "dependencies": { "@aragon/osx-ethers": "1.3.0-rc0.2", - "@aragon/sdk-client-common": "^1.4.0-rc0", - "@aragon/sdk-common": "^1.5.0", + "@aragon/sdk-client-common": "^1.5.0-rc0", + "@aragon/sdk-common": "^1.6.0", "@aragon/sdk-ipfs": "^1.1.0", "@ethersproject/abstract-signer": "^5.5.0", "@ethersproject/bignumber": "^5.6.0", diff --git a/modules/common/package.json b/modules/common/package.json index 5ed2ab0ba..623f95cc1 100644 --- a/modules/common/package.json +++ b/modules/common/package.json @@ -1,7 +1,7 @@ { "name": "@aragon/sdk-common", "author": "Aragon Association", - "version": "1.5.0", + "version": "1.6.0", "license": "MIT", "main": "dist/index.js", "module": "dist/sdk-common.esm.js", From 768a60721be844c7c6daa8c5dc4b5caf630d99bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Wed, 16 Aug 2023 17:26:47 +0200 Subject: [PATCH 13/25] fix bug from sonar --- modules/client/src/tokenVoting/internal/client/methods.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index ecf1488ac..e865247c1 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -778,7 +778,7 @@ export class TokenVotingClientMethods extends ClientCore signer, ); - if (!isERC20Token(tokenAddress, signer)) { + if (!await isERC20Token(tokenAddress, signer)) { return TokenVotingTokenCompatibility.INCOMPATIBLE; } try { From 97868aa8c7599f31138796a98e4d803038b4a843 Mon Sep 17 00:00:00 2001 From: josemarinas <36479864+josemarinas@users.noreply.github.com> Date: Thu, 17 Aug 2023 01:21:14 +0200 Subject: [PATCH 14/25] Update modules/client/CHANGELOG.md Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> --- modules/client/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client/CHANGELOG.md b/modules/client/CHANGELOG.md index 08812312f..c5d2de411 100644 --- a/modules/client/CHANGELOG.md +++ b/modules/client/CHANGELOG.md @@ -21,7 +21,7 @@ TEMPLATE: - Block param on `getVotingSettings` and `getMembers` functions to allow for historical data - Support for local chains - Support for ERC1155 deposits and withdrawals -- `isTokenGovernanceCompatible` function +- `isTokenVotingCompatibleToken` function ## [1.12.0-rc1] ### Added - Support for baseMainnet network From 7f661965381a56363f7895334a7e151a4b31f559 Mon Sep 17 00:00:00 2001 From: josemarinas <36479864+josemarinas@users.noreply.github.com> Date: Thu, 17 Aug 2023 01:21:25 +0200 Subject: [PATCH 15/25] Update modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> --- .../03-tokenVoting-client/20-is-governance-token-compatible.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts b/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts index 8cd1716e2..f8ca72894 100644 --- a/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts +++ b/modules/client/examples/03-tokenVoting-client/20-is-governance-token-compatible.ts @@ -1,6 +1,6 @@ /* MARKDOWN --- -title: Is governance token compatible +title: Is TokenVoting compatible token --- ## Check if a token is compatible with the TokenVoting Plugin as an underlying token From 695c27a00f26208ecff967509f7dd58e1c0f62b7 Mon Sep 17 00:00:00 2001 From: josemarinas <36479864+josemarinas@users.noreply.github.com> Date: Thu, 17 Aug 2023 01:21:38 +0200 Subject: [PATCH 16/25] Update modules/client/src/tokenVoting/internal/types.ts Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> --- modules/client/src/tokenVoting/internal/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client/src/tokenVoting/internal/types.ts b/modules/client/src/tokenVoting/internal/types.ts index 4ababf6f3..572afd787 100644 --- a/modules/client/src/tokenVoting/internal/types.ts +++ b/modules/client/src/tokenVoting/internal/types.ts @@ -93,6 +93,6 @@ export type SubgraphTokenVotingMember = { export enum TokenVotingTokenCompatibility { COMPATIBLE = "compatible", - NEEDS_WRAP = "needsWrap", + NEEDS_WRAPPING = "needsWrapping", INCOMPATIBLE = "incompatible", } From f5f9be1f9965e0c3d14e51ee587c837dd86c11ba Mon Sep 17 00:00:00 2001 From: josemarinas <36479864+josemarinas@users.noreply.github.com> Date: Thu, 17 Aug 2023 01:22:14 +0200 Subject: [PATCH 17/25] Update modules/common/src/errors.ts Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> --- modules/common/src/errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/common/src/errors.ts b/modules/common/src/errors.ts index 3604e735e..e84082cb0 100644 --- a/modules/common/src/errors.ts +++ b/modules/common/src/errors.ts @@ -279,7 +279,7 @@ export class InvalidParameter extends SdkError { export class NotAContractError extends SdkError { constructor(cause?: Error) { super( - "The provided address does not point to a contract or the contract is not deployed", + "The provided address does not point to a contract", cause, ); } From 7ae7ce866fd1130859e7379fa0d7278eb893cffc Mon Sep 17 00:00:00 2001 From: josemarinas <36479864+josemarinas@users.noreply.github.com> Date: Thu, 17 Aug 2023 01:22:23 +0200 Subject: [PATCH 18/25] Update modules/client/test/integration/tokenVoting-client/methods.test.ts Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> --- .../client/test/integration/tokenVoting-client/methods.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index 9304678fe..d84b1ccb7 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -1432,7 +1432,7 @@ describe("Token Voting Client", () => { expect(token).toBe(null); }); - it("Should check if a ERC20 is compatible with governance and throw", async () => { + it("Should check if a ERC20 is compatible with the TokenVotingSetup and throw", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const erc20Token = await deployErc20(); From ae74b61807751a15c297d4c6f9bd0c0ce60b3052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Thu, 17 Aug 2023 01:37:57 +0200 Subject: [PATCH 19/25] fix tests --- .../tokenVoting/internal/client/methods.ts | 6 ++-- .../tokenVoting-client/methods.test.ts | 31 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index e865247c1..caa36bd10 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -783,7 +783,7 @@ export class TokenVotingClientMethods extends ClientCore } try { if (!await contract.supportsInterface(ERC165_INTERFACE_ID)) { - return TokenVotingTokenCompatibility.NEEDS_WRAP; + return TokenVotingTokenCompatibility.NEEDS_WRAPPING; } for (const iface of GOVERNANCE_INTERFACES_SUPPORTED) { const isSupported = await contract.supportsInterface(iface); @@ -791,9 +791,9 @@ export class TokenVotingClientMethods extends ClientCore return TokenVotingTokenCompatibility.COMPATIBLE; } } - return TokenVotingTokenCompatibility.NEEDS_WRAP; + return TokenVotingTokenCompatibility.NEEDS_WRAPPING; } catch (e) { - return TokenVotingTokenCompatibility.NEEDS_WRAP; + return TokenVotingTokenCompatibility.NEEDS_WRAPPING; } } } diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index d84b1ccb7..dcbc00c53 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -31,8 +31,6 @@ import * as ganacheSetup from "../../helpers/ganache-setup"; import * as deployContracts from "../../helpers/deployContracts"; import { - ERC165NotSupportedError, - ERC20NotSupportedError, getExtendedProposalId, InvalidAddressError, InvalidAddressOrEnsError, @@ -76,6 +74,7 @@ import { SubgraphTokenVotingMember, SubgraphTokenVotingProposal, SubgraphTokenVotingProposalListItem, + TokenVotingTokenCompatibility, } from "../../../src/tokenVoting/internal/types"; import { deployErc20 } from "../../helpers/deploy-erc20"; import { deployErc721 } from "../../helpers/deploy-erc721"; @@ -1436,27 +1435,27 @@ describe("Token Voting Client", () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const erc20Token = await deployErc20(); - expect(() => - client.methods.isTokenGovernanceCompatible( - erc20Token.address, - ) - ).rejects.toThrow(ERC165NotSupportedError) + const compatibility = client.methods.isTokenVotingCompatibleToken( + erc20Token.address, + ); + expect(compatibility).toBe( + TokenVotingTokenCompatibility.NEEDS_WRAPPING, + ); }); it("Should check if ERC721 is compatible with governance and throw", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const erc721Token = await deployErc721(); - expect(() => - client.methods.isTokenGovernanceCompatible( - erc721Token.address, - ) - ).rejects.toThrow(ERC20NotSupportedError); + const compatibility = client.methods.isTokenVotingCompatibleToken( + erc721Token.address, + ); + expect(compatibility).toBe(TokenVotingTokenCompatibility.INCOMPATIBLE); }); it("Should be called with an invalid address and throw", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); expect(() => - client.methods.isTokenGovernanceCompatible( + client.methods.isTokenVotingCompatibleToken( "0x123", ) ).rejects.toThrow(InvalidAddressError); @@ -1465,7 +1464,7 @@ describe("Token Voting Client", () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); expect(() => - client.methods.isTokenGovernanceCompatible( + client.methods.isTokenVotingCompatibleToken( TEST_WALLET_ADDRESS, ) ).rejects.toThrow(NotAContractError); @@ -1474,10 +1473,10 @@ describe("Token Voting Client", () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const dao = await buildTokenVotingDAO(repoAddr, VotingMode.STANDARD); - const isCompatible = await client.methods.isTokenGovernanceCompatible( + const isCompatible = await client.methods.isTokenVotingCompatibleToken( dao.tokenAddress, ); - expect(isCompatible).toBe(true); + expect(isCompatible).toBe(TokenVotingTokenCompatibility.COMPATIBLE); }); }); }); From afb247be0581165fcb6f2cf27481a9c0ff4debf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Thu, 17 Aug 2023 02:15:55 +0200 Subject: [PATCH 20/25] improve iserc20 function --- .../client/src/tokenVoting/internal/utils.ts | 28 ++++++++++++------- .../tokenVoting-client/methods.test.ts | 14 +++++----- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/modules/client/src/tokenVoting/internal/utils.ts b/modules/client/src/tokenVoting/internal/utils.ts index 557690a6e..fb6448cc8 100644 --- a/modules/client/src/tokenVoting/internal/utils.ts +++ b/modules/client/src/tokenVoting/internal/utils.ts @@ -337,6 +337,18 @@ export function computeProposalStatusFilter(status: ProposalStatus) { return where; } + +/** + * Checks if the given address is an ERC20 token + * This function isn not 100% accurate. + * It just checks if the token has a balanceOf + * function and a decimals function + * + * @export + * @param {string} tokenAddress + * @param {Signer} signer + * @return {*} {Promise} + */ export async function isERC20Token( tokenAddress: string, signer: Signer, @@ -346,17 +358,13 @@ export async function isERC20Token( ERC_20_ABI, signer, ); - // Check that it has the balanceOf function try { - await contract.balanceOf(signer.getAddress()); - try { - await contract.metadata.tokenURI(0); - return false; - } catch { - return true; - } + await Promise.all([ + contract.balanceOf(await signer.getAddress()), + contract.decimals(), + ]); + return true; } catch { return false; } - // check that is not an ERC721 -} +} \ No newline at end of file diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index dcbc00c53..bdf1e6d24 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -1431,27 +1431,27 @@ describe("Token Voting Client", () => { expect(token).toBe(null); }); - it("Should check if a ERC20 is compatible with the TokenVotingSetup and throw", async () => { + it("Should check if a ERC20 is compatible with the TokenVotingSetup and return needs wrapping", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const erc20Token = await deployErc20(); - const compatibility = client.methods.isTokenVotingCompatibleToken( + const compatibility = await client.methods.isTokenVotingCompatibleToken( erc20Token.address, ); expect(compatibility).toBe( TokenVotingTokenCompatibility.NEEDS_WRAPPING, ); }); - it("Should check if ERC721 is compatible with governance and throw", async () => { + it("Should check if ERC721 is compatible with governance and return incompatible", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const erc721Token = await deployErc721(); - const compatibility = client.methods.isTokenVotingCompatibleToken( + const compatibility = await client.methods.isTokenVotingCompatibleToken( erc721Token.address, ); expect(compatibility).toBe(TokenVotingTokenCompatibility.INCOMPATIBLE); }); - it("Should be called with an invalid address and throw", async () => { + it("Should be called with an invalid address and throw InvalidAddressError", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); expect(() => @@ -1460,7 +1460,7 @@ describe("Token Voting Client", () => { ) ).rejects.toThrow(InvalidAddressError); }); - it("Should be called with wallet invalid address and throw", async () => { + it("Should be called with wallet invalid address and throw NotAContractError", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); expect(() => @@ -1469,7 +1469,7 @@ describe("Token Voting Client", () => { ) ).rejects.toThrow(NotAContractError); }); - it("Should check if GovernanceERC20 is compatible with governance and return true", async () => { + it("Should check if GovernanceERC20 is compatible with governance and return compatible", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); const dao = await buildTokenVotingDAO(repoAddr, VotingMode.STANDARD); From 0b3d5b31ab4d7a2df46b37248c2f9304810c4f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Thu, 17 Aug 2023 02:18:37 +0200 Subject: [PATCH 21/25] remove blank space --- modules/client/src/tokenVoting/internal/utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/client/src/tokenVoting/internal/utils.ts b/modules/client/src/tokenVoting/internal/utils.ts index fb6448cc8..8c5aaed89 100644 --- a/modules/client/src/tokenVoting/internal/utils.ts +++ b/modules/client/src/tokenVoting/internal/utils.ts @@ -337,7 +337,6 @@ export function computeProposalStatusFilter(status: ProposalStatus) { return where; } - /** * Checks if the given address is an ERC20 token * This function isn not 100% accurate. From 65005451b675c5b0f2e9c1d55d35ed3c520033de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Thu, 17 Aug 2023 09:45:57 +0200 Subject: [PATCH 22/25] rename constants and update subgraph endpoint --- modules/client/src/tokenVoting/internal/client/methods.ts | 6 +++--- modules/client/src/tokenVoting/internal/constants.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/client/src/tokenVoting/internal/client/methods.ts b/modules/client/src/tokenVoting/internal/client/methods.ts index caa36bd10..054a16b0b 100644 --- a/modules/client/src/tokenVoting/internal/client/methods.ts +++ b/modules/client/src/tokenVoting/internal/client/methods.ts @@ -102,7 +102,7 @@ import { } from "@aragon/sdk-client-common"; import { ERC165_INTERFACE_ID, - GOVERNANCE_INTERFACES_SUPPORTED, + GOVERNANCE_SUPPORTED_INTERFACE_IDS, INSTALLATION_ABI, } from "../constants"; import { abi as ERC165_ABI } from "@openzeppelin/contracts/build/contracts/ERC165.json"; @@ -785,8 +785,8 @@ export class TokenVotingClientMethods extends ClientCore if (!await contract.supportsInterface(ERC165_INTERFACE_ID)) { return TokenVotingTokenCompatibility.NEEDS_WRAPPING; } - for (const iface of GOVERNANCE_INTERFACES_SUPPORTED) { - const isSupported = await contract.supportsInterface(iface); + for (const interfaceId of GOVERNANCE_SUPPORTED_INTERFACE_IDS) { + const isSupported = await contract.supportsInterface(interfaceId); if (isSupported) { return TokenVotingTokenCompatibility.COMPATIBLE; } diff --git a/modules/client/src/tokenVoting/internal/constants.ts b/modules/client/src/tokenVoting/internal/constants.ts index 537db0008..32ab4dd06 100644 --- a/modules/client/src/tokenVoting/internal/constants.ts +++ b/modules/client/src/tokenVoting/internal/constants.ts @@ -120,7 +120,7 @@ export const ERC165_INTERFACE_ID = getInterfaceId( new Interface(ERC165_ABI), ); -export const GOVERNANCE_INTERFACES_SUPPORTED = [ +export const GOVERNANCE_SUPPORTED_INTERFACE_IDS = [ getInterfaceId(new Interface(IVOTES_UPGRADEABLE_ABI)), getInterfaceId(new Interface(IVOTES_ABI)), getInterfaceId(IGovernanceWrappedERC20__factory.createInterface()), From 91f5da49f8b0ec7869de33ae77c0bdbde30d5b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Thu, 17 Aug 2023 09:49:47 +0200 Subject: [PATCH 23/25] fix typo --- modules/client-common/src/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/client-common/src/constants.ts b/modules/client-common/src/constants.ts index cad707c04..00725597b 100644 --- a/modules/client-common/src/constants.ts +++ b/modules/client-common/src/constants.ts @@ -47,9 +47,9 @@ export const UNAVAILABLE_PROPOSAL_METADATA: ProposalMetadata = { resources: [], }; -const getGraphqlNode = (netowrk: SupportedNetwork): string => { +const getGraphqlNode = (network: SupportedNetwork): string => { return `https://subgraph.satsuma-prod.com/qHR2wGfc5RLi6/aragon/osx-${ - SupportedNetworksToGraphqlNetworks[netowrk] + SupportedNetworksToGraphqlNetworks[network] }/version/v1.3.0/api`; }; From bd97f4bf2c9aa5d1fd0963527e75327653c5eb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Thu, 17 Aug 2023 09:52:50 +0200 Subject: [PATCH 24/25] fix test --- .../test/integration/tokenVoting-client/methods.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index bdf1e6d24..45a268e7d 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -1438,7 +1438,7 @@ describe("Token Voting Client", () => { const compatibility = await client.methods.isTokenVotingCompatibleToken( erc20Token.address, ); - expect(compatibility).toBe( + await expect(compatibility).toBe( TokenVotingTokenCompatibility.NEEDS_WRAPPING, ); }); @@ -1454,7 +1454,7 @@ describe("Token Voting Client", () => { it("Should be called with an invalid address and throw InvalidAddressError", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); - expect(() => + await expect(() => client.methods.isTokenVotingCompatibleToken( "0x123", ) @@ -1463,7 +1463,7 @@ describe("Token Voting Client", () => { it("Should be called with wallet invalid address and throw NotAContractError", async () => { const ctx = new Context(contextParamsLocalChain); const client = new TokenVotingClient(ctx); - expect(() => + await expect(() => client.methods.isTokenVotingCompatibleToken( TEST_WALLET_ADDRESS, ) From 1619de97816918fd78fda7a4254970888274180a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Manuel=20Mari=C3=B1as=20Bascoy?= Date: Thu, 17 Aug 2023 11:29:03 +0200 Subject: [PATCH 25/25] fix test --- .../client/test/integration/tokenVoting-client/methods.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client/test/integration/tokenVoting-client/methods.test.ts b/modules/client/test/integration/tokenVoting-client/methods.test.ts index 45a268e7d..fa6d0ec5b 100644 --- a/modules/client/test/integration/tokenVoting-client/methods.test.ts +++ b/modules/client/test/integration/tokenVoting-client/methods.test.ts @@ -1438,7 +1438,7 @@ describe("Token Voting Client", () => { const compatibility = await client.methods.isTokenVotingCompatibleToken( erc20Token.address, ); - await expect(compatibility).toBe( + expect(compatibility).toBe( TokenVotingTokenCompatibility.NEEDS_WRAPPING, ); });