(Fix) Contract interaction ABI resets (#1394)
Co-authored-by: Daniel Sanchez <daniel.sanchez@gnosis.pm>
This commit is contained in:
parent
21ea1ad9dd
commit
5a41c3857d
|
@ -1,13 +1,17 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useField, useForm } from 'react-final-form'
|
||||||
|
|
||||||
import TextareaField from 'src/components/forms/TextareaField'
|
import TextareaField from 'src/components/forms/TextareaField'
|
||||||
|
import { mustBeEthereumAddress, mustBeEthereumContractAddress } from 'src/components/forms/validator'
|
||||||
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 { getNetwork } from 'src/config'
|
||||||
|
import { getConfiguredSource } from 'src/logic/contractInteraction/sources'
|
||||||
import { extractUsefulMethods } from 'src/logic/contractInteraction/sources/ABIService'
|
import { extractUsefulMethods } from 'src/logic/contractInteraction/sources/ABIService'
|
||||||
|
|
||||||
export const NO_DATA = 'no data'
|
export const NO_DATA = 'no data'
|
||||||
|
|
||||||
const mustBeValidABI = (abi: string): undefined | string => {
|
const hasUsefulMethods = (abi: string): undefined | string => {
|
||||||
try {
|
try {
|
||||||
const parsedABI = extractUsefulMethods(JSON.parse(abi))
|
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">
|
<Row margin="sm">
|
||||||
<Col>
|
<Col>
|
||||||
<TextareaField name="abi" placeholder="ABI*" text="ABI*" type="text" validate={mustBeValidABI} />
|
<TextareaField name="abi" placeholder="ABI*" text="ABI*" type="text" validate={hasUsefulMethods} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default ContractABI
|
export default ContractABI
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Header from './Header'
|
||||||
import MethodsDropdown from './MethodsDropdown'
|
import MethodsDropdown from './MethodsDropdown'
|
||||||
import RenderInputParams from './RenderInputParams'
|
import RenderInputParams from './RenderInputParams'
|
||||||
import RenderOutputParams from './RenderOutputParams'
|
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'
|
import { TransactionReviewType } from './Review'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
@ -92,7 +92,7 @@ const ContractInteraction: React.FC<ContractInteractionProps> = ({
|
||||||
<Header onClose={onClose} subTitle="1 of 2" title="Contract Interaction" />
|
<Header onClose={onClose} subTitle="1 of 2" title="Contract Interaction" />
|
||||||
<Hairline />
|
<Hairline />
|
||||||
<GnoForm
|
<GnoForm
|
||||||
decorators={[abiExtractor, ensResolver]}
|
decorators={[ensResolver]}
|
||||||
formMutators={formMutators}
|
formMutators={formMutators}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
|
|
@ -2,9 +2,6 @@ import { FORM_ERROR, Mutator, SubmissionErrors } from 'final-form'
|
||||||
import createDecorator from 'final-form-calculate'
|
import createDecorator from 'final-form-calculate'
|
||||||
import { ContractSendMethod } from 'web3-eth-contract'
|
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 { AbiItemExtended } from 'src/logic/contractInteraction/sources/ABIService'
|
||||||
import { getAddressFromENS, getWeb3 } from 'src/logic/wallets/getWeb3'
|
import { getAddressFromENS, getWeb3 } from 'src/logic/wallets/getWeb3'
|
||||||
import { TransactionReviewType } from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review'
|
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 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({
|
export const ensResolver = createDecorator({
|
||||||
field: 'contractAddress',
|
field: 'contractAddress',
|
||||||
updates: {
|
updates: {
|
||||||
|
@ -40,12 +19,12 @@ export const ensResolver = createDecorator({
|
||||||
if (resolvedAddress) {
|
if (resolvedAddress) {
|
||||||
return resolvedAddress
|
return resolvedAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return contractAddress
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
return contractAddress
|
return contractAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
return contractAddress
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -71,6 +50,9 @@ export const formMutators: Record<string, Mutator<{ selectedMethod: { name: stri
|
||||||
setCallResults: (args, state, utils) => {
|
setCallResults: (args, state, utils) => {
|
||||||
utils.changeValue(state, 'callResults', () => args[0])
|
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
|
export const isAddress = (type: string): boolean => type.indexOf('address') === 0
|
||||||
|
|
Loading…
Reference in New Issue