convert ABIService from class to module and add typings

This commit is contained in:
fernandomg 2020-06-02 10:22:49 -03:00
parent f049f8598d
commit 2c0bcfefe6
7 changed files with 70 additions and 50 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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[]

View File

@ -1,11 +1,10 @@
import { RateLimit } from 'async-sema' import { RateLimit } from 'async-sema'
import memoize from 'lodash.memoize' import memoize from 'lodash.memoize'
import ABIService from 'src/logic/contractInteraction/sources/ABIService'
import { ETHEREUM_NETWORK } from 'src/logic/wallets/getWeb3' import { ETHEREUM_NETWORK } from 'src/logic/wallets/getWeb3'
import { ETHERSCAN_API_KEY } from 'src/utils/constants' import { ETHERSCAN_API_KEY } from 'src/utils/constants'
class EtherscanService extends ABIService { class EtherscanService {
_rateLimit = async () => {} _rateLimit = async () => {}
_endpointsUrls = { _endpointsUrls = {
@ -38,7 +37,6 @@ class EtherscanService extends ABIService {
) )
constructor(options) { constructor(options) {
super()
this._rateLimit = RateLimit(options.rps) this._rateLimit = RateLimit(options.rps)
} }

View File

@ -3,13 +3,13 @@ import React from 'react'
import TextareaField from 'src/components/forms/TextareaField' import TextareaField from 'src/components/forms/TextareaField'
import Col from 'src/components/layout/Col' import Col from 'src/components/layout/Col'
import Row from 'src/components/layout/Row' 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' export const NO_DATA = 'no data'
const mustBeValidABI = (abi) => { const mustBeValidABI = (abi) => {
try { try {
const parsedABI = EtherscanService.extractUsefulMethods(JSON.parse(abi)) const parsedABI = extractUsefulMethods(JSON.parse(abi))
if (parsedABI.length === 0) { if (parsedABI.length === 0) {
return NO_DATA return NO_DATA

View File

@ -11,7 +11,7 @@ import ButtonLink from 'src/components/layout/ButtonLink'
import Col from 'src/components/layout/Col' import Col from 'src/components/layout/Col'
import Paragraph from 'src/components/layout/Paragraph' import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row' 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 { styles } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/style'
import { safeSelector } from 'src/routes/safe/store/selectors' import { safeSelector } from 'src/routes/safe/store/selectors'
@ -23,7 +23,7 @@ const EthValue = ({ onSetMax }) => {
const { const {
input: { value: method }, input: { value: method },
} = useField('selectedMethod', { value: true }) } = useField('selectedMethod', { value: true })
const disabled = !ABIService.isPayable(method) const disabled = !isPayable(method)
return disabled ? null : ( return disabled ? null : (
<> <>

View File

@ -11,11 +11,11 @@ import { useField, useFormState } from 'react-final-form'
import Col from 'src/components/layout/Col' import Col from 'src/components/layout/Col'
import Row from 'src/components/layout/Row' 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 { NO_CONTRACT } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils'
import CheckIcon from 'src/routes/safe/components/CurrencyDropdown/img/check.svg' import CheckIcon from 'src/routes/safe/components/CurrencyDropdown/img/check.svg'
import { useDropdownStyles } from 'src/routes/safe/components/CurrencyDropdown/style' import { useDropdownStyles } from 'src/routes/safe/components/CurrencyDropdown/style'
import { DropdownListTheme } from 'src/theme/mui' import { DropdownListTheme } from 'src/theme/mui'
import { extractUsefulMethods } from 'src/logic/contractInteraction/sources/ABIService'
const MENU_WIDTH = '452px' const MENU_WIDTH = '452px'
@ -37,7 +37,7 @@ const MethodsDropdown = ({ onChange }) => {
React.useEffect(() => { React.useEffect(() => {
if (abi) { if (abi) {
try { try {
setMethodsList(EtherscanService.extractUsefulMethods(JSON.parse(abi))) setMethodsList(extractUsefulMethods(JSON.parse(abi)))
} catch (e) { } catch (e) {
setMethodsList([]) setMethodsList([])
} }