dApps 的签名供应商
原文:https://docs.elrond.com/sdk-and-tools/erdjs/erdjs-signing-providers
该页面将引导您完成将 erdjs 签名供应商集成到不基于dapp-core
的 dApp 中的过程。
重要
注意,在大多数情况下,我们建议使用 dapp-core 而不是自己集成签名供应商。
重要
本页描述的代码示例也可以在 erdjs 范例库 中找到。
以下签名提供程序可用:
- 网络钱包提供商
- 扩展提供商(Maiar DeFi Wallet)
- 钱包连接提供商
- 硬件钱包(账本)提供商
网络钱包提供商
注
确保你提前看了一下网钩。
@elrondnetwork/erdjs-web-wallet-provider
允许 dApp 的用户使用网络钱包登录并签署交易。
为了创建提供程序的实例,请执行以下操作:
import { WalletProvider, WALLET_PROVIDER_DEVNET } from "@elrondnetwork/erdjs-web-wallet-provider";
const provider = new WalletProvider(WALLET_PROVIDER_DEVNET);
以下供应商 URL由包定义:WALLET_PROVIDER_TESTNET
,WALLET_PROVIDER_DEVNET
,WALLET_PROVIDER_MAINNET
。
登录和注销
然后,要求用户登录:
const callbackUrl = encodeURIComponent("http://my-dapp");
await provider.login({ callbackUrl });
一旦用户打开她的钱包,网络钱包就发出一个重定向回callbackUrl
,以及用户的地址。您可以获得如下地址:
import qs from "qs";
const queryString = window.location.search.slice(1);
const params = qs.parse(queryString);
console.log(params.address);
要注销,请执行以下操作:
const callbackUrl = window.location.href.split("?")[0];
await provider.logout({ callbackUrl: callbackUrl });
有时,dApp(和它的后端)可能想要可靠地分配一个离线用户身份到一个Elrond地址。在这种情况下,网络钱包供应商支持login()
方法的一个额外参数:一个对网络钱包完全不透明的定制认证代币,在登录时用用户的钱包签名:
// An identity token, provided by an identity provider (server-side)
// (e.g. Google ID, a custom identity token)
const authToken = "aaaabbbbaaaabbbb";
// A server-side handler used to acknowledge, validate and honour
// the relationship between "authToken" and the Elrond address of the user
const callbackUrl = encodeURIComponent("https://my-dapp/on-wallet-login");
await provider.login({ callbackUrl, token: authToken });
签约交易
交易可以按如下方式签名:
import { Transaction } from "@elrondnetwork/erdjs";
const firstTransaction = new Transaction({ ... });
const secondTransaction = new Transaction({ ... });
await provider.signTransactions(
[firstTransaction, secondTransaction],
{ callbackUrl: callbackUrl }
);
在使用网络钱包签署交易时,用户被重定向回callbackUrl
,而查询字符串包含关于交易的信息,包括它们的签名。该信息可用于使用getTransactionsFromWalletUrl()
重建Transaction
物体:
const plainSignedTransactions = provider.getTransactionsFromWalletUrl();
重要
以下解决方法可能会发生变化。
截至 2022 年 7 月,网络钱包提供商以普通字符串的形式返回数据字段。然而,erdjs' Transaction.fromPlainObject()
希望它是 base64 编码的。因此,我们需要对getTransactionsFromWalletUrl()
的结果应用一个变通方法(一个额外的转换)。
for (const plainTransaction of plainSignedTransactions) {
const plainTransactionClone = structuredClone(plainTransaction);
plainTransactionClone.data = Buffer.from(plainTransactionClone.data).toString("base64");
const transaction = Transaction.fromPlainObject(plainTransactionClone);
// "transaction" can now be broadcasted.
}
签约消息
重要
本节中的文档是初步的,可能会更改。
截至 2022 年 7 月,网络钱包提供商不允许对任意消息进行签名(仅支持交易签名)。
扩展提供商(Maiar DeFi 钱包)
注
确保你提前看了一下这一页。
@elrondnetwork/erdjs-extension-provider
允许 dApp 的用户使用 Maiar DeFi 钱包登录并签署交易。
为了获取提供程序的实例(单例),请执行以下操作:
import { ExtensionProvider } from "@elrondnetwork/erdjs-extension-provider";
const provider = ExtensionProvider.getInstance();
在执行任何操作之前,请确保初始化提供程序:
await provider.init();
登录和注销
然后,要求用户登录:
const address = await provider.login();
console.log(address);
console.log(provider.account);
要注销,请执行以下操作:
await provider.logout();
login()
方法支持token
参数(类似于 web 钱包供应商):
// A custom identity token (opaque to the signing provider)
const authToken = "aaaabbbbaaaabbbb";
await provider.login({ token: authToken });
console.log("Address:", provider.account.address);
console.log("Token signature:", provider.account.signature);
签约交易
交易可以按如下方式签名:
import { Transaction } from "@elrondnetwork/erdjs";
const firstTransaction = new Transaction({ ... });
const secondTransaction = new Transaction({ ... });
await provider.signTransactions([firstTransaction, secondTransaction]);
// "firstTransaction" and "secondTransaction" can now be broadcasted.
签约消息
可以对任意消息进行如下签名:
import { SignableMessage } from "@elrondnetwork/erdjs";
const message = new SignableMessage({
message: Buffer.from("hello")
});
await provider.signMessage(message);
console.log(message.toJSON());
钱包连接提供商
@elrondnetwork/erdjs-wallet-connect-provider
允许 dApp 的用户使用 Maiar(移动应用)登录并签署交易。
首先,让我们看一个使用 qrcode
(和引导程序)构建 QR 对话的(简单)方法:
import QRCode from "qrcode";
async function openModal(connectorUri) {
const svg = await QRCode.toString(connectorUri, { type: "svg" });
// The referenced elements must be added to your page, in advance
$("#MyWalletConnectQRContainer").html(svg);
$("#MyWalletConnectModal").modal("show");
}
function closeModal() {
$("#MyWalletConnectModal").modal("hide");
}
为了创建提供程序的实例,请执行以下操作:
import { WalletConnectProvider } from "@elrondnetwork/erdjs-wallet-connect-provider";
var provider;
const bridgeUrl = "https://bridge.walletconnect.org";
const callbacks = {
onClientLogin: async function () {
// closeModal() is defined above
closeModal();
const address = await provider.getAddress();
console.log("Address:", address);
},
onClientLogout: async function () {
console.log("onClientLogout()");
}
};
const provider = new WalletConnectProvider(bridgeUrl, callbacks);
在执行任何操作之前,请确保初始化提供程序:
await provider.init();
登录和注销
然后,要求用户在手机上使用 Maiar 登录:
const connectorUri = await provider.login();
// openModal() is defined above
openModal(connectorUri);
一旦用户确认登录,就会执行onClientLogin()
回调(如上所述)。
要注销,请执行以下操作:
await provider.logout();
签约交易
交易可以按如下方式签名:
import { Transaction } from "@elrondnetwork/erdjs";
const firstTransaction = new Transaction({ ... });
const secondTransaction = new Transaction({ ... });
await provider.signTransactions([firstTransaction, secondTransaction]);
// "firstTransaction" and "secondTransaction" can now be broadcasted.
或者,可以使用方法signTransaction()
签署单个交易。
签约消息
重要
本节中的文档是初步的,可能会更改。
截至 2022 年 7 月,erdjs 的钱包连接供应商不允许对任意消息进行签名(仅支持交易签名)。
硬件钱包(账本)提供商
注
确保你提前看了一下这一页。
@elrondnetwork/erdjs-hw-provider
允许 dApp 的用户使用账本设备登录并签署交易。
为了创建提供程序的实例,请执行以下操作:
import { HWProvider } from "@elrondnetwork/erdjs-hw-provider";
const provider = new HWProvider();
在执行任何操作之前,请确保初始化提供程序(此外,Elrond应用程序必须在设备上打开):
await provider.init();
登录
在要求用户使用账本登录之前,您可能想要获取设备上所有可用的地址,显示它们,并让用户选择其中一个:
const addresses = await provider.getAccounts();
console.log(addresses);
登录如下所示:
const chosenAddressIndex = 3;
await provider.login({ addressIndex: chosenAddressIndex });
alert(`Logged in. Address: ${await provider.getAddress()}`);
或者,为了在登录后选择设备上的特定地址,调用setAddressIndex()
:
const addressIndex = 3;
await provider.setAddressIndex(addressIndex);
console.log(`Address has been set: ${await provider.getAddress()}.`);
总帐提供程序本身不支持注销操作(在此上下文中不适用)。
登录流支持token
参数(类似于其他供应商),使用方法tokenLogin()
:
// A custom identity token (opaque to the signing provider)
const authToken = "aaaabbbbaaaabbbb";
// Note the additional suffix (required as of July 2022):
const payloadToSign = Buffer.from(`${authToken}{}`);
const { address, signature } = await provider.tokenLogin({ addressIndex: 0, token: payloadToSign });
console.log("Address:", address);
console.log("Signature:", signature.hex());
签约交易
交易可以按如下方式签名:
import { Transaction } from "@elrondnetwork/erdjs";
const firstTransaction = new Transaction({ ... });
const secondTransaction = new Transaction({ ... });
await provider.signTransactions([firstTransaction, secondTransaction]);
// "firstTransaction" and "secondTransaction" can now be broadcasted.
或者,可以使用方法signTransaction()
签署单个交易。
签约消息
可以对任意消息进行如下签名:
import { SignableMessage } from "@elrondnetwork/erdjs";
const message = new SignableMessage({
message: Buffer.from("hello")
});
await provider.signMessage(message);
console.log(message.toJSON());
验证登录代币签名
如前所述,dApp(及其后端)可能希望可靠地为Elrond地址分配一个离线用户身份。为此,签名供应商允许在登录流中使用一个登录代币——这个代币是使用用户的钱包签名的。之后,后端应用程序通常会验证代币的签名,如下所示:
export function verifyAuthTokenSignature(address, authToken, signature) {
console.log("verifyAuthTokenSignature()");
console.log("address:", address);
console.log("authToken:", authToken);
console.log("signature:", signature);
// Note that the verification API will be improved in a future version of erdjs-walletcore.
// As of @elrondnetwork/[email protected], this API is a bit tedious:
const verifier = UserVerifier.fromAddress(new Address(address));
const message = new SignableMessage({
signature: { hex: () => signature },
message: Buffer.from(`${address}${authToken}{}`)
});
const ok = verifier.verify(message);
if (ok) {
return `The bearer of the token [${authToken}] is also the owner of the address [${address}].`;
}
return "Verification failed.";
}
注
上述代码片段中应用的解决方法有待改进。