convert ABIService from class to module and add typings
This commit is contained in:
parent
f049f8598d
commit
2c0bcfefe6
|
@ -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
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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[]
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 : (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -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([])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue