首页 > 解决方案 > 处理来自 nearlib 的账户和交易签名

问题描述

我有一份合同叫做exchange. 用户Bob想要通过放置 的方式花钱near tokens购买头寸。 有一个名为 的字段,在这种情况下,合约必须证明某个地址归某个地址所有,这一点很重要。marketsOrderOrderownerorderBob

当前处理发送到exchange的事务的流程类似于:

const init = async () => {
  this.near = await window.nearlib.connect(Object.assign({ deps: { keyStore: new window.nearlib.keyStores.BrowserLocalStorageKeyStore() } }, window.nearConfig));
  this.walletAccount = new window.nearlib.WalletAccount(this.near);

  this.accountId = this.walletAccount.getAccountId();
  this.exchange = await this.near.loadContract(window.nearConfig.contractName, {
    viewMethods: [],
    changeMethods: ["place_new_order"],
    sender: this.accountId,
  });
}

await init();

// Bob logs into to near 
this.walletAccount.requestSignIn(
  window.nearConfig.contractName,
  window.nearConfig.contractName,
);

// Login process 
[...]

// Bob wants to place a new order
this.exchange.place_new_order(price, amount);

exchange合约导入一个struct被调用的Order.

Order看起来像:

use std::string::String;
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, BorshDeserialize, BorshSerialize, Clone)]
pub struct Order {
    pub owner: String,
    pub amount: u64,
    pub price: u64,
}


impl Order {
    pub fn new(owner: String, amount: u64, price: u64) -> Self {
        Order {
            owner,
            amount,
            price
        }
    }
}

Exchange在这种情况下,是实现 mod 的合约orderExchangeplace_new_order一种方法,我希望能够确保这Bob是发送交易的人:

  use near_bindgen::{near_bindgen, env};

  [...]

  mod Order;

  [...]

  pub fn place_new_order(&mut self, amount: u64, price: u64) {
    // Stuff happens here
    let order = Order::new(env::current_account_id(), amount, price);
    // Stuff happens here
  }

现在的问题是,以防万一,使用这个 nearlib 代码env::current_account_id()将始终返回exchangecurrent_account_id. 这是有道理的,因为所有登录所做的只是创建一个access_key允许exchange以 的名义做几件事,Bob但它仍在Exchange签署交易。

这里的问题是:我如何确保该交易所知道那Bob是初始化交易的人?

一种可行的方法是有意义的:

这将导致类似 Metamask 的 UX 问题,在每个 tx 上签名都是错误的 UX。

我建议如下:

标签: nearprotocol

解决方案


简短的回答

您应该使用env::predecessor_account_id()来获取在交换中调用方法的用户或合约的帐户 ID。

细节

在您的情况下,即使通过指向exchange它的访问密钥点仍然由bob. Thesigner_idand the前辈during the execution are both going to be_id bob`签名。

执行期间有 3 种不同类型的帐户:

  • env::current_account_id()返回当前正在执行的合约的当前账户 ID。
  • env::signer_account_id()返回签署原始交易的用户的帐户 ID。大多数时候你不应该依赖签名者帐户 ID,因为当前调用可以从另一个合约完成。
  • env::predecessor_account_id()返回调用当前合约的直接前任的帐户 ID。您应该使用它来验证呼叫您的用户的身份。

推荐阅读