Skip to content

Commit

Permalink
fix(sdk): getProtocolVersion function (#77)
Browse files Browse the repository at this point in the history
* add: getProtocolVersion function

* fix: prettier

* fix: linting

* Update sdk/src/introspection.ts

Co-authored-by: Carles <[email protected]>

* Update sdk/src/introspection.ts

Co-authored-by: Michael Heuer <[email protected]>

* Update sdk/test/unit/introspection.test.ts

Co-authored-by: Michael Heuer <[email protected]>

* 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 <[email protected]>
Co-authored-by: Michael Heuer <[email protected]>
  • Loading branch information
3 people authored Apr 23, 2024
1 parent b3bd6da commit ffa6b45
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 49 deletions.
5 changes: 3 additions & 2 deletions sdk/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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"
}
}
39 changes: 16 additions & 23 deletions sdk/src/introspection.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
}
18 changes: 17 additions & 1 deletion sdk/test/mocks.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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',
});
},
},
};
});
}
Expand Down
55 changes: 32 additions & 23 deletions sdk/test/unit/introspection.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand All @@ -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);
});
});
});

0 comments on commit ffa6b45

Please sign in to comment.