You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Substrate Ink中获取类似Solidity tx.origin的对应值?

问题

我正在开发一套跨合约调用的合约体系:当用户Alice通过合约A调用合约B时,希望在合约B中识别出发起这次调用的原始用户是Alice。但目前在合约B中使用let caller = self.env().caller();获取到的是合约A的地址,想知道在ink!合约中有没有类似Solidity里tx.origin的对应方法可以获取原始交易发起者?

回答
  • ink! 原生不提供与Solidity tx.origin完全等价的API。这是因为Substrate生态的合约设计更注重调用链的安全性,tx.origin这类直接暴露原始发起者的机制存在被钓鱼攻击利用的风险,因此默认不支持这类原生获取方式。
  • 有两种可行的替代方案:
    1. 主动传递原始调用者地址
      这是最安全可控的方式:在合约A调用合约B时,先获取自己的直接调用者(也就是Alice),再将该地址作为参数传递给合约B的调用方法。
      合约A中的调用代码示例:
      #[ink(message)]
      pub fn call_contract_b(&mut self) {
          let original_caller = self.env().caller(); // 获取Alice的地址
          // 调用合约B的目标方法并传入原始调用者地址
          contract_b::contract::Call::target_function(original_caller)
              .call()
              .expect("调用合约B失败");
      }
      
      合约B中接收并使用的代码示例:
      #[ink(message)]
      pub fn target_function(&mut self, original_caller: AccountId) {
          // 这里的original_caller就是发起交易的Alice
          // 可根据需求进行验证或业务逻辑处理
      }
      
    2. 通过调用栈获取原始发起者
      ink!的Env提供了call_stack()方法,该方法会返回整个调用链的账户序列,从最顶层的交易发起者开始,依次到直接调用当前合约的账户。对于Alice→合约A→合约B的调用链,在合约B中调用call_stack()会得到包含[Alice, 合约A地址]的列表,取第一个元素即可得到原始发起者。
      代码示例:
      #[ink(message)]
      pub fn get_original_caller(&self) -> AccountId {
          let call_stack = self.env().call_stack();
          // 正常交易场景下调用栈至少包含一个元素,即原始发起者
          call_stack.first().cloned().unwrap_or_default()
      }
      
      注意:这种方式依赖调用链的完整性,且同样存在类似tx.origin的安全风险,除非必要,优先推荐第一种方案。

内容的提问来源于stack exchange,提问作者s.Takahashi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:19:02