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/package.json +3 -1
- package/src/abis/BeaconProxy.json +68 -975
- package/src/abis/DeviceWallet.json +909 -904
- package/src/abis/DeviceWalletFactory.json +548 -464
- package/src/abis/ESIMWallet.json +325 -325
- package/src/abis/ESIMWalletFactory.json +296 -301
- package/src/abis/LazyWalletRegistry.json +488 -493
- package/src/abis/P256Verifier.json +30 -30
- package/src/abis/Registry.json +502 -507
- package/src/config.ts +11 -2
- package/src/interface/P256VerifierClass.ts +1 -1
- package/src/interface/constantsClass.ts +3 -3
- package/src/interface/deviceWalletClass.ts +1 -1
- package/src/interface/eSIMWalletClass.ts +1 -1
- package/src/interface/eSIMWalletFactoryClass.ts +1 -1
- package/src/interface/lazyWalletRegistryClass.ts +1 -1
- package/src/interface/smartAccountClass.ts +12 -6
- package/src/interface/utilsClass.ts +1 -1
- package/src/logic/P256Verifier.ts +1 -1
- package/src/logic/account-kit/createSmartAccount.ts +90 -88
- package/src/logic/constants.ts +17 -7
- package/src/logic/deviceWallet.ts +6 -6
- package/src/logic/eSIMWallet.ts +1 -1
- package/src/logic/services/turnkeyClient.ts +193 -65
- package/src/logic/utils.ts +38 -1
- package/src/types.ts +1 -1
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
|
+
}
|
|
@@ -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
|
-
|
|
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
|
|
22
|
-
return _getSmartWallet(this.client, this.turnkeyClient, this.organizationId, deviceUniqueIdentifier, deviceWalletOwnerKey, salt
|
|
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
|
+
}
|
|
@@ -25,7 +25,7 @@ export const _verifySignature = async (
|
|
|
25
25
|
target: values.factoryAddresses.P256VERIFIER,
|
|
26
26
|
data: encodeFunctionData({
|
|
27
27
|
abi: P256Verifier,
|
|
28
|
-
functionName: "
|
|
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
|
|
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 = "
|
|
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
|
|
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
|
-
|
|
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
|
|
174
|
+
const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
|
|
212
175
|
|
|
213
|
-
|
|
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 (
|
|
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
|
|
229
|
-
|
|
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
|
|
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
|
|
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(
|
|
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:
|
|
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
|
}
|
package/src/logic/constants.ts
CHANGED
|
@@ -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: '
|
|
73
|
-
ESIM_WALLET_FACTORY: '
|
|
74
|
-
LAZY_WALLET_REGISTRY: '
|
|
75
|
-
REGISTRY: '
|
|
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: '
|
|
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: [
|
|
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: [
|
|
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: [
|
|
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: [
|
|
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: [
|
|
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
|
+
}
|
package/src/logic/eSIMWallet.ts
CHANGED