@verbeth/sdk 0.1.4

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.
Files changed (86) hide show
  1. package/README.md +202 -0
  2. package/dist/esm/src/client/VerbethClient.d.ts +134 -0
  3. package/dist/esm/src/client/VerbethClient.d.ts.map +1 -0
  4. package/dist/esm/src/client/VerbethClient.js +191 -0
  5. package/dist/esm/src/client/index.d.ts +3 -0
  6. package/dist/esm/src/client/index.d.ts.map +1 -0
  7. package/dist/esm/src/client/index.js +2 -0
  8. package/dist/esm/src/client/types.d.ts +30 -0
  9. package/dist/esm/src/client/types.d.ts.map +1 -0
  10. package/dist/esm/src/client/types.js +2 -0
  11. package/dist/esm/src/crypto.d.ts +46 -0
  12. package/dist/esm/src/crypto.d.ts.map +1 -0
  13. package/dist/esm/src/crypto.js +137 -0
  14. package/dist/esm/src/executor.d.ts +73 -0
  15. package/dist/esm/src/executor.d.ts.map +1 -0
  16. package/dist/esm/src/executor.js +353 -0
  17. package/dist/esm/src/identity.d.ts +28 -0
  18. package/dist/esm/src/identity.d.ts.map +1 -0
  19. package/dist/esm/src/identity.js +70 -0
  20. package/dist/esm/src/index.d.ts +18 -0
  21. package/dist/esm/src/index.d.ts.map +1 -0
  22. package/dist/esm/src/index.js +17 -0
  23. package/dist/esm/src/payload.d.ts +94 -0
  24. package/dist/esm/src/payload.d.ts.map +1 -0
  25. package/dist/esm/src/payload.js +216 -0
  26. package/dist/esm/src/send.d.ts +50 -0
  27. package/dist/esm/src/send.d.ts.map +1 -0
  28. package/dist/esm/src/send.js +75 -0
  29. package/dist/esm/src/types.d.ts +73 -0
  30. package/dist/esm/src/types.d.ts.map +1 -0
  31. package/dist/esm/src/types.js +2 -0
  32. package/dist/esm/src/utils/nonce.d.ts +2 -0
  33. package/dist/esm/src/utils/nonce.d.ts.map +1 -0
  34. package/dist/esm/src/utils/nonce.js +6 -0
  35. package/dist/esm/src/utils/x25519.d.ts +6 -0
  36. package/dist/esm/src/utils/x25519.d.ts.map +1 -0
  37. package/dist/esm/src/utils/x25519.js +12 -0
  38. package/dist/esm/src/utils.d.ts +29 -0
  39. package/dist/esm/src/utils.d.ts.map +1 -0
  40. package/dist/esm/src/utils.js +123 -0
  41. package/dist/esm/src/verify.d.ts +54 -0
  42. package/dist/esm/src/verify.d.ts.map +1 -0
  43. package/dist/esm/src/verify.js +186 -0
  44. package/dist/src/client/VerbethClient.d.ts +134 -0
  45. package/dist/src/client/VerbethClient.d.ts.map +1 -0
  46. package/dist/src/client/VerbethClient.js +191 -0
  47. package/dist/src/client/index.d.ts +3 -0
  48. package/dist/src/client/index.d.ts.map +1 -0
  49. package/dist/src/client/index.js +2 -0
  50. package/dist/src/client/types.d.ts +30 -0
  51. package/dist/src/client/types.d.ts.map +1 -0
  52. package/dist/src/client/types.js +2 -0
  53. package/dist/src/crypto.d.ts +46 -0
  54. package/dist/src/crypto.d.ts.map +1 -0
  55. package/dist/src/crypto.js +137 -0
  56. package/dist/src/executor.d.ts +73 -0
  57. package/dist/src/executor.d.ts.map +1 -0
  58. package/dist/src/executor.js +353 -0
  59. package/dist/src/identity.d.ts +28 -0
  60. package/dist/src/identity.d.ts.map +1 -0
  61. package/dist/src/identity.js +70 -0
  62. package/dist/src/index.d.ts +18 -0
  63. package/dist/src/index.d.ts.map +1 -0
  64. package/dist/src/index.js +17 -0
  65. package/dist/src/payload.d.ts +94 -0
  66. package/dist/src/payload.d.ts.map +1 -0
  67. package/dist/src/payload.js +216 -0
  68. package/dist/src/send.d.ts +50 -0
  69. package/dist/src/send.d.ts.map +1 -0
  70. package/dist/src/send.js +75 -0
  71. package/dist/src/types.d.ts +73 -0
  72. package/dist/src/types.d.ts.map +1 -0
  73. package/dist/src/types.js +2 -0
  74. package/dist/src/utils/nonce.d.ts +2 -0
  75. package/dist/src/utils/nonce.d.ts.map +1 -0
  76. package/dist/src/utils/nonce.js +6 -0
  77. package/dist/src/utils/x25519.d.ts +6 -0
  78. package/dist/src/utils/x25519.d.ts.map +1 -0
  79. package/dist/src/utils/x25519.js +12 -0
  80. package/dist/src/utils.d.ts +29 -0
  81. package/dist/src/utils.d.ts.map +1 -0
  82. package/dist/src/utils.js +123 -0
  83. package/dist/src/verify.d.ts +54 -0
  84. package/dist/src/verify.d.ts.map +1 -0
  85. package/dist/src/verify.js +186 -0
  86. package/package.json +38 -0
@@ -0,0 +1,137 @@
1
+ // packages/sdk/src/crypto.ts
2
+ import nacl from 'tweetnacl';
3
+ import { keccak256, toUtf8Bytes, dataSlice } from 'ethers';
4
+ import { sha256 } from '@noble/hashes/sha2';
5
+ import { hkdf } from '@noble/hashes/hkdf';
6
+ import { encodePayload, decodePayload, encodeStructuredContent, decodeStructuredContent, extractKeysFromHandshakeResponse } from './payload.js';
7
+ /**
8
+ * Encrypts a structured payload (JSON-serializable objects)
9
+ */
10
+ export function encryptStructuredPayload(payload, recipientPublicKey, ephemeralSecretKey, ephemeralPublicKey, staticSigningSecretKey, staticSigningPublicKey) {
11
+ // encode payload as binary JSON
12
+ const plaintext = encodeStructuredContent(payload);
13
+ const nonce = nacl.randomBytes(nacl.box.nonceLength);
14
+ const box = nacl.box(plaintext, nonce, recipientPublicKey, ephemeralSecretKey);
15
+ let sig;
16
+ if (staticSigningSecretKey && staticSigningPublicKey) {
17
+ const dataToSign = Buffer.concat([ephemeralPublicKey, nonce, box]);
18
+ sig = nacl.sign.detached(dataToSign, staticSigningSecretKey);
19
+ }
20
+ return encodePayload(ephemeralPublicKey, nonce, box, sig);
21
+ }
22
+ /**
23
+ * Decrypts a structured payload with converter function
24
+ */
25
+ export function decryptStructuredPayload(payloadJson, recipientSecretKey, converter, staticSigningPublicKey) {
26
+ const { epk, nonce, ciphertext, sig } = decodePayload(payloadJson);
27
+ if (sig && staticSigningPublicKey) {
28
+ const dataToVerify = Buffer.concat([epk, nonce, ciphertext]);
29
+ const valid = nacl.sign.detached.verify(dataToVerify, sig, staticSigningPublicKey);
30
+ if (!valid)
31
+ return null;
32
+ }
33
+ const box = nacl.box.open(ciphertext, nonce, epk, recipientSecretKey);
34
+ if (!box)
35
+ return null;
36
+ return decodeStructuredContent(box, converter);
37
+ }
38
+ // wrappers for encrypting and decrypting messages
39
+ export function encryptMessage(message, recipientPublicKey, ephemeralSecretKey, ephemeralPublicKey, staticSigningSecretKey, staticSigningPublicKey) {
40
+ const payload = { content: message };
41
+ return encryptStructuredPayload(payload, recipientPublicKey, ephemeralSecretKey, ephemeralPublicKey, staticSigningSecretKey, staticSigningPublicKey);
42
+ }
43
+ export function decryptMessage(payloadJson, recipientSecretKey, staticSigningPublicKey) {
44
+ const result = decryptStructuredPayload(payloadJson, recipientSecretKey, (obj) => obj, staticSigningPublicKey);
45
+ return result ? result.content : null;
46
+ }
47
+ /**
48
+ * Decrypts handshake response and extracts individual keys from unified format
49
+ */
50
+ export function decryptHandshakeResponse(payloadJson, initiatorEphemeralSecretKey) {
51
+ return decryptStructuredPayload(payloadJson, initiatorEphemeralSecretKey, (obj) => {
52
+ if (!obj.identityProof) {
53
+ throw new Error("Invalid handshake response: missing identityProof");
54
+ }
55
+ return {
56
+ unifiedPubKeys: Uint8Array.from(Buffer.from(obj.unifiedPubKeys, 'base64')),
57
+ ephemeralPubKey: Uint8Array.from(Buffer.from(obj.ephemeralPubKey, 'base64')),
58
+ note: obj.note,
59
+ identityProof: obj.identityProof
60
+ };
61
+ });
62
+ }
63
+ /**
64
+ * helper to decrypt handshake response and extract individual keys
65
+ */
66
+ export function decryptAndExtractHandshakeKeys(payloadJson, initiatorEphemeralSecretKey) {
67
+ const decrypted = decryptHandshakeResponse(payloadJson, initiatorEphemeralSecretKey);
68
+ if (!decrypted)
69
+ return null;
70
+ const extracted = extractKeysFromHandshakeResponse(decrypted);
71
+ if (!extracted)
72
+ return null;
73
+ return {
74
+ identityPubKey: extracted.identityPubKey,
75
+ signingPubKey: extracted.signingPubKey,
76
+ ephemeralPubKey: extracted.ephemeralPubKey,
77
+ note: decrypted.note,
78
+ identityProof: decrypted.identityProof
79
+ };
80
+ }
81
+ /**
82
+ * HKDF(sha256) on shared secret, info="verbeth:hsr", then Keccak-256 -> bytes32 (0x...)
83
+ */
84
+ function finalizeHsrTag(shared) {
85
+ const okm = hkdf(sha256, shared, new Uint8Array(0), toUtf8Bytes("verbeth:hsr"), 32);
86
+ return keccak256(okm);
87
+ }
88
+ /**
89
+ * Responder: tag = H( KDF( ECDH(r, viewPubA), "verbeth:hsr"))
90
+ */
91
+ export function computeTagFromResponder(rSecretKey, viewPubA) {
92
+ const shared = nacl.scalarMult(rSecretKey, viewPubA);
93
+ return finalizeHsrTag(shared);
94
+ }
95
+ /**
96
+ * Initiator: tag = H( KDF( ECDH(viewPrivA, R), "verbeth:hsr"))
97
+ */
98
+ export function computeTagFromInitiator(viewPrivA, R) {
99
+ const shared = nacl.scalarMult(viewPrivA, R);
100
+ return finalizeHsrTag(shared);
101
+ }
102
+ /**
103
+ * Derives a bytes32 topic from the shared secret via HKDF(SHA256) + Keccak-256.
104
+ * - info: domain separation (e.g., "verbeth:topic-out:v1")
105
+ * - salt: recommended to use a tag as salt (stable and shareable)
106
+ */
107
+ function deriveTopic(shared, info, salt) {
108
+ const okm = hkdf(sha256, shared, salt ?? new Uint8Array(0), new TextEncoder().encode(info), 32);
109
+ return keccak256(okm);
110
+ }
111
+ export function deriveLongTermShared(myIdentitySecretKey, theirIdentityPublicKey) {
112
+ return nacl.scalarMult(myIdentitySecretKey, theirIdentityPublicKey);
113
+ }
114
+ /**
115
+ * Directional duplex topics (Initiator-Responder, Responder-Initiator).
116
+ * Recommended salt: tag (bytes)
117
+ */
118
+ export function deriveDuplexTopics(myIdentitySecretKey, theirIdentityPublicKey, salt) {
119
+ const shared = deriveLongTermShared(myIdentitySecretKey, theirIdentityPublicKey);
120
+ const topicOut = deriveTopic(shared, "verbeth:topic-out:v1", salt);
121
+ const topicIn = deriveTopic(shared, "verbeth:topic-in:v1", salt);
122
+ const chkFull = keccak256(Buffer.concat([
123
+ toUtf8Bytes("verbeth:topic-chk:v1"),
124
+ Buffer.from(topicOut.slice(2), 'hex'),
125
+ Buffer.from(topicIn.slice(2), 'hex'),
126
+ ]));
127
+ const checksum = dataSlice(chkFull, 8);
128
+ return { topicOut, topicIn, checksum };
129
+ }
130
+ export function verifyDuplexTopicsChecksum(topicOut, topicIn, checksum) {
131
+ const chkFull = keccak256(Buffer.concat([
132
+ toUtf8Bytes("verbeth:topic-chk:v1"),
133
+ Buffer.from(topicOut.slice(2), 'hex'),
134
+ Buffer.from(topicIn.slice(2), 'hex'),
135
+ ]));
136
+ return dataSlice(chkFull, 8) === checksum;
137
+ }
@@ -0,0 +1,73 @@
1
+ import { Signer, Contract, BaseContract } from "ethers";
2
+ import type { LogChainV1 } from "@verbeth/contracts/typechain-types";
3
+ export declare function split128x128(word: bigint): readonly [bigint, bigint];
4
+ export interface IExecutor {
5
+ sendMessage(ciphertext: Uint8Array, topic: string, timestamp: number, nonce: bigint): Promise<any>;
6
+ initiateHandshake(recipientHash: string, pubKeys: string, ephemeralPubKey: string, plaintextPayload: Uint8Array): Promise<any>;
7
+ respondToHandshake(inResponseTo: string, responderEphemeralR: string, ciphertext: Uint8Array): Promise<any>;
8
+ }
9
+ export declare class EOAExecutor implements IExecutor {
10
+ private contract;
11
+ constructor(contract: LogChainV1);
12
+ sendMessage(ciphertext: Uint8Array, topic: string, timestamp: number, nonce: bigint): Promise<any>;
13
+ initiateHandshake(recipientHash: string, pubKeys: string, ephemeralPubKey: string, plaintextPayload: Uint8Array): Promise<any>;
14
+ respondToHandshake(inResponseTo: string, responderEphemeralR: string, ciphertext: Uint8Array): Promise<any>;
15
+ }
16
+ export declare class BaseSmartAccountExecutor implements IExecutor {
17
+ private baseAccountProvider;
18
+ private logChainAddress;
19
+ private paymasterServiceUrl?;
20
+ private subAccountAddress?;
21
+ private logChainInterface;
22
+ private chainId;
23
+ constructor(baseAccountProvider: any, logChainAddress: string, chainId?: number, // Base mainnet by default
24
+ paymasterServiceUrl?: string | undefined, subAccountAddress?: string | undefined);
25
+ sendMessage(ciphertext: Uint8Array, topic: string, timestamp: number, nonce: bigint): Promise<any>;
26
+ initiateHandshake(recipientHash: string, pubKeys: string, ephemeralPubKey: string, plaintextPayload: Uint8Array): Promise<any>;
27
+ respondToHandshake(inResponseTo: string, responderEphemeralR: string, ciphertext: Uint8Array): Promise<any>;
28
+ private executeCalls;
29
+ }
30
+ export declare class UserOpExecutor implements IExecutor {
31
+ private smartAccountAddress;
32
+ private logChainAddress;
33
+ private bundlerClient;
34
+ private smartAccountClient;
35
+ private logChainInterface;
36
+ private smartAccountInterface;
37
+ constructor(smartAccountAddress: string, logChainAddress: string, bundlerClient: any, smartAccountClient: any);
38
+ sendMessage(ciphertext: Uint8Array, topic: string, timestamp: number, nonce: bigint): Promise<any>;
39
+ initiateHandshake(recipientHash: string, pubKeys: string, ephemeralPubKey: string, plaintextPayload: Uint8Array): Promise<any>;
40
+ respondToHandshake(inResponseTo: string, responderEphemeralR: string, ciphertext: Uint8Array): Promise<any>;
41
+ private executeUserOp;
42
+ }
43
+ export declare class DirectEntryPointExecutor implements IExecutor {
44
+ private smartAccountAddress;
45
+ private logChainAddress;
46
+ private smartAccountClient;
47
+ private signer;
48
+ private logChainInterface;
49
+ private smartAccountInterface;
50
+ private entryPointContract;
51
+ private spec;
52
+ constructor(smartAccountAddress: string, entryPointContract: Contract | BaseContract, logChainAddress: string, smartAccountClient: any, signer: Signer);
53
+ sendMessage(ciphertext: Uint8Array, topic: string, timestamp: number, nonce: bigint): Promise<any>;
54
+ initiateHandshake(recipientHash: string, pubKeys: string, ephemeralPubKey: string, plaintextPayload: Uint8Array): Promise<any>;
55
+ respondToHandshake(inResponseTo: string, responderEphemeralR: string, ciphertext: Uint8Array): Promise<any>;
56
+ private executeDirectUserOp;
57
+ }
58
+ export declare class ExecutorFactory {
59
+ static createEOA(contract: LogChainV1): IExecutor;
60
+ static createBaseSmartAccount(baseAccountProvider: any, logChainAddress: string, chainId?: number, paymasterServiceUrl?: string, subAccountAddress?: string): IExecutor;
61
+ static createUserOp(smartAccountAddress: string, _entryPointAddress: string, logChainAddress: string, bundlerClient: any, smartAccountClient: any): IExecutor;
62
+ static createDirectEntryPoint(smartAccountAddress: string, entryPointContract: Contract | BaseContract, logChainAddress: string, smartAccountClient: any, signer: Signer): IExecutor;
63
+ static createAuto(signerOrAccount: any, contract: LogChainV1, options?: {
64
+ entryPointAddress?: string;
65
+ entryPointContract?: Contract | BaseContract;
66
+ logChainAddress?: string;
67
+ bundlerClient?: any;
68
+ baseAccountProvider?: any;
69
+ chainId?: number;
70
+ isTestEnvironment?: boolean;
71
+ }): Promise<IExecutor>;
72
+ }
73
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,353 @@
1
+ // packages/sdk/src/executor.ts
2
+ import { Interface, toBeHex, zeroPadValue, } from "ethers";
3
+ function pack128x128(high, low) {
4
+ return (high << 128n) | (low & ((1n << 128n) - 1n));
5
+ }
6
+ // Unpack a packed 256-bit value into two 128-bit values
7
+ export function split128x128(word) {
8
+ const lowMask = (1n << 128n) - 1n;
9
+ return [word >> 128n, word & lowMask];
10
+ }
11
+ /* -------------------------------------------------------------------------- */
12
+ /* Helpers for compatibility between AA spec v0.6 and v0.7 */
13
+ /* -------------------------------------------------------------------------- */
14
+ const detectSpecVersion = (iface) => {
15
+ try {
16
+ iface.getFunction("getAccountGasLimits");
17
+ return "v0.7";
18
+ }
19
+ catch {
20
+ return "v0.6";
21
+ }
22
+ };
23
+ // transforms all bigints into padded bytes32 (uint256)
24
+ const padBigints = (op) => {
25
+ const out = { ...op };
26
+ for (const [k, v] of Object.entries(out)) {
27
+ if (typeof v === "bigint") {
28
+ out[k] = zeroPadValue(toBeHex(v), 32);
29
+ }
30
+ }
31
+ return out;
32
+ };
33
+ // EOA Executor - Direct contract calls via wallet signer
34
+ export class EOAExecutor {
35
+ constructor(contract) {
36
+ this.contract = contract;
37
+ }
38
+ async sendMessage(ciphertext, topic, timestamp, nonce) {
39
+ return this.contract.sendMessage(ciphertext, topic, timestamp, nonce);
40
+ }
41
+ async initiateHandshake(recipientHash, pubKeys, ephemeralPubKey, plaintextPayload) {
42
+ return this.contract.initiateHandshake(recipientHash, pubKeys, ephemeralPubKey, plaintextPayload);
43
+ }
44
+ async respondToHandshake(inResponseTo, responderEphemeralR, ciphertext) {
45
+ return this.contract.respondToHandshake(inResponseTo, responderEphemeralR, ciphertext);
46
+ }
47
+ }
48
+ // Base Smart Account Executor - Uses wallet_sendCalls for sponsored transactions
49
+ export class BaseSmartAccountExecutor {
50
+ constructor(baseAccountProvider, logChainAddress, chainId = 8453, // Base mainnet by default
51
+ paymasterServiceUrl, subAccountAddress) {
52
+ this.baseAccountProvider = baseAccountProvider;
53
+ this.logChainAddress = logChainAddress;
54
+ this.paymasterServiceUrl = paymasterServiceUrl;
55
+ this.subAccountAddress = subAccountAddress;
56
+ this.logChainInterface = new Interface([
57
+ "function sendMessage(bytes calldata ciphertext, bytes32 topic, uint256 timestamp, uint256 nonce)",
58
+ "function initiateHandshake(bytes32 recipientHash, bytes pubKeys, bytes ephemeralPubKey, bytes plaintextPayload)",
59
+ "function respondToHandshake(bytes32 inResponseTo, bytes32 responderEphemeralR, bytes ciphertext)",
60
+ ]);
61
+ // Convert chainId to hex
62
+ this.chainId =
63
+ chainId === 8453
64
+ ? "0x2105" // Base mainnet
65
+ : chainId === 84532
66
+ ? "0x14a34" // Base Sepolia
67
+ : `0x${chainId.toString(16)}`;
68
+ }
69
+ async sendMessage(ciphertext, topic, timestamp, nonce) {
70
+ const callData = this.logChainInterface.encodeFunctionData("sendMessage", [
71
+ ciphertext,
72
+ topic,
73
+ timestamp,
74
+ nonce,
75
+ ]);
76
+ return this.executeCalls([
77
+ {
78
+ to: this.logChainAddress,
79
+ value: "0x0",
80
+ data: callData,
81
+ },
82
+ ]);
83
+ }
84
+ async initiateHandshake(recipientHash, pubKeys, ephemeralPubKey, plaintextPayload) {
85
+ const callData = this.logChainInterface.encodeFunctionData("initiateHandshake", [recipientHash, pubKeys, ephemeralPubKey, plaintextPayload]);
86
+ return this.executeCalls([
87
+ {
88
+ to: this.logChainAddress,
89
+ value: "0x0",
90
+ data: callData,
91
+ },
92
+ ]);
93
+ }
94
+ async respondToHandshake(inResponseTo, responderEphemeralR, ciphertext) {
95
+ const callData = this.logChainInterface.encodeFunctionData("respondToHandshake", [inResponseTo, responderEphemeralR, ciphertext]);
96
+ return this.executeCalls([
97
+ {
98
+ to: this.logChainAddress,
99
+ value: "0x0",
100
+ data: callData,
101
+ },
102
+ ]);
103
+ }
104
+ async executeCalls(calls) {
105
+ try {
106
+ //console.log("DEBUG: Sub account address:", this.subAccountAddress);
107
+ const requestParams = {
108
+ version: "1.0",
109
+ chainId: this.chainId,
110
+ calls,
111
+ };
112
+ //** WORK IN PROGRESS */
113
+ if (this.subAccountAddress) {
114
+ requestParams.from = this.subAccountAddress;
115
+ //console.log("DEBUG: Using sub account for transaction");
116
+ }
117
+ if (this.paymasterServiceUrl) {
118
+ requestParams.capabilities = {
119
+ paymasterService: {
120
+ url: this.paymasterServiceUrl,
121
+ },
122
+ };
123
+ //console.log("DEBUG: Using paymaster for gas sponsorship");
124
+ }
125
+ //console.log("DEBUG: Request params:", requestParams);
126
+ const result = await this.baseAccountProvider.request({
127
+ method: "wallet_sendCalls",
128
+ params: [requestParams],
129
+ });
130
+ // first 32 bytes are the actual userop hash
131
+ if (typeof result === "string" &&
132
+ result.startsWith("0x") &&
133
+ result.length > 66) {
134
+ const actualTxHash = "0x" + result.slice(2, 66); // Extract first 32 bytes
135
+ //console.log("DEBUG: extracted tx hash:", actualTxHash);
136
+ return { hash: actualTxHash };
137
+ }
138
+ return result;
139
+ }
140
+ catch (error) {
141
+ console.error("Base Smart Account transaction failed:", error);
142
+ throw error;
143
+ }
144
+ }
145
+ }
146
+ // UserOp Executor - Account Abstraction via bundler
147
+ export class UserOpExecutor {
148
+ constructor(smartAccountAddress, logChainAddress, bundlerClient, smartAccountClient) {
149
+ this.smartAccountAddress = smartAccountAddress;
150
+ this.logChainAddress = logChainAddress;
151
+ this.bundlerClient = bundlerClient;
152
+ this.smartAccountClient = smartAccountClient;
153
+ this.logChainInterface = new Interface([
154
+ "function sendMessage(bytes calldata ciphertext, bytes32 topic, uint256 timestamp, uint256 nonce)",
155
+ "function initiateHandshake(bytes32 recipientHash, bytes pubKeys, bytes ephemeralPubKey, bytes plaintextPayload)",
156
+ "function respondToHandshake(bytes32 inResponseTo, bytes32 responderEphemeralR, bytes ciphertext)",
157
+ ]);
158
+ // Smart account interface for executing calls to other contracts
159
+ this.smartAccountInterface = new Interface([
160
+ "function execute(address target, uint256 value, bytes calldata data) returns (bytes)",
161
+ ]);
162
+ }
163
+ async sendMessage(ciphertext, topic, timestamp, nonce) {
164
+ const logChainCallData = this.logChainInterface.encodeFunctionData("sendMessage", [ciphertext, topic, timestamp, nonce]);
165
+ const smartAccountCallData = this.smartAccountInterface.encodeFunctionData("execute", [
166
+ this.logChainAddress,
167
+ 0, // value
168
+ logChainCallData,
169
+ ]);
170
+ return this.executeUserOp(smartAccountCallData);
171
+ }
172
+ async initiateHandshake(recipientHash, pubKeys, ephemeralPubKey, plaintextPayload) {
173
+ const logChainCallData = this.logChainInterface.encodeFunctionData("initiateHandshake", [recipientHash, pubKeys, ephemeralPubKey, plaintextPayload]);
174
+ const smartAccountCallData = this.smartAccountInterface.encodeFunctionData("execute", [
175
+ this.logChainAddress,
176
+ 0, // value
177
+ logChainCallData,
178
+ ]);
179
+ return this.executeUserOp(smartAccountCallData);
180
+ }
181
+ async respondToHandshake(inResponseTo, responderEphemeralR, ciphertext) {
182
+ const logChainCallData = this.logChainInterface.encodeFunctionData("respondToHandshake", [inResponseTo, responderEphemeralR, ciphertext]);
183
+ const smartAccountCallData = this.smartAccountInterface.encodeFunctionData("execute", [
184
+ this.logChainAddress,
185
+ 0, // value
186
+ logChainCallData,
187
+ ]);
188
+ return this.executeUserOp(smartAccountCallData);
189
+ }
190
+ async executeUserOp(callData) {
191
+ const callGasLimit = 1000000n;
192
+ const verificationGasLimit = 1000000n;
193
+ const maxFeePerGas = 1000000000n;
194
+ const maxPriorityFeePerGas = 1000000000n;
195
+ const userOp = {
196
+ sender: this.smartAccountAddress,
197
+ nonce: await this.smartAccountClient.getNonce(),
198
+ initCode: "0x", // No init code for existing accounts
199
+ callData,
200
+ accountGasLimits: pack128x128(verificationGasLimit, callGasLimit),
201
+ preVerificationGas: 100000n,
202
+ gasFees: pack128x128(maxFeePerGas, maxPriorityFeePerGas),
203
+ paymasterAndData: "0x",
204
+ signature: "0x",
205
+ };
206
+ const signedUserOp = await this.smartAccountClient.signUserOperation(userOp);
207
+ const userOpHash = await this.bundlerClient.sendUserOperation(signedUserOp);
208
+ const receipt = await this.bundlerClient.waitForUserOperationReceipt(userOpHash);
209
+ return receipt;
210
+ }
211
+ }
212
+ // Direct EntryPoint Executor - for local testing (bypasses bundler)
213
+ export class DirectEntryPointExecutor {
214
+ constructor(smartAccountAddress, entryPointContract, logChainAddress, smartAccountClient, signer) {
215
+ this.smartAccountAddress = smartAccountAddress;
216
+ this.logChainAddress = logChainAddress;
217
+ this.smartAccountClient = smartAccountClient;
218
+ this.signer = signer;
219
+ this.logChainInterface = new Interface([
220
+ "function sendMessage(bytes calldata ciphertext, bytes32 topic, uint256 timestamp, uint256 nonce)",
221
+ "function initiateHandshake(bytes32 recipientHash, bytes pubKeys, bytes ephemeralPubKey, bytes plaintextPayload)",
222
+ "function respondToHandshake(bytes32 inResponseTo, bytes32 responderEphemeralR, bytes ciphertext)",
223
+ ]);
224
+ // Smart account interface for executing calls to other contracts
225
+ this.smartAccountInterface = new Interface([
226
+ "function execute(address target, uint256 value, bytes calldata data) returns (bytes)",
227
+ ]);
228
+ this.entryPointContract = entryPointContract.connect(signer);
229
+ this.spec = detectSpecVersion(this.entryPointContract.interface);
230
+ }
231
+ async sendMessage(ciphertext, topic, timestamp, nonce) {
232
+ const logChainCallData = this.logChainInterface.encodeFunctionData("sendMessage", [ciphertext, topic, timestamp, nonce]);
233
+ const smartAccountCallData = this.smartAccountInterface.encodeFunctionData("execute", [
234
+ this.logChainAddress,
235
+ 0, // value
236
+ logChainCallData,
237
+ ]);
238
+ return this.executeDirectUserOp(smartAccountCallData);
239
+ }
240
+ async initiateHandshake(recipientHash, pubKeys, ephemeralPubKey, plaintextPayload) {
241
+ const logChainCallData = this.logChainInterface.encodeFunctionData("initiateHandshake", [recipientHash, pubKeys, ephemeralPubKey, plaintextPayload]);
242
+ const smartAccountCallData = this.smartAccountInterface.encodeFunctionData("execute", [
243
+ this.logChainAddress,
244
+ 0, // value
245
+ logChainCallData,
246
+ ]);
247
+ return this.executeDirectUserOp(smartAccountCallData);
248
+ }
249
+ async respondToHandshake(inResponseTo, responderEphemeralR, ciphertext) {
250
+ const logChainCallData = this.logChainInterface.encodeFunctionData("respondToHandshake", [inResponseTo, responderEphemeralR, ciphertext]);
251
+ const smartAccountCallData = this.smartAccountInterface.encodeFunctionData("execute", [
252
+ this.logChainAddress,
253
+ 0, // value
254
+ logChainCallData,
255
+ ]);
256
+ return this.executeDirectUserOp(smartAccountCallData);
257
+ }
258
+ async executeDirectUserOp(callData) {
259
+ const callGasLimit = 1000000n;
260
+ const verificationGasLimit = 1000000n;
261
+ const maxFeePerGas = 1000000000n;
262
+ const maxPriorityFeePerGas = 1000000000n;
263
+ // Build UserOperation
264
+ let userOp;
265
+ if (this.spec === "v0.6") {
266
+ userOp = {
267
+ sender: this.smartAccountAddress,
268
+ nonce: await this.smartAccountClient.getNonce(),
269
+ initCode: "0x",
270
+ callData,
271
+ callGasLimit,
272
+ verificationGasLimit,
273
+ preVerificationGas: 100000n,
274
+ maxFeePerGas,
275
+ maxPriorityFeePerGas,
276
+ paymasterAndData: "0x",
277
+ signature: "0x",
278
+ };
279
+ }
280
+ else {
281
+ userOp = {
282
+ sender: this.smartAccountAddress,
283
+ nonce: await this.smartAccountClient.getNonce(),
284
+ initCode: "0x",
285
+ callData,
286
+ accountGasLimits: pack128x128(verificationGasLimit, callGasLimit),
287
+ preVerificationGas: 100000n,
288
+ gasFees: pack128x128(maxFeePerGas, maxPriorityFeePerGas),
289
+ paymasterAndData: "0x",
290
+ signature: "0x",
291
+ };
292
+ }
293
+ // Pad bigints, bytes32 before signing
294
+ const paddedUserOp = padBigints(userOp);
295
+ //console.log("Padded UserOp:", paddedUserOp);
296
+ const signed = await this.smartAccountClient.signUserOperation(paddedUserOp);
297
+ // Direct submit to EntryPoint
298
+ const tx = await this.entryPointContract.handleOps([signed], await this.signer.getAddress());
299
+ return tx;
300
+ }
301
+ }
302
+ export class ExecutorFactory {
303
+ static createEOA(contract) {
304
+ return new EOAExecutor(contract);
305
+ }
306
+ static createBaseSmartAccount(baseAccountProvider, logChainAddress, chainId = 8453, paymasterServiceUrl, subAccountAddress) {
307
+ return new BaseSmartAccountExecutor(baseAccountProvider, logChainAddress, chainId, paymasterServiceUrl, subAccountAddress);
308
+ }
309
+ static createUserOp(smartAccountAddress, _entryPointAddress, logChainAddress, bundlerClient, smartAccountClient) {
310
+ return new UserOpExecutor(smartAccountAddress, logChainAddress, bundlerClient, smartAccountClient);
311
+ }
312
+ static createDirectEntryPoint(smartAccountAddress, entryPointContract, logChainAddress, smartAccountClient, signer) {
313
+ return new DirectEntryPointExecutor(smartAccountAddress, entryPointContract, logChainAddress, smartAccountClient, signer);
314
+ }
315
+ // Auto-detect executor based on environment and signer type
316
+ static async createAuto(signerOrAccount, contract, options) {
317
+ if (options?.baseAccountProvider && options?.logChainAddress) {
318
+ return new BaseSmartAccountExecutor(options.baseAccountProvider, options.logChainAddress, options.chainId || 8453);
319
+ }
320
+ try {
321
+ const provider = signerOrAccount?.provider || signerOrAccount;
322
+ if (provider && typeof provider.request === "function") {
323
+ // test if provider supports wallet_sendCalls
324
+ const capabilities = await provider
325
+ .request({
326
+ method: "wallet_getCapabilities",
327
+ params: [],
328
+ })
329
+ .catch(() => null);
330
+ if (capabilities && options?.logChainAddress) {
331
+ // if wallet supports capabilities, it's likely a Base Smart Account
332
+ return new BaseSmartAccountExecutor(provider, options.logChainAddress, options.chainId || 8453);
333
+ }
334
+ }
335
+ }
336
+ catch (error) { }
337
+ if (signerOrAccount.address &&
338
+ (options?.bundlerClient || options?.entryPointContract)) {
339
+ if (options.isTestEnvironment &&
340
+ options.entryPointContract &&
341
+ options.logChainAddress) {
342
+ return new DirectEntryPointExecutor(signerOrAccount.address, options.entryPointContract, options.logChainAddress, signerOrAccount, signerOrAccount.signer || signerOrAccount);
343
+ }
344
+ if (options.bundlerClient &&
345
+ options.entryPointAddress &&
346
+ options.logChainAddress) {
347
+ return new UserOpExecutor(signerOrAccount.address, options.logChainAddress, options.bundlerClient, signerOrAccount);
348
+ }
349
+ }
350
+ // default to EOA executor
351
+ return new EOAExecutor(contract);
352
+ }
353
+ }
@@ -0,0 +1,28 @@
1
+ import { Signer } from "ethers";
2
+ import { IdentityProof } from "./types.js";
3
+ interface IdentityKeyPair {
4
+ publicKey: Uint8Array;
5
+ secretKey: Uint8Array;
6
+ signingPublicKey: Uint8Array;
7
+ signingSecretKey: Uint8Array;
8
+ }
9
+ /**
10
+ * HKDF (RFC 5869) identity key derivation.
11
+ * Returns a proof binding the derived keypair to the wallet address.
12
+ */
13
+ export declare function deriveIdentityKeyPairWithProof(signer: any, address: string): Promise<{
14
+ keyPair: IdentityKeyPair;
15
+ identityProof: {
16
+ message: string;
17
+ signature: string;
18
+ messageRawHex?: `0x${string}`;
19
+ };
20
+ }>;
21
+ export declare function deriveIdentityWithUnifiedKeys(signer: Signer, address: string): Promise<{
22
+ identityProof: IdentityProof;
23
+ identityPubKey: Uint8Array;
24
+ signingPubKey: Uint8Array;
25
+ unifiedPubKeys: Uint8Array;
26
+ }>;
27
+ export {};
28
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/identity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAmB,MAAM,QAAQ,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,UAAU,eAAe;IAEvB,SAAS,EAAE,UAAU,CAAC;IACtB,SAAS,EAAE,UAAU,CAAC;IAEtB,gBAAgB,EAAE,UAAU,CAAC;IAC7B,gBAAgB,EAAE,UAAU,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,GAAG,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IACT,OAAO,EAAE,eAAe,CAAC;IACzB,aAAa,EAAE;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;KAC/B,CAAC;CACH,CAAC,CAyDD;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IACT,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,UAAU,CAAC;IAC3B,aAAa,EAAE,UAAU,CAAC;IAC1B,cAAc,EAAE,UAAU,CAAC;CAC5B,CAAC,CAcD"}