From ffa6b45fab9ec067d4bed3b81f5097f03861b876 Mon Sep 17 00:00:00 2001 From: josemarinas <36479864+josemarinas@users.noreply.github.com> Date: Tue, 23 Apr 2024 13:29:07 +0200 Subject: [PATCH] fix(sdk): `getProtocolVersion` function (#77) * add: getProtocolVersion function * fix: prettier * fix: linting * Update sdk/src/introspection.ts Co-authored-by: Carles <75954325+banasa44@users.noreply.github.com> * Update sdk/src/introspection.ts Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> * Update sdk/test/unit/introspection.test.ts Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> * remove: constant ADDRESS_ONE * fix: prettier * fix: export of addres one * fix: update getProtocolVersion return comment * chore: add ADDRESS_ONE to constants * feat: add getProtocolVersion * update pacakge.json --------- Co-authored-by: Carles <75954325+banasa44@users.noreply.github.com> Co-authored-by: Michael Heuer <20623991+Michael-A-Heuer@users.noreply.github.com> --- sdk/package.json | 5 +-- sdk/src/introspection.ts | 39 +++++++++----------- sdk/test/mocks.ts | 18 +++++++++- sdk/test/unit/introspection.test.ts | 55 +++++++++++++++++------------ 4 files changed, 68 insertions(+), 49 deletions(-) diff --git a/sdk/package.json b/sdk/package.json index df2480a7..450cdf02 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,7 +1,7 @@ { "name": "@aragon/osx-commons-sdk", "author": "Aragon Association", - "version": "0.0.1-alpha.9", + "version": "0.0.1-alpha.10", "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/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.0", - "@ethersproject/address": "^5.7.0", "ipfs-http-client": "^51.0.0" } } diff --git a/sdk/src/introspection.ts b/sdk/src/introspection.ts index 3b39d481..1b9e91c4 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,21 @@ 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; } 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); }); }); });