实现一个合约请求工具

demo地址

https://web03-1252477692.cos.ap-guangzhou.myqcloud.com/utils/eth-contract-request/index.html

实现

import React, {
    
    useMemo, useState} from 'react'
import {
    
    config, Contract,ChainId, multicallClient} from "@chainstarter/multicall-client.js";
import {
    
    Button, Card, Form, Input, message, Select} from "antd";
import {
    
    useConnectWallet} from "../../connectors";
import {
    
    useWeb3React} from "@web3-react/core";
import {
    
    InjectedConnector} from "@web3-react/injected-connector";
import {
    
    getContract} from "../../utils";
import ERC721Abi from "../../ABI/ERC721.json";
import ERC20Abi from "../../ABI/erc20.json";
import ERC1155Abi from "../../ABI/ERC1155.json";

import {
    
     Radio, Collapse } from 'antd';
import './index.css'
import {
    
    cloneDeep} from "lodash";
import web3 from "web3";
import axios from "axios";
const {
    
     Panel } = Collapse;
const {
    
     TextArea } = Input;
config({
    
    
  defaultChainId: ChainId.MATIC,
  allowFailure: false,
})
export const formatAddress = address => address.slice(0, 6) + '...' + address.slice(-3)

export default function MulticallClient(){
    
    
  const [chain, setChain] = useState(ChainId.BSC)
  const connectWallet = useConnectWallet()
  const {
    
    account, deactivate, library} = useWeb3React()
  const [contractAddress, setContractAddress] = useState('')
  const [abi, setAbi] = useState([])
  const [abiStr, setAbiStr] = useState("")
  const [readAbi, setReadAbi] = useState([])
  const [writeAbi, setWriteAbi] = useState([])
  const [mode, setMode] = useState('read') // read write

  const getAbiApi = () => {
    
    
    const contractAddress_ = contractAddress.toLowerCase()
    return {
    
    
      [ChainId.BSC] : `https://api.hecoinfo.com/api?module=contract&action=getabi&address=${
      
      contractAddress_}&apikey=YourApiKeyToken`,//去相关区块浏览器注册账号获得YourApiKeyToken
      [ChainId.HECO] : `https://api.hecoinfo.com/api?module=contract&action=getabi&address=${
      
      contractAddress_}d&apikey=YourApiKeyToken`,
      [ChainId.ETH] : `https://api.etherscan.io/api?module=contract&action=getabi&address=${
      
      contractAddress_}&apikey=YourApiKeyToken`,
      [ChainId.MATIC]: `https://api.polygonscan.com/api?module=contract&action=getabi&address=${
      
      contractAddress_}&apikey=YourApiKeyToken`
    }[chain]
  }
  const getAbi = () => {
    
    
    if (!web3.utils.isAddress(contractAddress)) {
    
    
      return alert("请输入正确的合约地址")
    }
    axios.get(getAbiApi()).then(res => {
    
    
      try {
    
    
        const abi_ = JSON.parse(res.data.result)
        if (Array.isArray(abi_))
        setAbi(abi_)
      } catch (e){
    
    

      }
    })
  }


  useMemo(() => {
    
    
    const readAbi_ = []
    const writeAbi_ = []
    for (let i = 0; i < abi.length; i++) {
    
    
      if (abi[i].type === 'function') {
    
    
        if (abi[i].stateMutability === 'view') {
    
    
          readAbi_.push(abi[i])
        } else {
    
    
          writeAbi_.push(abi[i])
        }
      }
    }
    setReadAbi(readAbi_)
    setWriteAbi(writeAbi_)
  }, [abi])

  useMemo(() => {
    
    
    if (!abiStr){
    
    
      setAbi([])
    } else {
    
    
      try {
    
    
        const abi_ = JSON.parse(abiStr)
        if (Array.isArray(abi_))
          setAbi(abi_)
      }catch (e){
    
    

      }
    }
  }, [abiStr])

  const onConnectWallMetaMask = () => {
    
    
    const supportedChainIds = []
    for (let i in ChainId) {
    
    
      supportedChainIds.push(ChainId[i])
    }
    connectWallet(new InjectedConnector({
    
    
      supportedChainIds,
    }), chain).then((res) => {
    
    

    })
  }
  const changeAbi = (e) => {
    
    
    setAbiStr(e.target.value)
  }
  const changeChain = (e) => {
    
    
    setChain(e)
    deactivate()
  }

  const onQuery = (params, method) => {
    
    
    console.log(params, method)
    if (!web3.utils.isAddress(contractAddress)) {
    
    
      return alert("请输入正确的合约地址")
    }
    const params_ = []
    for (const key in params) {
    
    
      params_.push(params[key])
    }
    const contract = new Contract(abi, contractAddress, chain)
    multicallClient([contract[method](...params_)]).then(res => {
    
    
      console.log(res)
      const readAbi_ = cloneDeep(readAbi)
      for (let i = 0; i < readAbi_.length; i++) {
    
    
        if (readAbi_[i].name === method) {
    
    
          readAbi_[i].result = typeof res[0] === 'object' ? JSON.stringify(res[0]) : res[0]
          setReadAbi(readAbi_)
          return
        }
      }
    })
  }

  const onWrite = (params, method) => {
    
    
    if (!web3.utils.isAddress(contractAddress)) {
    
    
      return alert("请输入正确的合约地址")
    }
    if (!account) {
    
    
      return alert("请连接钱包")
    }
    const contract = getContract(library, abi, contractAddress)
    const params_ = []
    for (const key in params) {
    
    
      params_.push(params[key])
    }
    contract.methods[method](...params_)
      .send({
    
    
        from: account
      })
      .on('receipt', async (_, receipt) => {
    
    
        message.success('success')
      })
      .on('error', (err, receipt) => {
    
    

      })
  }

  const selectAbi = (abi_) => {
    
    
    setAbi(abi_)
    setAbiStr(JSON.stringify(abi_))
  }
  return (
    <div className="contract-show-page">
      <div className="contract-show-box">
        <Select defaultValue={
    
    chain} style={
    
    {
    
    width: 180}} onChange={
    
    changeChain}>
          <Select.Option value={
    
    ChainId.BSC}>BSC({
    
    ChainId.BSC})</Select.Option>
          <Select.Option value={
    
    ChainId.ETH}>ETH({
    
    ChainId.ETH})</Select.Option>
          <Select.Option value={
    
    ChainId.MATIC}>MATIC({
    
    ChainId.MATIC})</Select.Option>
          <Select.Option value={
    
    ChainId.HECO}>HECO({
    
    ChainId.HECO})</Select.Option>
        </Select>
        <p style={
    
    {
    
    margin: '20px 0 0 0'}}>合约地址:</p>
        <div className="contract-address-input"><Input value={
    
    contractAddress} onInput={
    
    (e) => setContractAddress(e.target.value)}/>  <Button onClick={
    
    getAbi}>getAbi</Button></div>

        <p>ABI: <TextArea rows={
    
    5} value={
    
    abiStr} onInput={
    
    changeAbi}/></p>
        <div className="def-abi-btn">
          <span>选择&nbsp;</span>
          <Button size="small" onClick={
    
    () => selectAbi(ERC20Abi)}>ERC20</Button>
          <Button size="small" onClick={
    
    () => selectAbi(ERC721Abi)}>ERC721</Button>
          <Button size="small" onClick={
    
    () => selectAbi(ERC1155Abi)}>ERC1155</Button>
        </div>
        {
    
    
          abi.length > 0 && (
            <>
              <Radio.Group onChange={
    
    e => setMode(e.target.value)} value={
    
    mode} style={
    
    {
    
     marginBottom: 8 }} optionType="button"
                           buttonStyle="solid">
                <Radio.Button value="read">Read</Radio.Button>
                <Radio.Button value="write">Write</Radio.Button>
              </Radio.Group>
              {
    
    
                mode === 'read' && (
                  <div>
                    <Collapse >
                      {
    
    
                        readAbi.map((item, index) => (
                          <Panel header={
    
    item.name} key={
    
    index}>
                            <Form
                              name="basic"
                              labelCol={
    
    {
    
     span: 8 }}
                              wrapperCol={
    
    {
    
     span: 16 }}
                              initialValues={
    
    {
    
     remember: true }}
                              onFinish={
    
    (e) => onQuery(e, item.name)}
                              autoComplete="off"
                            >
                              {
    
    
                                item.inputs.map((it, idx) => (
                                  <div style={
    
    {
    
    marginBottom: '10px'}} key={
    
    idx}>
                                    <p>{
    
    it.name}({
    
    it.type})</p>
                                    <Form.Item name={
    
    idx} valuePropName="value" required>
                                      <Input ploceholder={
    
    `${
      
      it.name}(${
      
      it.type})`}/>
                                    </Form.Item>
                                  </div>
                                ))
                              }
                              <Button htmlType="submit">Query</Button>
                              {
    
    item.result && <p>{
    
    item.result}</p>}
                            </Form>
                          </Panel>
                        ))
                      }
                    </Collapse>
                  </div>
                )
              }
              {
    
    
                mode === 'write' && (
                  <div>
                    {
    
    
                      !account ? (
                        <Button type="dashed" onClick={
    
    onConnectWallMetaMask} danger>连接钱包</Button>
                      ) : <p style={
    
    {
    
    color: '#1890FF'}}>已连接:{
    
    formatAddress(account)}</p>
                    }
                    <Collapse>
                      {
    
    
                        writeAbi.map((item, index) => (
                          <Panel header={
    
    item.name} key={
    
    index}>
                            <Form
                              name="basic"
                              labelCol={
    
    {
    
     span: 8 }}
                              wrapperCol={
    
    {
    
     span: 16 }}
                              initialValues={
    
    {
    
     remember: true }}
                              onFinish={
    
    (e) => onWrite(e, item.name)}
                              autoComplete="off"
                            >
                              {
    
    
                                item.inputs.map((it, idx) => (
                                  <div style={
    
    {
    
    marginBottom: '10px'}} key={
    
    idx}>
                                    <p>{
    
    it.name}({
    
    it.type})</p>
                                    <Form.Item required name={
    
    idx} valuePropName="value">
                                      <Input ploceholder={
    
    `${
      
      it.name}(${
      
      it.type})`}/>
                                    </Form.Item>
                                  </div>
                                ))
                              }
                              <Button htmlType="submit" type="primary">Write</Button>
                              {
    
    item.result && <p>{
    
    item.result}</p>}
                            </Form>
                          </Panel>
                        ))
                      }
                    </Collapse>
                  </div>
                )
              }
            </>
          )
        }
      </div>
    </div>
  )
}

在一些没认证的合约,区块链浏览器不显示,但是知道它的abi的话,通过此工具调用是很不错的

猜你喜欢

转载自blog.csdn.net/weixin_43840202/article/details/122697986