准备交易
首先,我们需要准备交易以进行签名。要使用 Ethereum 原生钱包,我们必须将交易转换为 EIP712 类型数据,并使用钱包签名此类型数据。 使用我们对消息的自定义抽象,允许开发者直接从特定消息的 proto 文件获取 EIP712 TypedData。复制
询问AI
import {
MsgSend,
} from "@injectivelabs/sdk-ts/core/modules";
import {
BaseAccount,
} from "@injectivelabs/sdk-ts/core/accounts";
import {
ChainRestAuthApi,
ChainRestTendermintApi,
} from "@injectivelabs/sdk-ts/client/chain";
import {
getEip712TypedDataV2,
} from "@injectivelabs/sdk-ts/core/tx";
import {
toBigNumber,
toChainFormat,
DEFAULT_BLOCK_TIMEOUT_HEIGHT,
} from "@injectivelabs/utils";
import { ChainId, EvmChainId } from "@injectivelabs/ts-types";
import { Network, getNetworkEndpoints } from "@injectivelabs/networks";
const injectiveAddress = "inj1";
const chainId = ChainId.Mainnet;
const evmChainId = EvmChainId.Mainnet;
const restEndpoint =
"https://lcd.injective.network"; /* getNetworkEndpoints(Network.Mainnet).rest */
const amount = {
denom: "inj",
amount: toChainFormat(0.01).toFixed(),
};
/** 账户详情 **/
const chainRestAuthApi = new ChainRestAuthApi(restEndpoint);
const accountDetailsResponse = await chainRestAuthApi.fetchAccount(
injectiveAddress
);
const baseAccount = BaseAccount.fromRestApi(accountDetailsResponse);
const accountDetails = baseAccount.toAccountDetails();
/** 区块详情 */
const chainRestTendermintApi = new ChainRestTendermintApi(restEndpoint);
const latestBlock = await chainRestTendermintApi.fetchLatestBlock();
const latestHeight = latestBlock.header.height;
const timeoutHeight = toBigNumber(latestHeight).plus(
DEFAULT_BLOCK_TIMEOUT_HEIGHT
);
/** 准备交易 */
const msg = MsgSend.fromJSON({
amount,
srcInjectiveAddress: injectiveAddress,
dstInjectiveAddress: injectiveAddress,
});
/** 用于在 Ethereum 钱包上签名的 EIP712 */
const eip712TypedData = getEip712TypedDataV2({
msgs: [msg],
tx: {
accountNumber: accountDetails.accountNumber.toString(),
sequence: accountDetails.sequence.toString(),
timeoutHeight: timeoutHeight.toFixed(),
chainId: chainId,
},
evmChainId,
});
签名交易
准备好 EIP712 类型数据后,我们继续进行签名。复制
询问AI
/** 使用你喜欢的方法签名 EIP712 TypedData,以 Metamask 为例 */
const signature = await window.ethereum.request({
method: "eth_signTypedData_v4",
params: [
ethereumAddress,
JSON.stringify(eip712TypedData /* 来自上一步 */),
],
});
/** 获取签名者的公钥 */
const publicKeyHex = recoverTypedSignaturePubKey(eip712TypedData, signature);
const publicKeyBase64 = hexToBase64(publicKeyHex);
@injectivelabs/wallet-strategy 包来获取开箱即用的钱包提供者,它们提供了可用于签名交易的抽象方法。请参阅该包的文档,设置和使用都很简单。这是推荐的方式,因为你可以在 dApp 中使用多个钱包。WalletStrategy 提供的不仅仅是签名交易的抽象。
广播交易
签名准备好后,我们需要将交易广播到 Injective 链本身。从第二步获取签名后,我们需要将该签名包含在已签名的交易中并广播到链上。复制
询问AI
import {
Network,
SIGN_AMINO,
getNetworkEndpoints,
} from "@injectivelabs/networks";
import { getDefaultStdFee } from "@injectivelabs/utils";
import { ChainId, EvmChainId } from "@injectivelabs/ts-types";
import { createTransaction, TxRestApi } from "@injectivelabs/sdk-ts/core/tx";
const evmChainId = EvmChainId.Mainnet;
const { txRaw } = createTransaction({
message: msgs,
memo: memo,
signMode: SIGN_AMINO,
fee: getDefaultStdFee(),
pubKey: publicKeyBase64 /* 来自上一步 */,
sequence: baseAccount.sequence,
timeoutHeight: timeoutHeight.toNumber(),
accountNumber: baseAccount.accountNumber,
chainId: chainId,
});
const web3Extension = createWeb3Extension({
evmChainId,
});
const txRawEip712 = createTxRawEIP712(txRaw, web3Extension);
/** 附加签名 */
txRawEip712.signatures = [signatureBuff /* 来自上一步 */];
/** 广播交易 */
const restEndpoint =
"https://lcd.injective.network"; /* getNetworkEndpoints(Network.Mainnet).rest */
const txRestApi = new TxRestApi(restEndpoint);
const txHash = await txRestApi.broadcast(txRawEip712);
/**
* 获取 txHash 后,因为我们使用 Sync 模式,
* 我们不确定交易是否已包含在区块中,
* 它可能仍在 mempool 中,所以我们需要查询
* 链以查看交易何时被包含
*/
/** 这将轮询查询交易并等待其包含在区块中 */
const response = await txRestApi.fetchTxPoll(txHash);
不使用 WalletStrategy 的示例(准备 + 签名 + 广播)
让我们看看完整的流程(使用 Metamask 作为签名钱包)复制
询问AI
import {
MsgSend,
} from "@injectivelabs/sdk-ts/core/modules";
import {
BaseAccount,
} from "@injectivelabs/sdk-ts/core/accounts";
import {
TxRestApi,
SIGN_AMINO,
hexToBase64,
createTransaction,
createTxRawEIP712,
getEip712TypedData,
createWeb3Extension,
recoverTypedSignaturePubKey,
} from "@injectivelabs/sdk-ts/core/tx";
import {
ChainRestAuthApi,
ChainRestTendermintApi,
} from "@injectivelabs/sdk-ts/client/chain";
import {
getEthereumAddress,
} from "@injectivelabs/sdk-ts/utils";
import {
toBigNumber,
toChainFormat,
getDefaultStdFee,
DEFAULT_BLOCK_TIMEOUT_HEIGHT,
} from "@injectivelabs/utils";
import { ChainId, EvmChainId } from "@injectivelabs/ts-types";
import { Network, getNetworkEndpoints } from "@injectivelabs/networks";
const injectiveAddress = "inj1";
const chainId = ChainId.Mainnet;
const evmChainId = EvmChainId.Mainnet;
const ethereumAddress = getEthereumAddress(injectiveAddress);
const restEndpoint = getNetworkEndpoints(Network.MainnetSentry).rest;
const amount = {
denom: "inj",
amount: toChainFormat(0.01).toFixed(),
};
/** 账户详情 **/
const chainRestAuthApi = new ChainRestAuthApi(restEndpoint);
const accountDetailsResponse = await chainRestAuthApi.fetchAccount(
injectiveAddress
);
const baseAccount = BaseAccount.fromRestApi(accountDetailsResponse);
const accountDetails = baseAccount.toAccountDetails();
/** 区块详情 */
const chainRestTendermintApi = new ChainRestTendermintApi(restEndpoint);
const latestBlock = await chainRestTendermintApi.fetchLatestBlock();
const latestHeight = latestBlock.header.height;
const timeoutHeight = toBigNumber(latestHeight).plus(
DEFAULT_BLOCK_TIMEOUT_HEIGHT
);
/** 准备交易 */
const msg = MsgSend.fromJSON({
amount,
srcInjectiveAddress: injectiveAddress,
dstInjectiveAddress: injectiveAddress,
});
/** 用于在 Ethereum 钱包上签名的 EIP712 */
const eip712TypedData = getEip712TypedData({
msgs: [msg],
tx: {
accountNumber: accountDetails.accountNumber.toString(),
sequence: accountDetails.sequence.toString(),
timeoutHeight: timeoutHeight.toFixed(),
chainId,
},
evmChainId,
});
/** 使用你喜欢的方法签名 EIP712 TypedData,以 Metamask 为例 */
const signature = await window.ethereum.request({
method: "eth_signTypedData_v4",
params: [ethereumAddress, JSON.stringify(eip712TypedData)],
});
/** 获取签名者的公钥 */
const publicKeyHex = recoverTypedSignaturePubKey(eip712TypedData, signature);
const publicKeyBase64 = hexToBase64(publicKeyHex);
const signatureBuff = Buffer.from(signature.replace("0x", ""), "hex");
const { txRaw } = createTransaction({
message: [msg],
memo: "",
signMode: SIGN_AMINO,
fee: getDefaultStdFee(),
pubKey: publicKeyBase64,
sequence: baseAccount.sequence,
timeoutHeight: timeoutHeight.toNumber(),
accountNumber: baseAccount.accountNumber,
chainId: chainId,
});
const web3Extension = createWeb3Extension({
evmChainId,
});
const txRawEip712 = createTxRawEIP712(txRaw, web3Extension);
/** 附加签名 */
txRawEip712.signatures = [signatureBuff];
/** 广播交易 */
const txRestApi = new TxRestApi(restEndpoint);
const txResponse = await txRestApi.broadcast(txRawEip712);
const response = await txRestApi.fetchTxPoll(txResponse.txHash);
