如何在TON区块链的FunC中调用其他合约函数获取数据?
在FunC中调用其他TON智能合约获取数据的实现方法
TON智能合约之间的交互是异步的,无法在当前合约的recv_internal流程里直接同步获取其他合约的数据。你需要先向目标合约发送调用消息,等待对方将结果通过回调消息返回后,再在自己的合约里处理回调数据推进流程。以下是具体实现步骤和代码示例:
1. 构造并发送调用目标合约的消息
明确目标合约的地址、调用的函数名和参数,打包成消息体发送给对方。替换你代码中的TODO部分:
() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { if (in_msg_body.slice_empty?()) { ;; 忽略空消息 return (); } slice cs = in_msg_full.begin_parse(); int flags = cs~load_uint(4); if (flags & 1) { ;; 忽略所有 bounced 消息 return (); } slice sender_address = cs~load_msg_addr(); ;; -------------------------- ;; 调用其他合约的核心代码 ;; -------------------------- ;; 1. 定义目标合约地址(替换成实际地址) slice target_contract = parse_std_addr("EQ..."); ;; 2. 构造调用消息体:指定要调用的函数名和参数 cell call_body = begin_cell() .store_uint(0x18, 6) ;; 内部消息的opcode .store_slice("get_data") ;; 要调用的目标合约函数名 .store_uint(123, 32) ;; 传递给目标函数的参数(示例:32位整数) .end_cell(); ;; 3. 发送内部消息,附带足够的gas(这里用0.01TON作为手续费,可调整) send_raw_message( begin_cell() .store_uint(0, 2) ;; 消息类型:内部消息 .store_slice(target_contract) ;; 目标地址 .store_coins(10000000) ;; 附带的TON(0.01TON) .store_uint(0, 1+4+4+64+32) ;; 消息标志、过期时间等默认值 .store_slice(call_body.begin_parse()) .end_cell(), 64 ;; 发送模式:忽略错误,不要求回执 ); }
2. 处理目标合约的回调消息
目标合约处理完调用后,需要主动发送回调消息回来。在recv_internal中添加逻辑,识别回调消息并解析数据:
() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { if (in_msg_body.slice_empty?()) { return (); } slice cs = in_msg_full.begin_parse(); int flags = cs~load_uint(4); if (flags & 1) { return (); } slice sender_address = cs~load_msg_addr(); ;; 解析消息体,判断是否是目标合约的回调 slice body = in_msg_body; int op = body~load_uint(6); if (op == 0x18) { ;; 匹配内部消息opcode slice func_name = body~load_string(); if (func_name == "callback_data") { ;; 匹配回调函数名 ;; 解析目标合约返回的数据(示例:32位整数) int returned_data = body~load_uint(32); ;; -------------------------- ;; 这里用返回的数据推进后续流程 ;; 比如更新合约状态、触发其他逻辑等 ;; -------------------------- ;; 示例:打印日志(测试用,主网可移除) print("Received data from target contract: ", returned_data); return; } } ;; 原有的调用目标合约逻辑(保留) slice target_contract = parse_std_addr("EQ..."); cell call_body = begin_cell() .store_uint(0x18, 6) .store_slice("get_data") .store_uint(123, 32) .end_cell(); send_raw_message( begin_cell() .store_uint(0, 2) .store_slice(target_contract) .store_coins(10000000) .store_uint(0, 1+4+4+64+32) .store_slice(call_body.begin_parse()) .end_cell(), 64 ); }
关键注意事项
- Gas费用:发送消息时必须附带足够的TON作为手续费,否则消息会执行失败。
- 回调验证:要验证回调消息的发送者确实是目标合约,防止恶意伪造消息干扰合约逻辑。
- 异步特性:合约间调用是异步的,不能依赖立即获取结果,必须提前设计好回调处理流程。
- 只读方法查询:如果只是查询目标合约的只读数据(不修改状态),可以在链下通过
get_method接口查询,不需要合约间发送消息。
内容的提问来源于stack exchange,提问作者Tho Bui Ngoc
相关产品推荐
相关产品推荐

