abstractionkit 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -793,6 +793,52 @@ async function handlefetchGasPrice(providerRpc, polygonGasStation, gasLevel = Ga
793
793
  return [maxFeePerGas, maxPriorityFeePerGas];
794
794
  }
795
795
  //#endregion
796
+ //#region src/signer/negotiate.ts
797
+ /**
798
+ * Pick the best mutually-supported signing scheme for one signer against an
799
+ * account's accepted schemes. Later in the `accepted` array = lower preference;
800
+ * the account ranks by preference.
801
+ *
802
+ * Throws a detailed {@link AbstractionKitError} if no scheme overlaps,
803
+ * citing the signer's address, what the account accepts, and what the
804
+ * signer can do.
805
+ */
806
+ function pickScheme(signer, accepted, context) {
807
+ const signerCan = [];
808
+ if (typeof signer.signTypedData === "function") signerCan.push("typedData");
809
+ if (typeof signer.signHash === "function") signerCan.push("hash");
810
+ for (const scheme of accepted) if (signerCan.includes(scheme)) return scheme;
811
+ throw new AbstractionKitError("BAD_DATA", buildMismatchMessage({
812
+ accountName: context.accountName,
813
+ signerIndex: context.signerIndex,
814
+ signerAddress: signer.address,
815
+ accepted,
816
+ signerCan
817
+ }));
818
+ }
819
+ function buildMismatchMessage(params) {
820
+ const { accountName, signerIndex, signerAddress, accepted, signerCan } = params;
821
+ const canStr = signerCan.length > 0 ? signerCan.join(", ") : "none";
822
+ return `No compatible signing scheme for signer[${signerIndex}] ${signerAddress}. ${accountName} accepts: [${accepted.join(", ")}]; signer provides: [${canStr}]. ` + (signerCan.length === 0 ? "Signer must implement at least one of `signHash` or `signTypedData`. " : "") + "Hint: `fromViem` / `fromEthersWallet` give both; `fromViemWalletClient` gives only `typedData` (use Safe for JSON-RPC wallets).";
823
+ }
824
+ /**
825
+ * Invoke a signer for one scheme. Keeps the dispatch in one place so the
826
+ * account-side code stays linear. `typedData` is optional: accounts that
827
+ * only accept the `"hash"` scheme (Simple7702, Calibur) pass just `hash`.
828
+ *
829
+ * `context` is always forwarded to the signer so power-user implementations
830
+ * can inspect the userOp.
831
+ */
832
+ async function invokeSigner(signer, scheme, payload) {
833
+ if (scheme === "typedData") {
834
+ if (typeof signer.signTypedData !== "function") throw new AbstractionKitError("BAD_DATA", `signer ${signer.address} is missing signTypedData`);
835
+ if (!payload.typedData) throw new AbstractionKitError("BAD_DATA", `scheme "typedData" selected but no typedData payload provided`);
836
+ return signer.signTypedData(payload.typedData, payload.context);
837
+ }
838
+ if (typeof signer.signHash !== "function") throw new AbstractionKitError("BAD_DATA", `signer ${signer.address} is missing signHash`);
839
+ return signer.signHash(payload.hash, payload.context);
840
+ }
841
+ //#endregion
796
842
  //#region src/utils7702.ts
797
843
  const SET_CODE_TX_TYPE = "0x04";
798
844
  /**
@@ -1570,6 +1616,30 @@ var BaseSimple7702Account = class BaseSimple7702Account extends SmartAccount {
1570
1616
  return new Wallet(privateKey).signingKey.sign(userOperationHash).serialized;
1571
1617
  }
1572
1618
  /**
1619
+ * Schemes Simple7702 accepts from a Signer. Only raw-hash ECDSA, since
1620
+ * the delegatee verifies a plain signature over the userOp hash.
1621
+ */
1622
+ static ACCEPTED_SIGNING_SCHEMES = ["hash"];
1623
+ /**
1624
+ * Sign a UserOperation with an {@link AkSigner}. Signer must implement
1625
+ * `signHash`, since Simple7702 only verifies raw ECDSA over the userOp
1626
+ * hash. JSON-RPC wallets and anything that only provides `signTypedData`
1627
+ * fail offline with a specific error.
1628
+ */
1629
+ async baseSignUserOperationWithSigner(useroperation, signer, chainId) {
1630
+ return invokeSigner(signer, pickScheme(signer, BaseSimple7702Account.ACCEPTED_SIGNING_SCHEMES, {
1631
+ accountName: "Simple7702 (raw ECDSA over userOpHash)",
1632
+ signerIndex: 0
1633
+ }), {
1634
+ hash: createUserOperationHash(useroperation, this.entrypointAddress, chainId),
1635
+ context: {
1636
+ userOperation: useroperation,
1637
+ chainId,
1638
+ entryPoint: this.entrypointAddress
1639
+ }
1640
+ });
1641
+ }
1642
+ /**
1573
1643
  * Submit a signed UserOperation to a bundler for on-chain inclusion.
1574
1644
  * @param userOperation - The signed UserOperation to submit
1575
1645
  * @param bundlerRpc - Bundler RPC endpoint
@@ -1680,6 +1750,18 @@ var Simple7702Account = class Simple7702Account extends BaseSimple7702Account {
1680
1750
  return this.baseSignUserOperation(useroperation, privateKey, chainId);
1681
1751
  }
1682
1752
  /**
1753
+ * Sign a {@link UserOperationV8} using an {@link ExternalSigner}.
1754
+ * Simple7702 only accepts raw-hash ECDSA; signers without `signHash`
1755
+ * fail offline with an actionable error.
1756
+ *
1757
+ * For signing with a raw private-key string, use the sync
1758
+ * {@link signUserOperation} method, or wrap explicitly with
1759
+ * `fromPrivateKey(pk)`.
1760
+ */
1761
+ async signUserOperationWithSigner(useroperation, signer, chainId) {
1762
+ return this.baseSignUserOperationWithSigner(useroperation, signer, chainId);
1763
+ }
1764
+ /**
1683
1765
  * Send a signed {@link UserOperationV8} to a bundler for on-chain inclusion.
1684
1766
  * @param userOperation - The signed UserOperation to submit
1685
1767
  * @param bundlerRpc - Bundler RPC endpoint
@@ -1745,6 +1827,15 @@ var Simple7702AccountV09 = class Simple7702AccountV09 extends BaseSimple7702Acco
1745
1827
  return this.baseSignUserOperation(useroperation, privateKey, chainId);
1746
1828
  }
1747
1829
  /**
1830
+ * Sign a {@link UserOperationV9} using an {@link ExternalSigner}.
1831
+ * Simple7702 only accepts raw-hash ECDSA; signers without `signHash`
1832
+ * fail offline with an actionable error. For a raw pk string, use the
1833
+ * sync {@link signUserOperation} method or wrap with `fromPrivateKey`.
1834
+ */
1835
+ async signUserOperationWithSigner(useroperation, signer, chainId) {
1836
+ return this.baseSignUserOperationWithSigner(useroperation, signer, chainId);
1837
+ }
1838
+ /**
1748
1839
  * Send a signed {@link UserOperationV9} to a bundler for on-chain inclusion.
1749
1840
  * @param userOperation - The signed UserOperation to submit
1750
1841
  * @param bundlerRpc - Bundler RPC endpoint
@@ -3149,6 +3240,68 @@ var SafeAccount = class SafeAccount extends SmartAccount {
3149
3240
  });
3150
3241
  }
3151
3242
  /**
3243
+ * Schemes Safe accepts from a {@link Signer}, in preference order.
3244
+ * `typedData` is preferred because wallets can display structured fields
3245
+ * rather than a hex blob; `hash` is accepted as a fallback for signers
3246
+ * that only support raw ECDSA.
3247
+ */
3248
+ static ACCEPTED_SIGNING_SCHEMES = ["typedData", "hash"];
3249
+ /**
3250
+ * Sign a UserOperation using one or more {@link Signer}s. This is the
3251
+ * capability-oriented signing path: each signer declares what it can do
3252
+ * (`signHash`, `signTypedData`, both) and the account picks the best
3253
+ * match per signer. Incompatible signers fail offline with an actionable
3254
+ * error rather than a silent bundler rejection.
3255
+ *
3256
+ * Signers are invoked in parallel. For interactive wallets that share a
3257
+ * popup session, sequence the prompts inside your Signer implementation.
3258
+ *
3259
+ * @param useroperation - UserOperation to sign
3260
+ * @param signers - Signer instances (`fromViem(account)`, `fromEthersWallet(wallet)`, etc.)
3261
+ * @param chainId - target chain id
3262
+ * @param entrypointAddress - target EntryPoint
3263
+ * @param safe4337ModuleAddress - Safe 4337 module
3264
+ * @param overrides - optional validAfter / validUntil / multi-chain flag
3265
+ * @returns formatted signature
3266
+ */
3267
+ static async baseSignUserOperationWithSigners(useroperation, signers, chainId, entrypointAddress, safe4337ModuleAddress, context, overrides = {}) {
3268
+ const validAfter = overrides.validAfter ?? 0n;
3269
+ const validUntil = overrides.validUntil ?? 0n;
3270
+ if (signers.length < 1) throw new RangeError("There should be at least one signer");
3271
+ const typedDataRaw = SafeAccount.getUserOperationEip712Data(useroperation, chainId, {
3272
+ validAfter,
3273
+ validUntil,
3274
+ entrypointAddress,
3275
+ safe4337ModuleAddress
3276
+ });
3277
+ const userOpHash = TypedDataEncoder.hash(typedDataRaw.domain, typedDataRaw.types, typedDataRaw.messageValue);
3278
+ const { EIP712Domain: _drop, ...primaryTypes } = typedDataRaw.types;
3279
+ const typedData = {
3280
+ domain: typedDataRaw.domain,
3281
+ types: primaryTypes,
3282
+ primaryType: EIP712_SAFE_OPERATION_PRIMARY_TYPE,
3283
+ message: typedDataRaw.messageValue
3284
+ };
3285
+ const normalizedAddresses = signers.map((signer) => getAddress(signer.address));
3286
+ const schemes = signers.map((signer, signerIndex) => pickScheme(signer, SafeAccount.ACCEPTED_SIGNING_SCHEMES, {
3287
+ accountName: "Safe (EIP-712 or raw hash over SafeOp digest)",
3288
+ signerIndex
3289
+ }));
3290
+ const signerSignaturePairs = (await Promise.all(signers.map((signer, i) => invokeSigner(signer, schemes[i], {
3291
+ hash: userOpHash,
3292
+ typedData,
3293
+ context
3294
+ })))).map((signature, i) => ({
3295
+ signer: normalizedAddresses[i],
3296
+ signature
3297
+ }));
3298
+ return SafeAccount.formatSignaturesToUseroperationSignature(signerSignaturePairs, {
3299
+ validAfter,
3300
+ validUntil,
3301
+ isMultiChainSignature: overrides.isMultiChainSignature
3302
+ });
3303
+ }
3304
+ /**
3152
3305
  * compute the deterministic address for a webauthn proxy verifier based on a
3153
3306
  * webauthn public key(x, y)
3154
3307
  * @param x - webauthn public key x parameter
@@ -3795,7 +3948,7 @@ var SafeAccount = class SafeAccount extends SmartAccount {
3795
3948
  * @param toolVersion - tool version, defaults to current abstractionkit version
3796
3949
  * @returns the onchain idenetifier as a hex string (not 0x prefixed)
3797
3950
  */
3798
- function generateOnChainIdentifier(project, platform = "Web", tool = "abstractionkit", toolVersion = "0.3.1") {
3951
+ function generateOnChainIdentifier(project, platform = "Web", tool = "abstractionkit", toolVersion = "0.3.2") {
3799
3952
  const identifierPrefix = "5afe";
3800
3953
  const identifierVersion = "00";
3801
3954
  const projectHash = keccak256("0x" + Buffer.from(project, "utf8").toString("hex")).slice(-20);
@@ -3872,6 +4025,17 @@ const DEFAULT_WEB_AUTHN_DAIMO_VERIFIER_V_0_2_1 = "0xc2b78104907F722DABAc4C69f826
3872
4025
  * with the Daimo P256 verifier instead of the FCL P256 verifier
3873
4026
  * used by the base SafeAccount class.
3874
4027
  * @see {@link https://github.com/safe-fndn/safe-modules/blob/04e65efbce634e776cc8c1fbe90061f09e09a71b/modules/passkey/CHANGELOG.md?plain=1#L23}
4028
+ *
4029
+ * @remarks Signer typing on this class is asymmetric:
4030
+ * - {@link signUserOperationWithSigners} (singular Operation) signs one op
4031
+ * and uses {@link SignContext} like every other account.
4032
+ * - {@link signUserOperationsWithSigners} (plural Operations) signs a bundle
4033
+ * under one signature and uses {@link MultiOpSignContext}.
4034
+ *
4035
+ * To author one signer that works on both methods, type it as
4036
+ * `ExternalSigner<unknown>` (the shape returned by the built-in adapters).
4037
+ * The two narrow context types exist so signers that DO read the context
4038
+ * get accurate, non-optional fields per path.
3875
4039
  */
3876
4040
  var SafeMultiChainSigAccountV1 = class SafeMultiChainSigAccountV1 extends SafeAccount {
3877
4041
  static DEFAULT_ENTRYPOINT_ADDRESS = ENTRYPOINT_V9;
@@ -4090,6 +4254,23 @@ var SafeMultiChainSigAccountV1 = class SafeMultiChainSigAccountV1 extends SafeAc
4090
4254
  });
4091
4255
  }
4092
4256
  /**
4257
+ * Sign a single UserOperation for multi-chain using one or more
4258
+ * {@link AkSigner} instances. See
4259
+ * {@link SafeAccountV0_3_0.signUserOperationWithSigners} for the full
4260
+ * design rationale. Sets the multi-chain flag automatically.
4261
+ */
4262
+ signUserOperationWithSigners(userOperation, signers, chainId, overrides = {}) {
4263
+ const context = {
4264
+ userOperation,
4265
+ chainId,
4266
+ entryPoint: this.entrypointAddress
4267
+ };
4268
+ return SafeAccount.baseSignUserOperationWithSigners(userOperation, signers, chainId, this.entrypointAddress, this.safe4337ModuleAddress, context, {
4269
+ ...overrides,
4270
+ isMultiChainSignature: true
4271
+ });
4272
+ }
4273
+ /**
4093
4274
  * sign a list of useroperations - multi chain signature
4094
4275
  * @param useroperation - useroperation to sign
4095
4276
  * @param privateKeys - for the signers
@@ -4140,6 +4321,86 @@ var SafeMultiChainSigAccountV1 = class SafeMultiChainSigAccountV1 extends SafeAc
4140
4321
  })];
4141
4322
  }
4142
4323
  /**
4324
+ * Sign a list of UserOperations with a single multi-chain signature,
4325
+ * using {@link AkSigner} instances typed for {@link MultiOpSignContext}
4326
+ * (viem, ethers, hardware wallet, HSM, MPC, Uint8Array-only). Each
4327
+ * signer signs the Merkle root of the UserOperation EIP-712 hashes via
4328
+ * raw-hash signing. `signTypedData` isn't exposed here because the
4329
+ * Merkle root is opaque and has no meaningful typed-data display.
4330
+ *
4331
+ * Signers always receive {@link MultiOpSignContext} regardless of bundle
4332
+ * length, so multi-op-typed signers can rely on `ctx.userOperations`
4333
+ * being defined. Pre-built adapters `fromPrivateKey`, `fromViem`, and
4334
+ * `fromEthersWallet` return a universal `Signer<unknown>` and work
4335
+ * here without retyping; user-defined single-op signers
4336
+ * (`Signer<SignContext>`) do not — they would receive a context shape
4337
+ * they didn't declare. `fromViemWalletClient` is **not** usable on the
4338
+ * multi-op Merkle path: it only exposes `signTypedData`, and the
4339
+ * Merkle root has no meaningful typed-data display. {@link pickScheme}
4340
+ * rejects it offline with an actionable error.
4341
+ *
4342
+ * @param userOperationsToSign - UserOperations + chain IDs + validity windows
4343
+ * @param signers - one Signer per owner (any order; sorted by address on-chain)
4344
+ * @returns one signature per input UserOperation, in the same order
4345
+ */
4346
+ async signUserOperationsWithSigners(userOperationsToSign, signers) {
4347
+ if (userOperationsToSign.length < 1) throw new RangeError("There should be at least one userOperationsToSign");
4348
+ if (signers.length < 1) throw new RangeError("There should be at least one signer");
4349
+ const context = {
4350
+ userOperations: userOperationsToSign.map((u) => ({
4351
+ userOperation: u.userOperation,
4352
+ chainId: u.chainId
4353
+ })),
4354
+ entryPoint: this.entrypointAddress
4355
+ };
4356
+ if (userOperationsToSign.length > 1) {
4357
+ const userOperationsHashes = [];
4358
+ userOperationsToSign.forEach((uopToSign) => {
4359
+ const userOperationHash = SafeAccount.getUserOperationEip712Hash_V9(uopToSign.userOperation, uopToSign.chainId, {
4360
+ validAfter: uopToSign.validAfter,
4361
+ validUntil: uopToSign.validUntil,
4362
+ safe4337ModuleAddress: this.safe4337ModuleAddress,
4363
+ entrypointAddress: this.entrypointAddress
4364
+ });
4365
+ userOperationsHashes.push(userOperationHash);
4366
+ });
4367
+ const [root, proofs] = generateMerkleProofs(userOperationsHashes);
4368
+ const merkleTreeRootHash = TypedDataEncoder.hash({ verifyingContract: this.safe4337ModuleAddress }, EIP712_MULTI_CHAIN_OPERATIONS_TYPE, { merkleTreeRoot: root });
4369
+ const normalizedAddresses = signers.map((signer) => getAddress(signer.address));
4370
+ signers.forEach((signer, i) => {
4371
+ pickScheme(signer, ["hash"], {
4372
+ accountName: "SafeMultiChainSigAccountV1 (multi-op Merkle root)",
4373
+ signerIndex: i
4374
+ });
4375
+ });
4376
+ const signatures = await Promise.all(signers.map((signer) => invokeSigner(signer, "hash", {
4377
+ hash: merkleTreeRootHash,
4378
+ context
4379
+ })));
4380
+ const signerSignaturePairs = signers.map((_signer, i) => ({
4381
+ signer: normalizedAddresses[i],
4382
+ signature: signatures[i]
4383
+ }));
4384
+ const userOpSignatures = [];
4385
+ userOperationsToSign.forEach((uopToSign, index) => {
4386
+ userOpSignatures.push(SafeAccount.formatSignaturesToUseroperationSignature(signerSignaturePairs, {
4387
+ validAfter: uopToSign.validAfter,
4388
+ validUntil: uopToSign.validUntil,
4389
+ isMultiChainSignature: true,
4390
+ multiChainMerkleProof: proofs[index]
4391
+ }));
4392
+ });
4393
+ return userOpSignatures;
4394
+ } else {
4395
+ const u = userOperationsToSign[0];
4396
+ return [await SafeAccount.baseSignUserOperationWithSigners(u.userOperation, signers, u.chainId, this.entrypointAddress, this.safe4337ModuleAddress, context, {
4397
+ validAfter: u.validAfter,
4398
+ validUntil: u.validUntil,
4399
+ isMultiChainSignature: true
4400
+ })];
4401
+ }
4402
+ }
4403
+ /**
4143
4404
  * Compute the EIP-712 hash of a multi-chain Merkle tree root for a set of UserOperations.
4144
4405
  * This hash is what signers sign to approve multiple cross-chain operations at once.
4145
4406
  * @param userOperationsToSignsToSign - list of UserOperations with their target chain IDs
@@ -4616,34 +4877,42 @@ var Calibur7702Account = class Calibur7702Account extends SmartAccount {
4616
4877
  return Calibur7702Account.wrapSignature(keyHash, ecdsaSig, hookData);
4617
4878
  }
4618
4879
  /**
4619
- * Sign a UserOperation with an external signer (viem, ethers Signer,
4620
- * hardware wallet, MPC signer, etc.).
4621
- * Computes the UserOperation hash and wraps the returned signature in
4622
- * Calibur's format: `abi.encode(keyHash, ecdsaSig, hookData)`.
4623
- *
4624
- * By default signs with the root key. To sign with a registered
4625
- * secondary key, pass its key hash via `overrides.keyHash`.
4880
+ * Schemes Calibur accepts from a Signer. Only raw-hash ECDSA, since
4881
+ * the account verifies a plain signature over the userOp hash, then
4882
+ * wraps with `(keyHash, signature, hookData)`.
4883
+ */
4884
+ static ACCEPTED_SIGNING_SCHEMES = ["hash"];
4885
+ /**
4886
+ * Sign a UserOperation using an {@link ExternalSigner}. Calibur only
4887
+ * accepts raw-hash ECDSA; signers without `signHash` fail offline with
4888
+ * an actionable error.
4626
4889
  *
4627
- * @param userOperation - The UserOperation to sign
4628
- * @param signer - Async signing function: `(hash: string) => Promise<string>`
4629
- * @param chainId - Target chain ID
4630
- * @param overrides - Optional overrides (keyHash for secondary keys, hookData)
4631
- * @returns Promise resolving to the hex-encoded wrapped signature
4890
+ * For signing with a raw private-key string, use the sync
4891
+ * {@link signUserOperation} method, or wrap explicitly with
4892
+ * `fromPrivateKey(pk)`. For secondary (non-root) keys, pass the key
4893
+ * hash via `overrides.keyHash`.
4632
4894
  *
4633
4895
  * @example
4634
- * // Sign with a viem wallet client
4896
+ * import { fromViem, fromEthersWallet } from "abstractionkit";
4635
4897
  * userOp.signature = await account.signUserOperationWithSigner(
4636
- * userOp,
4637
- * (hash) => walletClient.signMessage({ message: { raw: hash } }),
4638
- * chainId,
4898
+ * userOp, fromViem(privateKeyToAccount(pk)), chainId,
4639
4899
  * );
4640
4900
  */
4641
4901
  async signUserOperationWithSigner(userOperation, signer, chainId, overrides = {}) {
4642
- const userOperationHash = createUserOperationHash(userOperation, this.entrypointAddress, chainId);
4902
+ const signature = await invokeSigner(signer, pickScheme(signer, Calibur7702Account.ACCEPTED_SIGNING_SCHEMES, {
4903
+ accountName: "Calibur (raw ECDSA over userOpHash)",
4904
+ signerIndex: 0
4905
+ }), {
4906
+ hash: createUserOperationHash(userOperation, this.entrypointAddress, chainId),
4907
+ context: {
4908
+ userOperation,
4909
+ chainId,
4910
+ entryPoint: this.entrypointAddress
4911
+ }
4912
+ });
4643
4913
  const keyHash = overrides.keyHash ?? ROOT_KEY_HASH;
4644
4914
  const hookData = overrides.hookData ?? "0x";
4645
- const ecdsaSig = await signer(userOperationHash);
4646
- return Calibur7702Account.wrapSignature(keyHash, ecdsaSig, hookData);
4915
+ return Calibur7702Account.wrapSignature(keyHash, signature, hookData);
4647
4916
  }
4648
4917
  /**
4649
4918
  * Format a WebAuthn (passkey) assertion into Calibur's signature format.
@@ -5114,6 +5383,88 @@ var Calibur7702Account = class Calibur7702Account extends SmartAccount {
5114
5383
  }
5115
5384
  };
5116
5385
  //#endregion
5386
+ //#region src/signer/adapters.ts
5387
+ /**
5388
+ * Build a Signer from a raw private key. Uses the library's existing
5389
+ * ethers dependency internally, so no additional packages are required on
5390
+ * the caller side. Supports both raw-hash and typed-data signing.
5391
+ *
5392
+ * Prefer this when all you have is a private key (test suites, server-side
5393
+ * scripts, scripts with env-injected keys, etc.). If you already hold a
5394
+ * viem Account or ethers Wallet from elsewhere in your app, pass it to
5395
+ * {@link fromViem} or {@link fromEthersWallet} instead.
5396
+ *
5397
+ * @example
5398
+ * import { fromPrivateKey } from "abstractionkit";
5399
+ * const signer = fromPrivateKey(process.env.PRIVATE_KEY!);
5400
+ * userOp.signature = await safe.signUserOperationWithSigners(userOp, [signer], chainId);
5401
+ */
5402
+ function fromPrivateKey(privateKey) {
5403
+ const wallet = new Wallet(privateKey);
5404
+ return {
5405
+ address: getAddress(wallet.address),
5406
+ signHash: async (hash) => wallet.signingKey.sign(hash).serialized,
5407
+ signTypedData: async (td) => await wallet.signTypedData(td.domain, td.types, td.message)
5408
+ };
5409
+ }
5410
+ /**
5411
+ * Adapt a viem Local Account (e.g. `privateKeyToAccount(pk)`) to a Signer.
5412
+ * Supports both raw-hash and typed-data signing.
5413
+ *
5414
+ * @remarks Requires viem &gt;= 2.0.
5415
+ */
5416
+ function fromViem(account) {
5417
+ return {
5418
+ address: account.address,
5419
+ signHash: (hash) => account.sign({ hash }),
5420
+ signTypedData: (td) => account.signTypedData({
5421
+ domain: td.domain,
5422
+ types: td.types,
5423
+ primaryType: td.primaryType,
5424
+ message: td.message
5425
+ })
5426
+ };
5427
+ }
5428
+ /**
5429
+ * Adapt a viem WalletClient to a Signer. WalletClient is the client-style
5430
+ * API dApps use to drive browser / JSON-RPC wallets, so only typed-data
5431
+ * signing is exposed (JSON-RPC wallets can't sign raw hashes).
5432
+ *
5433
+ * Requires the client to have been constructed with an `account` (local or
5434
+ * JSON-RPC). For local accounts, pass that directly to `fromViem` instead
5435
+ * if you want raw-hash fallback.
5436
+ *
5437
+ * @remarks Requires viem &gt;= 2.0.
5438
+ */
5439
+ function fromViemWalletClient(client) {
5440
+ if (!client.account) throw new Error("fromViemWalletClient: client has no `account` configured. Construct with `createWalletClient({ account, transport, chain })`.");
5441
+ const account = client.account;
5442
+ const signTypedData = client.signTypedData;
5443
+ return {
5444
+ address: account.address,
5445
+ signTypedData: (td) => signTypedData({
5446
+ account,
5447
+ domain: td.domain,
5448
+ types: td.types,
5449
+ primaryType: td.primaryType,
5450
+ message: td.message
5451
+ })
5452
+ };
5453
+ }
5454
+ /**
5455
+ * Adapt an ethers `Wallet` / `HDNodeWallet` to a Signer. Supports both
5456
+ * raw-hash and typed-data signing.
5457
+ *
5458
+ * @remarks Requires ethers &gt;= 6.0.
5459
+ */
5460
+ function fromEthersWallet(wallet) {
5461
+ return {
5462
+ address: wallet.address,
5463
+ signHash: async (hash) => wallet.signingKey.sign(hash).serialized,
5464
+ signTypedData: async (td) => await wallet.signTypedData(td.domain, td.types, td.message)
5465
+ };
5466
+ }
5467
+ //#endregion
5117
5468
  //#region src/account/Safe/modules/SafeModule.ts
5118
5469
  /**
5119
5470
  * Abstract base class for Safe modules. Provides shared utilities for
@@ -6117,6 +6468,45 @@ var SafeAccountV0_3_0 = class SafeAccountV0_3_0 extends SafeAccount {
6117
6468
  signUserOperation(useroperation, privateKeys, chainId, overrides = {}) {
6118
6469
  return SafeAccount.baseSignSingleUserOperation(useroperation, privateKeys, chainId, this.entrypointAddress, this.safe4337ModuleAddress, overrides);
6119
6470
  }
6471
+ /**
6472
+ * Sign a UserOperation using one or more {@link ExternalSigner} instances.
6473
+ * Capability-oriented entry point: each Signer declares what it can do
6474
+ * (`signHash`, `signTypedData`, both) and the account picks the best
6475
+ * match per signer. Incompatible signers fail offline with an actionable
6476
+ * error — no silent bundler rejections.
6477
+ *
6478
+ * This method is for external signers only (viem, ethers, hardware
6479
+ * wallets, MPC, HSMs, Uint8Array-only signers). If you just have a raw
6480
+ * private-key string, use the sync {@link signUserOperation} method
6481
+ * instead, or wrap explicitly with `fromPrivateKey(pk)`.
6482
+ *
6483
+ * Prebuilt adapters: `fromViem`, `fromEthersWallet`,
6484
+ * `fromViemWalletClient`, `fromPrivateKey`. Custom signers just need to
6485
+ * match the `ExternalSigner` shape.
6486
+ *
6487
+ * @example
6488
+ * import { fromViem } from "abstractionkit";
6489
+ * import { privateKeyToAccount } from "viem/accounts";
6490
+ *
6491
+ * const signer = fromViem(privateKeyToAccount(pk));
6492
+ * userOp.signature = await account.signUserOperationWithSigners(
6493
+ * userOp, [signer], chainId,
6494
+ * );
6495
+ *
6496
+ * @param useroperation - UserOperation to sign
6497
+ * @param signers - one ExternalSigner per owner (any order)
6498
+ * @param chainId - target chain ID
6499
+ * @param overrides - optional validAfter / validUntil / multi-chain flag
6500
+ * @returns Promise resolving to the formatted signature string
6501
+ */
6502
+ signUserOperationWithSigners(useroperation, signers, chainId, overrides = {}) {
6503
+ const context = {
6504
+ userOperation: useroperation,
6505
+ chainId,
6506
+ entryPoint: this.entrypointAddress
6507
+ };
6508
+ return SafeAccount.baseSignUserOperationWithSigners(useroperation, signers, chainId, this.entrypointAddress, this.safe4337ModuleAddress, context, overrides);
6509
+ }
6120
6510
  };
6121
6511
  //#endregion
6122
6512
  //#region src/account/Safe/SafeAccountV0_2_0.ts
@@ -6359,6 +6749,19 @@ var SafeAccountV0_2_0 = class SafeAccountV0_2_0 extends SafeAccount {
6359
6749
  signUserOperation(useroperation, privateKeys, chainId, overrides = {}) {
6360
6750
  return SafeAccount.baseSignSingleUserOperation(useroperation, privateKeys, chainId, this.entrypointAddress, this.safe4337ModuleAddress, overrides);
6361
6751
  }
6752
+ /**
6753
+ * Sign a UserOperation using one or more {@link AkSigner} instances.
6754
+ * See {@link SafeAccountV0_3_0.signUserOperationWithSigners} for full
6755
+ * design rationale and examples.
6756
+ */
6757
+ signUserOperationWithSigners(useroperation, signers, chainId, overrides = {}) {
6758
+ const context = {
6759
+ userOperation: useroperation,
6760
+ chainId,
6761
+ entryPoint: this.entrypointAddress
6762
+ };
6763
+ return SafeAccount.baseSignUserOperationWithSigners(useroperation, signers, chainId, this.entrypointAddress, this.safe4337ModuleAddress, context, overrides);
6764
+ }
6362
6765
  };
6363
6766
  //#endregion
6364
6767
  //#region src/account/Safe/SafeAccountV1_5_0_M_0_3_0.ts
@@ -7524,6 +7927,10 @@ var abstractionkit_exports = /* @__PURE__ */ __exportAll({
7524
7927
  createWorldIdSignal: () => createWorldIdSignal,
7525
7928
  fetchAccountNonce: () => fetchAccountNonce,
7526
7929
  fetchGasPrice: () => fetchGasPrice,
7930
+ fromEthersWallet: () => fromEthersWallet,
7931
+ fromPrivateKey: () => fromPrivateKey,
7932
+ fromViem: () => fromViem,
7933
+ fromViemWalletClient: () => fromViemWalletClient,
7527
7934
  getBalanceOf: () => getBalanceOf,
7528
7935
  getDelegatedAddress: () => getDelegatedAddress,
7529
7936
  getDepositInfo: () => getDepositInfo,
@@ -7540,6 +7947,6 @@ var abstractionkit_exports = /* @__PURE__ */ __exportAll({
7540
7947
  simulateUserOperationWithTenderlyAndCreateShareLink: () => simulateUserOperationWithTenderlyAndCreateShareLink
7541
7948
  });
7542
7949
  //#endregion
7543
- export { ALLOWANCE_MODULE_V0_1_0_ADDRESS, AbstractionKitError, AllowanceModule, BaseUserOperationDummyValues, Bundler, CALIBUR_CANDIDE_V0_1_0_SINGLETON_ADDRESS, CALIBUR_UNISWAP_V1_0_0_SINGLETON_ADDRESS, Calibur7702Account, CaliburKeyType, CandidePaymaster, DEFAULT_SECP256R1_PRECOMPILE_ADDRESS, EIP712_MULTI_CHAIN_OPERATIONS_PRIMARY_TYPE, EIP712_MULTI_CHAIN_OPERATIONS_TYPE, EIP712_RECOVERY_MODULE_TYPE, EIP712_SAFE_OPERATION_PRIMARY_TYPE, EIP712_SAFE_OPERATION_V6_TYPE, EIP712_SAFE_OPERATION_V7_TYPE, ENTRYPOINT_V6, ENTRYPOINT_V7, ENTRYPOINT_V8, ENTRYPOINT_V9, EOADummySignerSignaturePair, EXECUTE_RECOVERY_PRIMARY_TYPE, Erc7677Paymaster, ExperimentalAllowAllParallelPaymaster, GasOption, Operation, PolygonChain, SAFE_MESSAGE_MODULE_TYPE, SAFE_MESSAGE_PRIMARY_TYPE, SafeAccountFactory, SafeAccountV0_2_0, SafeAccountV0_3_0, SafeAccountV1_5_0_M_0_3_0, SafeModuleExecutorFunctionSelector, SafeMultiChainSigAccountV1, SendUseroperationResponse, Simple7702Account, Simple7702AccountV09, SmartAccount, SmartAccountFactory, SocialRecoveryModule, SocialRecoveryModuleGracePeriodSelector, WebauthnDummySignerSignaturePair, WorldIdPermissionlessPaymaster, ZeroAddress, abstractionkit_exports as abstractionkit, calculateUserOperationMaxGasCost, callTenderlySimulateBundle, createAndSignEip7702DelegationAuthorization, createAndSignEip7702RawTransaction, createAndSignLegacyRawTransaction, createCallData, createEip7702DelegationAuthorizationHash, createEip7702TransactionHash, createUserOperationHash, createWorldIdSignal, fetchAccountNonce, fetchGasPrice, getBalanceOf, getDelegatedAddress, getDepositInfo, getFunctionSelector, getSafeMessageEip712Data, sendJsonRpcRequest, shareTenderlySimulationAndCreateLink, signHash, simulateSenderCallDataWithTenderly, simulateSenderCallDataWithTenderlyAndCreateShareLink, simulateUserOperationCallDataWithTenderly, simulateUserOperationCallDataWithTenderlyAndCreateShareLink, simulateUserOperationWithTenderly, simulateUserOperationWithTenderlyAndCreateShareLink };
7950
+ export { ALLOWANCE_MODULE_V0_1_0_ADDRESS, AbstractionKitError, AllowanceModule, BaseUserOperationDummyValues, Bundler, CALIBUR_CANDIDE_V0_1_0_SINGLETON_ADDRESS, CALIBUR_UNISWAP_V1_0_0_SINGLETON_ADDRESS, Calibur7702Account, CaliburKeyType, CandidePaymaster, DEFAULT_SECP256R1_PRECOMPILE_ADDRESS, EIP712_MULTI_CHAIN_OPERATIONS_PRIMARY_TYPE, EIP712_MULTI_CHAIN_OPERATIONS_TYPE, EIP712_RECOVERY_MODULE_TYPE, EIP712_SAFE_OPERATION_PRIMARY_TYPE, EIP712_SAFE_OPERATION_V6_TYPE, EIP712_SAFE_OPERATION_V7_TYPE, ENTRYPOINT_V6, ENTRYPOINT_V7, ENTRYPOINT_V8, ENTRYPOINT_V9, EOADummySignerSignaturePair, EXECUTE_RECOVERY_PRIMARY_TYPE, Erc7677Paymaster, ExperimentalAllowAllParallelPaymaster, GasOption, Operation, PolygonChain, SAFE_MESSAGE_MODULE_TYPE, SAFE_MESSAGE_PRIMARY_TYPE, SafeAccountFactory, SafeAccountV0_2_0, SafeAccountV0_3_0, SafeAccountV1_5_0_M_0_3_0, SafeModuleExecutorFunctionSelector, SafeMultiChainSigAccountV1, SendUseroperationResponse, Simple7702Account, Simple7702AccountV09, SmartAccount, SmartAccountFactory, SocialRecoveryModule, SocialRecoveryModuleGracePeriodSelector, WebauthnDummySignerSignaturePair, WorldIdPermissionlessPaymaster, ZeroAddress, abstractionkit_exports as abstractionkit, calculateUserOperationMaxGasCost, callTenderlySimulateBundle, createAndSignEip7702DelegationAuthorization, createAndSignEip7702RawTransaction, createAndSignLegacyRawTransaction, createCallData, createEip7702DelegationAuthorizationHash, createEip7702TransactionHash, createUserOperationHash, createWorldIdSignal, fetchAccountNonce, fetchGasPrice, fromEthersWallet, fromPrivateKey, fromViem, fromViemWalletClient, getBalanceOf, getDelegatedAddress, getDepositInfo, getFunctionSelector, getSafeMessageEip712Data, sendJsonRpcRequest, shareTenderlySimulationAndCreateLink, signHash, simulateSenderCallDataWithTenderly, simulateSenderCallDataWithTenderlyAndCreateShareLink, simulateUserOperationCallDataWithTenderly, simulateUserOperationCallDataWithTenderlyAndCreateShareLink, simulateUserOperationWithTenderly, simulateUserOperationWithTenderlyAndCreateShareLink };
7544
7951
 
7545
7952
  //# sourceMappingURL=index.mjs.map