Skip to main content

Integrate Web3Auth MPC CoreKit SDK with the Near Blockchain in Javascript

To sign the transactions for Near using MPC CoreKit JS SDK, you can utilize the @toruslabs/tss-frost-lib to instantiate Web3AuthMPCCoreKit with ed25519 KeyType. To support the ed25519 curve Web3Auth internally uses the FROST algorithm to provide the EdDSA sginature using threshold protocols.

This EdDSA signature can be used to submit the transactions on Near blockchain.

Installation

To interact with the Near blockchain, you can use near-api-js package with Web3Auth CoreKit SDK along with @toruslabs/tss-frost-lib package.

$ npm install near-api-js
$ npm install @toruslabs/tss-frost-lib

Initializing and instantiating the Web3Auth MPC CoreKit JS SDK

Considering you have already installed the @toruslabs/tss-frost-lib package, let's use the tssLib to create Web3AuthMPCCoreKit instance.

import { Web3AuthMPCCoreKit, WEB3AUTH_NETWORK } from "@web3auth/mpc-core-kit";
import { tssLib } from "@toruslabs/tss-frost-lib";

const coreKitInstance = new Web3AuthMPCCoreKit({
web3AuthClientId: "YOUR_CLIENT_ID",
web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET,
manualSync: true, // This is the recommended approach
tssLib: tssLib,
storage: window.storage,
});

Get User Info

Gives you the user's information received from the ID Token.

const userInfo = coreKitInstance?.getUserInfo();

Get account

Once you have an Web3AuthMPCCoreKit instance, it can be used as along with near-api-js package.

To generate the Near implicit address, you can use the getPubKeyEd25519 method to retrieve the ed25519 curve compatible pubKey. Once you have the pubkey, you can create PublicKey instance, and retrive the implicit address which is basically hex of PublicKey.

import { PublicKey } from "near-api-js/lib/utils";
import { KeyType } from "near-api-js/lib/utils/key_pair";

const coreKitPubKey = coreKitInstance.getPubKeyEd25519();
const publicKey = new PublicKey({ keyType: KeyType.ED25519, data: coreKitPubKey });

const address = Buffer.from(this.publicKey.data).toString("hex");

Get account balance

To get the user's balance, we can use the JsonRpcProvider.query method, which takes request_type as an parameter. For request_type we gonna pass view_account as an argument. The view_account RPC method enables you to view details about account.

import { JsonRpcProvider } from "near-api-js/lib/providers";
import { AccountView } from "@near-js/types/lib/provider/response";

try {
const state = await this.jsonRPCProvider.query<AccountView>({
request_type: "view_account",
account_id: this.getAccount(),
finality: "optimistic",
});

const balance = state.amount;
} catch (error) {
if (error.type === "AccountDoesNotExist") {
// Account has no funds and it does not exist. Please add funds to the account
}

// Handle error
}

Sign a message

Signing a message for Near is pretty straight forward. You can simply use the sign method to generate the EdDSA signature.

const msg = Buffer.from("Welcome to Web3Auth");
const sig = await this.coreKitInstance.sign(msg);

Sign a transaction

To sign a Near transaction, you can use Transaction class to get a buffer of the transaction data to sign, and use the generated signature to create SignedTransaction.

Before we create a Near blockchain transaction, let's implement getAccessKey. We'll use the JsonRpcProvider.query method, and pass view_access_key as an argument for request_type. The view_access_key RPC method returns the information about an account's access key such as nonce, permission, along with block details which are used to create transaction.

import { AccessKeyViewRaw } from "@near-js/types";

async getAccessKey(): Promise<AccessKeyViewRaw> {
try {
// Use the jsonRPCProvider, address, and publicKey defined early.
const acessKey = await jsonRPCProvider.query<AccessKeyViewRaw>({
request_type: "view_access_key",
account_id: address,
finality: 'optimistic',
public_key: publicKey.toString(),
});

return acessKey;

} catch (e) {
throw e;
}
}

Once we have implemented getAccessKey, we can create the transaction using createTransaction helper method.

import {
Signature,
SignedTransaction,
createTransaction,
encodeTransaction,
transfer,
} from "near-api-js/lib/transaction";
import { AccessKeyViewRaw } from "@near-js/types";
import { base_decode } from "near-api-js/lib/utils/serialize";
import { sha256 } from "@noble/hashes/sha256";
import { base64 } from "@scure/base";
import { parseNearAmount } from "near-api-js/lib/utils/format";

// Defined above
const accessKey = await getAccessKey();
const nonce = accessKey.nonce + 1;

const block = await this.jsonRPCProvider.block({ finality: "final" });
const blockHash = block.header.hash;

const transaction = createTransaction(
address,
publicKey,
"blackjaguar7625.testnet",
nonce,
[transfer(BigInt(parseNearAmount("0.02")!))],
base_decode(blockHash),
);

const serializeTransaction = encodeTransaction(transaction);
const tssSignature = await this.coreKitInstance.sign(Buffer.from(sha256(serializeTransaction)));

const signature = new Signature({
keyType: KeyType.ED25519,
data: Uint8Array.from(tssSignature),
});

To broadcast the signed transaction, you can utilize the JsonRpcProvider.sendTransaction method.

// transaction and signature are defined above
const executionDetails = await this.jsonRPCProvider.sendTransaction(
new SignedTransaction({
transaction,
signature,
}),
);

const hash = executionDetails.transaction.hash;