(Fix) Contract interaction ABI resets (#1394)

Co-authored-by: Daniel Sanchez <daniel.sanchez@gnosis.pm>
This commit is contained in:
Fernando 2020-10-05 12:13:19 -03:00 committed by GitHub
parent 21ea1ad9dd
commit 5a41c3857d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 33 deletions

View File

@ -1,13 +1,17 @@
import React from 'react'
import { useField, useForm } from 'react-final-form'
import TextareaField from 'src/components/forms/TextareaField'
import { mustBeEthereumAddress, mustBeEthereumContractAddress } from 'src/components/forms/validator'
import Col from 'src/components/layout/Col'
import Row from 'src/components/layout/Row'
import { getNetwork } from 'src/config'
import { getConfiguredSource } from 'src/logic/contractInteraction/sources'
import { extractUsefulMethods } from 'src/logic/contractInteraction/sources/ABIService'
export const NO_DATA = 'no data'
const mustBeValidABI = (abi: string): undefined | string => {
const hasUsefulMethods = (abi: string): undefined | string => {
try {
const parsedABI = extractUsefulMethods(JSON.parse(abi))
@ -19,12 +23,44 @@ const mustBeValidABI = (abi: string): undefined | string => {
}
}
const ContractABI = () => (
const ContractABI = (): React.ReactElement => {
const {
input: { value: contractAddress },
} = useField('contractAddress', { subscription: { value: true } })
const { mutators } = useForm()
const setAbiValue = React.useRef(mutators.setAbiValue)
React.useEffect(() => {
const validateAndSetAbi = async () => {
const isEthereumAddress = mustBeEthereumAddress(contractAddress) === undefined
const isEthereumContractAddress = (await mustBeEthereumContractAddress(contractAddress)) === undefined
if (isEthereumAddress && isEthereumContractAddress) {
const network = getNetwork()
const source = getConfiguredSource()
const abi = await source.getContractABI(contractAddress, network)
const isValidABI = hasUsefulMethods(abi) === undefined
// this check may help in scenarios where the user first pastes the ABI,
// and then sets a Proxy contract that has no useful methods
if (isValidABI) {
setAbiValue.current(abi)
}
}
}
if (contractAddress) {
validateAndSetAbi()
}
}, [contractAddress])
return (
<Row margin="sm">
<Col>
<TextareaField name="abi" placeholder="ABI*" text="ABI*" type="text" validate={mustBeValidABI} />
<TextareaField name="abi" placeholder="ABI*" text="ABI*" type="text" validate={hasUsefulMethods} />
</Col>
</Row>
)
}
export default ContractABI

View File

@ -19,7 +19,7 @@ import Header from './Header'
import MethodsDropdown from './MethodsDropdown'
import RenderInputParams from './RenderInputParams'
import RenderOutputParams from './RenderOutputParams'
import { abiExtractor, createTxObject, formMutators, handleSubmitError, isReadMethod, ensResolver } from './utils'
import { createTxObject, formMutators, handleSubmitError, isReadMethod, ensResolver } from './utils'
import { TransactionReviewType } from './Review'
const useStyles = makeStyles(styles)
@ -92,7 +92,7 @@ const ContractInteraction: React.FC<ContractInteractionProps> = ({
<Header onClose={onClose} subTitle="1 of 2" title="Contract Interaction" />
<Hairline />
<GnoForm
decorators={[abiExtractor, ensResolver]}
decorators={[ensResolver]}
formMutators={formMutators}
initialValues={initialValues}
onSubmit={handleSubmit}

View File

@ -2,9 +2,6 @@ import { FORM_ERROR, Mutator, SubmissionErrors } from 'final-form'
import createDecorator from 'final-form-calculate'
import { ContractSendMethod } from 'web3-eth-contract'
import { mustBeEthereumAddress, mustBeEthereumContractAddress } from 'src/components/forms/validator'
import { getNetwork } from 'src/config'
import { getConfiguredSource } from 'src/logic/contractInteraction/sources'
import { AbiItemExtended } from 'src/logic/contractInteraction/sources/ABIService'
import { getAddressFromENS, getWeb3 } from 'src/logic/wallets/getWeb3'
import { TransactionReviewType } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review'
@ -12,24 +9,6 @@ import { isValidEnsName } from 'src/logic/wallets/ethAddresses'
export const NO_CONTRACT = 'no contract'
export const abiExtractor = createDecorator({
field: 'contractAddress',
updates: {
abi: async (contractAddress) => {
if (
!contractAddress ||
mustBeEthereumAddress(contractAddress) ||
(await mustBeEthereumContractAddress(contractAddress))
) {
return
}
const network = getNetwork()
const source = getConfiguredSource()
return source.getContractABI(contractAddress, network)
},
},
})
export const ensResolver = createDecorator({
field: 'contractAddress',
updates: {
@ -40,12 +19,12 @@ export const ensResolver = createDecorator({
if (resolvedAddress) {
return resolvedAddress
}
return contractAddress
} catch (e) {
console.error(e.message)
return contractAddress
}
return contractAddress
},
},
})
@ -71,6 +50,9 @@ export const formMutators: Record<string, Mutator<{ selectedMethod: { name: stri
setCallResults: (args, state, utils) => {
utils.changeValue(state, 'callResults', () => args[0])
},
setAbiValue: (args, state, utils) => {
utils.changeValue(state, 'abi', () => args[0])
},
}
export const isAddress = (type: string): boolean => type.indexOf('address') === 0