@etherspot/remote-signer
Version:
Etherspot Permissioned Signer SDK - signs the UserOp with SessionKey and sends it to the Bundler
764 lines (759 loc) • 27 kB
JavaScript
import {
isModuleInstalled
} from "./chunk-DNBP5Z37.mjs";
import {
signUserOpWithSessionKey
} from "./chunk-RUG2C3EH.mjs";
import {
isAValidSessionKey
} from "./chunk-3CLTAXSX.mjs";
import {
getOnchainSessionKeyData,
isSessionKeyLiveOnChain
} from "./chunk-M2QU7VOG.mjs";
import {
validateDto
} from "./chunk-EPBRUPO6.mjs";
import {
SignMessageDto
} from "./chunk-EKOEYO6L.mjs";
import {
EtherspotBundler
} from "./chunk-DHYNFLYW.mjs";
import {
HttpRpcClient
} from "./chunk-67OVV5YO.mjs";
import {
ErrorHandler
} from "./chunk-FVCQUX3O.mjs";
import {
VerifyingPaymasterAPI
} from "./chunk-OYGOAYJB.mjs";
import {
calcPreVerificationGas
} from "./chunk-APTQT4MR.mjs";
import {
getGasFee
} from "./chunk-SKQVU7ST.mjs";
import {
getUserOpHash,
packUserOp
} from "./chunk-XNGSGKPY.mjs";
import {
getExecuteMode,
resolveProperties
} from "./chunk-M6FK2HC2.mjs";
import {
getPublicClient,
getViemAddress
} from "./chunk-BHLNGJH5.mjs";
import {
DEFAULT_MULTIPLE_OWNER_ECDSA_VALIDATOR_ADDRESS,
Networks
} from "./chunk-NJPIYKQV.mjs";
import {
BigNumber
} from "./chunk-Q4Z2NTL2.mjs";
import {
_makeBootstrapConfig,
makeBootstrapConfig
} from "./chunk-32NXSZNM.mjs";
import {
accountAbi,
bootstrapAbi,
entryPointAbi,
factoryAbi
} from "./chunk-KNNHGAPS.mjs";
import {
http,
isBytes
} from "./chunk-EGVR4AKQ.mjs";
import {
concat,
encodeAbiParameters,
encodeFunctionData,
formatEther,
getAddress,
pad,
parseAbi,
parseAbiItem,
parseAbiParameters,
toHex
} from "./chunk-VPBLFL5G.mjs";
// src/sdk/base/EtherspotWalletAPI.ts
var ADDRESS_ZERO = getAddress("0x0000000000000000000000000000000000000000");
var EtherspotWalletAPI = class extends BaseAccountAPI {
constructor(params) {
super(params);
this.index = params.index ?? 0;
this.multipleOwnerECDSAValidatorAddress = Networks[params.chainId]?.contracts?.multipleOwnerECDSAValidator ?? DEFAULT_MULTIPLE_OWNER_ECDSA_VALIDATOR_ADDRESS;
}
getEOAAddress() {
return this.externalViemAccount.address;
}
/**
* return the value to put into the "initCode" field, if the account is not yet deployed.
* this value holds the "factory" address, followed by this account's information
*/
async getAccountInitCode() {
if (this.factoryAddress == null || this.factoryAddress == "") {
throw new Error("no factory to get initCode");
}
const initCode = await this.getInitCodeData();
const salt = pad(toHex(this.index), { size: 32 });
const functionData = encodeFunctionData({
functionName: "createAccount",
abi: parseAbi(factoryAbi),
args: [
salt,
initCode
]
});
return concat([
this.factoryAddress,
functionData
]);
}
async getInitCodeData() {
const validators = makeBootstrapConfig(this.multipleOwnerECDSAValidatorAddress, "0x");
const executors = makeBootstrapConfig(ADDRESS_ZERO, "0x");
const hook = _makeBootstrapConfig(ADDRESS_ZERO, "0x");
const fallbacks = makeBootstrapConfig(ADDRESS_ZERO, "0x");
const initMSAData = encodeFunctionData({
functionName: "initMSA",
abi: parseAbi(bootstrapAbi),
args: [validators, executors, hook, fallbacks]
});
const eoaAddress = await this.getEOAAddress();
const initCode = encodeAbiParameters(
parseAbiParameters("address, address, bytes"),
[eoaAddress, this.bootstrapAddress, initMSAData]
);
return initCode;
}
async getNonce(key = BigNumber.from(0)) {
const etherspotWalletAddress = await this.getEtherspotWalletAddress();
const dummyKey = key.eq(0) ? getAddress(this.multipleOwnerECDSAValidatorAddress) + "00000000" : getAddress(key.toHexString()) + "00000000";
const nonceResponse = await this.publicClient.readContract({
address: this.entryPointAddress,
abi: parseAbi(entryPointAbi),
functionName: "getNonce",
args: [etherspotWalletAddress, BigInt(dummyKey)]
});
return nonceResponse;
}
/**
* encode a method call from entryPoint to our contract
* @param target
* @param value
* @param data
*/
async encodeExecute(target, value, data) {
const executeMode = getExecuteMode({
callType: "0x00" /* SINGLE */,
execType: "0x00" /* DEFAULT */
});
let valueToProcess;
if (BigNumber.isBigNumber(value)) {
valueToProcess = value.toString();
} else if (isBytes(value)) {
valueToProcess = new Uint8Array(value);
} else {
if (typeof value === "object" && value !== null && "length" in value) {
valueToProcess = new Uint8Array(Object.values(value));
} else {
valueToProcess = value;
}
}
const calldata = concat([
target,
pad(toHex(valueToProcess), { size: 32 }),
data
]);
return encodeFunctionData({
functionName: "execute",
abi: parseAbi(accountAbi),
args: [executeMode, calldata]
});
}
async encodeBatch(targets, values, datas) {
const executeMode = getExecuteMode({
callType: "0x01" /* BATCH */,
execType: "0x00" /* DEFAULT */
});
const result = targets.map((target, index) => ({
target,
value: values[index],
callData: datas[index]
}));
const convertedResult = result.map((item) => ({
...item,
// Convert `value` from BigNumberish to bigint
value: typeof item.value === "bigint" ? item.value : BigInt(item.value.toString())
}));
const calldata = encodeAbiParameters(
parseAbiParameters("(address target,uint256 value,bytes callData)[]"),
[convertedResult]
);
return encodeFunctionData({
functionName: "execute",
abi: parseAbi(accountAbi),
args: [executeMode, calldata]
});
}
};
// src/sdk/sdk.ts
var RemoteSignerSdk = class _RemoteSignerSdk {
constructor(externalViemAccount, sdkOptions) {
this.userOpsBatch = { to: [], data: [], value: [] };
const { index, etherspotWalletAddress, chainId, apiKey, sessionKey, rpcProviderUrl } = sdkOptions;
if (!externalViemAccount) throw new Error("EOAAddress - ViemAccount object is required");
this.externalViemAccount = externalViemAccount;
if (!etherspotWalletAddress) throw new Error("etherspotWalletAddress is required");
this.etherspotWalletAddress = etherspotWalletAddress;
if (!chainId || chainId <= 0) throw new Error("chainId is required");
if (!Networks[chainId]) {
throw new Error("ChainId not found in the Networks");
}
this.chainId = chainId;
this.index = index ?? 0;
if (!apiKey) throw new Error("apiKey is required");
this.apiKey = apiKey;
if (!sessionKey) throw new Error("sessionKey is required");
this.sessionKey = sessionKey;
if (!sdkOptions.bundlerProvider) {
sdkOptions.bundlerProvider = new EtherspotBundler(chainId);
}
this.factoryUsed = sdkOptions.factoryWallet ?? "etherspot" /* ETHERSPOT */;
let viemClientUrl = "";
if (rpcProviderUrl) {
viemClientUrl = rpcProviderUrl;
} else {
viemClientUrl = sdkOptions.bundlerProvider.url;
}
this.providerUrl = viemClientUrl;
this.publicClient = getPublicClient({
chainId,
transport: http(viemClientUrl)
});
let entryPointAddress = Networks[chainId].contracts.entryPoint;
if (Networks[chainId].contracts.walletFactory == "") throw new Error("The selected factory is not deployed in the selected chain_id");
let walletFactoryAddress = Networks[chainId].contracts.walletFactory;
if (sdkOptions.entryPointAddress) entryPointAddress = sdkOptions.entryPointAddress;
if (sdkOptions.walletFactoryAddress) walletFactoryAddress = sdkOptions.walletFactoryAddress;
if (entryPointAddress == "") throw new Error("entryPointAddress not set on the given chain_id");
if (walletFactoryAddress == "") throw new Error("walletFactoryAddress not set on the given chain_id");
this.etherspotWallet = new EtherspotWalletAPI({
sdkOptions,
entryPointAddress,
factoryAddress: walletFactoryAddress,
etherspotWalletAddress,
externalViemAccount: this.externalViemAccount,
publicClient: this.publicClient,
index: this.index,
chainId: this.chainId
});
this.bundler = new HttpRpcClient(sdkOptions.bundlerProvider.url, entryPointAddress, chainId, this.publicClient);
}
async initialize(sdkOptions) {
const isPhantom = await this.etherspotWallet.checkAccountPhantom();
if (isPhantom) {
throw new Error(`EtherspotWallet: ${this.etherspotWalletAddress} is not deployed/initialized on chain: ${this.chainId}`);
}
const erc20SessionKeyValidator = await this.getERC20SessionKeyValidator();
const isModuleInstalledIndicator = await isModuleInstalled(
this.publicClient,
this.etherspotWalletAddress,
"0x01" /* VALIDATOR */,
erc20SessionKeyValidator
);
if (!isModuleInstalledIndicator) {
throw new Error(`Module: ${erc20SessionKeyValidator} is not installed on etherspotWalletAddress: ${this.etherspotWalletAddress} on chainId: ${Networks[this.chainId].chain.name}`);
}
const sessionKeyExists = await isAValidSessionKey(this.publicClient, erc20SessionKeyValidator, this.etherspotWalletAddress, this.chainId, this.apiKey, this.sessionKey);
if (!sessionKeyExists) {
throw new Error(`Sessionkey: ${sdkOptions.sessionKey} is invalid for etherspotWalletAddress: ${this.etherspotWalletAddress} and apiKey: ${this.apiKey} on chainId: ${Networks[this.chainId].chain.name}`);
}
}
async getERC20SessionKeyValidator() {
if (this.erc20SessionKeyValidator) {
return this.erc20SessionKeyValidator;
}
this.erc20SessionKeyValidator = Networks[this.chainId]?.contracts?.erc20SessionKeyValidator;
if (!this.erc20SessionKeyValidator) {
throw new Error("erc20SessionKeyValidator not found in the Networks for chainId: `" + this.chainId + "`");
}
return this.erc20SessionKeyValidator;
}
static async create(externalViemAccount, sdkOptions) {
const instance = new _RemoteSignerSdk(externalViemAccount, sdkOptions);
await instance.initialize(sdkOptions);
return instance;
}
getPublicClient() {
return this.publicClient;
}
getProviderUrl() {
return this.providerUrl;
}
async validateSessionKey() {
const sessionKeyValidator = await this.getERC20SessionKeyValidator();
return isAValidSessionKey(
this.publicClient,
sessionKeyValidator,
this.etherspotWalletAddress,
this.chainId,
this.apiKey,
this.sessionKey
);
}
async isSessionKeyLiveOnChain() {
const sessionKeyValidator = await this.getERC20SessionKeyValidator();
return isSessionKeyLiveOnChain(
this.etherspotWalletAddress,
this.publicClient,
sessionKeyValidator,
this.sessionKey
);
}
async getSessionKeyOnChainData() {
const sessionKeyValidator = await this.getERC20SessionKeyValidator();
return getOnchainSessionKeyData(
this.etherspotWalletAddress,
this.publicClient,
sessionKeyValidator,
this.sessionKey
);
}
async signUserOp(userOp) {
if (!this.etherspotWallet.etherspotWalletAddress) {
throw new ErrorHandler("EtherspotWalletAddress not found", 500);
}
const sessionSignedUserOp = await signUserOpWithSessionKey(
this.etherspotWallet.etherspotWalletAddress,
this.chainId,
this.apiKey,
this.sessionKey,
userOp
);
return sessionSignedUserOp;
}
async getCounterFactualAddress() {
return this.etherspotWallet.getEtherspotWalletAddress();
}
async estimate(params = { nonceKey: BigNumber.from(0) }) {
const { paymasterDetails, gasDetails, callGasLimit, nonceKey } = params;
const dummySignature = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";
if (this.userOpsBatch.to.length < 1) {
throw new ErrorHandler("cannot sign empty transaction batch", 1);
}
if (paymasterDetails?.url) {
const paymasterAPI = new VerifyingPaymasterAPI(paymasterDetails.url, this.etherspotWallet.entryPointAddress, paymasterDetails.context ?? {});
this.etherspotWallet.setPaymasterApi(paymasterAPI);
} else this.etherspotWallet.setPaymasterApi(null);
const tx = {
target: this.userOpsBatch.to,
values: this.userOpsBatch.value,
data: this.userOpsBatch.data,
dummySignature,
...gasDetails
};
const gasInfo = await this.getGasFee();
const partialtx = await this.etherspotWallet.createUnsignedUserOp({
...tx,
maxFeePerGas: gasInfo.maxFeePerGas,
maxPriorityFeePerGas: gasInfo.maxPriorityFeePerGas
}, nonceKey);
if (callGasLimit) {
partialtx.callGasLimit = BigNumber.from(callGasLimit).toHexString();
}
const bundlerGasEstimate = await this.bundler.getVerificationGasInfo(partialtx);
if (gasDetails?.maxFeePerGas && gasDetails?.maxPriorityFeePerGas) {
partialtx.maxFeePerGas = gasDetails.maxFeePerGas;
partialtx.maxPriorityFeePerGas = gasDetails.maxPriorityFeePerGas;
} else if (bundlerGasEstimate.maxFeePerGas && bundlerGasEstimate.maxPriorityFeePerGas) {
partialtx.maxFeePerGas = bundlerGasEstimate.maxFeePerGas;
partialtx.maxPriorityFeePerGas = bundlerGasEstimate.maxPriorityFeePerGas;
} else {
const gas = await this.getGasFee();
partialtx.maxFeePerGas = gas.maxFeePerGas;
partialtx.maxPriorityFeePerGas = gas.maxPriorityFeePerGas;
}
if (bundlerGasEstimate.preVerificationGas) {
partialtx.preVerificationGas = BigNumber.from(bundlerGasEstimate.preVerificationGas);
partialtx.verificationGasLimit = BigNumber.from(bundlerGasEstimate.verificationGasLimit ?? bundlerGasEstimate.verificationGas);
const expectedCallGasLimit = BigNumber.from(bundlerGasEstimate.callGasLimit);
if (!callGasLimit)
partialtx.callGasLimit = expectedCallGasLimit;
else if (BigNumber.from(callGasLimit).lt(expectedCallGasLimit))
throw new ErrorHandler(`CallGasLimit is too low. Expected atleast ${expectedCallGasLimit.toString()}`);
}
return partialtx;
}
async send(signedUserOp) {
return this.bundler.sendUserOpToBundler(signedUserOp);
}
async getGasFee() {
const version = await this.bundler.getBundlerVersion();
if (version && version.includes("skandha"))
return this.bundler.getSkandhaGasPrice();
return getGasFee(this.publicClient);
}
async getNativeBalance() {
const balance = await this.publicClient.getBalance({ address: getViemAddress(this.etherspotWallet.accountAddress) });
return formatEther(balance);
}
async getUserOpReceipt(userOpHash) {
return await this.etherspotWallet.getUserOpReceipt(userOpHash);
}
async getUserOpHash(userOp) {
return this.etherspotWallet.getUserOpHash(userOp);
}
async addUserOpsToBatch(tx) {
if (!tx.data && !tx.value) throw new ErrorHandler("Data and Value both cannot be empty", 1);
this.userOpsBatch.to.push(tx.to);
this.userOpsBatch.value.push(tx.value ?? BigNumber.from(0));
this.userOpsBatch.data.push(tx.data ?? "0x");
return this.userOpsBatch;
}
async clearUserOpsFromBatch() {
this.userOpsBatch.to = [];
this.userOpsBatch.data = [];
this.userOpsBatch.value = [];
}
async totalGasEstimated(userOp) {
const callGasLimit = BigNumber.from(await userOp.callGasLimit);
const verificationGasLimit = BigNumber.from(await userOp.verificationGasLimit);
const preVerificationGas = BigNumber.from(await userOp.preVerificationGas);
return callGasLimit.add(verificationGasLimit).add(preVerificationGas);
}
};
// src/sdk/index.ts
var sdk_default = RemoteSignerSdk;
// src/sdk/base/BaseAccountAPI.ts
var BaseAccountAPI = class {
/**
* base constructor.
* subclass SHOULD add parameters that define the owner (signer) of this wallet
*/
constructor(params) {
this.isPhantom = true;
const sdkOptions = params.sdkOptions;
const {
chainId,
//
rpcProviderUrl,
factoryWallet,
bundlerProvider
} = sdkOptions;
this.factoryUsed = factoryWallet;
this.overheads = params.overheads;
this.entryPointAddress = params.entryPointAddress;
this.externalViemAccount = params.externalViemAccount;
this.etherspotWalletAddress = params.etherspotWalletAddress;
this.factoryAddress = params.factoryAddress;
this.walletClient = params.walletClient;
this.publicClient = params.publicClient;
}
// sdk
// wallet
/**
* signs message
* @param dto
* @return Promise<string>
*/
async signMessage(dto) {
const { message } = await validateDto(dto, SignMessageDto);
await this.require({
network: false
});
return this.walletClient.signMessage(
{
account: this.externalViemAccount,
message
}
);
}
async setPaymasterApi(paymaster) {
this.paymasterAPI = paymaster;
}
// private
async require(options = {}) {
options = {
network: true,
wallet: true,
...options
};
}
async init() {
if (await this.publicClient.getCode({ address: this.entryPointAddress }) === "0x") {
throw new Error(`entryPoint not deployed at ${this.entryPointAddress}`);
}
await this.getEtherspotWalletAddress();
return this;
}
/**
* check if the contract is already deployed.
*/
async checkAccountPhantom() {
if (!this.isPhantom) {
return this.isPhantom;
}
const etherspotWalletAddress = await this.getEtherspotWalletAddress();
const senderAddressCode = await this.publicClient.getCode({ address: etherspotWalletAddress });
if (!senderAddressCode || senderAddressCode === "0x" || senderAddressCode.length <= 2) {
this.isPhantom = true;
} else {
this.isPhantom = false;
}
return this.isPhantom;
}
/**
* calculate the account address even before it is deployed
*/
async getCounterFactualAddress() {
const initCode = await this.getAccountInitCode();
try {
await this.publicClient.simulateContract({
address: this.entryPointAddress,
abi: parseAbi(entryPointAbi),
functionName: "getSenderAddress",
args: [initCode]
});
} catch (e) {
return e.errorArgs.sender;
}
throw new Error("must handle revert");
}
/**
* return initCode value to into the UserOp.
* (either deployment code, or empty hex if contract already deployed)
*/
async getInitCode() {
if (await this.checkAccountPhantom()) {
return await this.getAccountInitCode();
}
return "0x";
}
/**
* return maximum gas used for verification.
* NOTE: createUnsignedUserOp will add to this value the cost of creation, if the contract is not yet created.
*/
async getVerificationGasLimit() {
return 1e5;
}
/**
* should cover cost of putting calldata on-chain, and some overhead.
* actual overhead depends on the expected bundle size
*/
async getPreVerificationGas(userOp) {
const p = await resolveProperties(userOp);
return calcPreVerificationGas(p, this.overheads);
}
/**
* ABI-encode a user operation. used for calldata cost estimation
*/
packUserOp(userOp) {
return packUserOp(userOp, false);
}
async encodeUserOpCallDataAndGasLimit(detailsForUserOp) {
function parseNumber(a) {
if (a == null || a === "") return null;
return BigNumber.from(a.toString());
}
const value = parseNumber(detailsForUserOp.value) ?? BigNumber.from(0);
let callData;
const data = detailsForUserOp.data;
let target = detailsForUserOp.target;
if (typeof data === "string") {
if (typeof target !== "string") {
throw new Error("must have target address if data is single value");
}
callData = await this.encodeExecute(target, value, data);
} else {
if (typeof target === "string") {
target = Array(data.length).fill(target);
}
callData = await this.encodeBatch(target, detailsForUserOp.values, data);
}
const callGasLimit = parseNumber(detailsForUserOp.gasLimit) ?? BigNumber.from(35e3);
return {
callData,
callGasLimit
};
}
/**
* return userOpHash for signing.
* This value matches entryPoint.getUserOpHash (calculated off-chain, to avoid a view call)
* @param userOp userOperation, (signature field ignored)
*/
async getUserOpHash(userOp) {
const op = await resolveProperties(userOp);
const chainId = await this.publicClient.getChainId();
return getUserOpHash(op, this.entryPointAddress, chainId);
}
/**
* return the account's address.
* this value is valid even before deploying the contract.
*/
async getEtherspotWalletAddress() {
if (this.senderAddress == null) {
if (this.etherspotWalletAddress != null) {
this.senderAddress = this.etherspotWalletAddress;
} else {
this.senderAddress = await this.getCounterFactualAddress();
}
}
return this.senderAddress;
}
async estimateCreationGas(initCode) {
if (initCode == null || initCode === "0x") return 0;
const deployerAddress = initCode.substring(0, 42);
const deployerCallData = "0x" + initCode.substring(42);
const estimatedGas = await this.publicClient.estimateGas({
account: this.externalViemAccount,
to: deployerAddress,
data: deployerCallData
});
return estimatedGas ? estimatedGas : 0;
}
async getViemFeeData() {
const block = await this.publicClient.getBlock();
const gasPrice = await this.publicClient.getGasPrice();
const gasPriceInDecimals = BigNumber.from(gasPrice);
let lastBaseFeePerGas = null, maxFeePerGas = null, maxPriorityFeePerGas = null;
if (block && block.baseFeePerGas) {
lastBaseFeePerGas = block.baseFeePerGas;
const baseFeePerGasAsBigNumber = BigNumber.from(block.baseFeePerGas);
maxPriorityFeePerGas = BigNumber.from("1500000000");
maxFeePerGas = baseFeePerGasAsBigNumber.mul(2).add(maxPriorityFeePerGas);
}
return { lastBaseFeePerGas, maxFeePerGas, maxPriorityFeePerGas, gasPrice: gasPriceInDecimals };
}
/**
* create a UserOperation, filling all details (except signature)
* - if account is not yet created, add initCode to deploy it.
* - if gas or nonce are missing, read them from the chain (note that we can't fill gaslimit before the account is created)
* @param info
*/
async createUnsignedUserOp(info, key = BigNumber.from(0)) {
const { callData, callGasLimit } = await this.encodeUserOpCallDataAndGasLimit(info);
const factoryData = await this.getInitCode();
const initGas = await this.estimateCreationGas(factoryData);
const verificationGasLimit = BigNumber.from(await this.getVerificationGasLimit()).add(initGas);
let { maxFeePerGas, maxPriorityFeePerGas } = info;
if (maxFeePerGas == null || maxPriorityFeePerGas == null) {
let feeData = {};
try {
feeData = await this.getViemFeeData();
} catch (err) {
console.warn(
"getGas: eth_maxPriorityFeePerGas failed, falling back to legacy gas price."
);
const gas = await this.publicClient.getGasPrice();
feeData = { maxFeePerGas: gas, maxPriorityFeePerGas: gas };
}
if (maxFeePerGas == null) {
maxFeePerGas = feeData.maxFeePerGas ?? void 0;
}
if (maxPriorityFeePerGas == null) {
maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? void 0;
}
}
let partialUserOp;
if (factoryData !== "0x") {
partialUserOp = {
sender: await this.getEtherspotWalletAddress(),
nonce: await this.getNonce(key),
factory: this.factoryAddress,
factoryData: "0x" + factoryData.substring(42),
callData,
callGasLimit,
verificationGasLimit,
maxFeePerGas,
maxPriorityFeePerGas
};
} else {
partialUserOp = {
sender: await this.getEtherspotWalletAddress(),
nonce: await this.getNonce(key),
factoryData: "0x" + factoryData.substring(42),
callData,
callGasLimit,
verificationGasLimit,
maxFeePerGas,
maxPriorityFeePerGas
};
}
let paymasterData = null;
if (this.paymasterAPI != null) {
const userOpForPm = {
...partialUserOp,
preVerificationGas: this.getPreVerificationGas(partialUserOp)
};
paymasterData = await this.paymasterAPI.getPaymasterData(userOpForPm);
partialUserOp.verificationGasLimit = paymasterData.result.verificationGasLimit;
partialUserOp.preVerificationGas = paymasterData.result.preVerificationGas;
partialUserOp.callGasLimit = paymasterData.result.callGasLimit;
partialUserOp.paymaster = paymasterData.result.paymaster;
partialUserOp.paymasterVerificationGasLimit = paymasterData.result.paymasterVerificationGasLimit;
partialUserOp.paymasterPostOpGasLimit = paymasterData.result.paymasterPostOpGasLimit;
}
partialUserOp.paymasterData = paymasterData ? paymasterData.result.paymasterData : "0x";
return {
...partialUserOp,
preVerificationGas: this.getPreVerificationGas(partialUserOp),
signature: info.dummySignature ?? "0x"
};
}
/**
* get the transaction that has this userOpHash mined, or null if not found
* @param userOpHash returned by sendUserOpToBundler (or by getUserOpHash..)
* @param timeout stop waiting after this timeout
* @param interval time to wait between polls.
* @return the transactionHash this userOp was mined, or null if not found.
*/
async getUserOpReceipt(userOpHash, timeout = 3e4, interval = 5e3) {
const endtime = Date.now() + timeout;
while (Date.now() < endtime) {
const filter = await this.publicClient.createEventFilter({
address: this.entryPointAddress,
args: {
userOpHash
},
event: parseAbiItem("event UserOperationEvent(bytes32 indexed userOpHash,address indexed sender,address indexed paymaster,uint256 nonce,bool success,uint256 actualGasCost,uint256 actualGasUsed)")
});
const logs = await this.publicClient.getFilterLogs({ filter });
if (logs && logs.length > 0) {
return logs[0].transactionHash;
}
await new Promise((resolve) => setTimeout(resolve, interval));
}
return null;
}
// TODO fix signTypedData
async signTypedData(domain, types, message) {
const typesObject = {};
types.forEach((type) => {
if (!typesObject[type.type]) {
typesObject[type.type] = [type];
} else {
typesObject[type.type].push(type);
}
});
return await this.walletClient.signTypedData({
domain,
types: typesObject,
primaryType: "UserOperation",
account: this.externalViemAccount,
message
});
}
};
export {
BaseAccountAPI,
EtherspotWalletAPI,
RemoteSignerSdk,
sdk_default
};
//# sourceMappingURL=chunk-HQVIQWLZ.mjs.map