diff --git a/package.json b/package.json index 0c79d2b9..d10f3bae 100644 --- a/package.json +++ b/package.json @@ -235,6 +235,7 @@ "react-app-rewired": "^2.1.6", "truffle": "5.1.23", "typescript": "~3.7.2", - "wait-on": "5.0.0" + "wait-on": "5.0.0", + "web3-utils": "^1.2.8" } } diff --git a/src/logic/contractInteraction/sources/ABIService/index.ts b/src/logic/contractInteraction/sources/ABIService/index.ts index 8625bdb5..78afd210 100644 --- a/src/logic/contractInteraction/sources/ABIService/index.ts +++ b/src/logic/contractInteraction/sources/ABIService/index.ts @@ -1,38 +1,48 @@ -import { getWeb3 } from 'src/logic/wallets/getWeb3' -import { ABI, ExtendedABI } from './types' +import { AbiItem } from 'web3-utils' -export const getMethodSignature = ({ inputs, name }) => { +import { web3ReadOnly as web3 } from 'src/logic/wallets/getWeb3' + +export interface AbiItemExtended extends AbiItem { + action: string + methodSignature: string + signatureHash: string +} + +export const getMethodSignature = ({ inputs, name }: AbiItem) => { const params = inputs.map((x) => x.type).join(',') return `${name}(${params})` } -export const getSignatureHash = (signature) => { - const web3 = getWeb3() +export const getSignatureHash = (signature: string): string => { return web3.utils.keccak256(signature).toString() } -export const getMethodHash = (method) => { +export const getMethodHash = (method: AbiItem): string => { const signature = getMethodSignature(method) return getSignatureHash(signature) } -export const getMethodSignatureAndSignatureHash = (method) => { +export const getMethodSignatureAndSignatureHash = ( + method: AbiItem, +): { methodSignature: string; signatureHash: string } => { const methodSignature = getMethodSignature(method) const signatureHash = getSignatureHash(methodSignature) return { methodSignature, signatureHash } } -export const extractUsefulMethods = (abi: ABI): ExtendedABI => { +export const extractUsefulMethods = (abi: AbiItem[]): AbiItemExtended[] => { return abi .filter(({ constant, name, type }) => type === 'function' && !!name && typeof constant === 'boolean') - .map((method) => ({ - action: method.constant ? 'read' : 'write', - ...getMethodSignatureAndSignatureHash(method), - ...method, - })) + .map( + (method): AbiItemExtended => ({ + action: method.constant ? 'read' : 'write', + ...getMethodSignatureAndSignatureHash(method), + ...method, + }), + ) .sort(({ name: a }, { name: b }) => (a.toLowerCase() > b.toLowerCase() ? 1 : -1)) } -export const isPayable = (method) => { +export const isPayable = (method: AbiItem | AbiItemExtended): boolean => { return method.payable } diff --git a/src/logic/contractInteraction/sources/ABIService/types.d.ts b/src/logic/contractInteraction/sources/ABIService/types.d.ts deleted file mode 100644 index b5b10065..00000000 --- a/src/logic/contractInteraction/sources/ABIService/types.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -export interface InterfaceParams { - internalType: string - name: string - type: string -} - -export interface MethodInterface { - constant: boolean - inputs: InterfaceParams[] - name: string - outputs: InterfaceParams[] - payable: boolean - stateMutability: string - type: string -} - -export interface ExtendedContractInterface extends MethodInterface { - action: string - methodSignature: string - signatureHash: string -} - -export type ABI = MethodInterface[] - -export type ExtendedABI = ExtendedContractInterface[] diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Buttons/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Buttons/index.tsx index 82db6855..9022b85d 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Buttons/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Buttons/index.tsx @@ -17,7 +17,7 @@ const Buttons = ({ onClose }: ButtonProps) => { const classes = useStyles() const { input: { value: method }, - } = useField('selectedMethod', { value: true }) + } = useField('selectedMethod', { subscription: { value: true } }) const { modifiedSinceLastSubmit, submitError, submitting, valid, validating } = useFormState({ subscription: { modifiedSinceLastSubmit: true, 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 0a020269..551dab91 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 @@ -25,7 +25,7 @@ const EthValue = ({ onSetMax }: EthValueProps) => { const { ethBalance } = useSelector(safeSelector) const { input: { value: method }, - } = useField('selectedMethod', { value: true }) + } = useField('selectedMethod', { subscription: { value: true } }) 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 be3a42ad..8d19d0ee 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 @@ -8,6 +8,7 @@ import SearchIcon from '@material-ui/icons/Search' import classNames from 'classnames' import React from 'react' import { useField, useFormState } from 'react-final-form' +import { AbiItem } from 'web3-utils' import Col from 'src/components/layout/Col' import Row from 'src/components/layout/Row' @@ -16,12 +17,11 @@ 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' -import { MethodInterface } from 'src/logic/contractInteraction/sources/ABIService/types' const MENU_WIDTH = '452px' interface MethodsDropdownProps { - onChange: (method: MethodInterface) => void + onChange: (method: AbiItem) => void } const MethodsDropdown = ({ onChange }: MethodsDropdownProps) => { @@ -29,7 +29,7 @@ const MethodsDropdown = ({ onChange }: MethodsDropdownProps) => { const { input: { value: abi }, meta: { valid }, - } = useField('abi', { value: true, valid: true } as any) + } = useField('abi', { subscription: { value: true, valid: true } }) const { initialValues: { selectedMethod: selectedMethodByDefault }, } = useFormState({ subscription: { initialValues: true } }) @@ -61,7 +61,7 @@ const MethodsDropdown = ({ onChange }: MethodsDropdownProps) => { setAnchorEl(null) } - const onMethodSelectedChanged = (chosenMethod: MethodInterface) => { + const onMethodSelectedChanged = (chosenMethod: AbiItem) => { setSelectedMethod(chosenMethod) onChange(chosenMethod) handleClose() diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderInputParams/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderInputParams/index.tsx index 1aa97926..f28d4202 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderInputParams/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderInputParams/index.tsx @@ -10,10 +10,10 @@ import Row from 'src/components/layout/Row' const RenderInputParams = () => { const { meta: { valid: validABI }, - } = useField('abi', { value: true }) + } = useField('abi', { subscription: { valid: true, value: true } }) const { input: { value: method }, - }: any = useField('selectedMethod', { value: true }) + }: any = useField('selectedMethod', { subscription: { value: true } }) const renderInputs = validABI && !!method && method.inputs.length return !renderInputs diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderOutputParams/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderOutputParams/index.tsx index 2f728580..1e637d37 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderOutputParams/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/RenderOutputParams/index.tsx @@ -9,10 +9,10 @@ import Row from 'src/components/layout/Row' const RenderOutputParams = () => { const { input: { value: method }, - }: any = useField('selectedMethod', { value: true }) + }: any = useField('selectedMethod', { subscription: { value: true } }) const { input: { value: results }, - }: any = useField('callResults', { value: true }) + }: any = useField('callResults', { subscription: { value: true } }) const multipleResults = !!method && method.outputs.length > 1 return results ? ( diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils/index.ts b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils/index.ts index 2c961591..c63667f7 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils/index.ts +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils/index.ts @@ -1,9 +1,11 @@ import { FORM_ERROR } from 'final-form' import createDecorator from 'final-form-calculate' +import { AbiItem } from 'web3-utils' 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 { getWeb3 } from 'src/logic/wallets/getWeb3' export const NO_CONTRACT = 'no contract' @@ -60,7 +62,7 @@ export const handleSubmitError = (error, values) => { return { [FORM_ERROR]: error.message } } -export const createTxObject = (method, contractAddress, values) => { +export const createTxObject = (method: AbiItem, contractAddress: string, values) => { const web3 = getWeb3() const contract: any = new web3.eth.Contract([method], contractAddress) const { inputs, name } = method @@ -69,4 +71,4 @@ export const createTxObject = (method, contractAddress, values) => { return contract.methods[name](...args) } -export const isReadMethod = (method: any) => method && method.action === 'read' +export const isReadMethod = (method: AbiItemExtended): boolean => method && method.action === 'read' diff --git a/yarn.lock b/yarn.lock index 26515e8a..22e88e7b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17146,7 +17146,7 @@ web3-utils@1.2.1: underscore "1.9.1" utf8 "3.0.0" -web3-utils@1.2.8, web3-utils@^1.2.7: +web3-utils@1.2.8, web3-utils@^1.2.7, web3-utils@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.8.tgz#5321d91715cd4c0869005705a33c4c042a532b18" integrity sha512-9SIVGFLajwlmo5joC4DGxuy2OeDkRCXVWT8JWcDQ+BayNVHyAWGvn0oGkQ0ys14Un0KK6bjjKoD0xYs4k+FaVw==