From 2c0bcfefe64624ac85b69b72586adfc75c5967e6 Mon Sep 17 00:00:00 2001 From: fernandomg Date: Tue, 2 Jun 2020 10:22:49 -0300 Subject: [PATCH] convert ABIService from class to module and add typings --- .../contractInteraction/sources/ABIService.ts | 41 ------------------- .../sources/ABIService/index.ts | 38 +++++++++++++++++ .../sources/ABIService/types.d.ts | 25 +++++++++++ .../sources/EtherscanService.ts | 4 +- .../ContractInteraction/ContractABI/index.tsx | 4 +- .../ContractInteraction/EthValue/index.tsx | 4 +- .../MethodsDropdown/index.tsx | 4 +- 7 files changed, 70 insertions(+), 50 deletions(-) delete mode 100644 src/logic/contractInteraction/sources/ABIService.ts create mode 100644 src/logic/contractInteraction/sources/ABIService/index.ts create mode 100644 src/logic/contractInteraction/sources/ABIService/types.d.ts diff --git a/src/logic/contractInteraction/sources/ABIService.ts b/src/logic/contractInteraction/sources/ABIService.ts deleted file mode 100644 index 09ca6553..00000000 --- a/src/logic/contractInteraction/sources/ABIService.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { getWeb3 } from 'src/logic/wallets/getWeb3' - -class ABIService { - static extractUsefulMethods(abi) { - return abi - .filter(({ constant, name, type }) => type === 'function' && !!name && typeof constant === 'boolean') - .map((method) => ({ - action: method.constant ? 'read' : 'write', - ...ABIService.getMethodSignatureAndSignatureHash(method), - ...method, - })) - .sort(({ name: a }, { name: b }) => (a.toLowerCase() > b.toLowerCase() ? 1 : -1)) - } - - static getMethodHash(method) { - const signature = ABIService.getMethodSignature(method) - return ABIService.getSignatureHash(signature) - } - - static getMethodSignatureAndSignatureHash(method) { - const methodSignature = ABIService.getMethodSignature(method) - const signatureHash = ABIService.getSignatureHash(methodSignature) - return { methodSignature, signatureHash } - } - - static getMethodSignature({ inputs, name }) { - const params = inputs.map((x) => x.type).join(',') - return `${name}(${params})` - } - - static getSignatureHash(signature) { - const web3 = getWeb3() - return web3.utils.keccak256(signature).toString() - } - - static isPayable(method) { - return method.payable - } -} - -export default ABIService diff --git a/src/logic/contractInteraction/sources/ABIService/index.ts b/src/logic/contractInteraction/sources/ABIService/index.ts new file mode 100644 index 00000000..8625bdb5 --- /dev/null +++ b/src/logic/contractInteraction/sources/ABIService/index.ts @@ -0,0 +1,38 @@ +import { getWeb3 } from 'src/logic/wallets/getWeb3' +import { ABI, ExtendedABI } from './types' + +export const getMethodSignature = ({ inputs, name }) => { + const params = inputs.map((x) => x.type).join(',') + return `${name}(${params})` +} + +export const getSignatureHash = (signature) => { + const web3 = getWeb3() + return web3.utils.keccak256(signature).toString() +} + +export const getMethodHash = (method) => { + const signature = getMethodSignature(method) + return getSignatureHash(signature) +} + +export const getMethodSignatureAndSignatureHash = (method) => { + const methodSignature = getMethodSignature(method) + const signatureHash = getSignatureHash(methodSignature) + return { methodSignature, signatureHash } +} + +export const extractUsefulMethods = (abi: ABI): ExtendedABI => { + return abi + .filter(({ constant, name, type }) => type === 'function' && !!name && typeof constant === 'boolean') + .map((method) => ({ + action: method.constant ? 'read' : 'write', + ...getMethodSignatureAndSignatureHash(method), + ...method, + })) + .sort(({ name: a }, { name: b }) => (a.toLowerCase() > b.toLowerCase() ? 1 : -1)) +} + +export const isPayable = (method) => { + return method.payable +} diff --git a/src/logic/contractInteraction/sources/ABIService/types.d.ts b/src/logic/contractInteraction/sources/ABIService/types.d.ts new file mode 100644 index 00000000..5cd04f5d --- /dev/null +++ b/src/logic/contractInteraction/sources/ABIService/types.d.ts @@ -0,0 +1,25 @@ +export interface InterfaceParams { + internalType: string + name: string + type: string +} + +export interface ContractInterface { + constant: boolean + inputs: InterfaceParams[] + name: string + outputs: InterfaceParams[] + payable: boolean + stateMutability: string + type: string +} + +export interface ExtendedContractInterface extends ContractInterface { + action: string + methodSignature: string + signatureHash: string +} + +export type ABI = ContractInterface[] + +export type ExtendedABI = ExtendedContractInterface[] diff --git a/src/logic/contractInteraction/sources/EtherscanService.ts b/src/logic/contractInteraction/sources/EtherscanService.ts index 81ebc298..e03c6d46 100644 --- a/src/logic/contractInteraction/sources/EtherscanService.ts +++ b/src/logic/contractInteraction/sources/EtherscanService.ts @@ -1,11 +1,10 @@ import { RateLimit } from 'async-sema' import memoize from 'lodash.memoize' -import ABIService from 'src/logic/contractInteraction/sources/ABIService' import { ETHEREUM_NETWORK } from 'src/logic/wallets/getWeb3' import { ETHERSCAN_API_KEY } from 'src/utils/constants' -class EtherscanService extends ABIService { +class EtherscanService { _rateLimit = async () => {} _endpointsUrls = { @@ -38,7 +37,6 @@ class EtherscanService extends ABIService { ) constructor(options) { - super() this._rateLimit = RateLimit(options.rps) } diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ContractABI/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ContractABI/index.tsx index 0acba016..37aabf00 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ContractABI/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/ContractABI/index.tsx @@ -3,13 +3,13 @@ import React from 'react' import TextareaField from 'src/components/forms/TextareaField' import Col from 'src/components/layout/Col' import Row from 'src/components/layout/Row' -import EtherscanService from 'src/logic/contractInteraction/sources/EtherscanService' +import { extractUsefulMethods } from 'src/logic/contractInteraction/sources/ABIService' export const NO_DATA = 'no data' const mustBeValidABI = (abi) => { try { - const parsedABI = EtherscanService.extractUsefulMethods(JSON.parse(abi)) + const parsedABI = extractUsefulMethods(JSON.parse(abi)) if (parsedABI.length === 0) { return NO_DATA diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/EthValue/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/EthValue/index.tsx index d084f797..b9cafb46 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/EthValue/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/EthValue/index.tsx @@ -11,7 +11,7 @@ import ButtonLink from 'src/components/layout/ButtonLink' import Col from 'src/components/layout/Col' import Paragraph from 'src/components/layout/Paragraph' import Row from 'src/components/layout/Row' -import ABIService from 'src/logic/contractInteraction/sources/ABIService' +import { isPayable } from 'src/logic/contractInteraction/sources/ABIService' import { styles } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/style' import { safeSelector } from 'src/routes/safe/store/selectors' @@ -23,7 +23,7 @@ const EthValue = ({ onSetMax }) => { const { input: { value: method }, } = useField('selectedMethod', { value: true }) - const disabled = !ABIService.isPayable(method) + const disabled = !isPayable(method) return disabled ? null : ( <> diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/MethodsDropdown/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/MethodsDropdown/index.tsx index 102a0cd7..b9988c81 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/MethodsDropdown/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/MethodsDropdown/index.tsx @@ -11,11 +11,11 @@ import { useField, useFormState } from 'react-final-form' import Col from 'src/components/layout/Col' import Row from 'src/components/layout/Row' -import EtherscanService from 'src/logic/contractInteraction/sources/EtherscanService' import { NO_CONTRACT } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils' import CheckIcon from 'src/routes/safe/components/CurrencyDropdown/img/check.svg' import { useDropdownStyles } from 'src/routes/safe/components/CurrencyDropdown/style' import { DropdownListTheme } from 'src/theme/mui' +import { extractUsefulMethods } from 'src/logic/contractInteraction/sources/ABIService' const MENU_WIDTH = '452px' @@ -37,7 +37,7 @@ const MethodsDropdown = ({ onChange }) => { React.useEffect(() => { if (abi) { try { - setMethodsList(EtherscanService.extractUsefulMethods(JSON.parse(abi))) + setMethodsList(extractUsefulMethods(JSON.parse(abi))) } catch (e) { setMethodsList([]) }