@web3auth/no-modal
Version:
Multi chain wallet aggregator for web3Auth
259 lines (247 loc) • 8.94 kB
JavaScript
import _objectSpread from '@babel/runtime/helpers/objectSpread2';
import { createScaffoldMiddleware, createAsyncMiddleware, rpcErrors } from '@web3auth/auth';
import { isHex, toHex } from 'viem';
function createWalletMiddleware({
getAccounts,
getPrivateKey,
getPublicKey,
processEthSignMessage,
processPersonalMessage,
processTransaction,
processSignTransaction,
processTypedMessageV4,
processGetCapabilities,
processSendCalls,
processGetCallsStatus,
processShowCallsStatus
}) {
if (!getAccounts) {
throw new Error("opts.getAccounts is required");
}
//
// utility
//
/**
* Validates the keyholder address, and returns a normalized (i.e. lowercase)
* copy of it.
*
* an error
*/
async function validateAndNormalizeKeyholder(address, req) {
if (typeof address === "string" && address.length > 0) {
// ensure address is included in provided accounts
const accounts = await getAccounts(req);
const normalizedAccounts = accounts.map(_address => _address.toLowerCase());
const normalizedAddress = address.toLowerCase();
if (normalizedAccounts.includes(normalizedAddress)) {
return normalizedAddress;
}
}
throw rpcErrors.invalidParams({
message: `Invalid parameters: must provide an Ethereum address.`
});
}
//
// account lookups
//
async function lookupAccounts(req, res) {
res.result = await getAccounts(req);
}
//
// transaction signatures
//
async function sendTransaction(req, res) {
if (!processTransaction) {
throw rpcErrors.methodNotSupported();
}
const txParams = req.params[0] || {
from: ""
};
txParams.from = await validateAndNormalizeKeyholder(txParams.from, req);
res.result = await processTransaction(txParams, req);
}
async function signTransaction(req, res) {
if (!processSignTransaction) {
throw rpcErrors.methodNotSupported();
}
const txParams = req.params[0] || {
from: ""
};
txParams.from = await validateAndNormalizeKeyholder(txParams.from, req);
res.result = await processSignTransaction(txParams, req);
}
//
// message signatures
//
async function ethSign(req, res) {
if (!processEthSignMessage) {
throw rpcErrors.methodNotSupported();
}
let msgParams = req.params;
const extraParams = req.params[2] || {};
if (Array.isArray(req.params)) {
if (!(req.params.length === 2)) throw new Error(`WalletMiddleware - incorrect params for ${req.method} method. expected [address, message]`);
const params = req.params;
const address = params[0];
const message = params[1];
msgParams = {
from: address,
data: message
};
}
msgParams = _objectSpread(_objectSpread({}, extraParams), msgParams);
res.result = await processEthSignMessage(msgParams, req);
}
async function signTypedDataV4(req, res) {
if (!processTypedMessageV4) {
throw rpcErrors.methodNotSupported();
}
if (!(req !== null && req !== void 0 && req.params)) throw new Error("WalletMiddleware - missing params");
let msgParams = req.params;
if (Array.isArray(req.params)) {
if (!(req.params.length === 2)) throw new Error(`WalletMiddleware - incorrect params for ${req.method} method. expected [address, typedData]`);
const params = req.params;
const address = params[0];
const message = params[1];
msgParams = {
from: address,
data: message
};
}
res.result = await processTypedMessageV4(msgParams, req);
}
async function personalSign(req, res) {
if (!processPersonalMessage) {
throw rpcErrors.methodNotSupported();
}
let msgParams = req.params;
const extraParams = req.params[2] || {};
if (Array.isArray(req.params)) {
if (!(req.params.length >= 2)) throw new Error(`WalletMiddleware - incorrect params for ${req.method} method. expected [message, address]`);
const params = req.params;
if (typeof params[0] === "object") {
const {
challenge,
address
} = params[0];
msgParams = {
from: address,
data: challenge
};
} else {
const message = params[0];
const address = params[1];
msgParams = {
from: address,
data: message
};
}
}
msgParams = _objectSpread(_objectSpread({}, extraParams), msgParams);
res.result = await processPersonalMessage(msgParams, req);
}
async function fetchPrivateKey(req, res) {
if (!getPrivateKey) {
throw rpcErrors.methodNotSupported();
}
res.result = await getPrivateKey(req);
}
async function fetchPublicKey(req, res) {
if (!getPublicKey) {
throw rpcErrors.methodNotSupported();
}
res.result = await getPublicKey(req);
}
async function getWalletCapabilitiesMiddleware(req, res) {
if (!processGetCapabilities) {
throw rpcErrors.methodNotSupported();
}
if (!Array.isArray(req.params) || req.params.length === 0) {
throw rpcErrors.invalidParams("Invalid parameters");
}
const account = req.params[0];
if (!isHex(account)) {
throw rpcErrors.invalidParams("Invalid account address");
}
let chainIds = req.params[1] || []; // if empty array is provided, the wallet will return capabilities for all supported chains
if (!Array.isArray(chainIds)) {
throw rpcErrors.invalidParams(`Invalid params, received: ${chainIds}. expected: Array`);
}
// format chain ids
chainIds = chainIds.map(chainId => isHex(chainId) ? chainId : toHex(chainId));
const getCapabilitiesParams = [account,
// account address
chainIds // [`0xstring`, `0xstring`, ...]
];
res.result = await processGetCapabilities(getCapabilitiesParams);
}
async function walletSendCallsMiddleware(req, res) {
if (!processSendCalls) {
throw rpcErrors.methodNotSupported();
}
const params = Array.isArray(req.params) ? req.params[0] : req.params;
if (!params || typeof params !== "object") {
throw rpcErrors.invalidParams("Missing or invalid params for wallet_sendCalls");
}
if (!params.version || typeof params.version !== "string") {
throw rpcErrors.invalidParams(`Invalid version: expected string, got "${params.version || "undefined"}"`);
}
if (!params.chainId) {
throw rpcErrors.invalidParams("Missing required field: chainId");
}
if (!Array.isArray(params.calls) || params.calls.length === 0) {
throw rpcErrors.invalidParams("calls must be a non-empty array");
}
const from = params.from;
if (from) {
await validateAndNormalizeKeyholder(from, req);
}
const walletSendCallsParams = _objectSpread(_objectSpread({}, params), {}, {
chainId: isHex(params.chainId) ? params.chainId : toHex(params.chainId)
});
res.result = await processSendCalls(walletSendCallsParams);
}
async function walletBatchCallStatusMiddleware(req, res) {
if (!processGetCallsStatus) {
throw rpcErrors.methodNotSupported();
}
const batchId = Array.isArray(req.params) ? req.params[0] : req.params;
if (!batchId || typeof batchId !== "string") {
throw rpcErrors.invalidParams("Missing or invalid batchId");
}
res.result = await processGetCallsStatus(batchId);
}
async function walletShowCallsStatusMiddleware(req, res) {
if (!processShowCallsStatus) {
throw rpcErrors.methodNotSupported();
}
const batchId = Array.isArray(req.params) ? req.params[0] : req.params;
if (!batchId || typeof batchId !== "string") {
throw rpcErrors.invalidParams("Missing or invalid batchId");
}
await processShowCallsStatus(batchId);
res.result = true;
}
return createScaffoldMiddleware({
// account lookups
eth_accounts: createAsyncMiddleware(lookupAccounts),
eth_requestAccounts: createAsyncMiddleware(lookupAccounts),
eth_private_key: createAsyncMiddleware(fetchPrivateKey),
eth_public_key: createAsyncMiddleware(fetchPublicKey),
public_key: createAsyncMiddleware(fetchPublicKey),
private_key: createAsyncMiddleware(fetchPrivateKey),
// tx signatures
eth_sendTransaction: createAsyncMiddleware(sendTransaction),
eth_signTransaction: createAsyncMiddleware(signTransaction),
// message signatures
eth_sign: createAsyncMiddleware(ethSign),
eth_signTypedData_v4: createAsyncMiddleware(signTypedDataV4),
personal_sign: createAsyncMiddleware(personalSign),
// EIP-5792
wallet_getCapabilities: createAsyncMiddleware(getWalletCapabilitiesMiddleware),
wallet_sendCalls: createAsyncMiddleware(walletSendCallsMiddleware),
wallet_getCallsStatus: createAsyncMiddleware(walletBatchCallStatusMiddleware),
wallet_showCallsStatus: createAsyncMiddleware(walletShowCallsStatusMiddleware)
});
}
export { createWalletMiddleware };