kokio-sdk 0.0.4 → 0.0.6

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/src/config.ts CHANGED
@@ -13,7 +13,10 @@ import { TurnkeyClient } from "@turnkey/http";
13
13
  export class Kokio {
14
14
  viemWalletClient: WalletClient;
15
15
  turnkeyClient: TurnkeyClient;
16
+ credentialId: string;
17
+ rpId: string;
16
18
  organizationId: string;
19
+ pimlicoAPIKey: string;
17
20
  gasPolicyId: string;
18
21
 
19
22
  constants: ConstantsSubPackage;
@@ -29,7 +32,10 @@ export class Kokio {
29
32
  constructor(
30
33
  viemWalletClient: WalletClient,
31
34
  turnkeyClient: TurnkeyClient,
35
+ credentialId: string,
36
+ rpId: string,
32
37
  organizationId: string,
38
+ pimlicoAPIKey: string,
33
39
  gasPolicyId: string,
34
40
  smartAccountClient?: SmartAccountClient,
35
41
  deviceWalletAddress?: Address,
@@ -37,12 +43,15 @@ export class Kokio {
37
43
  ) {
38
44
  this.viemWalletClient = viemWalletClient;
39
45
  this.turnkeyClient = turnkeyClient;
46
+ this.credentialId = credentialId;
47
+ this.rpId = rpId;
40
48
  this.organizationId = organizationId;
49
+ this.pimlicoAPIKey = pimlicoAPIKey;
41
50
  this.gasPolicyId = gasPolicyId;
42
51
 
43
- this.constants = new ConstantsSubPackage(this.viemWalletClient);
52
+ this.constants = new ConstantsSubPackage(this.viemWalletClient, this.pimlicoAPIKey);
44
53
 
45
- this.smartAccount = new SmartAccountSubPackage(this.viemWalletClient, this.turnkeyClient, this.organizationId, this.gasPolicyId);
54
+ this.smartAccount = new SmartAccountSubPackage(this.viemWalletClient, this.turnkeyClient, this.credentialId, this.rpId, this.organizationId, this.pimlicoAPIKey, this.gasPolicyId);
46
55
  this.deviceWalletFactory = smartAccountClient? new DeviceWalletFactorySubPackage(viemWalletClient, smartAccountClient): undefined;
47
56
  this.eSIMWalletFactory = smartAccountClient? new ESIMWalletFactorySubPackage(viemWalletClient, smartAccountClient): undefined;
48
57
  this.lazyWalletRegistry = smartAccountClient? new LazyWalletRegistrySubPackage(smartAccountClient): undefined;
@@ -16,4 +16,4 @@ export class P256VerifierSubPackage {
16
16
  verifySignature (message: string, requireMessageVerification: boolean, webAuthnSignature: WebAuthnSignature, x: bigint, y: bigint) {
17
17
  return _verifySignature(this.client, message, requireMessageVerification, webAuthnSignature, x, y);
18
18
  }
19
- }
19
+ }
@@ -21,11 +21,11 @@ export class ConstantsSubPackage {
21
21
  typeof arbitrumSepoliaFactoryAddresses;
22
22
  customErrors!: typeof customErrors;
23
23
 
24
- constructor(client: WalletClient) {
24
+ constructor(client: WalletClient, pimlicoAPIKey: string) {
25
25
  (async () => {
26
26
  const chainID = await _extractChainID(client);
27
27
  const rpcURL = client.transport.url;
28
- const values = _getChainSpecificConstants(chainID, rpcURL);
28
+ const values = _getChainSpecificConstants(chainID, rpcURL, pimlicoAPIKey);
29
29
 
30
30
  this.factoryAddresses = values?.factoryAddresses;
31
31
  this.customErrors = values?.customErrors;
@@ -33,4 +33,4 @@ export class ConstantsSubPackage {
33
33
  return this;
34
34
  })();
35
35
  }
36
- }
36
+ }
@@ -59,4 +59,4 @@ export class DeviceWalletSubPackage {
59
59
  getOwner () {
60
60
  return _getOwner (this.walletClient, this.address);
61
61
  }
62
- }
62
+ }
@@ -52,4 +52,4 @@ export class ESIMWalletSubPackage {
52
52
  _transferOwnership (amount: bigint) {
53
53
  return _transferOwnership(this.client, this.address, amount);
54
54
  }
55
- }
55
+ }
@@ -33,4 +33,4 @@ export class ESIMWalletFactorySubPackage {
33
33
  _getCurrentESIMWalletImplementation () {
34
34
  return _getCurrentESIMWalletImplementation(this.smartAccountClient);
35
35
  }
36
- }
36
+ }
@@ -31,4 +31,4 @@ export class LazyWalletRegistrySubPackage {
31
31
  _switchESIMIdentifierToNewDeviceIdentifier (eSIMIdentifier: string, oldDeviceIdentifier: string, newDeviceIdentifier: string) {
32
32
  return _switchESIMIdentifierToNewDeviceIdentifier(this.client, eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier);
33
33
  }
34
- }
34
+ }
@@ -8,21 +8,27 @@ export class SmartAccountSubPackage {
8
8
 
9
9
  client;
10
10
  turnkeyClient;
11
- organizationId;
11
+ credentialId;
12
+ rpId;
13
+ organizationId;
14
+ pimlicoAPIKey;
12
15
  gasPolicyId;
13
16
 
14
- constructor(client: WalletClient, turnkeyClient: TurnkeyClient, organiationId: string, gasPolicyId: string) {
17
+ constructor(client: WalletClient, turnkeyClient: TurnkeyClient, credentialId: string, rpId: string, organiationId: string, pimlicoAPIKey: string, gasPolicyId: string) {
15
18
  this.client = client;
16
19
  this.turnkeyClient = turnkeyClient;
20
+ this.credentialId = credentialId;
21
+ this.rpId = rpId;
17
22
  this.organizationId = organiationId;
23
+ this.pimlicoAPIKey = pimlicoAPIKey;
18
24
  this.gasPolicyId = gasPolicyId;
19
25
  }
20
26
 
21
- getSmartWallet (deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: bigint, sender?: Address) {
22
- return _getSmartWallet(this.client, this.turnkeyClient, this.organizationId, deviceUniqueIdentifier, deviceWalletOwnerKey, salt, sender)
27
+ getSmartWallet (deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: bigint) {
28
+ return _getSmartWallet(this.client, this.turnkeyClient, this.credentialId, this.rpId, this.organizationId, deviceUniqueIdentifier, deviceWalletOwnerKey, salt);
23
29
  }
24
30
 
25
31
  getSmartWalletClient (account: SmartContractAccount) {
26
- return _getSmartWalletClient(this.client, this.gasPolicyId, account)
32
+ return _getSmartWalletClient(this.client, this.pimlicoAPIKey, this.gasPolicyId, account);
27
33
  }
28
- }
34
+ }
@@ -18,4 +18,4 @@ export class UtilsSubPackage {
18
18
  _remove0x(data);
19
19
  }
20
20
 
21
- }
21
+ }
@@ -25,7 +25,7 @@ export const _verifySignature = async (
25
25
  target: values.factoryAddresses.P256VERIFIER,
26
26
  data: encodeFunctionData({
27
27
  abi: P256Verifier,
28
- functionName: "deployLazyWalletAndSetESIMIdentifier",
28
+ functionName: "verifySignature",
29
29
  args: [message, requireMessageVerification, webAuthnSignature, x, y]
30
30
  })
31
31
  }
@@ -4,6 +4,7 @@ import {
4
4
  getEntryPoint,
5
5
  SmartContractAccount,
6
6
  toSmartContractAccount,
7
+ split
7
8
  } from "@aa-sdk/core";
8
9
  import {
9
10
  http,
@@ -17,15 +18,18 @@ import {
17
18
  encodeAbiParameters,
18
19
  getContract,
19
20
  TypedDataDefinition,
20
- TypedData
21
+ TypedData,
22
+ hashMessage,
23
+ stringToBytes,
24
+ toHex
21
25
  } from "viem";
22
26
  import { TurnkeyClient } from "@turnkey/http";
23
- import { BytesLike, ethers, hexlify } from "ethers";
24
- import { _getChainSpecificConstants, ZERO } from "../constants.js";
27
+ import { BytesLike, ethers, hexlify, toBeHex, toBigInt, zeroPadValue } from "ethers";
28
+ import { _getChainSpecificConstants, ZERO, SIGNATURE_VALIDITY_SECONDS } from "../constants.js";
25
29
  import { _add0x, _concatUint8Arrays, _remove0x, _shouldRemoveLeadingZero } from "../utils.js";
26
30
  import { P256Key, WebAuthnSignature } from "../../types.js";
27
31
  import { DeviceWallet, DeviceWalletFactory } from "../../abis/index.js";
28
- import { _signMessageWithTurnkey, _signTypedDataWithTurnkey, _stampAndSignMessageWithTurnkey, _stampAndSignTypedDataWithTurnkey } from "../services/turnkeyClient.js";
32
+ import { _signMessageWithTurnkey, _signTypedDataWithTurnkey, _stamp, _stampAndSignMessageWithTurnkey, _stampAndSignTypedDataWithTurnkey } from "../services/turnkeyClient.js";
29
33
  import { alchemyGasManagerMiddleware } from "@account-kit/infra";
30
34
 
31
35
  const _encodeExecute = async (tx: AccountOp) => {
@@ -70,7 +74,7 @@ const _getAccountInitCode = async (client: WalletClient, deviceUniqueIdentifier:
70
74
  const callData = encodeFunctionData({
71
75
  abi: DeviceWalletFactory,
72
76
  functionName: "createAccount",
73
- args: [deviceUniqueIdentifier, deviceWalletOwnerKey, salt, ZERO],
77
+ args: [deviceUniqueIdentifier, deviceWalletOwnerKey, salt],
74
78
  })
75
79
 
76
80
  return values.factoryAddresses.DEVICE_WALLET_FACTORY.concat(_remove0x(callData)) as Hex;
@@ -85,6 +89,7 @@ const getInitCodeHash = async (client: WalletClient, deviceUniqueIdentifier: str
85
89
  // off-chain computation of the DeviceWallet address
86
90
  const registry = values.factoryAddresses.REGISTRY;
87
91
  const deviceWalletFactoryAddress = values.factoryAddresses.DEVICE_WALLET_FACTORY;
92
+ const eSIMWalletFactoryAddress = values.factoryAddresses.ESIM_WALLET_FACTORY;
88
93
 
89
94
  const deviceWalletFactory = getContract({
90
95
  abi: DeviceWalletFactory,
@@ -102,9 +107,10 @@ const getInitCodeHash = async (client: WalletClient, deviceUniqueIdentifier: str
102
107
  registry,
103
108
  deviceWalletOwnerKey,
104
109
  deviceUniqueIdentifier,
110
+ eSIMWalletFactoryAddress
105
111
  ]);
106
112
 
107
- const beaconProxyBytecode = "0x60a06040526040516105bf3803806105bf83398101604081905261002291610387565b61002c828261003e565b506001600160a01b031660805261047e565b610047826100fe565b6040516001600160a01b038316907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a28051156100f2576100ed826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e79190610447565b82610211565b505050565b6100fa610288565b5050565b806001600160a01b03163b60000361013957604051631933b43b60e21b81526001600160a01b03821660048201526024015b60405180910390fd5b807fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392831617905560408051635c60da1b60e01b81529051600092841691635c60da1b9160048083019260209291908290030181865afa1580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d99190610447565b9050806001600160a01b03163b6000036100fa57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610130565b6060600080846001600160a01b03168460405161022e9190610462565b600060405180830381855af49150503d8060008114610269576040519150601f19603f3d011682016040523d82523d6000602084013e61026e565b606091505b50909250905061027f8583836102a9565b95945050505050565b34156102a75760405163b398979f60e01b815260040160405180910390fd5b565b6060826102be576102b982610308565b610301565b81511580156102d557506001600160a01b0384163b155b156102fe57604051639996b31560e01b81526001600160a01b0385166004820152602401610130565b50805b9392505050565b8051156103185780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80516001600160a01b038116811461034857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561037e578181015183820152602001610366565b50506000910152565b6000806040838503121561039a57600080fd5b6103a383610331565b60208401519092506001600160401b03808211156103c057600080fd5b818501915085601f8301126103d457600080fd5b8151818111156103e6576103e661034d565b604051601f8201601f19908116603f0116810190838211818310171561040e5761040e61034d565b8160405282815288602084870101111561042757600080fd5b610438836020830160208801610363565b80955050505050509250929050565b60006020828403121561045957600080fd5b61030182610331565b60008251610474818460208701610363565b9190910192915050565b6080516101276104986000396000601e01526101276000f3fe6080604052600a600c565b005b60186014601a565b60a0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156079573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190609b919060c3565b905090565b3660008037600080366000845af43d6000803e80801560be573d6000f35b3d6000fd5b60006020828403121560d457600080fd5b81516001600160a01b038116811460ea57600080fd5b939250505056fea2646970667358221220d2ef783a147afe4beaf6cec0d85c3b6cd6a11a48e1a7f60eac2d7a83dac8508e64736f6c63430008190033";
113
+ const beaconProxyBytecode = "0x60a06040908082526104a8803803809161001982856102ae565b8339810182828203126101e95761002f826102e7565b60208084015191939091906001600160401b0382116101e9570182601f820112156101e957805190610060826102fb565b9361006d875195866102ae565b8285528383830101116101e957829060005b83811061029a57505060009184010152823b1561027a577fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b038581169182179092558551635c60da1b60e01b8082529194928482600481895afa91821561026f57600092610238575b50813b1561021f5750508551847f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e600080a282511561020057508290600487518096819382525afa9283156101f5576000936101b3575b5091600080848461019096519101845af4903d156101aa573d610174816102fb565b90610181885192836102ae565b8152600081943d92013e610316565b505b6080525161012e908161037a82396080518160180152f35b60609250610316565b92508183813d83116101ee575b6101ca81836102ae565b810103126101e9576000806101e1610190956102e7565b945050610152565b600080fd5b503d6101c0565b85513d6000823e3d90fd5b9350505050346102105750610192565b63b398979f60e01b8152600490fd5b8751634c9c8ce360e01b81529116600482015260249150fd5b9091508481813d8311610268575b61025081836102ae565b810103126101e957610261906102e7565b90386100fb565b503d610246565b88513d6000823e3d90fd5b8351631933b43b60e21b81526001600160a01b0384166004820152602490fd5b81810183015186820184015284920161007f565b601f909101601f19168101906001600160401b038211908210176102d157604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101e957565b6001600160401b0381116102d157601f01601f191660200190565b9061033d575080511561032b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580610370575b61034e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561034656fe60806040819052635c60da1b60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811560a9576000916054575b5060da565b905060203d60201160a3575b601f8101601f191682019167ffffffffffffffff831181841017608d576088926040520160b5565b38604f565b634e487b7160e01b600052604160045260246000fd5b503d6060565b6040513d6000823e3d90fd5b602090607f19011260d5576080516001600160a01b038116810360d55790565b600080fd5b6000808092368280378136915af43d82803e1560f4573d90f35b3d90fdfea264697066735822122099ba460fd62b3e22c737d15959887e6cae3498f3495d31e43e2bcf1283aec7d264736f6c63430008190033";
108
114
 
109
115
  // Encode BeaconProxy constructor args
110
116
  const beaconProxyConstructorArgs = abiCoder.encode(
@@ -118,31 +124,14 @@ const getInitCodeHash = async (client: WalletClient, deviceUniqueIdentifier: str
118
124
  return ethers.keccak256(initCode);
119
125
  }
120
126
 
121
- const prepareSaltForCreate2 = (sender: Address, salt: BigInt): BytesLike => {
122
-
123
- // Calculating unique salt based on createAccount function's implementation
124
- const abiCoder = ethers.AbiCoder.defaultAbiCoder();
125
- const encoded = abiCoder.encode(
126
- ["address", "uint256"],
127
- [sender, salt]
128
- );
129
- const uniqueSaltBytes32 = ethers.keccak256(encoded);
130
-
131
- return uniqueSaltBytes32;
132
- }
133
-
134
- // NOTE: Sender is the address that deploys the contract.
135
- // In case of ERC-4337, it is the Entry Point contract address
136
- const getCounterFactualAddress = async (client: WalletClient, deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: BigInt, sender?: Address):Promise<Hex> => {
127
+ const getCounterFactualAddress = async (client: WalletClient, deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: bigint):Promise<Hex> => {
137
128
 
138
129
  const chainID = await client.getChainId();
139
130
  const rpcURL = client.transport.url;
140
131
  const values = _getChainSpecificConstants(chainID, rpcURL);
141
132
  const deviceWalletFactoryAddress = values.factoryAddresses.DEVICE_WALLET_FACTORY;
142
133
 
143
-
144
- sender = sender? sender : values.factoryAddresses.SENDER_CREATOR;
145
- const uniqueSaltBytes32 = prepareSaltForCreate2(sender, salt);
134
+ const uniqueSaltBytes32 = toHex(salt, {size: 32});
146
135
  const initCodeHash = await getInitCodeHash(client, deviceUniqueIdentifier, deviceWalletOwnerKey);
147
136
 
148
137
  // Calculate deterministic address from init code hash
@@ -151,66 +140,46 @@ const getCounterFactualAddress = async (client: WalletClient, deviceUniqueIdenti
151
140
  return ethers.getAddress(create2Address) as Address;
152
141
  }
153
142
 
154
- const _encodeSignature = async (webAuthnSignature: WebAuthnSignature): Promise<Hex> => {
143
+ const _encodeSignature = async (webAuthnSignature: WebAuthnSignature, validUntil: number): Promise<Hex> => {
144
+
145
+ const encodedWebAuthnSignatureBytes = encodeAbiParameters([
146
+ {
147
+ type: "tuple",
148
+ name: "WebAuthnSignature",
149
+ components: [
150
+ { name: "authenticatorData", type: "bytes", },
151
+ { name: "clientDataJSON", type: "string", },
152
+ { name: "challengeIndex", type: "uint256", },
153
+ { name: "typeIndex", type: "uint256", },
154
+ { name: "r", type: "uint256", },
155
+ { name: "s", type: "uint256", },
156
+ ],
157
+ },
158
+ ],
159
+ [
160
+ webAuthnSignature
161
+ ]);
155
162
 
156
163
  const signature = encodePacked(
157
164
  ["uint8", "uint48", "bytes"],
158
- [
159
- 1,
160
- 0,
161
- encodeAbiParameters([
162
- {
163
- type: "tuple",
164
- name: "credentials",
165
- components: [
166
- {
167
- name: "authenticatorData",
168
- type: "bytes",
169
- },
170
- {
171
- name: "clientDataJSON",
172
- type: "string",
173
- },
174
- {
175
- name: "challengeIndex",
176
- type: "uint256",
177
- },
178
- {
179
- name: "typeIndex",
180
- type: "uint256",
181
- },
182
- {
183
- name: "r",
184
- type: "uint256",
185
- },
186
- {
187
- name: "s",
188
- type: "uint256",
189
- },
190
- ],
191
- },
192
- ],
193
- [
194
- {
195
- authenticatorData: _add0x(webAuthnSignature.authenticatorData),
196
- clientDataJSON: JSON.stringify(webAuthnSignature.clientDataJSON),
197
- challengeIndex: BigInt(23),
198
- typeIndex: BigInt(1),
199
- r: webAuthnSignature.r,
200
- s: webAuthnSignature.s,
201
- },
202
- ]),
203
- ],
165
+ [1, validUntil, encodedWebAuthnSignatureBytes]
204
166
  );
205
167
 
206
168
  return signature;
207
- }
169
+ };
208
170
 
209
- const _signMessage = async (message: SignableMessage, turnkeyClient: TurnkeyClient, organiationId: string, signWith: Address): Promise<Hex> => {
171
+ // message here is the original message data (string or Uint8Array) directly from the app
172
+ const _signMessage = async (message: SignableMessage, credentialId: string, rpId: string): Promise<Hex> => {
210
173
 
211
- const webAuthnSignature = await _stampAndSignMessageWithTurnkey(turnkeyClient, organiationId, signWith, message);
174
+ const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
212
175
 
213
- return _encodeSignature(webAuthnSignature);
176
+ const payload = hashMessage({raw: stringToBytes(message as string)});
177
+ // The original message is passed to the stamp and sign function.
178
+ // The stamp and sign function creates the EIP-191 digest hash using its hashMessage function
179
+ // The result of the hashMessage(message) will be the `payload` used by Turnkey as a challenge
180
+ const webAuthnSignature = await _stamp(credentialId, rpId, payload);
181
+
182
+ return _encodeSignature(webAuthnSignature, validUntil);
214
183
  }
215
184
 
216
185
  const _signTypedData = async <
@@ -218,25 +187,40 @@ const _signTypedData = async <
218
187
  primaryType extends keyof typedData | "EIP712Domain" = keyof typedData
219
188
  > (typedData: TypedDataDefinition<typedData, primaryType>, turnkeyClient: TurnkeyClient, organiationId: string, signWith: Address): Promise<Hex> => {
220
189
 
190
+ // signature valid until, UNIX timestamp in seconds
191
+ const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
192
+
221
193
  const webAuthnSignature = await _stampAndSignTypedDataWithTurnkey(turnkeyClient, organiationId, signWith, typedData);
222
194
 
223
- return _encodeSignature(webAuthnSignature);
195
+ return _encodeSignature(webAuthnSignature, validUntil);
224
196
  }
225
197
 
226
- const _signUserOperationHash = async (hash: Hex, turnkeyClient: TurnkeyClient, organiationId: string, signWith: Address): Promise<Hex> => {
198
+ const _signUserOperationHash = async (credentialId: string, rpId: string, userOpHash: Hex): Promise<Hex> => {
199
+
200
+ const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
201
+
202
+ const messagePrecursor = encodePacked(["uint8", "uint48", "bytes32"], [
203
+ 1,
204
+ validUntil,
205
+ userOpHash
206
+ ]);
207
+
208
+ const payload = hashMessage({ raw: messagePrecursor });
227
209
 
228
- const message = encodePacked(["uint8", "uint48", "bytes32"], [1, 0, hash]);
229
- return _signMessage(message, turnkeyClient, organiationId, signWith);
210
+ const webAuthnSignature = await _stamp(credentialId, rpId, payload);
211
+
212
+ return _encodeSignature(webAuthnSignature, validUntil);
230
213
  }
231
214
 
232
215
  export const _getSmartWallet = async (
233
216
  client: WalletClient,
234
217
  turnkeyClient: TurnkeyClient,
218
+ credentialId: string,
219
+ rpId: string,
235
220
  organiationId: string,
236
221
  deviceUniqueIdentifier: string,
237
222
  deviceWalletOwnerKey: P256Key,
238
- salt: bigint,
239
- sender?: Address
223
+ salt: bigint
240
224
  ): Promise<SmartContractAccount> => {
241
225
 
242
226
  const chainID = await client.getChainId();
@@ -266,33 +250,51 @@ export const _getSmartWallet = async (
266
250
  // given a UO in the form of {target, data, value} should output the calldata for calling your contract's execution method
267
251
  encodeExecute: async (uo): Promise<Hash> => _encodeExecute(uo),
268
252
 
269
- signMessage: async ({ message }): Promise<Hash> => _signMessage(message, turnkeyClient, organiationId, signWith),
253
+ signMessage: async ({ message}): Promise<Hash> => _signMessage(message, credentialId, rpId),
270
254
 
271
255
  signTypedData: async (typedData): Promise<Hash> => _signTypedData(typedData, turnkeyClient, organiationId, signWith),
272
256
 
273
257
  /// OPTIONAL PARAMS ///
274
258
  // if you already know your account's address, pass that in here to avoid generating a new counterfactual
275
- accountAddress: await getCounterFactualAddress(client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt, sender),
259
+ accountAddress: await getCounterFactualAddress(client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt),
276
260
  // if your account supports batching, this should take an array of UOs and return the calldata for calling your contract's batchExecute method
277
261
  encodeBatchExecute: async (uos): Promise<Hash> => _encodeBatchExecute(uos),
278
262
  // if your contract expects a different signing scheme than the default signMessage scheme, you can override that here
279
- signUserOperationHash: async (hash): Promise<Hash> => _signUserOperationHash(hash, turnkeyClient, organiationId, signWith),
263
+ signUserOperationHash: async (hash): Promise<Hash> => _signUserOperationHash(credentialId, rpId, hash),
280
264
  // allows you to define the calldata for upgrading your account
281
265
  // encodeUpgradeToAndCall: async (params): Promise<Hash> => "0x...",
282
266
  });
283
267
  }
284
268
 
285
- export const _getSmartWalletClient = async (client: WalletClient, gasPolicyId: string, account: SmartContractAccount) => {
269
+ export const _getSmartWalletClient = async (client: WalletClient, pimlicoAPIKey: string, gasPolicyId: string, account: SmartContractAccount) => {
286
270
 
287
271
  const chainID = await client.getChainId();
288
272
  const rpcURL = client.transport.url;
289
- const values = _getChainSpecificConstants(chainID, rpcURL);
273
+ const values = _getChainSpecificConstants(chainID, rpcURL, pimlicoAPIKey);
290
274
 
275
+ const bundlerMethods = [
276
+ "eth_sendUserOperation",
277
+ "eth_estimateUserOperationGas",
278
+ "eth_getUserOperationReceipt",
279
+ "eth_getUserOperationByHash",
280
+ "eth_supportedEntryPoints",
281
+ ];
282
+
283
+ // Uses Pimlico paymaster by default for above defined bundler methods and Alchemy as fallback
291
284
  return createSmartAccountClient({
292
285
  // created above
293
286
  account: account,
294
287
  chain: values.chain,
295
- transport: http(values.rpcURL),
288
+ transport: split({
289
+ overrides: [
290
+ {
291
+ methods: bundlerMethods,
292
+ transport: http(`${values.pimlicoRpcURL}`),
293
+ },
294
+ ],
295
+ fallback: http(values.rpcURL),
296
+ }),
297
+ // transport: http(values.rpcURL),
296
298
  ...alchemyGasManagerMiddleware(gasPolicyId)
297
299
  });
298
300
  }
@@ -10,6 +10,8 @@ import {
10
10
 
11
11
  export const ZERO = BigInt('0');
12
12
 
13
+ export const SIGNATURE_VALIDITY_SECONDS = 180; // 3 minutes validity
14
+
13
15
  export enum CHAIN_ID {
14
16
  MAINNET = 1,
15
17
  SEPOLIA = 11155111,
@@ -34,7 +36,8 @@ export interface chainSpecifcConstants {
34
36
  typeof optimismSepolia |
35
37
  typeof arbitrum |
36
38
  typeof arbitrumSepolia
37
- rpcURL: string;
39
+ rpcURL: string;
40
+ pimlicoRpcURL: string;
38
41
  customErrors: typeof customErrors;
39
42
  }
40
43
 
@@ -69,13 +72,13 @@ export const optimismMainnetFactoryAddresses: Record<string, Address> = {
69
72
  }
70
73
 
71
74
  export const optimismSepoliaFactoryAddresses: Record<string, Address> = {
72
- DEVICE_WALLET_FACTORY: '0x3feA4dB0C0bBB73142d5bB6b776EE238884a3705',
73
- ESIM_WALLET_FACTORY: '0xaD2Ba6248D0e6990a844C94ACE78F8775A68b631',
74
- LAZY_WALLET_REGISTRY: '0x29b98C32D83604664fd0742b9112b0825a74849F',
75
- REGISTRY: '0xaeB98F0f092fCb4a476ea3a5EB6A4B9E3D63A686',
75
+ DEVICE_WALLET_FACTORY: '0x243cCdE6a56b0Ba740E067f39896772748E20fFD',
76
+ ESIM_WALLET_FACTORY: '0x8444bF9C39F01e4B092e42DC11695C61f8B93957',
77
+ LAZY_WALLET_REGISTRY: '0x3F14D060074B174B0784056bDe5e0f8970D25ff1',
78
+ REGISTRY: '0x96dA9cE92D2C09f7b3ADE01260608e9079f16d12',
76
79
  ENTRY_POINT: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
77
80
  SENDER_CREATOR: '0xefc2c1444ebcc4db75e7613d20c6a62ff67a167c',
78
- P256VERIFIER: '0x5349aEA97Faa6D5d6D78A8847068300a4eC9D39E'
81
+ P256VERIFIER: '0x3c15a78046838481788613A9F111F972B562623C'
79
82
  }
80
83
 
81
84
  export const arbitrumOneFactoryAddresses: Record<string, Address> = {
@@ -120,7 +123,8 @@ export const _getChainSpecificConstants = (
120
123
  CHAIN_ID.OPTIMISM_SEPOLIA |
121
124
  CHAIN_ID.ARBITRUM_ONE |
122
125
  CHAIN_ID.ARBITRUM_SEPOLIA,
123
- rpcURL: string
126
+ rpcURL: string,
127
+ pimlicoAPIKey?: string
124
128
  ): chainSpecifcConstants => {
125
129
 
126
130
  if (chainID == CHAIN_ID.SEPOLIA) {
@@ -128,6 +132,7 @@ export const _getChainSpecificConstants = (
128
132
  factoryAddresses: sepoliaFactoryAddresses,
129
133
  chain: sepolia,
130
134
  rpcURL: rpcURL,
135
+ pimlicoRpcURL: pimlicoAPIKey ? `https://api.pimlico.io/v2/${chainID}/rpc?apikey=${pimlicoAPIKey}` : "",
131
136
  customErrors: customErrors
132
137
  }
133
138
  }
@@ -136,6 +141,7 @@ export const _getChainSpecificConstants = (
136
141
  factoryAddresses: mainnetFactoryAddresses,
137
142
  chain: mainnet,
138
143
  rpcURL: rpcURL,
144
+ pimlicoRpcURL: pimlicoAPIKey ? `https://api.pimlico.io/v2/${chainID}/rpc?apikey=${pimlicoAPIKey}` : "",
139
145
  customErrors: customErrors
140
146
  }
141
147
  }
@@ -144,6 +150,7 @@ export const _getChainSpecificConstants = (
144
150
  factoryAddresses: optimismMainnetFactoryAddresses,
145
151
  chain: optimism,
146
152
  rpcURL: rpcURL,
153
+ pimlicoRpcURL: pimlicoAPIKey ? `https://api.pimlico.io/v2/${chainID}/rpc?apikey=${pimlicoAPIKey}` : "",
147
154
  customErrors: customErrors
148
155
  }
149
156
  }
@@ -152,6 +159,7 @@ export const _getChainSpecificConstants = (
152
159
  factoryAddresses: optimismSepoliaFactoryAddresses,
153
160
  chain: optimismSepolia,
154
161
  rpcURL: rpcURL,
162
+ pimlicoRpcURL: pimlicoAPIKey ? `https://api.pimlico.io/v2/${chainID}/rpc?apikey=${pimlicoAPIKey}` : "",
155
163
  customErrors: customErrors
156
164
  }
157
165
  }
@@ -160,6 +168,7 @@ export const _getChainSpecificConstants = (
160
168
  factoryAddresses: arbitrumOneFactoryAddresses,
161
169
  chain: arbitrum,
162
170
  rpcURL: rpcURL,
171
+ pimlicoRpcURL: pimlicoAPIKey ? `https://api.pimlico.io/v2/${chainID}/rpc?apikey=${pimlicoAPIKey}` : "",
163
172
  customErrors: customErrors
164
173
  }
165
174
  }
@@ -168,6 +177,7 @@ export const _getChainSpecificConstants = (
168
177
  factoryAddresses: arbitrumSepoliaFactoryAddresses,
169
178
  chain: arbitrumSepolia,
170
179
  rpcURL: rpcURL,
180
+ pimlicoRpcURL: pimlicoAPIKey ? `https://api.pimlico.io/v2/${chainID}/rpc?apikey=${pimlicoAPIKey}` : "",
171
181
  customErrors: customErrors
172
182
  }
173
183
  }
@@ -78,7 +78,7 @@ export const _pullETH = async (client: SmartAccountClient, address: Address, amo
78
78
  data: encodeFunctionData({
79
79
  abi: DeviceWallet,
80
80
  functionName: "pullETH",
81
- args: [address, amount]
81
+ args: [amount]
82
82
  })
83
83
  }
84
84
  });
@@ -96,7 +96,7 @@ export const _getVaultAddress = async (client: SmartAccountClient, address: Addr
96
96
  data: encodeFunctionData({
97
97
  abi: DeviceWallet,
98
98
  functionName: "getVaultAddress",
99
- args: [address]
99
+ args: []
100
100
  })
101
101
  }
102
102
  });
@@ -114,7 +114,7 @@ export const _toggleAccessToETH = async (client: SmartAccountClient, address: Ad
114
114
  data: encodeFunctionData({
115
115
  abi: DeviceWallet,
116
116
  functionName: "toggleAccessToETH",
117
- args: [address, eSIMWalletAddress, hasAccessToETH]
117
+ args: [eSIMWalletAddress, hasAccessToETH]
118
118
  })
119
119
  }
120
120
  });
@@ -132,7 +132,7 @@ export const _addESIMWallet = async (client: SmartAccountClient, address: Addres
132
132
  data: encodeFunctionData({
133
133
  abi: DeviceWallet,
134
134
  functionName: "addESIMWallet",
135
- args: [address, eSIMWalletAddress, hasAccessToETH]
135
+ args: [eSIMWalletAddress, hasAccessToETH]
136
136
  })
137
137
  }
138
138
  });
@@ -150,7 +150,7 @@ export const _removeESIMWallet = async (client: SmartAccountClient, address: Add
150
150
  data: encodeFunctionData({
151
151
  abi: DeviceWallet,
152
152
  functionName: "removeESIMWallet",
153
- args: [address, eSIMWalletAddress, hasAccessToETH]
153
+ args: [eSIMWalletAddress, hasAccessToETH]
154
154
  })
155
155
  }
156
156
  });
@@ -169,4 +169,4 @@ export const _getOwner = async (client: WalletClient, address: Address) => {
169
169
 
170
170
  const owner = [x,y];
171
171
  return owner as P256Key;
172
- }
172
+ }
@@ -70,7 +70,7 @@ export const _owner = async (client: SmartAccountClient, address: Address) => {
70
70
  target: address,
71
71
  data: encodeFunctionData({
72
72
  abi: ESIMWallet,
73
- functionName: "ow",
73
+ functionName: "owner",
74
74
  args: []
75
75
  })
76
76
  }