处理来自 nearlib 的账户和交易签名

Handling accounts and transaction signatures from nearlib

我有一份名为 exchange 的合同。用户 Bob 想要花费 near tokens 通过放置 Order 的方式购买 markets 中的位置。 Order 有一个名为 owner 的字段,在这种情况下 Bob,合同必须证明某个 order 属于某个地址,这一点很重要。

目前如何处理发送至 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 合约导入了一个名为 Orderstruct

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 order 的合约。 Exchangeplace_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() 将始终 return exchange 作为 current_account_id。这是有道理的,因为所有登录所做的就是创建一个 access_key,它允许 exchangeBob 的名义做一些事情,但它仍然是 Exchange 签署交易.

这里的问题是:我如何确保交易所知道 Bob 是发起交易的人?

一种有意义的工作方式:

这会导致类似 Metamask 的 UX 问题,其中在每个 tx 上签名都是糟糕的 UX。

我的建议如下:

简答

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

详情

在你的情况下,即使通过指向 exchange 的访问密钥,它仍然由 bob. Thesigner_idand thepredecessor_id[=14= 签名]鲍勃`.

执行过程中有3种不同类型的账户:

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