5 useWriteContract 有 writeContractAsync,useWaitForTransactionReceipt 有类似的,可以 wait 的 component 么?

比如在代码 https://github.com/linghuccc/multi-call-test/blob/main/src/App.tsx 中,
先完成 action 1,然后再执行 action 2。

在实践中,执行 action 1 的时候, await writeContractAsync 只能保证 startDelay transaction 已经 send 了,而 startDelay 这个 function 在链上执行需要一定时间,await writeContractAsync 并不能保证这个 transaction 已经完成了,所以在执行第二步 doSomething 的时候,有时会出错。

所以我想,如果 useWaitForTransactionReceipt 有类似的 component,就可以 await 它,确定 approve transaction 已经完成了,再执行下一步。

请先 登录 后评论

最佳答案 2024-11-23 11:43

将等待交易确认的逻辑移到组件的最顶层,或者使用另一个自定义的Hooks来封装这个逻辑

  const [action1Hash, setAction1Hash] = useState<string | null>(null);
  const [action2Hash, setAction2Hash] = useState<string | null>(null);

  const { writeAsync: writeContractAsync } = useWriteContract({
    abi: contractAbi,
    address: contractAddress,
  });

  const { isLoading: isAction1Loading, isSuccess: isAction1Success } = useWaitForTransactionReceipt({
    hash: action1Hash,
  });

  const { isLoading: isAction2Loading, isSuccess: isAction2Success } = useWaitForTransactionReceipt({
    hash: action2Hash,
  });
请先 登录 后评论

其它 2 个回答

Wade - Footprint Analytics CTO
  擅长:数据分析,GameFi,NFT

await writeContractAsync 只能保证交易已经被发送到区块链网络,但并不能保证交易已经被矿工确认并完成。为了确保 startDelay 函数在链上执行完成后再执行 doSomething,
可以在 action1 函数中使用它来等待 startDelay 交易的完成。

async function action1() {
  try {
    // 执行一些异步操作
    const action1Tx = await writeContractAsync({
      abi: contractAbi,
      address: contractAddress,
      functionName: 'startDelay',
      args: [BigInt(10)],
    });

    console.log('Action 1 hash:', action1Tx);

    // 等待交易完成
    await waitForTransaction(action1Tx.hash);

    return Promise.resolve('Action 1 completed');
  } catch (error) {
    console.error('An error occurred in action1:', error);
    throw error; // 重新抛出错误,以便在 handleClick 中捕获
  }
}

// 使用 useWaitForTransactionReceipt 钩子来等待交易完成
async function waitForTransaction(hash: string) {
  const { isLoading, isSuccess } = useWaitForTransactionReceipt({
    hash,
  });

  // 等待交易成功
  if (isLoading) {
    return new Promise<void>((resolve, reject) => {
      const unsubscribe = useWaitForTransactionReceipt(hash, {
        onSettled: (receipt) => {
          if (receipt) {
            resolve();
          } else {
            reject(new Error('Transaction failed or was not confirmed'));
          }
          unsubscribe();
        },
      });
    });
  }

  if (!isSuccess) {
    throw new Error('Transaction failed or was not confirmed');
  }
}

为了在组件中正确使用 useWaitForTransactionReceipt,需要创建一个新的状态来跟踪第一个交易的确认状态,并在该状态更新后执行第二个操作

function App() {
  // ... 其他状态和钩子

  const [action1Completed, setAction1Completed] = useState(false);

  // ... action1 和 action2 函数

  // 使用 useWaitForTransactionReceipt 钩子来等待 action1 的交易完成
  useWaitForTransactionReceipt({
    hash: data,
    onSuccess: () => {
      setAction1Completed(true);
    },
  });
请先 登录 后评论
Ric Li C

useWaitForTransactionReceipt 的用法不对

error1.png

请先 登录 后评论
  • 2 关注
  • 1 收藏,844 浏览
  • Ric Li C 提出于 2024-11-21 09:59