kokio-sdk 0.0.1
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/.env.example +1 -0
- package/.github/workflows/npm_publish.yaml +19 -0
- package/LICENSE +21 -0
- package/package.json +45 -0
- package/src/abis/BeaconProxy.json +985 -0
- package/src/abis/DeviceWallet.json +907 -0
- package/src/abis/DeviceWalletFactory.json +739 -0
- package/src/abis/ESIMWallet.json +486 -0
- package/src/abis/ESIMWalletFactory.json +467 -0
- package/src/abis/LazyWalletRegistry.json +734 -0
- package/src/abis/P256Verifier.json +73 -0
- package/src/abis/Registry.json +811 -0
- package/src/abis/RegistryHelper.json +382 -0
- package/src/abis/index.ts +21 -0
- package/src/config.ts +46 -0
- package/src/interface/P256VerifierClass.ts +19 -0
- package/src/interface/constantsClass.ts +35 -0
- package/src/interface/deviceWalletClass.ts +62 -0
- package/src/interface/deviceWalletFactoryClass.ts +35 -0
- package/src/interface/eSIMWalletClass.ts +55 -0
- package/src/interface/eSIMWalletFactoryClass.ts +36 -0
- package/src/interface/lazyWalletRegistryClass.ts +34 -0
- package/src/interface/smartAccountClass.ts +26 -0
- package/src/interface/utilsClass.ts +21 -0
- package/src/logic/P256Verifier.ts +31 -0
- package/src/logic/account-kit/createSmartAccount.ts +282 -0
- package/src/logic/constants.ts +188 -0
- package/src/logic/deviceWallet.ts +175 -0
- package/src/logic/deviceWalletFactory.ts +70 -0
- package/src/logic/eSIMWallet.ts +149 -0
- package/src/logic/eSIMWalletFactory.ts +78 -0
- package/src/logic/lazyWalletRegistry.ts +98 -0
- package/src/logic/services/turnkeyClient.ts +80 -0
- package/src/logic/utils.ts +86 -0
- package/src/types.ts +38 -0
- package/tsconfig.json +114 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Address, WalletClient } from "viem";
|
|
2
|
+
import {
|
|
3
|
+
_addRegistryAddress,
|
|
4
|
+
_deployESIMWalletWithEOA,
|
|
5
|
+
_deployESIMWalletWithUserOp,
|
|
6
|
+
_getCurrentESIMWalletImplementation
|
|
7
|
+
} from "../logic/eSIMWalletFactory.js"
|
|
8
|
+
import { SmartAccountClient } from "@aa-sdk/core";
|
|
9
|
+
|
|
10
|
+
export class eSIMWalletFactorySubPackage {
|
|
11
|
+
|
|
12
|
+
smartAccountClient;
|
|
13
|
+
walletClient;
|
|
14
|
+
|
|
15
|
+
constructor(walletClient: WalletClient, smartAccountClient: SmartAccountClient) {
|
|
16
|
+
this.smartAccountClient = smartAccountClient;
|
|
17
|
+
this.walletClient = walletClient
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
deployESIMWalletWithEOA (deviceWalletAddress: Address, salt: bigint) {
|
|
21
|
+
return _deployESIMWalletWithEOA (this.walletClient, deviceWalletAddress, salt);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
deployESIMWalletWithUserOp (deviceWalletAddress: Address, salt: bigint) {
|
|
26
|
+
return _deployESIMWalletWithUserOp (this.smartAccountClient, deviceWalletAddress, salt);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
addRegistryAddress (registryContractAddress: Address) {
|
|
30
|
+
return _addRegistryAddress(this.smartAccountClient, registryContractAddress);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_getCurrentESIMWalletImplementation () {
|
|
34
|
+
return _getCurrentESIMWalletImplementation(this.smartAccountClient);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Address, Hex, WalletClient } from "viem";
|
|
2
|
+
import {
|
|
3
|
+
_batchPopulateHistory,
|
|
4
|
+
_deployLazyWalletAndSetESIMIdentifier,
|
|
5
|
+
_isLazyWalletDeployed,
|
|
6
|
+
_switchESIMIdentifierToNewDeviceIdentifier
|
|
7
|
+
} from "../logic/lazyWalletRegistry.js"
|
|
8
|
+
import { DataBundleDetails } from "../types";
|
|
9
|
+
import { SmartAccountClient } from "@aa-sdk/core";
|
|
10
|
+
|
|
11
|
+
export class lazyWalletRegistrySubPackage {
|
|
12
|
+
|
|
13
|
+
client;
|
|
14
|
+
|
|
15
|
+
constructor(client: SmartAccountClient) {
|
|
16
|
+
this.client = client;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_batchPopulateHistory (deviceUniqueIdentifiers: Array<string>, eSIMUniqueIdentifiers: Array<Array<string>>, dataBundleDetails: Array<Array<DataBundleDetails>>) {
|
|
20
|
+
return _batchPopulateHistory(this.client, deviceUniqueIdentifiers, eSIMUniqueIdentifiers, dataBundleDetails);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_deployLazyWalletAndSetESIMIdentifier (deviceOwnerPublicKey: Hex[2], deviceUniqueIdentifier: string, salt: bigint, depositAmount: bigint) {
|
|
24
|
+
return _deployLazyWalletAndSetESIMIdentifier(this.client, deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_isLazyWalletDeployed (deviceUniqueIdentifier: string) {
|
|
28
|
+
return _isLazyWalletDeployed(this.client, deviceUniqueIdentifier);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_switchESIMIdentifierToNewDeviceIdentifier (eSIMIdentifier: string, oldDeviceIdentifier: string, newDeviceIdentifier: string) {
|
|
32
|
+
return _switchESIMIdentifierToNewDeviceIdentifier(this.client, eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Address, WalletClient } from "viem";
|
|
2
|
+
import { _getSmartWallet, _getSmartWalletClient } from "../logic/account-kit/createSmartAccount.js";
|
|
3
|
+
import { P256Key, SignedRequest } from "../types";
|
|
4
|
+
import { SmartAccountClient, SmartContractAccount } from "@aa-sdk/core";
|
|
5
|
+
import { TurnkeyClient } from "@turnkey/http";
|
|
6
|
+
|
|
7
|
+
export class smartAccountSubPackage {
|
|
8
|
+
|
|
9
|
+
client;
|
|
10
|
+
turnkeyClient;
|
|
11
|
+
organizationId;
|
|
12
|
+
|
|
13
|
+
constructor(client: WalletClient, turnkeyClient: TurnkeyClient, organiationId: string) {
|
|
14
|
+
this.client = client;
|
|
15
|
+
this.turnkeyClient = turnkeyClient;
|
|
16
|
+
this.organizationId = organiationId;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getSmartWallet (deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: bigint, sender?: Address) {
|
|
20
|
+
return _getSmartWallet(this.client, this.turnkeyClient, this.organizationId, deviceUniqueIdentifier, deviceWalletOwnerKey, salt, sender)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getSmartWalletClient (account: SmartContractAccount) {
|
|
24
|
+
return _getSmartWalletClient(this.client, account)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WalletClient } from "viem";
|
|
2
|
+
import { _add0x, _remove0x } from "../logic/utils.js";
|
|
3
|
+
import { AccountOp, SmartAccountClient } from "@aa-sdk/core";
|
|
4
|
+
|
|
5
|
+
export class UtilsSubPackage {
|
|
6
|
+
|
|
7
|
+
client;
|
|
8
|
+
|
|
9
|
+
constructor(client: WalletClient) {
|
|
10
|
+
this.client = client;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
add0x(data: string) {
|
|
14
|
+
_add0x(data);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
remove0x(data: string) {
|
|
18
|
+
_remove0x(data);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { encodeFunctionData, WalletClient } from "viem";
|
|
2
|
+
import { WebAuthnSignature } from "../types.js";
|
|
3
|
+
import { SmartAccountClient } from "@aa-sdk/core";
|
|
4
|
+
import { _getChainSpecificConstants, customErrors } from "./constants.js";
|
|
5
|
+
import { P256Verifier } from "../abis/index.js";
|
|
6
|
+
|
|
7
|
+
export const _verifySignature = async (
|
|
8
|
+
client: SmartAccountClient,
|
|
9
|
+
message: string,
|
|
10
|
+
requireMessageVerification: boolean,
|
|
11
|
+
webAuthnSignature: WebAuthnSignature,
|
|
12
|
+
x: bigint,
|
|
13
|
+
y: bigint
|
|
14
|
+
) => {
|
|
15
|
+
|
|
16
|
+
const values = _getChainSpecificConstants(await client.getChainId());
|
|
17
|
+
if(!client.account) throw new Error(customErrors.MISSING_SMART_WALLET)
|
|
18
|
+
|
|
19
|
+
// UserOp
|
|
20
|
+
return client.sendUserOperation({
|
|
21
|
+
account: client.account,
|
|
22
|
+
uo:{
|
|
23
|
+
target: values.factoryAddresses.P256VERIFIER,
|
|
24
|
+
data: encodeFunctionData({
|
|
25
|
+
abi: P256Verifier,
|
|
26
|
+
functionName: "deployLazyWalletAndSetESIMIdentifier",
|
|
27
|
+
args: [message, requireMessageVerification, webAuthnSignature, x, y]
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccountOp,
|
|
3
|
+
createSmartAccountClient,
|
|
4
|
+
getEntryPoint,
|
|
5
|
+
SmartContractAccount,
|
|
6
|
+
toSmartContractAccount,
|
|
7
|
+
} from "@aa-sdk/core";
|
|
8
|
+
import {
|
|
9
|
+
http,
|
|
10
|
+
type SignableMessage,
|
|
11
|
+
type Hash,
|
|
12
|
+
WalletClient,
|
|
13
|
+
Hex,
|
|
14
|
+
encodeFunctionData,
|
|
15
|
+
Address,
|
|
16
|
+
encodePacked,
|
|
17
|
+
encodeAbiParameters,
|
|
18
|
+
getContract,
|
|
19
|
+
TypedDataDefinition,
|
|
20
|
+
TypedData
|
|
21
|
+
} from "viem";
|
|
22
|
+
import { TurnkeyClient } from "@turnkey/http";
|
|
23
|
+
import { BytesLike, ethers, hexlify } from "ethers";
|
|
24
|
+
import { _getChainSpecificConstants, ZERO } from "../constants.js";
|
|
25
|
+
import { _add0x, _concatUint8Arrays, _remove0x, _shouldRemoveLeadingZero } from "../utils.js";
|
|
26
|
+
import { P256Key, WebAuthnSignature } from "../../types.js";
|
|
27
|
+
import { DeviceWallet, DeviceWalletFactory } from "../../abis/index.js";
|
|
28
|
+
import { _signMessageWithTurnkey, _signTypedDataWithTurnkey } from "../services/turnkeyClient.js";
|
|
29
|
+
|
|
30
|
+
const _encodeExecute = async (tx: AccountOp) => {
|
|
31
|
+
|
|
32
|
+
return encodeFunctionData({
|
|
33
|
+
abi: DeviceWallet,
|
|
34
|
+
functionName: "execute",
|
|
35
|
+
args: [{
|
|
36
|
+
dest: tx.target,
|
|
37
|
+
value: tx.value ?? ZERO,
|
|
38
|
+
data: tx.data
|
|
39
|
+
}]
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const _encodeBatchExecute = async (txs: AccountOp[]) => {
|
|
44
|
+
|
|
45
|
+
const new_txs:{dest:Address, value:bigint, data: Hex | '0x'}[] = [];
|
|
46
|
+
|
|
47
|
+
for (let i=0; i<txs.length; ++i) {
|
|
48
|
+
new_txs.push({
|
|
49
|
+
dest: txs[i].target,
|
|
50
|
+
value: txs[i].value ?? ZERO,
|
|
51
|
+
data: txs[i].data
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return encodeFunctionData({
|
|
56
|
+
abi: DeviceWallet,
|
|
57
|
+
functionName: "executeBatch",
|
|
58
|
+
args: [new_txs]
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const _getAccountInitCode = async (client: WalletClient, deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: bigint): Promise<Hex> => {
|
|
63
|
+
|
|
64
|
+
// To send with user operations
|
|
65
|
+
const chainID = await client.getChainId();
|
|
66
|
+
const values = _getChainSpecificConstants(chainID);
|
|
67
|
+
|
|
68
|
+
const callData = encodeFunctionData({
|
|
69
|
+
abi: DeviceWalletFactory,
|
|
70
|
+
functionName: "createAccount",
|
|
71
|
+
args: [deviceUniqueIdentifier, deviceWalletOwnerKey, salt, ZERO],
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
return values.factoryAddresses.DEVICE_WALLET_FACTORY.concat(_remove0x(callData)) as Hex;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const getInitCodeHash = async (client: WalletClient, deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key): Promise<BytesLike> => {
|
|
78
|
+
|
|
79
|
+
const chainID = await client.getChainId();
|
|
80
|
+
const values = _getChainSpecificConstants(chainID);
|
|
81
|
+
|
|
82
|
+
// off-chain computation of the DeviceWallet address
|
|
83
|
+
const registry = values.factoryAddresses.REGISTRY;
|
|
84
|
+
const deviceWalletFactoryAddress = values.factoryAddresses.DEVICE_WALLET_FACTORY;
|
|
85
|
+
|
|
86
|
+
const deviceWalletFactory = getContract({
|
|
87
|
+
abi: DeviceWalletFactory,
|
|
88
|
+
address: deviceWalletFactoryAddress,
|
|
89
|
+
client
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const beacon = await deviceWalletFactory.read.beacon([]);
|
|
93
|
+
|
|
94
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
95
|
+
|
|
96
|
+
// Encode the DeviceWallet.init with the init params
|
|
97
|
+
const deviceWallet = new ethers.Interface(DeviceWallet);
|
|
98
|
+
const deviceWalletInitData = deviceWallet.encodeFunctionData("init", [
|
|
99
|
+
registry,
|
|
100
|
+
deviceWalletOwnerKey,
|
|
101
|
+
deviceUniqueIdentifier,
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
const beaconProxyBytecode = "0x60a06040526040516105bf3803806105bf83398101604081905261002291610387565b61002c828261003e565b506001600160a01b031660805261047e565b610047826100fe565b6040516001600160a01b038316907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a28051156100f2576100ed826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e79190610447565b82610211565b505050565b6100fa610288565b5050565b806001600160a01b03163b60000361013957604051631933b43b60e21b81526001600160a01b03821660048201526024015b60405180910390fd5b807fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392831617905560408051635c60da1b60e01b81529051600092841691635c60da1b9160048083019260209291908290030181865afa1580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d99190610447565b9050806001600160a01b03163b6000036100fa57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610130565b6060600080846001600160a01b03168460405161022e9190610462565b600060405180830381855af49150503d8060008114610269576040519150601f19603f3d011682016040523d82523d6000602084013e61026e565b606091505b50909250905061027f8583836102a9565b95945050505050565b34156102a75760405163b398979f60e01b815260040160405180910390fd5b565b6060826102be576102b982610308565b610301565b81511580156102d557506001600160a01b0384163b155b156102fe57604051639996b31560e01b81526001600160a01b0385166004820152602401610130565b50805b9392505050565b8051156103185780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80516001600160a01b038116811461034857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561037e578181015183820152602001610366565b50506000910152565b6000806040838503121561039a57600080fd5b6103a383610331565b60208401519092506001600160401b03808211156103c057600080fd5b818501915085601f8301126103d457600080fd5b8151818111156103e6576103e661034d565b604051601f8201601f19908116603f0116810190838211818310171561040e5761040e61034d565b8160405282815288602084870101111561042757600080fd5b610438836020830160208801610363565b80955050505050509250929050565b60006020828403121561045957600080fd5b61030182610331565b60008251610474818460208701610363565b9190910192915050565b6080516101276104986000396000601e01526101276000f3fe6080604052600a600c565b005b60186014601a565b60a0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156079573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190609b919060c3565b905090565b3660008037600080366000845af43d6000803e80801560be573d6000f35b3d6000fd5b60006020828403121560d457600080fd5b81516001600160a01b038116811460ea57600080fd5b939250505056fea2646970667358221220d2ef783a147afe4beaf6cec0d85c3b6cd6a11a48e1a7f60eac2d7a83dac8508e64736f6c63430008190033";
|
|
105
|
+
|
|
106
|
+
// Encode BeaconProxy constructor args
|
|
107
|
+
const beaconProxyConstructorArgs = abiCoder.encode(
|
|
108
|
+
["address", "bytes"],
|
|
109
|
+
[beacon, deviceWalletInitData]
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Compute initCode
|
|
113
|
+
const initCode:BytesLike = ethers.concat([beaconProxyBytecode, beaconProxyConstructorArgs]);
|
|
114
|
+
|
|
115
|
+
return ethers.keccak256(initCode);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const prepareSaltForCreate2 = (sender: Address, salt: BigInt): BytesLike => {
|
|
119
|
+
|
|
120
|
+
// Calculating unique salt based on createAccount function's implementation
|
|
121
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
122
|
+
const encoded = abiCoder.encode(
|
|
123
|
+
["address", "uint256"],
|
|
124
|
+
[sender, salt]
|
|
125
|
+
);
|
|
126
|
+
const uniqueSaltBytes32 = ethers.keccak256(encoded);
|
|
127
|
+
|
|
128
|
+
return uniqueSaltBytes32;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// NOTE: Sender is the address that deploys the contract.
|
|
132
|
+
// In case of ERC-4337, it is the Entry Point contract address
|
|
133
|
+
const getCounterFactualAddress = async (client: WalletClient, deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: BigInt, sender?: Address):Promise<Hex> => {
|
|
134
|
+
|
|
135
|
+
const chainID = await client.getChainId();
|
|
136
|
+
const values = _getChainSpecificConstants(chainID);
|
|
137
|
+
const deviceWalletFactoryAddress = values.factoryAddresses.DEVICE_WALLET_FACTORY;
|
|
138
|
+
|
|
139
|
+
sender = sender? sender : values.factoryAddresses.SENDER_CREATOR;
|
|
140
|
+
const uniqueSaltBytes32 = prepareSaltForCreate2(sender, salt);
|
|
141
|
+
const initCodeHash = await getInitCodeHash(client, deviceUniqueIdentifier, deviceWalletOwnerKey);
|
|
142
|
+
|
|
143
|
+
// Calculate deterministic address from init code hash
|
|
144
|
+
const create2Address = ethers.getCreate2Address(deviceWalletFactoryAddress, uniqueSaltBytes32, initCodeHash);
|
|
145
|
+
|
|
146
|
+
return ethers.getAddress(create2Address) as Address;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const _encodeSignature = async (webAuthnSignature: WebAuthnSignature): Promise<Hex> => {
|
|
150
|
+
|
|
151
|
+
const signature = encodePacked(
|
|
152
|
+
["uint8", "uint48", "bytes"],
|
|
153
|
+
[
|
|
154
|
+
1,
|
|
155
|
+
0,
|
|
156
|
+
encodeAbiParameters([
|
|
157
|
+
{
|
|
158
|
+
type: "tuple",
|
|
159
|
+
name: "credentials",
|
|
160
|
+
components: [
|
|
161
|
+
{
|
|
162
|
+
name: "authenticatorData",
|
|
163
|
+
type: "bytes",
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: "clientDataJSON",
|
|
167
|
+
type: "string",
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: "challengeIndex",
|
|
171
|
+
type: "uint256",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "typeIndex",
|
|
175
|
+
type: "uint256",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "r",
|
|
179
|
+
type: "uint256",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: "s",
|
|
183
|
+
type: "uint256",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
[
|
|
189
|
+
{
|
|
190
|
+
authenticatorData: _add0x(webAuthnSignature.authenticatorData),
|
|
191
|
+
clientDataJSON: JSON.stringify(webAuthnSignature.clientDataJSON),
|
|
192
|
+
challengeIndex: BigInt(23),
|
|
193
|
+
typeIndex: BigInt(1),
|
|
194
|
+
r: webAuthnSignature.r,
|
|
195
|
+
s: webAuthnSignature.s,
|
|
196
|
+
},
|
|
197
|
+
]),
|
|
198
|
+
],
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return signature;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const _signMessage = async (message: SignableMessage, turnkeyClient: TurnkeyClient, organiationId: string, signWith: Address): Promise<Hex> => {
|
|
205
|
+
|
|
206
|
+
const webAuthnSignature = await _signMessageWithTurnkey(turnkeyClient, organiationId, signWith, message);
|
|
207
|
+
|
|
208
|
+
return _encodeSignature(webAuthnSignature);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const _signTypedData = async <
|
|
212
|
+
const typedData extends TypedData | Record<string, unknown>,
|
|
213
|
+
primaryType extends keyof typedData | "EIP712Domain" = keyof typedData
|
|
214
|
+
> (typedData: TypedDataDefinition<typedData, primaryType>, turnkeyClient: TurnkeyClient, organiationId: string, signWith: Address): Promise<Hex> => {
|
|
215
|
+
|
|
216
|
+
const webAuthnSignature = await _signTypedDataWithTurnkey(turnkeyClient, organiationId, signWith, typedData);
|
|
217
|
+
|
|
218
|
+
return _encodeSignature(webAuthnSignature);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const _signUserOperationHash = async (hash: Hex, turnkeyClient: TurnkeyClient, organiationId: string, signWith: Address): Promise<Hex> => {
|
|
222
|
+
|
|
223
|
+
const message = encodePacked(["uint8", "uint48", "bytes32"], [1, 0, hash]);
|
|
224
|
+
return _signMessage(message, turnkeyClient, organiationId, signWith);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export const _getSmartWallet = async (client: WalletClient, turnkeyClient: TurnkeyClient, organiationId: string, deviceUniqueIdentifier: string, deviceWalletOwnerKey: P256Key, salt: bigint, sender?: Address): Promise<SmartContractAccount> => {
|
|
228
|
+
|
|
229
|
+
const chainID = await client.getChainId();
|
|
230
|
+
const values = _getChainSpecificConstants(chainID);
|
|
231
|
+
|
|
232
|
+
if (!client.account) throw new Error ('Error: No signer account found with WalletClient')
|
|
233
|
+
const signWith = client.account.address;
|
|
234
|
+
|
|
235
|
+
return toSmartContractAccount({
|
|
236
|
+
/// REQUIRED PARAMS ///
|
|
237
|
+
source: "MyAccount",
|
|
238
|
+
transport: http(values.rpcURL),
|
|
239
|
+
|
|
240
|
+
chain: values.chain,
|
|
241
|
+
|
|
242
|
+
// The EntryPointDef that your account is compatible with
|
|
243
|
+
entryPoint: getEntryPoint(values.chain, {addressOverride: values.factoryAddresses.ENTRY_POINT}),
|
|
244
|
+
|
|
245
|
+
getAccountInitCode: async (): Promise<Hex> => await _getAccountInitCode(client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt),
|
|
246
|
+
|
|
247
|
+
// getAccountInitCodeHash: async (): Promise<BytesLike> => await getInitCodeHash(client, deviceUniqueIdentifier, deviceWalletOwnerKey),
|
|
248
|
+
|
|
249
|
+
// an invalid signature that doesn't cause your account to revert during validation
|
|
250
|
+
getDummySignature: async (): Promise<Hash> => "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c", //from Alchemy docs
|
|
251
|
+
|
|
252
|
+
// given a UO in the form of {target, data, value} should output the calldata for calling your contract's execution method
|
|
253
|
+
encodeExecute: async (uo): Promise<Hash> => _encodeExecute(uo),
|
|
254
|
+
|
|
255
|
+
signMessage: async ({ message }): Promise<Hash> => _signMessage(message, turnkeyClient, organiationId, signWith),
|
|
256
|
+
|
|
257
|
+
signTypedData: async (typedData): Promise<Hash> => _signTypedData(typedData, turnkeyClient, organiationId, signWith),
|
|
258
|
+
|
|
259
|
+
/// OPTIONAL PARAMS ///
|
|
260
|
+
// if you already know your account's address, pass that in here to avoid generating a new counterfactual
|
|
261
|
+
accountAddress: await getCounterFactualAddress(client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt, sender),
|
|
262
|
+
// if your account supports batching, this should take an array of UOs and return the calldata for calling your contract's batchExecute method
|
|
263
|
+
encodeBatchExecute: async (uos): Promise<Hash> => _encodeBatchExecute(uos),
|
|
264
|
+
// if your contract expects a different signing scheme than the default signMessage scheme, you can override that here
|
|
265
|
+
signUserOperationHash: async (hash): Promise<Hash> => _signUserOperationHash(hash, turnkeyClient, organiationId, signWith),
|
|
266
|
+
// allows you to define the calldata for upgrading your account
|
|
267
|
+
// encodeUpgradeToAndCall: async (params): Promise<Hash> => "0x...",
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export const _getSmartWalletClient = async (client: WalletClient, account: SmartContractAccount) => {
|
|
272
|
+
|
|
273
|
+
const chainID = await client.getChainId();
|
|
274
|
+
const values = _getChainSpecificConstants(chainID);
|
|
275
|
+
|
|
276
|
+
return createSmartAccountClient({
|
|
277
|
+
// created above
|
|
278
|
+
account: account,
|
|
279
|
+
chain: values.chain,
|
|
280
|
+
transport: http(values.rpcURL),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as dotenv from 'dotenv';
|
|
2
|
+
dotenv.config();
|
|
3
|
+
|
|
4
|
+
import { WalletClient } from "viem";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
mainnet,
|
|
8
|
+
sepolia,
|
|
9
|
+
optimism,
|
|
10
|
+
optimismSepolia,
|
|
11
|
+
arbitrum,
|
|
12
|
+
arbitrumSepolia
|
|
13
|
+
} from "viem/chains";
|
|
14
|
+
|
|
15
|
+
export const ZERO = BigInt('0');
|
|
16
|
+
|
|
17
|
+
export const API_KEY = process.env.API_KEY;
|
|
18
|
+
|
|
19
|
+
export enum CHAIN_ID {
|
|
20
|
+
MAINNET = 1,
|
|
21
|
+
SEPOLIA = 11155111,
|
|
22
|
+
OPTIMISM_MAINNET = 10,
|
|
23
|
+
OPTIMISM_SEPOLIA = 11155420,
|
|
24
|
+
ARBITRUM_ONE = 42161,
|
|
25
|
+
ARBITRUM_SEPOLIA = 421614,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const rpcURLs: Record<string, string> = {
|
|
29
|
+
mainnet: `https://eth-mainnet.g.alchemy.com/v2/${API_KEY}`,
|
|
30
|
+
sepolia: `https://eth-sepolia.g.alchemy.com/v2/${API_KEY}`,
|
|
31
|
+
optimismMainnet : `https://opt-mainnet.g.alchemy.com/v2/${API_KEY}`,
|
|
32
|
+
optimismSepolia: `https://opt-sepolia.g.alchemy.com/v2/${API_KEY}`,
|
|
33
|
+
arbitrum: `https://arb-mainnet.g.alchemy.com/v2/${API_KEY}`,
|
|
34
|
+
arbitrumSepolia: `https://arb-sepolia.g.alchemy.com/v2/${API_KEY}`,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface chainSpecifcConstants {
|
|
38
|
+
factoryAddresses:
|
|
39
|
+
typeof sepoliaFactoryAddresses |
|
|
40
|
+
typeof mainnetFactoryAddresses |
|
|
41
|
+
typeof optimismMainnetFactoryAddresses |
|
|
42
|
+
typeof optimismSepoliaFactoryAddresses |
|
|
43
|
+
typeof arbitrumOneFactoryAddresses |
|
|
44
|
+
typeof arbitrumSepoliaFactoryAddresses;
|
|
45
|
+
chain:
|
|
46
|
+
typeof mainnet |
|
|
47
|
+
typeof sepolia |
|
|
48
|
+
typeof optimism |
|
|
49
|
+
typeof optimismSepolia |
|
|
50
|
+
typeof arbitrum |
|
|
51
|
+
typeof arbitrumSepolia
|
|
52
|
+
rpcURL: string;
|
|
53
|
+
customErrors: typeof customErrors;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const sepoliaFactoryAddresses: Record<string, `0x${string}`> = {
|
|
57
|
+
DEVICE_WALLET_FACTORY: '0x63005d8214533fC7209678Aa39F7b9b0b51a7bcB',
|
|
58
|
+
ESIM_WALLET_FACTORY: '0xB4473979ff8cE4e09161B08f74EEb66BD7718076',
|
|
59
|
+
LAZY_WALLET_REGISTRY: '0x8a1E53b903efcc6b252CE4bD3b255202318505Ef',
|
|
60
|
+
REGISTRY: '0xCa447f5C75C57f6C59027304A5Fb5A09F0E005c9',
|
|
61
|
+
ENTRY_POINT: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
|
|
62
|
+
SENDER_CREATOR: '0x9406Cc6185a346906296840746125a0E44976454',
|
|
63
|
+
P256VERIFIER: '0xF04f3b3935aD461D17d4a8a78E7ea21d4a61AEb1'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const mainnetFactoryAddresses: Record<string, `0x${string}`> = {
|
|
67
|
+
DEVICE_WALLET_FACTORY: '0x',
|
|
68
|
+
ESIM_WALLET_FACTORY: '0x',
|
|
69
|
+
LAZY_WALLET_REGISTRY: '0x',
|
|
70
|
+
REGISTRY: '0x',
|
|
71
|
+
ENTRY_POINT: '0x',
|
|
72
|
+
SENDER_CREATOR: '0x',
|
|
73
|
+
P256VERIFIER: '0x'
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const optimismMainnetFactoryAddresses: Record<string, `0x${string}`> = {
|
|
77
|
+
DEVICE_WALLET_FACTORY: '0x',
|
|
78
|
+
ESIM_WALLET_FACTORY: '0x',
|
|
79
|
+
LAZY_WALLET_REGISTRY: '0x',
|
|
80
|
+
REGISTRY: '0x',
|
|
81
|
+
ENTRY_POINT: '0x',
|
|
82
|
+
SENDER_CREATOR: '0x',
|
|
83
|
+
P256VERIFIER: '0x'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const optimismSepoliaFactoryAddresses: Record<string, `0x${string}`> = {
|
|
87
|
+
DEVICE_WALLET_FACTORY: '0x3feA4dB0C0bBB73142d5bB6b776EE238884a3705',
|
|
88
|
+
ESIM_WALLET_FACTORY: '0xaD2Ba6248D0e6990a844C94ACE78F8775A68b631',
|
|
89
|
+
LAZY_WALLET_REGISTRY: '0x29b98C32D83604664fd0742b9112b0825a74849F',
|
|
90
|
+
REGISTRY: '0xaeB98F0f092fCb4a476ea3a5EB6A4B9E3D63A686',
|
|
91
|
+
ENTRY_POINT: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789',
|
|
92
|
+
SENDER_CREATOR: '0x7fc98430eaedbb6070b35b39d798725049088348',
|
|
93
|
+
P256VERIFIER: '0x5349aEA97Faa6D5d6D78A8847068300a4eC9D39E'
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const arbitrumOneFactoryAddresses: Record<string, `0x${string}`> = {
|
|
97
|
+
DEVICE_WALLET_FACTORY: '0x',
|
|
98
|
+
ESIM_WALLET_FACTORY: '0x',
|
|
99
|
+
LAZY_WALLET_REGISTRY: '0x',
|
|
100
|
+
REGISTRY: '0x',
|
|
101
|
+
ENTRY_POINT: '0x',
|
|
102
|
+
SENDER_CREATOR: '0x',
|
|
103
|
+
P256VERIFIER: '0x'
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const arbitrumSepoliaFactoryAddresses: Record<string, `0x${string}`> = {
|
|
107
|
+
DEVICE_WALLET_FACTORY: '0x',
|
|
108
|
+
ESIM_WALLET_FACTORY: '0x',
|
|
109
|
+
LAZY_WALLET_REGISTRY: '0x',
|
|
110
|
+
REGISTRY: '0x',
|
|
111
|
+
ENTRY_POINT: '0x',
|
|
112
|
+
SENDER_CREATOR: '0x',
|
|
113
|
+
P256VERIFIER: '0x'
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const customErrors: Record<string, string> = {
|
|
117
|
+
NULL_OR_UNDEFINED_VALUE: "Error: Null or undefined value provided",
|
|
118
|
+
MISSING_SMART_WALLET: "Error: Client does not have smart wallet account associated",
|
|
119
|
+
MISSING_EOA_WALLET: "Error: Client does not have EOA wallet associated"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const _extractChainID = async (client: WalletClient) => {
|
|
123
|
+
|
|
124
|
+
if (!client) {
|
|
125
|
+
throw "Invalid Signer or Provider instance";
|
|
126
|
+
}
|
|
127
|
+
return client.getChainId();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const _getChainSpecificConstants = (
|
|
131
|
+
chainID:
|
|
132
|
+
CHAIN_ID.SEPOLIA |
|
|
133
|
+
CHAIN_ID.MAINNET |
|
|
134
|
+
CHAIN_ID.OPTIMISM_MAINNET |
|
|
135
|
+
CHAIN_ID.OPTIMISM_SEPOLIA |
|
|
136
|
+
CHAIN_ID.ARBITRUM_ONE |
|
|
137
|
+
CHAIN_ID.ARBITRUM_SEPOLIA
|
|
138
|
+
): chainSpecifcConstants => {
|
|
139
|
+
|
|
140
|
+
if (chainID == CHAIN_ID.SEPOLIA) {
|
|
141
|
+
return {
|
|
142
|
+
factoryAddresses: sepoliaFactoryAddresses,
|
|
143
|
+
chain: sepolia,
|
|
144
|
+
rpcURL: rpcURLs.sepolia,
|
|
145
|
+
customErrors: customErrors
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (chainID == CHAIN_ID.MAINNET) {
|
|
149
|
+
return {
|
|
150
|
+
factoryAddresses: mainnetFactoryAddresses,
|
|
151
|
+
chain: mainnet,
|
|
152
|
+
rpcURL: rpcURLs.mainnet,
|
|
153
|
+
customErrors: customErrors
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else if (chainID == CHAIN_ID.OPTIMISM_MAINNET) {
|
|
157
|
+
return {
|
|
158
|
+
factoryAddresses: optimismMainnetFactoryAddresses,
|
|
159
|
+
chain: optimism,
|
|
160
|
+
rpcURL: rpcURLs.optimismMainnet,
|
|
161
|
+
customErrors: customErrors
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (chainID == CHAIN_ID.OPTIMISM_SEPOLIA) {
|
|
165
|
+
return {
|
|
166
|
+
factoryAddresses: optimismSepoliaFactoryAddresses,
|
|
167
|
+
chain: optimismSepolia,
|
|
168
|
+
rpcURL: rpcURLs.optimismSepolia,
|
|
169
|
+
customErrors: customErrors
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else if (chainID == CHAIN_ID.ARBITRUM_ONE) {
|
|
173
|
+
return {
|
|
174
|
+
factoryAddresses: arbitrumOneFactoryAddresses,
|
|
175
|
+
chain: arbitrum,
|
|
176
|
+
rpcURL: rpcURLs.arbitrum,
|
|
177
|
+
customErrors: customErrors
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
return {
|
|
182
|
+
factoryAddresses: arbitrumSepoliaFactoryAddresses,
|
|
183
|
+
chain: arbitrumSepolia,
|
|
184
|
+
rpcURL: rpcURLs.arbitrumSepolia,
|
|
185
|
+
customErrors: customErrors
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|