在以太坊智能合约中,异常处理是一个非常重要的问题,因为任何一个函数调用都有可能导致异常。常见的异常包括函数调用失败、无效参数、内部错误等。

在Solidity中,可以使用require、assert和revert等关键字来处理异常。这些关键字可以用于检查输入参数、状态变量和函数调用的返回值,并在发生异常时抛出异常。

今天我们主要从前端的角度来进行异常处理,这样可以保证我们交互的正常进行。

1、工程目录划分,更好的管理我们web3脚本

让我们的代码更加清晰明了

  • web3中与智能合约交互使用的是ABI,他是我们和智能合约交互的通道,可以将ABI通过命名统一管理,方便后续维护;
  • 在与智能合约交互的过程中,需要调用ABI的接口,以及通过web3.js/ethers.js等web3的一些库进行钱包连接,获取地址等操作,可以将其放入web3的文件夹中进行统一管理。

ABI(ApplicationBinary Interface)是一种接口规范,用于描述不同模块之间的通信方式和数据格式。在以太坊智能合约中,ABI 用于描述智能合约的接口,包括合约地址、函数名、函数参数和返回值等。

2、前端在合约交互中的异常处理

在web3的脚本中,我们需要通过try{} catch {}将异常抛出,常见的异常情况包含:

  • 钱包连接异常;
  • 区块链交互付费过程中拒绝支付;
  • rpc不对,交互异常;
  • 调用合约报错(不存在方法、传参不对等);
  • 还有很多很多……

3、以下是一些常见的异常处理方式

3.1、try{}catch {}捕获抛出异常

/*** 域名是否可注册* @param domainName domainName without .bnb* @returns boolean, if no error*/ static async isDomainAvailable(domainName: String): Promise {try {const isAvailable = await BnbDomainUtils.registrarControllerContractReadOnly.available(domainName)return isAvailable} catch (error) {console.log(error);return false}}

3.2、检查交易是否成功

在向智能合约发送交易时,需要检查交易是否成功。可以使用 Web3.js 提供的send方法,该方法会返回一个 Promise 对象,可以在then方法中获取交易的哈希值,并在catch方法中处理异常。

myContract.methods.myFunction().send({ from: myAddress }).then((receipt) => {// 处理交易成功的情况}).catch((error) => {// 处理交易失败的情况});

3.3、捕获智能合约函数调用异常

在调用智能合约的函数时,可能会出现异常,例如传入的参数无效、状态不满足要求等。可以使用 Web3.js 提供的 call 方法,该方法会返回一个 Promise 对象,可以在 then 方法中获取函数的返回值,并在 catch 方法中处理异常。

myContract.methods.myFunction(myArg).call().then((result) => {// 处理函数调用成功的情况}).catch((error) => {// 处理函数调用失败的情况});

3.4、处理 MetaMask 异常

在使用 MetaMask 与智能合约交互时,可能会出现用户未授权、交易被拒绝等异常。可以使用 MetaMask 提供的ethereum对象,该对象包含了与钱包交互的 API。

if (window.ethereum) {try {await window.ethereum.enable();// 处理用户已授权的情况} catch (error) {// 处理用户未授权的情况}} else {// 处理用户未安装 MetaMask 的情况}

3.5、使用事件监听器

在智能合约中,可以使用事件来通知前端某些状态的变化。可以在智能合约中定义事件,然后在前端使用 Web3.js 监听事件的触发。

通过使用事件监听器,前端可以实时获取智能合约的状态变化,从而更加及时地处理异常情况。

// Solidity 中定义事件event Transfer(address indexed from, address indexed to, uint256 value);// 前端中监听事件myContract.events.Transfer().on('data', (event) => {// 处理事件触发的情况}).on('error', (error) => {// 处理事件监听失败的情况});

3.6、限制交易的 gas 量

在向智能合约发送交易时,可以指定交易的 gas 量。如果 gas 不足,交易会失败,并回滚交易。可以在前端限制交易的 gas 量,从而确保交易能够成功执行。

通过限制交易的 gas 量,前端可以避免交易失败的情况。

const gasLimit = 250000;myContract.methods.myFunction().send({ from: myAddress, gas: gasLimit }).then((receipt) => {// 处理交易成功的情况}).catch((error) => {// 处理交易失败的情况});

3.7、处理网络异常

在与智能合约交互时,可能会遇到网络异常,例如网络延迟、断开等。可以在前端使用 Web3.js 提供的setProvider方法设置网络 provider,从而确保交互的稳定性。

通过设置网络 provider,前端可以避免网络异常的情况。

// 1、使用web3const provider = new Web3.providers.HttpProvider('https://ropsten.infura.io/v3/YOUR-PROJECT-ID');const web3 = new Web3(provider);// 2、使用ethersconst provider = new ethers.providers.JsonRpcProvider(process.env.READ_ONLY_RPC)new ethers.Contract(contractAddress,Abi,provider)

总之,在与智能合约交互时,需要仔细处理异常,以保证交易的正确性和可靠性。可以使用 Web3.js 和 MetaMask 提供的 API 来处理异常。