上一次的交互是只读的,现在通过发送交易来与合约进行交互。
合约上开发的第一个功能是计数器。在主界面上添加一个按钮来发送这笔交易,发送链上交易会花费Gas费,因此我们需要钱包向用户确认并显示这将花费多少TON币。
在开始之前,添加一个钩子,用于从TON Connect接口生成一个发送者对象。这个发送者代表已连接的钱包,并允许我代表其发送交易。
处理这个交易请求时,我还会在UI中显示钱包连接状态,这样UI可以隐藏需要授权的元素。
像之前的一样,使用React钩子来保持一些功能,以便在代码中使用。
创建文件src/hooks/useTonConnect.ts,内容如下:
import { useTonConnectUI } from '@tonconnect/ui-react'; import { Sender, SenderArguments } from 'ton-core'; export function useTonConnect(): { sender: Sender; connected: boolean } { const [tonConnectUI] = useTonConnectUI(); return { sender: { send: async (args: SenderArguments) => { tonConnectUI.sendTransaction({ messages: [ { address: args.to.toString(), amount: args.value.toString(), payload: args.body?.toBoc().toString('base64'), }, ], validUntil: Date.now() + 5 * 60 * 1000, // 用户有5分钟的时间来批准 }); }, }, connected: tonConnectUI.connected, }; }
可以看到返回了一个对象,其中包含一个发送函数,用于触发交易请求,以及一个存储当前连接状态的connected参数。
接下来,改进现有的useCounterContract钩子,增加两个小功能:
- 每5秒自动轮询一次计数器值。这将有助于显示值确实已更改。
- 暴露接口类的sendIncrement并将其连接到发送者。
需要更新代码的一些内容:
// ... 之前的导入 import { toNano } from "ton-core"; import { useTonConnect } from "./useTonConnect"; export function useCounterContract() { // ... 变量定义 const { sender } = useTonConnect(); const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time)); // ... mainContract定义 useEffect(() => { async function getValue() { // ... 之前的getValue代码 await sleep(5000); // 睡眠5秒钟并再次轮询值 getValue(); } getValue(); }, [counterContract]); return { value: val, address: counterContract?.address.toString(), sendIncrement: () => { return mainContract?.sendIncrement(sender, toNano(0.05), 3); }, }; }
现在更新UI即可触发所需的交易。在UI中添加两项内容:
// ... 之前的导入 import { useTonConnect } from "./hooks/useTonConnect"; function App() { const { ..., sendIncrement } = useMainContract(); const { connected } = useTonConnect(); return ( // ... 其他HTML代码 {connected && ( <a onClick={() => { sendIncrement(); }} > Increment </a> )} // ... 其他HTML代码 ) }
一切就绪,发送增量交易的功能已经可以正常工作了。