目前为止已经实现了终端用户授权以与合约交互的功能。
现在,将实际连接之前部署的合约。
为确保操作顺利,请注意以下几点:
- 使用testnet。确保你已将合约部署到testnet。
- 确保在使用正确的初始数据部署合约,包括:
- 计数器值
- 最近的发送者地址
- 拥有者地址(必须是你活跃的testnet钱包地址,因为进行取款操作,合约逻辑会拒绝非拥有者的取款尝试)。
- 确保拥有testnet的测试币。
我的合约地址如下:
EQCS7PUYXVFI-4uvP1_vZsMVqLDmzwuimhEPtsyQKIcdeNPu
在编写测试时,我已经与合约进行了一些交互。创建了一个包装文件,帮助发送内部消息并运行getter方法,可以使用相同的包装文件。
在src文件夹中创建contracts文件夹,并复制之前章节中的wrappers/MainContract.ts文件内容。
现在有了合约的包装器,如何从浏览器实际连接链上合约?使用ton-access RPC提供者从链上检索信息并发送请求给我们的合约。
在开始之前先实现一个通用的React钩子,帮助我们初始化异步对象并用它连接TonClient。
创建文件src/hooks/useAsyncInitialize.ts,内容如下:
import { useEffect, useState } from "react"; export function useAsyncInitialize<T>( func: () => Promise<T>, deps: any[] = [] ) { const [state, setState] = useState<T | undefined>(); useEffect(() => { (async () => { setState(await func()); })(); }, deps); return state; }
接下来,创建另一个React钩子useTonClient(),它将依赖useAsyncInitialize并在我们的应用中初始化RPC客户端。我使用TON Access提供无速率限制的免费API访问,这也是首选的去中心化访问方式。
创建文件src/hooks/useTonClient.ts,内容如下:
import { getHttpEndpoint } from '@orbs-network/ton-access'; import { TonClient } from 'ton'; import { useAsyncInitialize } from './useAsyncInitialize'; export function useTonClient() { return useAsyncInitialize( async () => new TonClient({ endpoint: await getHttpEndpoint({ network: 'testnet' }), }) ); }
再创建一个钩子useMainContract(),接受一个已部署合约的链上地址并运行getter方法(通过我们的包装器的.getData()方法)。
此钩子的代码如下:
import { useEffect, useState } from "react"; import { MainContract } from "../contracts/MainContract"; import { useTonClient } from "./useTonClient"; import { useAsyncInitialize } from "./useAsyncInitialize"; import { Address, OpenedContract } from "ton-core"; export function useMainContract() { const client = useTonClient(); const [contractData, setContractData] = useState<null | { counter_value: number; recent_sender: Address; owner_address: Address; }>(); const mainContract = useAsyncInitialize(async () => { if (!client) return; const contract = new MainContract( Address.parse("EQCS7PUYXVFI-4uvP1_vZsMVqLDmzwuimhEPtsyQKIcdeNPu") // 替换为你的合约地址 ); return client.open(contract) as OpenedContract<MainContract>; }, [client]); useEffect(() => { async function getValue() { if (!mainContract) return; setContractData(null); const val = await mainContract.getData(); setContractData({ counter_value: val.number, recent_sender: val.recent_sender, owner_address: val.owner_address, }); } getValue(); }, [mainContract]); return { contract_address: mainContract?.address.toString(), ...contractData, }; }
现在可以在界面上展示从链上读取的数据了。更新src/App.tsx文件:
import "./App.css"; import { TonConnectButton } from "@tonconnect/ui-react"; import { useMainContract } from "./hooks/useMainContract"; function App() { const { contract_address, counter_value, recent_sender, owner_address, contract_balance, } = useMainContract(); return ( <div> <div> <TonConnectButton /> </div> <div> <div className='Card'> <b>Our contract Address</b> <div className='Hint'>{contract_address?.slice(0, 30) + "..."}</div> <b>Our contract Balance</b> <div className='Hint'>{contract_balance}</div> </div> <div className='Card'> <b>Counter Value</b> <div>{counter_value ?? "Loading..."}</div> </div> </div> </div> ); } export default App;
到此为止已经可以从链上读取合约的数据了。即使没有使用TON Connect授权也能读取,因为这是只读操作,只有在需要执行写操作时才需要授权。