@thirdweb-dev/wallets
Version:
<p align="center"> <br /> <a href="https://thirdweb.com"><img src="https://github.com/thirdweb-dev/js/blob/main/legacy_packages/sdk/logo.svg?raw=true" width="200" alt=""/></a> <br /> </p> <h1 align="center">thirdweb Wallet SDK</h1> <p align="center"> <a h
207 lines (197 loc) • 7.44 kB
JavaScript
import { utils, BigNumber, providers } from 'ethers';
import { i as isTwUrl } from './url-a45219bd.browser.esm.js';
import { s as setAnalyticsHeaders } from './headers-733a8199.browser.esm.js';
import { e as isZkSyncChain, M as MANAGED_ACCOUNT_GAS_BUFFER } from './utils-f58e7acc.browser.esm.js';
async function hexlifyUserOp(
// TODO: types
op) {
const userOp = await utils.resolveProperties(op);
return Object.keys(userOp).map(key => {
let val = userOp[key];
if (typeof val !== "string" || !val.startsWith("0x")) {
val = utils.hexValue(val);
}
return [key, val];
}).reduce((set, _ref) => {
let [k, v] = _ref;
return {
...set,
[k]: v
};
}, {});
}
// v0.6 userOpHash calculation
async function getUserOpHashV06(userOp, entryPoint, chainId) {
const op = await utils.resolveProperties(userOp);
const hashedUserOp = {
sender: op.sender,
nonce: op.nonce,
initCodeHash: utils.keccak256(op.initCode),
callDataHash: utils.keccak256(op.callData),
callGasLimit: op.callGasLimit,
verificationGasLimit: op.verificationGasLimit,
preVerificationGas: op.preVerificationGas,
maxFeePerGas: op.maxFeePerGas,
maxPriorityFeePerGas: op.maxPriorityFeePerGas,
paymasterAndDataHash: utils.keccak256(op.paymasterAndData)
};
const userOpType = {
components: [{
type: "address",
name: "sender"
}, {
type: "uint256",
name: "nonce"
}, {
type: "bytes32",
name: "initCodeHash"
}, {
type: "bytes32",
name: "callDataHash"
}, {
type: "uint256",
name: "callGasLimit"
}, {
type: "uint256",
name: "verificationGasLimit"
}, {
type: "uint256",
name: "preVerificationGas"
}, {
type: "uint256",
name: "maxFeePerGas"
}, {
type: "uint256",
name: "maxPriorityFeePerGas"
}, {
type: "bytes32",
name: "paymasterAndDataHash"
}],
name: "hashedUserOp",
type: "tuple"
};
const encoded = utils.defaultAbiCoder.encode([userOpType], [{
...hashedUserOp
}]);
// remove leading word (total length) and trailing word (zero-length signature)
const userOpHash = utils.keccak256(encoded);
const enc = utils.defaultAbiCoder.encode(["bytes32", "address", "uint256"], [userOpHash, entryPoint, chainId]);
return utils.keccak256(enc);
}
const generateRandomUint192 = () => {
const rand1 = BigInt(Math.floor(Math.random() * 0x100000000));
const rand2 = BigInt(Math.floor(Math.random() * 0x100000000));
const rand3 = BigInt(Math.floor(Math.random() * 0x100000000));
const rand4 = BigInt(Math.floor(Math.random() * 0x100000000));
const rand5 = BigInt(Math.floor(Math.random() * 0x100000000));
const rand6 = BigInt(Math.floor(Math.random() * 0x100000000));
return rand1 << BigInt(160) | rand2 << BigInt(128) | rand3 << BigInt(96) | rand4 << BigInt(64) | rand5 << BigInt(32) | rand6;
};
const randomNonce = () => {
let hexString = generateRandomUint192().toString(16);
if (hexString.length % 2 !== 0) {
hexString = "0" + hexString;
}
hexString = "0x" + hexString;
return BigNumber.from(utils.concat([hexString, "0x0000000000000000"]));
};
const DEBUG = false; // TODO set as public flag
class HttpRpcClient {
constructor(bundlerUrl, entryPointAddress, chainId, clientId, secretKey) {
this.bundlerUrl = bundlerUrl;
this.entryPointAddress = entryPointAddress;
this.chainId = chainId;
const headers = {};
if (isTwUrl(this.bundlerUrl)) {
const bundleId = typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis ? globalThis.APP_BUNDLE_ID : undefined;
if (secretKey) {
headers["x-secret-key"] = secretKey;
} else if (clientId) {
headers["x-client-id"] = clientId;
if (bundleId) {
headers["x-bundle-id"] = bundleId;
}
}
// Dashboard token
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis && typeof globalThis.TW_AUTH_TOKEN === "string") {
headers["authorization"] = `Bearer ${globalThis.TW_AUTH_TOKEN}`;
}
// CLI token
if (typeof globalThis !== "undefined" && "TW_CLI_AUTH_TOKEN" in globalThis && typeof globalThis.TW_CLI_AUTH_TOKEN === "string") {
headers["authorization"] = `Bearer ${globalThis.TW_CLI_AUTH_TOKEN}`;
headers["x-authorize-wallet"] = "true";
}
setAnalyticsHeaders(headers);
}
this.userOpJsonRpcProvider = new providers.StaticJsonRpcProvider({
url: this.bundlerUrl,
headers
}, {
name: "Connected bundler network",
chainId
});
this.initializing = this.validateChainId();
}
async validateChainId() {
if (await isZkSyncChain(this.chainId)) {
return;
}
// validate chainId is in sync with expected chainid
const chain = await this.userOpJsonRpcProvider.send("eth_chainId", []);
const bundlerChain = parseInt(chain);
if (bundlerChain !== this.chainId) {
throw new Error(`bundler ${this.bundlerUrl} is on chainId ${bundlerChain}, but provider is on chainId ${this.chainId}`);
}
}
/**
* send a UserOperation to the bundler
* @param userOp1 - The UserOperation to send
* @returns userOpHash the id of this operation, for getUserOperationTransaction
*/
async sendUserOpToBundler(userOp1) {
await this.initializing;
const hexifiedUserOp = await hexlifyUserOp(userOp1);
const jsonRequestData = [hexifiedUserOp, this.entryPointAddress];
await this.printUserOperation("eth_sendUserOperation", jsonRequestData);
return await this.userOpJsonRpcProvider.send("eth_sendUserOperation", [hexifiedUserOp, this.entryPointAddress]);
}
async estimateUserOpGas(userOp) {
await this.initializing;
const hexifiedUserOp = await hexlifyUserOp(userOp);
const jsonRequestData = [hexifiedUserOp, this.entryPointAddress];
await this.printUserOperation("eth_estimateUserOperationGas", jsonRequestData);
const data = await this.userOpJsonRpcProvider.send("eth_estimateUserOperationGas", [hexifiedUserOp, this.entryPointAddress]);
// adds gas buffer to callGasLimit to account for ManagedAccountFactory delegate calls
return {
preVerificationGas: BigNumber.from(data.preVerificationGas),
verificationGas: BigNumber.from(data.verificationGas),
verificationGasLimit: BigNumber.from(data.verificationGasLimit),
callGasLimit: BigNumber.from(data.callGasLimit).add(MANAGED_ACCOUNT_GAS_BUFFER)
};
}
async getUserOperationGasPrice() {
await this.initializing;
return await this.userOpJsonRpcProvider.send("thirdweb_getUserOperationGasPrice", []);
}
async getUserOperationReceipt(userOpHash) {
await this.initializing;
return await this.userOpJsonRpcProvider.send("eth_getUserOperationReceipt", [userOpHash]);
}
async zkPaymasterData(transactionInput) {
await this.initializing;
return await this.userOpJsonRpcProvider.send("zk_paymasterData", [await hexlifyUserOp({
...transactionInput,
gas: transactionInput.gasLimit
})]);
}
async zkBroadcastTransaction(transactionInput) {
await this.initializing;
return await this.userOpJsonRpcProvider.send("zk_broadcastTransaction", [transactionInput]);
}
async printUserOperation(method, _ref) {
{
return;
}
}
}
export { DEBUG as D, HttpRpcClient as H, getUserOpHashV06 as g, hexlifyUserOp as h, randomNonce as r };