kokio-sdk 1.0.0 → 2.0.0

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 (107) hide show
  1. package/README.md +68 -19
  2. package/dist/esm/abis/BeaconProxy.js +30 -46
  3. package/dist/esm/abis/DeviceWallet.js +546 -535
  4. package/dist/esm/abis/DeviceWalletFactory.js +537 -544
  5. package/dist/esm/abis/ESIMWallet.js +440 -299
  6. package/dist/esm/abis/ESIMWalletFactory.js +372 -289
  7. package/dist/esm/abis/LazyWalletRegistry.js +941 -421
  8. package/dist/esm/abis/P256Verifier.js +29 -29
  9. package/dist/esm/abis/ProtocolAdmin.js +1228 -0
  10. package/dist/esm/abis/Registry.js +1207 -466
  11. package/dist/esm/abis/RegistryHelper.js +414 -20
  12. package/dist/esm/abis/index.js +2 -1
  13. package/dist/esm/admin/config-admin.js +24 -0
  14. package/dist/esm/admin/interface/deviceWalletClass.js +27 -6
  15. package/dist/esm/admin/interface/deviceWalletFactoryClass.js +41 -19
  16. package/dist/esm/admin/interface/eSIMWalletClass.js +10 -1
  17. package/dist/esm/admin/interface/eSIMWalletFactoryClass.js +24 -2
  18. package/dist/esm/admin/interface/lazyWalletRegistryClass.js +83 -4
  19. package/dist/esm/admin/interface/protocolAdminClass.js +195 -0
  20. package/dist/esm/admin/interface/registryClass.js +93 -2
  21. package/dist/esm/config.js +42 -7
  22. package/dist/esm/interface/deviceWalletClass.js +45 -5
  23. package/dist/esm/interface/deviceWalletFactoryClass.js +20 -1
  24. package/dist/esm/interface/eSIMWalletClass.js +12 -3
  25. package/dist/esm/interface/registryClass.js +47 -0
  26. package/dist/esm/interface/smartAccountClass.js +2 -4
  27. package/dist/esm/logic/account-kit/createSmartAccount.js +156 -102
  28. package/dist/esm/logic/admin/deviceWallet.eoa.js +23 -12
  29. package/dist/esm/logic/admin/deviceWalletFactory.eoa.js +63 -42
  30. package/dist/esm/logic/admin/eSIMWallet.eoa.js +3 -5
  31. package/dist/esm/logic/admin/eSIMWalletFactory.eoa.js +76 -8
  32. package/dist/esm/logic/admin/lazyWalletRegistry.eoa.js +330 -19
  33. package/dist/esm/logic/admin/protocolAdmin.eoa.js +524 -0
  34. package/dist/esm/logic/admin/reads/deviceWallet.reads.js +82 -7
  35. package/dist/esm/logic/admin/reads/deviceWalletFactory.reads.js +82 -23
  36. package/dist/esm/logic/admin/reads/eSIMWallet.reads.js +50 -6
  37. package/dist/esm/logic/admin/reads/eSIMWalletFactory.reads.js +63 -5
  38. package/dist/esm/logic/admin/reads/lazyWalletRegistry.reads.js +171 -10
  39. package/dist/esm/logic/admin/reads/protocolAdmin.reads.js +154 -0
  40. package/dist/esm/logic/admin/reads/registry.reads.js +289 -9
  41. package/dist/esm/logic/admin/registry.eoa.js +274 -4
  42. package/dist/esm/logic/constants.js +53 -26
  43. package/dist/esm/logic/deviceWallet.js +224 -31
  44. package/dist/esm/logic/deviceWalletFactory.js +89 -0
  45. package/dist/esm/logic/eSIMWallet.js +113 -43
  46. package/dist/esm/logic/eSIMWalletFactory.js +8 -8
  47. package/dist/esm/logic/errors.js +64 -0
  48. package/dist/esm/logic/registry.js +236 -0
  49. package/dist/esm/logic/utils.js +2 -1
  50. package/dist/types/abis/BeaconProxy.d.ts +21 -33
  51. package/dist/types/abis/DeviceWallet.d.ts +372 -365
  52. package/dist/types/abis/DeviceWalletFactory.d.ts +438 -448
  53. package/dist/types/abis/ESIMWallet.d.ts +352 -245
  54. package/dist/types/abis/ESIMWalletFactory.d.ts +278 -216
  55. package/dist/types/abis/LazyWalletRegistry.d.ts +710 -317
  56. package/dist/types/abis/P256Verifier.d.ts +16 -16
  57. package/dist/types/abis/ProtocolAdmin.d.ts +947 -0
  58. package/dist/types/abis/Registry.d.ts +960 -393
  59. package/dist/types/abis/RegistryHelper.d.ts +317 -16
  60. package/dist/types/abis/index.d.ts +2 -1
  61. package/dist/types/admin/config-admin.d.ts +16 -0
  62. package/dist/types/admin/interface/deviceWalletClass.d.ts +10 -3
  63. package/dist/types/admin/interface/deviceWalletFactoryClass.d.ts +14 -7
  64. package/dist/types/admin/interface/eSIMWalletClass.d.ts +3 -0
  65. package/dist/types/admin/interface/eSIMWalletFactoryClass.d.ts +8 -1
  66. package/dist/types/admin/interface/lazyWalletRegistryClass.d.ts +38 -2
  67. package/dist/types/admin/interface/protocolAdminClass.d.ts +95 -0
  68. package/dist/types/admin/interface/registryClass.d.ts +30 -0
  69. package/dist/types/config.d.ts +26 -5
  70. package/dist/types/interface/P256VerifierClass.d.ts +3 -4
  71. package/dist/types/interface/constantsClass.d.ts +2 -2
  72. package/dist/types/interface/deviceWalletClass.d.ts +22 -2569
  73. package/dist/types/interface/deviceWalletFactoryClass.d.ts +10 -2564
  74. package/dist/types/interface/eSIMWalletClass.d.ts +11 -8
  75. package/dist/types/interface/eSIMWalletFactoryClass.d.ts +5 -2565
  76. package/dist/types/interface/registryClass.d.ts +19 -0
  77. package/dist/types/interface/smartAccountClass.d.ts +6 -2568
  78. package/dist/types/logic/P256Verifier.d.ts +2 -2
  79. package/dist/types/logic/account-kit/createSmartAccount.d.ts +43 -19
  80. package/dist/types/logic/admin/deviceWallet.eoa.d.ts +15 -9
  81. package/dist/types/logic/admin/deviceWalletFactory.eoa.d.ts +34 -23
  82. package/dist/types/logic/admin/eSIMWallet.eoa.d.ts +0 -5
  83. package/dist/types/logic/admin/eSIMWalletFactory.eoa.d.ts +27 -9
  84. package/dist/types/logic/admin/lazyWalletRegistry.eoa.d.ts +102 -10
  85. package/dist/types/logic/admin/protocolAdmin.eoa.d.ts +163 -0
  86. package/dist/types/logic/admin/reads/deviceWallet.reads.d.ts +28 -8
  87. package/dist/types/logic/admin/reads/deviceWalletFactory.reads.d.ts +45 -14
  88. package/dist/types/logic/admin/reads/eSIMWallet.reads.d.ts +25 -6
  89. package/dist/types/logic/admin/reads/eSIMWalletFactory.reads.d.ts +21 -6
  90. package/dist/types/logic/admin/reads/lazyWalletRegistry.reads.d.ts +44 -11
  91. package/dist/types/logic/admin/reads/protocolAdmin.reads.d.ts +53 -0
  92. package/dist/types/logic/admin/reads/registry.reads.d.ts +105 -9
  93. package/dist/types/logic/admin/registry.eoa.d.ts +102 -5
  94. package/dist/types/logic/constants.d.ts +2 -0
  95. package/dist/types/logic/deviceWallet.d.ts +78 -6
  96. package/dist/types/logic/deviceWalletFactory.d.ts +32 -3
  97. package/dist/types/logic/eSIMWallet.d.ts +48 -7
  98. package/dist/types/logic/eSIMWalletFactory.d.ts +3 -3
  99. package/dist/types/logic/errors.d.ts +45 -0
  100. package/dist/types/logic/registry.d.ts +78 -0
  101. package/dist/types/types-export.d.ts +1 -1
  102. package/dist/types/types.d.ts +111 -1
  103. package/package.json +11 -13
  104. package/dist/esm/interface/lazyWalletRegistryClass.js +0 -10
  105. package/dist/esm/logic/lazyWalletRegistry.js +0 -19
  106. package/dist/types/interface/lazyWalletRegistryClass.d.ts +0 -6
  107. package/dist/types/logic/lazyWalletRegistry.d.ts +0 -2
@@ -2,6 +2,22 @@ import { InvalidClientError, UnconfiguredChainError, UnsupportedChainError, } fr
2
2
  import { mainnet, sepolia, optimism, optimismSepolia, arbitrum, arbitrumSepolia, base, baseSepolia } from "viem/chains";
3
3
  export const ZERO = BigInt('0');
4
4
  export const SIGNATURE_VALIDITY_SECONDS = 180; // 3 minutes validity
5
+ // Gas estimation runs before a passkey signature exists, so the account hands the
6
+ // bundler "0x" as a stub. Account4337 rejects any signature of 39 bytes or fewer
7
+ // before it reaches the P256 verifier, so the bundler measures an early return and
8
+ // prices calldata that is 519 bytes short of the real thing. Both estimates come
9
+ // back too low and an operation sized from them is refused, so both are padded.
10
+ //
11
+ // Measured on Base Sepolia: verification estimated at 33,703 gas against a floor of
12
+ // 76,628, and preVerificationGas 11,536 lower than the same operation carrying a
13
+ // real-length signature.
14
+ // Unused verification gas is refunded in full, unlike callGasLimit, so headroom
15
+ // here only raises the prefund the sponsor has to post and costs nothing when it
16
+ // goes unspent.
17
+ export const STUB_VERIFICATION_GAS_PAD = BigInt(60_000);
18
+ // preVerificationGas is charged whether or not it is used, so this stays close to
19
+ // the measured shortfall.
20
+ export const STUB_PRE_VERIFICATION_GAS_PAD = BigInt(15_000);
5
21
  export var CHAIN_ID;
6
22
  (function (CHAIN_ID) {
7
23
  CHAIN_ID[CHAIN_ID["MAINNET"] = 1] = "MAINNET";
@@ -13,14 +29,17 @@ export var CHAIN_ID;
13
29
  CHAIN_ID[CHAIN_ID["ARBITRUM_ONE"] = 42161] = "ARBITRUM_ONE";
14
30
  CHAIN_ID[CHAIN_ID["ARBITRUM_SEPOLIA"] = 421614] = "ARBITRUM_SEPOLIA";
15
31
  })(CHAIN_ID || (CHAIN_ID = {}));
32
+ // Cleared: the deployment here targets EntryPoint v0.7, which this SDK no longer
33
+ // speaks. Refill only after a redeploy on v0.8.
16
34
  export const sepoliaFactoryAddresses = {
17
- DEVICE_WALLET_FACTORY: '0x63005d8214533fC7209678Aa39F7b9b0b51a7bcB',
18
- ESIM_WALLET_FACTORY: '0xB4473979ff8cE4e09161B08f74EEb66BD7718076',
19
- LAZY_WALLET_REGISTRY: '0x8a1E53b903efcc6b252CE4bD3b255202318505Ef',
20
- REGISTRY: '0xCa447f5C75C57f6C59027304A5Fb5A09F0E005c9',
21
- ENTRY_POINT: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
22
- SENDER_CREATOR: '0xefc2c1444ebcc4db75e7613d20c6a62ff67a167c',
23
- P256VERIFIER: '0xF04f3b3935aD461D17d4a8a78E7ea21d4a61AEb1'
35
+ DEVICE_WALLET_FACTORY: '0x',
36
+ ESIM_WALLET_FACTORY: '0x',
37
+ LAZY_WALLET_REGISTRY: '0x',
38
+ REGISTRY: '0x',
39
+ ENTRY_POINT: '0x',
40
+ SENDER_CREATOR: '0x',
41
+ P256VERIFIER: '0x',
42
+ PROTOCOL_ADMIN: '0x'
24
43
  };
25
44
  export const mainnetFactoryAddresses = {
26
45
  DEVICE_WALLET_FACTORY: '0x',
@@ -29,7 +48,8 @@ export const mainnetFactoryAddresses = {
29
48
  REGISTRY: '0x',
30
49
  ENTRY_POINT: '0x',
31
50
  SENDER_CREATOR: '0x',
32
- P256VERIFIER: '0x'
51
+ P256VERIFIER: '0x',
52
+ PROTOCOL_ADMIN: '0x'
33
53
  };
34
54
  export const optimismMainnetFactoryAddresses = {
35
55
  DEVICE_WALLET_FACTORY: '0x',
@@ -38,16 +58,19 @@ export const optimismMainnetFactoryAddresses = {
38
58
  REGISTRY: '0x',
39
59
  ENTRY_POINT: '0x',
40
60
  SENDER_CREATOR: '0x',
41
- P256VERIFIER: '0x'
61
+ P256VERIFIER: '0x',
62
+ PROTOCOL_ADMIN: '0x'
42
63
  };
64
+ // Cleared for the same reason as Sepolia: a v0.7 deployment this SDK cannot use.
43
65
  export const optimismSepoliaFactoryAddresses = {
44
- DEVICE_WALLET_FACTORY: '0x243cCdE6a56b0Ba740E067f39896772748E20fFD',
45
- ESIM_WALLET_FACTORY: '0x8444bF9C39F01e4B092e42DC11695C61f8B93957',
46
- LAZY_WALLET_REGISTRY: '0x3F14D060074B174B0784056bDe5e0f8970D25ff1',
47
- REGISTRY: '0x96dA9cE92D2C09f7b3ADE01260608e9079f16d12',
48
- ENTRY_POINT: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
49
- SENDER_CREATOR: '0xefc2c1444ebcc4db75e7613d20c6a62ff67a167c',
50
- P256VERIFIER: '0x3c15a78046838481788613A9F111F972B562623C'
66
+ DEVICE_WALLET_FACTORY: '0x',
67
+ ESIM_WALLET_FACTORY: '0x',
68
+ LAZY_WALLET_REGISTRY: '0x',
69
+ REGISTRY: '0x',
70
+ ENTRY_POINT: '0x',
71
+ SENDER_CREATOR: '0x',
72
+ P256VERIFIER: '0x',
73
+ PROTOCOL_ADMIN: '0x'
51
74
  };
52
75
  export const baseMainnetFactoryAddresses = {
53
76
  DEVICE_WALLET_FACTORY: '0x',
@@ -56,16 +79,18 @@ export const baseMainnetFactoryAddresses = {
56
79
  REGISTRY: '0x',
57
80
  ENTRY_POINT: '0x',
58
81
  SENDER_CREATOR: '0x',
59
- P256VERIFIER: '0x'
82
+ P256VERIFIER: '0x',
83
+ PROTOCOL_ADMIN: '0x'
60
84
  };
61
85
  export const baseSepoliaFactoryAddresses = {
62
- DEVICE_WALLET_FACTORY: '0xB4473979ff8cE4e09161B08f74EEb66BD7718076',
63
- ESIM_WALLET_FACTORY: '0x63005d8214533fC7209678Aa39F7b9b0b51a7bcB',
64
- LAZY_WALLET_REGISTRY: '0x8a1E53b903efcc6b252CE4bD3b255202318505Ef',
65
- REGISTRY: '0xCa447f5C75C57f6C59027304A5Fb5A09F0E005c9',
66
- ENTRY_POINT: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
67
- SENDER_CREATOR: '0xefc2c1444ebcc4db75e7613d20c6a62ff67a167c',
68
- P256VERIFIER: '0xF04f3b3935aD461D17d4a8a78E7ea21d4a61AEb1'
86
+ DEVICE_WALLET_FACTORY: '0xB006c7066C89a5d7Bfc229e9fb0bADf96c8F979f',
87
+ ESIM_WALLET_FACTORY: '0x13998C0bb7433c51cE5101922B12EE69F459699A',
88
+ LAZY_WALLET_REGISTRY: '0x394177c5cc4762b897c37de1820259B75993e033',
89
+ REGISTRY: '0x89e386E3251692F21a2E9048A46518AdC2A5Cb4A',
90
+ ENTRY_POINT: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108',
91
+ SENDER_CREATOR: '0x449ED7C3e6Fee6a97311d4b55475DF59C44AdD33',
92
+ P256VERIFIER: '0x625561429bD99d647956ccBCA4eBf762aaA142c5',
93
+ PROTOCOL_ADMIN: '0x77A1D6f27462c34BF038832d9Cff6b3E94a9Fe6F'
69
94
  };
70
95
  export const arbitrumOneFactoryAddresses = {
71
96
  DEVICE_WALLET_FACTORY: '0x',
@@ -74,7 +99,8 @@ export const arbitrumOneFactoryAddresses = {
74
99
  REGISTRY: '0x',
75
100
  ENTRY_POINT: '0x',
76
101
  SENDER_CREATOR: '0x',
77
- P256VERIFIER: '0x'
102
+ P256VERIFIER: '0x',
103
+ PROTOCOL_ADMIN: '0x'
78
104
  };
79
105
  export const arbitrumSepoliaFactoryAddresses = {
80
106
  DEVICE_WALLET_FACTORY: '0x',
@@ -83,7 +109,8 @@ export const arbitrumSepoliaFactoryAddresses = {
83
109
  REGISTRY: '0x',
84
110
  ENTRY_POINT: '0x',
85
111
  SENDER_CREATOR: '0x',
86
- P256VERIFIER: '0x'
112
+ P256VERIFIER: '0x',
113
+ PROTOCOL_ADMIN: '0x'
87
114
  };
88
115
  export const customErrors = {
89
116
  NULL_OR_UNDEFINED_VALUE: "Error: Null or undefined value provided",
@@ -4,59 +4,159 @@ import { MissingSmartWalletError } from "./errors.js";
4
4
  // A userOp from a device wallet runs through `execute`, so at the target contract
5
5
  // msg.sender is the device-wallet account itself. That constrains which DeviceWallet
6
6
  // functions this surface can expose:
7
- // - deployESIMWallet / setESIMUniqueIdentifierForAnESIMWallet are `onlyESIMWalletAdmin`
8
- // / `onlyESIMWalletAdminOrRegistry` - only the admin EOA (or registry) may call, so a
9
- // device-wallet userOp always reverts. They are exposed on `KokioAdmin.deviceWallet`.
10
- // - payETHForDataBundles / pullETH are `onlyAssociatedESIMWallets` - callable only by an
11
- // associated eSIM wallet contract, never by the device wallet or an EOA.
7
+ // - deployESIMWallet is `onlyESIMWalletAdmin` - only the admin EOA may call, so a
8
+ // device-wallet userOp always reverts. It is exposed on `KokioAdmin.deviceWallet`.
9
+ // - pullETH is `onlyAssociatedESIMWallets` - callable only by an associated eSIM
10
+ // wallet contract, never by the device wallet or an EOA. An eSIM wallet reaches it
11
+ // on its own during `buyDataBundle`.
12
+ // - execute and executeBatch are what a userOp runs through, so the smart account
13
+ // client already uses them; calling one directly would nest a userOp inside a userOp.
14
+ // `_sendUserOperation` below is the generic entry point instead: it hands the smart
15
+ // account client raw calls, and the account's own `encodeCalls` is what turns those
16
+ // into `execute` or `executeBatch`, never this file.
17
+ // - init runs at deploy, and validateUserOp is `onlyEntryPoint`.
12
18
  // The functions below are self-callable (target = the device wallet's own address, so
13
19
  // msg.sender == self), so they succeed via a userOp.
20
+ /**
21
+ * Send one or more calls from this device wallet as a single user operation.
22
+ * The only escape hatch on this surface for anything not named below: sending
23
+ * ETH to any address, calling another contract, moving tokens, interacting
24
+ * with a DeFi protocol. A lone call encodes to `execute`, several batch
25
+ * atomically through `executeBatch`.
26
+ */
27
+ export const _sendUserOperation = async (client, calls) => {
28
+ if (!client.account)
29
+ throw new MissingSmartWalletError();
30
+ return client.sendUserOperation({
31
+ account: client.account,
32
+ calls
33
+ });
34
+ };
14
35
  export const _toggleAccessToETH = async (client, address, eSIMWalletAddress, hasAccessToETH) => {
15
36
  if (!client.account)
16
37
  throw new MissingSmartWalletError();
17
38
  // UserOp - `onlySelf`; the device wallet toggles ETH access for an eSIM wallet it owns.
18
39
  return client.sendUserOperation({
19
40
  account: client.account,
20
- uo: {
21
- target: address,
22
- data: encodeFunctionData({
23
- abi: DeviceWallet,
24
- functionName: "toggleAccessToETH",
25
- args: [eSIMWalletAddress, hasAccessToETH]
26
- })
27
- }
41
+ calls: [{
42
+ to: address,
43
+ data: encodeFunctionData({
44
+ abi: DeviceWallet,
45
+ functionName: "toggleAccessToETH",
46
+ args: [eSIMWalletAddress, hasAccessToETH]
47
+ })
48
+ }]
28
49
  });
29
50
  };
30
- export const _addESIMWallet = async (client, address, eSIMWalletAddress, hasAccessToETH) => {
51
+ /**
52
+ * Bind an eSIM wallet this device wallet already owns.
53
+ *
54
+ * A bind never carries ETH access: the contract reverts on a `true` rather than
55
+ * downgrading it quietly, so the SDK passes `false` and there is nothing to
56
+ * choose. `toggleAccessToETH` is the only way to grant it, which is what stops a
57
+ * bind from undoing the owner's revocation.
58
+ */
59
+ export const _addESIMWallet = async (client, address, eSIMWalletAddress) => {
31
60
  if (!client.account)
32
61
  throw new MissingSmartWalletError();
33
62
  // UserOp - `onlyRegistryOrDeviceWalletFactoryOrOwner`; self is permitted.
34
63
  return client.sendUserOperation({
35
64
  account: client.account,
36
- uo: {
37
- target: address,
38
- data: encodeFunctionData({
39
- abi: DeviceWallet,
40
- functionName: "addESIMWallet",
41
- args: [eSIMWalletAddress, hasAccessToETH]
42
- })
43
- }
65
+ calls: [{
66
+ to: address,
67
+ data: encodeFunctionData({
68
+ abi: DeviceWallet,
69
+ functionName: "addESIMWallet",
70
+ args: [eSIMWalletAddress, false]
71
+ })
72
+ }]
44
73
  });
45
74
  };
46
- export const _removeESIMWallet = async (client, address, eSIMWalletAddress, hasAccessToETH) => {
75
+ /**
76
+ * Release an eSIM wallet and put it on standby for a transfer.
77
+ *
78
+ * `callBackETH` sweeps whatever ETH the eSIM wallet still holds back here. It
79
+ * runs after the release, so a wallet whose handler misbehaves has already lost
80
+ * its ETH access and its registry association. A failed sweep is swallowed by
81
+ * the contract, so a `true` is not a promise that anything arrived.
82
+ */
83
+ export const _removeESIMWallet = async (client, address, eSIMWalletAddress, callBackETH) => {
47
84
  if (!client.account)
48
85
  throw new MissingSmartWalletError();
49
86
  // UserOp - `onlySelfOrAssociatedESIMWallet`; self is permitted.
50
87
  return client.sendUserOperation({
51
88
  account: client.account,
52
- uo: {
53
- target: address,
54
- data: encodeFunctionData({
55
- abi: DeviceWallet,
56
- functionName: "removeESIMWallet",
57
- args: [eSIMWalletAddress, hasAccessToETH]
58
- })
59
- }
89
+ calls: [{
90
+ to: address,
91
+ data: encodeFunctionData({
92
+ abi: DeviceWallet,
93
+ functionName: "removeESIMWallet",
94
+ args: [eSIMWalletAddress, callBackETH]
95
+ })
96
+ }]
97
+ });
98
+ };
99
+ /**
100
+ * Rotate the P256 key that owns this wallet. The registry is told in the same
101
+ * call, so its record of the owner cannot drift from the wallet's.
102
+ *
103
+ * A key that cannot produce a verifiable signature bricks the wallet: this is
104
+ * reachable only through a signed userOp, so there is no rotating back and no
105
+ * reaching the balance afterwards. The contract rejects a key it can tell is
106
+ * unusable, but check the new key can sign before calling.
107
+ */
108
+ export const _transferOwnership = async (client, address, newOwner) => {
109
+ if (!client.account)
110
+ throw new MissingSmartWalletError();
111
+ // UserOp - `onlySelf`.
112
+ return client.sendUserOperation({
113
+ account: client.account,
114
+ calls: [{
115
+ to: address,
116
+ data: encodeFunctionData({
117
+ abi: DeviceWallet,
118
+ functionName: "transferOwnership",
119
+ args: [newOwner]
120
+ })
121
+ }]
122
+ });
123
+ };
124
+ /**
125
+ * Top up the gas deposit the EntryPoint holds for this wallet, from the wallet's
126
+ * own balance. Anyone may pay into any account's deposit, so an EOA can do this
127
+ * with a plain transfer too and not spend a userOp on it.
128
+ */
129
+ export const _addDeposit = async (client, address, amount) => {
130
+ if (!client.account)
131
+ throw new MissingSmartWalletError();
132
+ return client.sendUserOperation({
133
+ account: client.account,
134
+ calls: [{
135
+ to: address,
136
+ value: amount,
137
+ data: encodeFunctionData({
138
+ abi: DeviceWallet,
139
+ functionName: "addDeposit",
140
+ args: []
141
+ })
142
+ }]
143
+ });
144
+ };
145
+ /** Pull part of the EntryPoint gas deposit back out to any address. */
146
+ export const _withdrawDepositTo = async (client, address, withdrawAddress, amount) => {
147
+ if (!client.account)
148
+ throw new MissingSmartWalletError();
149
+ // UserOp - `onlySelf`.
150
+ return client.sendUserOperation({
151
+ account: client.account,
152
+ calls: [{
153
+ to: address,
154
+ data: encodeFunctionData({
155
+ abi: DeviceWallet,
156
+ functionName: "withdrawDepositTo",
157
+ args: [withdrawAddress, amount]
158
+ })
159
+ }]
60
160
  });
61
161
  };
62
162
  // `getVaultAddress` is a `view` - read it directly instead of spending a userOp.
@@ -68,6 +168,99 @@ export const _getVaultAddress = async (client, address) => {
68
168
  args: []
69
169
  });
70
170
  };
171
+ /** Gas this wallet has on deposit at the EntryPoint. */
172
+ export const _getDeposit = async (client, address) => {
173
+ return client.readContract({
174
+ address,
175
+ abi: DeviceWallet,
176
+ functionName: "getDeposit",
177
+ args: []
178
+ });
179
+ };
180
+ /** The device identifier this wallet was deployed for. Set once, at deploy. */
181
+ export const _deviceUniqueIdentifier = async (client, address) => {
182
+ return client.readContract({
183
+ address,
184
+ abi: DeviceWallet,
185
+ functionName: "deviceUniqueIdentifier",
186
+ args: []
187
+ });
188
+ };
189
+ /** Whether this wallet currently holds the given eSIM wallet. */
190
+ export const _isValidESIMWallet = async (client, address, eSIMWalletAddress) => {
191
+ return client.readContract({
192
+ address,
193
+ abi: DeviceWallet,
194
+ functionName: "isValidESIMWallet",
195
+ args: [eSIMWalletAddress]
196
+ });
197
+ };
198
+ /**
199
+ * Whether an eSIM wallet may pull ETH from this one. Binding a wallet never
200
+ * grants it, so this stays false until `toggleAccessToETH` says otherwise.
201
+ */
202
+ export const _canPullETH = async (client, address, eSIMWalletAddress) => {
203
+ return client.readContract({
204
+ address,
205
+ abi: DeviceWallet,
206
+ functionName: "canPullETH",
207
+ args: [eSIMWalletAddress]
208
+ });
209
+ };
210
+ /**
211
+ * Check a signature over an arbitrary message, per ERC-1271. Returns
212
+ * `0x1626ba7e` when the signature is valid and unexpired, `0xffffffff` otherwise.
213
+ *
214
+ * The signature is a version byte, then six bytes of `validUntil`, then the
215
+ * ABI-encoded WebAuthn assertion. What was signed is not `messageHash` itself but
216
+ * an EIP-191 digest over version, validUntil, chain id, this wallet's address and
217
+ * `messageHash`, so a signature cannot be replayed on another chain or against
218
+ * the same owner key's wallet at a different salt.
219
+ */
220
+ export const _isValidSignature = async (client, address, messageHash, signature) => {
221
+ return client.readContract({
222
+ address,
223
+ abi: DeviceWallet,
224
+ functionName: "isValidSignature",
225
+ args: [messageHash, signature]
226
+ });
227
+ };
228
+ /** The registry this wallet reports its ownership changes to. */
229
+ export const _registry = async (client, address) => {
230
+ return client.readContract({
231
+ address,
232
+ abi: DeviceWallet,
233
+ functionName: "registry",
234
+ args: []
235
+ });
236
+ };
237
+ /** The factory that deploys this wallet's eSIM wallets. */
238
+ export const _eSIMWalletFactory = async (client, address) => {
239
+ return client.readContract({
240
+ address,
241
+ abi: DeviceWallet,
242
+ functionName: "eSIMWalletFactory",
243
+ args: []
244
+ });
245
+ };
246
+ /** The ERC-4337 EntryPoint this wallet answers to. Immutable. */
247
+ export const _entryPoint = async (client, address) => {
248
+ return client.readContract({
249
+ address,
250
+ abi: DeviceWallet,
251
+ functionName: "entryPoint",
252
+ args: []
253
+ });
254
+ };
255
+ /** The P256 verifier used when the RIP-7212 precompile is unavailable. */
256
+ export const _verifier = async (client, address) => {
257
+ return client.readContract({
258
+ address,
259
+ abi: DeviceWallet,
260
+ functionName: "verifier",
261
+ args: []
262
+ });
263
+ };
71
264
  export const _getOwner = async (client, address) => {
72
265
  const contract = getContract({
73
266
  abi: DeviceWallet,
@@ -45,3 +45,92 @@ export const _getCurrentDeviceWalletImplementation = async (client) => {
45
45
  args: []
46
46
  });
47
47
  };
48
+ /**
49
+ * Check an identifier and owner key before deploying. Answers the zero address
50
+ * when both are free, or the wallet already holding one of them.
51
+ *
52
+ * Call this first. `createAccount` runs inside EntryPoint validation, where the
53
+ * 4337 rules bar it from reading the registry, so it cannot see that an
54
+ * identifier or a key is taken: it deploys a second wallet at a fresh address
55
+ * and the `postCreateAccount` that would register it fails afterwards.
56
+ *
57
+ * Reverts on an empty identifier or a key that is not a point on the P256 curve.
58
+ */
59
+ export const _preCreateAccountValidation = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey) => {
60
+ const chainID = await client.getChainId();
61
+ const rpcURL = client.transport.url;
62
+ const values = _getChainSpecificConstants(chainID, rpcURL);
63
+ return client.readContract({
64
+ address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
65
+ abi: DeviceWalletFactory,
66
+ functionName: "preCreateAccountValidation",
67
+ args: [deviceUniqueIdentifier, deviceWalletOwnerKey]
68
+ });
69
+ };
70
+ /**
71
+ * Whether the factory has recorded this wallet. Set by `postCreateAccount`, not
72
+ * by the deploy, so a wallet the app just created reads false until the backend
73
+ * registers it.
74
+ */
75
+ export const _deviceWalletInfoAdded = async (client, deviceWallet) => {
76
+ const chainID = await client.getChainId();
77
+ const rpcURL = client.transport.url;
78
+ const values = _getChainSpecificConstants(chainID, rpcURL);
79
+ return client.readContract({
80
+ address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
81
+ abi: DeviceWalletFactory,
82
+ functionName: "deviceWalletInfoAdded",
83
+ args: [deviceWallet]
84
+ });
85
+ };
86
+ /**
87
+ * The beacon every device wallet reads its implementation from. One update moves
88
+ * all of them and no wallet can decline it.
89
+ */
90
+ export const _beacon = async (client) => {
91
+ const chainID = await client.getChainId();
92
+ const rpcURL = client.transport.url;
93
+ const values = _getChainSpecificConstants(chainID, rpcURL);
94
+ return client.readContract({
95
+ address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
96
+ abi: DeviceWalletFactory,
97
+ functionName: "beacon",
98
+ args: []
99
+ });
100
+ };
101
+ /** The registry the factory writes new wallets into. */
102
+ export const _registry = async (client) => {
103
+ const chainID = await client.getChainId();
104
+ const rpcURL = client.transport.url;
105
+ const values = _getChainSpecificConstants(chainID, rpcURL);
106
+ return client.readContract({
107
+ address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
108
+ abi: DeviceWalletFactory,
109
+ functionName: "registry",
110
+ args: []
111
+ });
112
+ };
113
+ /** The EntryPoint baked into every device wallet this factory deploys. */
114
+ export const _entryPoint = async (client) => {
115
+ const chainID = await client.getChainId();
116
+ const rpcURL = client.transport.url;
117
+ const values = _getChainSpecificConstants(chainID, rpcURL);
118
+ return client.readContract({
119
+ address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
120
+ abi: DeviceWalletFactory,
121
+ functionName: "entryPoint",
122
+ args: []
123
+ });
124
+ };
125
+ /** The contract new device wallets verify WebAuthn assertions through. */
126
+ export const _verifier = async (client) => {
127
+ const chainID = await client.getChainId();
128
+ const rpcURL = client.transport.url;
129
+ const values = _getChainSpecificConstants(chainID, rpcURL);
130
+ return client.readContract({
131
+ address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
132
+ abi: DeviceWalletFactory,
133
+ functionName: "verifier",
134
+ args: []
135
+ });
136
+ };