diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index 5995346a..79c20e38 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Add `PluginType` enum - Add `resolveEnsName` functions - Add `getProtocolVersion` function diff --git a/sdk/package.json b/sdk/package.json index b828161e..ad39accc 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,7 +1,7 @@ { "name": "@aragon/osx-commons-sdk", "author": "Aragon X", - "version": "0.0.1-alpha.9", + "version": "0.0.1-alpha.11", "license": "MIT", "main": "dist/index.js", "module": "dist/osx-commons-sdk.esm.js", @@ -54,11 +54,12 @@ }, "dependencies": { "@aragon/osx-commons-configs": "^0.4.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/contracts": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/providers": "^5.7.0", - "@ethersproject/address": "^5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/providers": "5.7.2", "ipfs-http-client": "^51.0.0" } } diff --git a/sdk/src/introspection.ts b/sdk/src/introspection.ts index 3b39d481..95e5aa9d 100644 --- a/sdk/src/introspection.ts +++ b/sdk/src/introspection.ts @@ -1,9 +1,12 @@ -import {InvalidAddressError} from './errors'; import {Interface} from '@ethersproject/abi'; -import {isAddress} from '@ethersproject/address'; import {BigNumber} from '@ethersproject/bignumber'; import {Contract} from '@ethersproject/contracts'; -import {JsonRpcProvider} from '@ethersproject/providers'; +import {ErrorCode} from '@ethersproject/logger'; + +// The protocol version number of contracts not having a `getProtocolVersion()` function because they don't inherit from `ProtocolVersion.sol` yet. +export const IMPLICIT_INITIAL_PROTOCOL_VERSION: [number, number, number] = [ + 1, 0, 0, +]; /** * Gets the interfaceId of a given interface @@ -26,31 +29,34 @@ export function getInterfaceId(iface: Interface): string { * protocolVersion function, it will return [1, 0, 0] * * @export - * @param {string} rpc - * @param {string} contractAddress + * @param {Contract} contract * @return {*} {Promise<[number, number, number]>} */ export async function getProtocolVersion( - rpc: string, - contractAddress: string + contract: Contract ): Promise<[number, number, number]> { - if (!isAddress(contractAddress)) { - throw new InvalidAddressError(contractAddress); - } - const provider = new JsonRpcProvider(rpc); - const iface = new Interface([ - 'function protocolVersion() public pure returns (uint8[3] memory)', - ]); - const contract = new Contract(contractAddress, iface, provider); - let version: [number, number, number]; + let protocolVersion: [number, number, number]; try { - version = await contract.protocolVersion(); + contract.interface.getFunction('protocolVersion'); + protocolVersion = await contract.protocolVersion(); } catch (e) { - // version 1.0.0 of the contract does not have a protocolVersion function - // so if we receive an error we cannot differentiate between a call exception - // and a contract that does not have the function. So we assume that is - // a version 1.0.0 contract that does not have the function and return [1, 0, 0] - version = [1, 0, 0]; + if ((e as any).code === ErrorCode.INVALID_ARGUMENT) { + return IMPLICIT_INITIAL_PROTOCOL_VERSION; + } + throw e; } - return version; + return protocolVersion; +} + +/** + * Enum for PluginType + * Reference: https://github.com/aragon/osx-commons/blob/ffa6b45fab9ec067d4bed3b81f5097f03861b876/contracts/src/plugin/IPlugin.sol + * + * @export + * @enum {number} + */ +export enum PluginType { + UUPS = 0, + Cloneable = 1, + Constructable = 2, } diff --git a/sdk/src/permission.ts b/sdk/src/permission.ts index a6f9731e..e0d0bfe4 100644 --- a/sdk/src/permission.ts +++ b/sdk/src/permission.ts @@ -2,7 +2,7 @@ import {id} from '@ethersproject/hash'; /** * Enum for PermissionType - * Reference: + * Reference: https://github.com/aragon/osx-commons/blob/ffa6b45fab9ec067d4bed3b81f5097f03861b876/contracts/src/permission/PermissionLib.sol * * @export * @enum {number} diff --git a/sdk/test/mocks.ts b/sdk/test/mocks.ts index e4f0443a..37f8776a 100644 --- a/sdk/test/mocks.ts +++ b/sdk/test/mocks.ts @@ -1,3 +1,6 @@ +import {FunctionFragment} from '@ethersproject/abi'; +import {ErrorCode, Logger} from '@ethersproject/logger'; + export function mockContractProtocolVersion( version: [number, number, number] = [1, 0, 0], throwException: boolean = false @@ -8,10 +11,23 @@ export function mockContractProtocolVersion( return { protocolVersion: () => { if (throwException) { - throw new Error('Error'); + const logger = new Logger('5.7.0'); + logger.throwError( + 'Protocol version not found', + ErrorCode.INVALID_ARGUMENT + ); } return Promise.resolve(version); }, + interface: { + getFunction: (name: string): FunctionFragment => { + return FunctionFragment.from({ + name: name, + type: 'function', + stateMutability: 'pure', + }); + }, + }, }; }); } diff --git a/sdk/test/unit/introspection.test.ts b/sdk/test/unit/introspection.test.ts index 7950794b..ea0e38b9 100644 --- a/sdk/test/unit/introspection.test.ts +++ b/sdk/test/unit/introspection.test.ts @@ -1,11 +1,13 @@ import { - InvalidAddressError, + IMPLICIT_INITIAL_PROTOCOL_VERSION, getInterfaceId, getProtocolVersion, } from '../../src'; import {ADDRESS_ONE, TEST_HTTP_URI} from '../constants'; -import {mockContractProtocolVersion, mockJSONRPCProvider} from '../mocks'; +import {mockJSONRPCProvider, mockContractProtocolVersion} from '../mocks'; import {Interface} from '@ethersproject/abi'; +import {Contract} from '@ethersproject/contracts'; +import {JsonRpcProvider} from '@ethersproject/providers'; describe('introspection', () => { describe('getInterfaceId', () => { @@ -21,33 +23,40 @@ describe('introspection', () => { }); describe('getProtocolVersion', () => { - it('should return the correct protocol version', async () => { - const expectedVersion: [number, number, number] = [1, 3, 0]; - // mock call to the contract + let iface: Interface; + let contract: Contract; + let provider: JsonRpcProvider; + beforeAll(() => { + // mock JSONRPCProvider to return chainId 1 and blockNumber 1 mockJSONRPCProvider(); - // mock the call to the contract - mockContractProtocolVersion(expectedVersion); - const version = await getProtocolVersion(TEST_HTTP_URI, ADDRESS_ONE); - expect(version).toEqual(expectedVersion); }); - it('should fail when an invalid address is passed', async () => { + it('should return the correct protocol version', async () => { + // Expected protocol version const expectedVersion: [number, number, number] = [1, 3, 0]; - // mock call to the contract - mockJSONRPCProvider(); - // mock the call to the contract + // mock Contract to return the expected protocol version mockContractProtocolVersion(expectedVersion); - await expect(() => - getProtocolVersion(TEST_HTTP_URI, '0x') - ).rejects.toThrow(new InvalidAddressError('0x')); + // Initialize the contract + provider = new JsonRpcProvider(TEST_HTTP_URI); + iface = new Interface([ + 'function protocolVersion() public pure returns (uint8[3] memory)', + ]); + contract = new Contract(ADDRESS_ONE, iface, provider); + // Call getProtocolVersion + const version = await getProtocolVersion(contract); + expect(version).toEqual(expectedVersion); }); it('should return [1,0,0] when the call throws an error', async () => { - const expectedVersion: [number, number, number] = [1, 0, 0]; - // mock call to the contract - mockJSONRPCProvider(); - // mock the call to the contract - mockContractProtocolVersion(expectedVersion, true); - const version = await getProtocolVersion(TEST_HTTP_URI, ADDRESS_ONE); - expect(version).toEqual(expectedVersion); + // mock Contract to throw an error + mockContractProtocolVersion(IMPLICIT_INITIAL_PROTOCOL_VERSION, true); + // Initialize the contract + const iface = new Interface([ + 'function protocolVersion() public pure returns (uint8[3] memory)', + ]); + const provider = new JsonRpcProvider(TEST_HTTP_URI); + const contract = new Contract(ADDRESS_ONE, iface, provider); + // Call getProtocolVersion + const version = await getProtocolVersion(contract); + expect(version).toEqual(IMPLICIT_INITIAL_PROTOCOL_VERSION); }); }); }); diff --git a/sdk/yarn.lock b/sdk/yarn.lock index 2a4e08cc..1fc8368d 100644 --- a/sdk/yarn.lock +++ b/sdk/yarn.lock @@ -1139,7 +1139,7 @@ dependencies: "@ethersproject/bignumber" "^5.7.0" -"@ethersproject/contracts@5.7.0", "@ethersproject/contracts@^5.7.0": +"@ethersproject/contracts@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== @@ -1242,7 +1242,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.0": +"@ethersproject/providers@5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==