UNPKG

@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

268 lines (261 loc) • 9.71 kB
import { _ as _defineProperty } from './defineProperty-7303a112.esm.js'; import { C as Connector } from './connector-20f7cf73.esm.js'; import { H as HttpRpcClient } from './http-rpc-client-25e8ff7a.esm.js'; import { e as isZkSyncChain, f as ENTRYPOINT_ADDRESS } from './utils-80af2010.esm.js'; import { Signer, ethers, utils, BigNumber } from 'ethers'; import { defineReadOnly } from 'ethers/lib/utils'; import 'eventemitter3'; import './url-0d129c6b.esm.js'; import '@thirdweb-dev/chains'; import './headers-31b6ef3b.esm.js'; import '../evm/wallets/abstract/dist/thirdweb-dev-wallets-evm-wallets-abstract.esm.js'; import '@thirdweb-dev/sdk'; import '@account-abstraction/contracts'; const DEFAULT_GAS_PER_PUBDATA_LIMIT = 50000; const EIP712_TX_TYPE = 0x71; const EIP712_TYPES = { Transaction: [{ name: "txType", type: "uint256" }, { name: "from", type: "uint256" }, { name: "to", type: "uint256" }, { name: "gasLimit", type: "uint256" }, { name: "gasPerPubdataByteLimit", type: "uint256" }, { name: "maxFeePerGas", type: "uint256" }, { name: "maxPriorityFeePerGas", type: "uint256" }, { name: "paymaster", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "value", type: "uint256" }, { name: "data", type: "bytes" }, { name: "factoryDeps", type: "bytes32[]" }, { name: "paymasterInput", type: "bytes" }] }; class ZkWrappedSigner extends Signer { constructor(signer, httpRpcClient) { super(); this.signer = signer; defineReadOnly(this, "provider", signer.provider); this.httpRpcClient = httpRpcClient; } async getAddress() { return await this.signer.getAddress(); } async signMessage(message) { return await this.signer.signMessage(message); } async signTransaction(transaction) { return await this.signer.signTransaction(transaction); } connect(provider) { return new ZkWrappedSigner(this.signer.connect(provider), this.httpRpcClient); } _signTypedData(domain, types, value) { return this.signer._signTypedData(domain, types, value); } async sendTransaction(transaction) { return await this.sendZkSyncTransaction(transaction); } async sendZkSyncTransaction(_transaction) { let transaction = await this.populateTransaction(_transaction); if (!transaction.chainId) { throw new Error("ChainId is required to send a ZkSync transaction"); } if (!this.provider) { throw new Error("Provider is required to send a ZkSync transaction"); } const address = await this.getAddress(); const gasLimit = ethers.BigNumber.from(transaction.gasLimit || (await this.provider.estimateGas(transaction))).mul(3); const gasPrice = ethers.BigNumber.from(transaction.gasPrice || (await this.provider.getGasPrice())).mul(2); if (!transaction.maxFeePerGas) { transaction.maxFeePerGas = gasPrice; } else { transaction.maxFeePerGas = transaction.maxFeePerGas.mul(2); } if (!transaction.maxPriorityFeePerGas) { transaction.maxPriorityFeePerGas = gasPrice; } else { transaction.maxPriorityFeePerGas = transaction.maxPriorityFeePerGas.mul(2); } transaction = { ...transaction, from: address, gasLimit, gasPrice, chainId: (await this.provider.getNetwork()).chainId, nonce: await this.provider.getTransactionCount(address), type: 113, value: BigInt(0) }; const pmDataResult = await this.httpRpcClient?.zkPaymasterData(transaction); transaction.customData = { gasPerPubdata: DEFAULT_GAS_PER_PUBDATA_LIMIT, factoryDeps: [], paymasterParams: { paymaster: pmDataResult.paymaster, paymasterInput: pmDataResult.paymasterInput } }; const eip712tx = { txType: EIP712_TX_TYPE, from: BigInt(transaction.from || (await this.getAddress())).toString(), to: BigInt(transaction.to || "0x0").toString(), gasLimit: transaction.gasLimit ? Number(transaction.gasLimit) : 0, gasPerPubdataByteLimit: DEFAULT_GAS_PER_PUBDATA_LIMIT, maxFeePerGas: ethers.BigNumber.from(transaction.maxFeePerGas).toNumber(), maxPriorityFeePerGas: ethers.BigNumber.from(transaction.maxPriorityFeePerGas).toNumber(), paymaster: BigInt(pmDataResult.paymaster).toString(), nonce: ethers.BigNumber.from(transaction.nonce).toNumber(), value: ethers.BigNumber.from(transaction.value).toNumber(), data: transaction.data || "0x", factoryDeps: [], paymasterInput: ethers.utils.arrayify(pmDataResult.paymasterInput) }; const signature = await this._signTypedData({ name: "zkSync", version: "2", chainId: transaction.chainId }, EIP712_TYPES, eip712tx); const serializedTx = this.serialize(transaction, signature); const zkSignedTx = { from: transaction.from?.toString() || (await this.getAddress()), to: transaction.to?.toString() || "", gas: transaction.gasLimit?.toString() || "", maxFeePerGas: transaction.maxFeePerGas?.toString() || "0", maxPriorityFeePerGas: transaction.maxPriorityFeePerGas?.toString() || "0", signedTransaction: serializedTx, paymaster: pmDataResult.paymaster }; const broadcastResult = await this.httpRpcClient?.zkBroadcastTransaction(zkSignedTx); const hash = broadcastResult.transactionHash; return await this.provider?.getTransaction(hash); } serialize(transaction, signature) { if (!transaction.customData && transaction.type !== EIP712_TX_TYPE) { return utils.serializeTransaction(transaction, signature); } if (!transaction.chainId) { throw Error("Transaction chainId isn't set!"); } function formatNumber(value, name) { const result = utils.stripZeros(BigNumber.from(value).toHexString()); if (result.length > 32) { throw new Error(`Invalid length for ${name}!`); } return result; } if (!transaction.from) { throw new Error("Explicitly providing `from` field is required for EIP712 transactions!"); } const from = transaction.from; const meta = transaction.customData ?? {}; const maxFeePerGas = transaction.maxFeePerGas || transaction.gasPrice || 0; const maxPriorityFeePerGas = transaction.maxPriorityFeePerGas || maxFeePerGas; const fields = [formatNumber(transaction.nonce || 0, "nonce"), formatNumber(maxPriorityFeePerGas, "maxPriorityFeePerGas"), formatNumber(maxFeePerGas, "maxFeePerGas"), formatNumber(transaction.gasLimit || 0, "gasLimit"), transaction.to ? utils.getAddress(transaction.to) : "0x", formatNumber(transaction.value || 0, "value"), transaction.data || "0x"]; if (signature) { const sig = utils.splitSignature(signature); fields.push(formatNumber(sig.recoveryParam, "recoveryParam")); fields.push(utils.stripZeros(sig.r)); fields.push(utils.stripZeros(sig.s)); } else { fields.push(formatNumber(transaction.chainId, "chainId")); fields.push("0x"); fields.push("0x"); } fields.push(formatNumber(transaction.chainId, "chainId")); fields.push(utils.getAddress(from)); // Add meta fields.push(formatNumber(meta.gasPerPubdata || DEFAULT_GAS_PER_PUBDATA_LIMIT, "gasPerPubdata")); fields.push((meta.factoryDeps ?? []).map(dep => utils.hexlify(dep))); if (meta.customSignature && ethers.utils.arrayify(meta.customSignature).length === 0) { throw new Error("Empty signatures are not supported!"); } fields.push(meta.customSignature || "0x"); if (meta.paymasterParams) { fields.push([meta.paymasterParams.paymaster, ethers.utils.hexlify(meta.paymasterParams.paymasterInput)]); } else { fields.push([]); } return utils.hexConcat([[EIP712_TX_TYPE], utils.RLP.encode(fields)]); } } class ZkSyncConnector extends Connector { constructor(config) { super(); _defineProperty(this, "chainId", 1); this.config = config; } async connect(args) { this.personalWallet = args.personalWallet; this.chainId = await (await this.personalWallet.getSigner()).getChainId(); if (!(await isZkSyncChain(this.chainId))) { throw new Error("Invalid zksync chain id"); } const bundlerUrl = this.config.bundlerUrl || `https://${this.chainId}.bundler.thirdweb.com`; const entryPointAddress = this.config.entryPointAddress || ENTRYPOINT_ADDRESS; this.httpRpcClient = new HttpRpcClient(bundlerUrl, entryPointAddress, this.chainId, this.config.clientId, this.config.secretKey); return this.getAddress(); } disconnect() { throw new Error("Method not implemented."); } async getAddress() { const signer = await this.getSigner(); return signer.getAddress(); } async getSigner() { if (!this.personalWallet) { throw new Error("Wallet not connected"); } return new ZkWrappedSigner(await this.personalWallet.getSigner(), this.httpRpcClient); } // eslint-disable-next-line @typescript-eslint/no-unused-vars switchChain(chainId) { throw new Error("Method not implemented."); } isConnected() { return Promise.resolve(!!this.personalWallet); } setupListeners() { throw new Error("Method not implemented."); } // eslint-disable-next-line @typescript-eslint/no-unused-vars updateChains(chains) { throw new Error("Method not implemented."); } async getProvider() { if (!this.getSigner()) { throw new Error("Personal wallet not connected"); } const signer = await this.getSigner(); if (!signer.provider) { throw new Error("Provider not found"); } return signer.provider; } } export { ZkSyncConnector };