kokio-sdk 1.1.0 → 2.1.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 (106) 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 +7 -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 +26 -15
  29. package/dist/esm/logic/admin/deviceWalletFactory.eoa.js +69 -48
  30. package/dist/esm/logic/admin/eSIMWallet.eoa.js +5 -7
  31. package/dist/esm/logic/admin/eSIMWalletFactory.eoa.js +79 -11
  32. package/dist/esm/logic/admin/lazyWalletRegistry.eoa.js +333 -22
  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 +276 -6
  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 +94 -1
  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 +3 -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/deviceWalletClass.d.ts +22 -2569
  72. package/dist/types/interface/deviceWalletFactoryClass.d.ts +10 -2564
  73. package/dist/types/interface/eSIMWalletClass.d.ts +11 -8
  74. package/dist/types/interface/eSIMWalletFactoryClass.d.ts +5 -2565
  75. package/dist/types/interface/registryClass.d.ts +19 -0
  76. package/dist/types/interface/smartAccountClass.d.ts +6 -2568
  77. package/dist/types/logic/P256Verifier.d.ts +2 -2
  78. package/dist/types/logic/account-kit/createSmartAccount.d.ts +43 -19
  79. package/dist/types/logic/admin/deviceWallet.eoa.d.ts +15 -9
  80. package/dist/types/logic/admin/deviceWalletFactory.eoa.d.ts +34 -23
  81. package/dist/types/logic/admin/eSIMWallet.eoa.d.ts +0 -5
  82. package/dist/types/logic/admin/eSIMWalletFactory.eoa.d.ts +27 -9
  83. package/dist/types/logic/admin/lazyWalletRegistry.eoa.d.ts +102 -10
  84. package/dist/types/logic/admin/protocolAdmin.eoa.d.ts +163 -0
  85. package/dist/types/logic/admin/reads/deviceWallet.reads.d.ts +28 -8
  86. package/dist/types/logic/admin/reads/deviceWalletFactory.reads.d.ts +45 -14
  87. package/dist/types/logic/admin/reads/eSIMWallet.reads.d.ts +25 -6
  88. package/dist/types/logic/admin/reads/eSIMWalletFactory.reads.d.ts +21 -6
  89. package/dist/types/logic/admin/reads/lazyWalletRegistry.reads.d.ts +44 -11
  90. package/dist/types/logic/admin/reads/protocolAdmin.reads.d.ts +53 -0
  91. package/dist/types/logic/admin/reads/registry.reads.d.ts +105 -9
  92. package/dist/types/logic/admin/registry.eoa.d.ts +102 -5
  93. package/dist/types/logic/constants.d.ts +2 -0
  94. package/dist/types/logic/deviceWallet.d.ts +78 -6
  95. package/dist/types/logic/deviceWalletFactory.d.ts +32 -3
  96. package/dist/types/logic/eSIMWallet.d.ts +48 -7
  97. package/dist/types/logic/eSIMWalletFactory.d.ts +3 -3
  98. package/dist/types/logic/errors.d.ts +61 -1
  99. package/dist/types/logic/registry.d.ts +78 -0
  100. package/dist/types/types-export.d.ts +1 -1
  101. package/dist/types/types.d.ts +111 -1
  102. package/package.json +11 -13
  103. package/dist/esm/interface/lazyWalletRegistryClass.js +0 -10
  104. package/dist/esm/logic/lazyWalletRegistry.js +0 -19
  105. package/dist/types/interface/lazyWalletRegistryClass.d.ts +0 -6
  106. package/dist/types/logic/lazyWalletRegistry.d.ts +0 -2
@@ -1,20 +1,51 @@
1
+ import { BaseError, ContractFunctionRevertedError, isAddressEqual, parseEventLogs, publicActions, } from "viem";
1
2
  import { _getChainSpecificConstants } from "../constants.js";
2
- import { MissingEOAWalletError } from "../errors.js";
3
- import { LazyWalletRegistry } from "../../abis/index.js";
3
+ import { BatchSizeOutOfRangeError, DepositOnResumeError, ESIMWalletNotLazyDeployedError, MissingBatchEventError, MissingEOAWalletError, StalledBatchError, writeContractOrThrow, } from "../errors.js";
4
+ import { LazyWalletRegistry, Registry } from "../../abis/index.js";
5
+ import { _eSIMWalletsDeployed, _lazyDeployedESIMWallet } from "./reads/lazyWalletRegistry.reads.js";
6
+ // Admin-EOA logic for `LazyWalletRegistry`. Every function here is
7
+ // `onlyESIMWalletAdmin` on chain, so they can only succeed from the admin EOA -
8
+ // a device-wallet userOp (whose sender is the smart account) always reverts.
9
+ // This is why they belong on the EOA surface rather than the mobile userOp one.
10
+ //
11
+ // Deployment and the history copy are both paginated on chain. The thin wrappers
12
+ // send one batch each; the two `AllBatches` functions below run a device or an
13
+ // eSIM to completion and are what the backend should normally call.
14
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
4
15
  /**
5
- * Admin-EOA logic for `LazyWalletRegistry`. All three functions are
6
- * `onlyESIMWalletAdmin` on chain, so they can only succeed from the admin EOA -
7
- * a device-wallet userOp (whose sender is the smart account) always reverts.
8
- * This is why they belong on the EOA surface rather than the mobile userOp one.
16
+ * The contract's own caps, mirrored here because they are `constant` on chain and
17
+ * reading them would cost a round trip on every call. The fork tier checks these
18
+ * against the live deployment, so an upgrade that moved one would fail there
19
+ * rather than turning every call into a reverted transaction.
9
20
  */
10
- /** Record fiat/lazy purchase history for a batch of devices. `onlyESIMWalletAdmin`. */
11
- export const _batchPopulateHistory = async (client, deviceUniqueIdentifiers, eSIMUniqueIdentifiers, dataBundleDetails) => {
21
+ export const MAX_ESIM_WALLETS_PER_CALL = 20n;
22
+ export const MAX_HISTORY_ENTRIES_PER_CALL = 50n;
23
+ /**
24
+ * Default batch sizes, both below the caps above.
25
+ *
26
+ * A continuation call costs about 28,000 gas before it deploys anything, against
27
+ * roughly 556,000 per eSIM wallet, so a smaller batch buys headroom for almost
28
+ * nothing: running a 45 eSIM device at 10 rather than 20 costs about 0.4% more
29
+ * gas in total. That headroom matters because a full batch of 20 measures between
30
+ * 9.3M and 11.8M gas depending on identifier length and storage warmth, which is
31
+ * uncomfortably close to a per-transaction gas ceiling.
32
+ */
33
+ export const DEFAULT_ESIM_WALLETS_PER_CALL = 10n;
34
+ export const DEFAULT_HISTORY_ENTRIES_PER_CALL = 25n;
35
+ const _resolve = async (client) => {
12
36
  const chainID = await client.getChainId();
13
37
  const rpcURL = client.transport.url;
14
- const values = _getChainSpecificConstants(chainID, rpcURL);
38
+ return _getChainSpecificConstants(chainID, rpcURL);
39
+ };
40
+ // ---------------------------------------------------------------------------
41
+ // One transaction each, mirroring the contract
42
+ // ---------------------------------------------------------------------------
43
+ /** Record fiat/lazy purchase history for a batch of devices. `onlyESIMWalletAdmin`. */
44
+ export const _batchPopulateHistory = async (client, deviceUniqueIdentifiers, eSIMUniqueIdentifiers, dataBundleDetails) => {
45
+ const values = await _resolve(client);
15
46
  if (!client.account)
16
47
  throw new MissingEOAWalletError();
17
- return client.writeContract({
48
+ return writeContractOrThrow(client, {
18
49
  address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
19
50
  chain: values.chain,
20
51
  account: client.account.address,
@@ -24,39 +55,319 @@ export const _batchPopulateHistory = async (client, deviceUniqueIdentifiers, eSI
24
55
  });
25
56
  };
26
57
  /**
27
- * Materialise a lazily-provisioned device wallet and its eSIMs on chain.
28
- * `onlyESIMWalletAdmin`, `payable`: the contract requires `depositAmount == msg.value`,
29
- * so `value` is set to `depositAmount` here.
58
+ * Materialise a lazily-provisioned device wallet and the first batch of its eSIMs
59
+ * on chain. `onlyESIMWalletAdmin`, `payable`: the contract requires
60
+ * `depositAmount == msg.value`, so `value` is set to `depositAmount` here.
61
+ *
62
+ * One transaction. `maxWallets` caps how many eSIM wallets it deploys, and the
63
+ * contract refuses anything above `MAX_ESIM_WALLETS_PER_CALL` rather than
64
+ * clamping it. Prefer `_deployLazyWalletAllBatches`, which finishes the device.
30
65
  */
31
- export const _deployLazyWalletAndSetESIMIdentifier = async (client, deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount) => {
32
- const chainID = await client.getChainId();
33
- const rpcURL = client.transport.url;
34
- const values = _getChainSpecificConstants(chainID, rpcURL);
66
+ export const _deployLazyWalletAndSetESIMIdentifier = async (client, deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount, maxWallets) => {
67
+ const values = await _resolve(client);
35
68
  if (!client.account)
36
69
  throw new MissingEOAWalletError();
37
- return client.writeContract({
70
+ return writeContractOrThrow(client, {
38
71
  address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
39
72
  chain: values.chain,
40
73
  account: client.account.address,
41
74
  abi: LazyWalletRegistry,
42
75
  functionName: 'deployLazyWalletAndSetESIMIdentifier',
43
- args: [deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount],
76
+ args: [deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount, maxWallets],
44
77
  value: depositAmount
45
78
  });
46
79
  };
80
+ /**
81
+ * Deploy the next batch of eSIM wallets for a device the lazy route already
82
+ * started. `onlyESIMWalletAdmin`.
83
+ *
84
+ * One transaction. The contract reads its position from a cursor, so a dropped
85
+ * transaction is retried by repeating the identical call. It reverts
86
+ * `AllESIMWalletsDeployed` once nothing is left, which is the terminal condition
87
+ * rather than a failure.
88
+ */
89
+ export const _deployMoreESIMWalletsForLazyDevice = async (client, deviceUniqueIdentifier, maxWallets) => {
90
+ const values = await _resolve(client);
91
+ if (!client.account)
92
+ throw new MissingEOAWalletError();
93
+ return writeContractOrThrow(client, {
94
+ address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
95
+ chain: values.chain,
96
+ account: client.account.address,
97
+ abi: LazyWalletRegistry,
98
+ functionName: 'deployMoreESIMWalletsForLazyDevice',
99
+ args: [deviceUniqueIdentifier, maxWallets]
100
+ });
101
+ };
102
+ /**
103
+ * Copy the next batch of an eSIM's stored purchase history onto its deployed
104
+ * wallet. `onlyESIMWalletAdmin`.
105
+ *
106
+ * One transaction, with its own cursor per eSIM. Reverts `HistoryAlreadyCopied`
107
+ * once nothing is left. Prefer `_setHistoryForLazyWalletAllBatches`.
108
+ */
109
+ export const _setHistoryForLazyWallet = async (client, eSIMIdentifier, maxEntries) => {
110
+ const values = await _resolve(client);
111
+ if (!client.account)
112
+ throw new MissingEOAWalletError();
113
+ return writeContractOrThrow(client, {
114
+ address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
115
+ chain: values.chain,
116
+ account: client.account.address,
117
+ abi: LazyWalletRegistry,
118
+ functionName: 'setHistoryForLazyWallet',
119
+ args: [eSIMIdentifier, maxEntries]
120
+ });
121
+ };
47
122
  /** Re-point an eSIM identifier from an old device to a new one. `onlyESIMWalletAdmin`. */
48
123
  export const _switchESIMIdentifierToNewDeviceIdentifier = async (client, eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier) => {
124
+ const values = await _resolve(client);
125
+ if (!client.account)
126
+ throw new MissingEOAWalletError();
127
+ return writeContractOrThrow(client, {
128
+ address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
129
+ chain: values.chain,
130
+ account: client.account.address,
131
+ abi: LazyWalletRegistry,
132
+ functionName: 'switchESIMIdentifierToNewDeviceIdentifier',
133
+ args: [eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier]
134
+ });
135
+ };
136
+ // ---------------------------------------------------------------------------
137
+ // Reading a batch back
138
+ // ---------------------------------------------------------------------------
139
+ // `writeContract` returns a hash, not the function's return values, so how much
140
+ // is left comes from the event each batch emits rather than from the call.
141
+ const _batchEvent = async (client, lazyRegistryAddress, hash, eventName) => {
142
+ const receipt = await client.waitForTransactionReceipt({ hash });
143
+ const logs = parseEventLogs({
144
+ abi: LazyWalletRegistry,
145
+ eventName,
146
+ logs: receipt.logs.filter((log) => isAddressEqual(log.address, lazyRegistryAddress)),
147
+ });
148
+ if (logs.length === 0)
149
+ throw new MissingBatchEventError(eventName, hash);
150
+ return logs[0].args;
151
+ };
152
+ /**
153
+ * Whether a call hit its terminal condition. Both paginated calls revert when
154
+ * there is nothing left rather than returning quietly, so a simulation is the
155
+ * only way to tell "already finished" from "more to do" without paying for a
156
+ * transaction that fails.
157
+ */
158
+ const _isFinished = async (client, request, terminalError) => {
159
+ try {
160
+ await client.simulateContract(request);
161
+ return false;
162
+ }
163
+ catch (err) {
164
+ if (err instanceof BaseError) {
165
+ const revert = err.walk((e) => e instanceof ContractFunctionRevertedError);
166
+ if (revert instanceof ContractFunctionRevertedError && revert.data?.errorName === terminalError) {
167
+ return true;
168
+ }
169
+ }
170
+ throw err;
171
+ }
172
+ };
173
+ // ---------------------------------------------------------------------------
174
+ // Run a device or an eSIM to completion
175
+ // ---------------------------------------------------------------------------
176
+ /**
177
+ * Deploy a lazy device and every one of its eSIM wallets, over as many
178
+ * transactions as that takes. `onlyESIMWalletAdmin`.
179
+ *
180
+ * Resumable. A device that is part-deployed, because a batch was dropped or an
181
+ * earlier call threw, is continued from its cursor instead of being restarted,
182
+ * so retrying is just calling this again with the same arguments. Pass a deposit
183
+ * of 0 on a retry: only the first batch is payable and it already took one.
184
+ *
185
+ * All of a device's purchase history has to be recorded before this runs. The
186
+ * first batch creates the device wallet, and `batchPopulateHistory` refuses any
187
+ * device that has one.
188
+ *
189
+ * @param maxWallets eSIM wallets per transaction, 1 to `MAX_ESIM_WALLETS_PER_CALL`.
190
+ */
191
+ export const _deployLazyWalletAllBatches = async (client, deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount, maxWallets = DEFAULT_ESIM_WALLETS_PER_CALL) => {
192
+ const values = await _resolve(client);
193
+ if (!client.account)
194
+ throw new MissingEOAWalletError();
195
+ const publicClient = client.extend(publicActions);
196
+ const lazyRegistryAddress = values.factoryAddresses.LAZY_WALLET_REGISTRY;
197
+ if (maxWallets < 1n || maxWallets > MAX_ESIM_WALLETS_PER_CALL) {
198
+ throw new BatchSizeOutOfRangeError("maxWallets", maxWallets, MAX_ESIM_WALLETS_PER_CALL);
199
+ }
200
+ const alreadyDeployed = await _eSIMWalletsDeployed(client, deviceUniqueIdentifier);
201
+ const batches = [];
202
+ let deviceWallet;
203
+ let outstanding;
204
+ if (alreadyDeployed === 0n) {
205
+ const hash = await _deployLazyWalletAndSetESIMIdentifier(client, deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount, maxWallets);
206
+ const first = await _batchEvent(publicClient, lazyRegistryAddress, hash, "LazyESIMWalletsDeployed");
207
+ deviceWallet = first._deviceWallet;
208
+ outstanding = first._remaining > 0n;
209
+ batches.push({
210
+ hash,
211
+ eSIMWallets: first._eSIMWallets,
212
+ eSIMIdentifiers: first._eSIMUniqueIdentifiers,
213
+ remaining: first._remaining,
214
+ });
215
+ }
216
+ else {
217
+ if (depositAmount !== 0n)
218
+ throw new DepositOnResumeError(deviceUniqueIdentifier, depositAmount);
219
+ deviceWallet = await publicClient.readContract({
220
+ address: values.factoryAddresses.REGISTRY,
221
+ abi: Registry,
222
+ functionName: "uniqueIdentifierToDeviceWallet",
223
+ args: [deviceUniqueIdentifier]
224
+ });
225
+ const finished = await _isFinished(publicClient, {
226
+ address: lazyRegistryAddress,
227
+ abi: LazyWalletRegistry,
228
+ functionName: "deployMoreESIMWalletsForLazyDevice",
229
+ args: [deviceUniqueIdentifier, maxWallets],
230
+ account: client.account.address,
231
+ }, "AllESIMWalletsDeployed");
232
+ if (finished) {
233
+ return { deviceWallet, eSIMWallets: [], eSIMIdentifiers: [], batches: [], alreadyComplete: true };
234
+ }
235
+ outstanding = true;
236
+ }
237
+ while (outstanding) {
238
+ const hash = await _deployMoreESIMWalletsForLazyDevice(client, deviceUniqueIdentifier, maxWallets);
239
+ const next = await _batchEvent(publicClient, lazyRegistryAddress, hash, "LazyESIMWalletsDeployed");
240
+ if (next._eSIMWallets.length === 0)
241
+ throw new StalledBatchError(hash, next._remaining);
242
+ batches.push({
243
+ hash,
244
+ eSIMWallets: next._eSIMWallets,
245
+ eSIMIdentifiers: next._eSIMUniqueIdentifiers,
246
+ remaining: next._remaining,
247
+ });
248
+ outstanding = next._remaining > 0n;
249
+ }
250
+ return {
251
+ deviceWallet,
252
+ eSIMWallets: batches.flatMap((batch) => [...batch.eSIMWallets]),
253
+ eSIMIdentifiers: batches.flatMap((batch) => [...batch.eSIMIdentifiers]),
254
+ batches,
255
+ alreadyComplete: false,
256
+ };
257
+ };
258
+ /**
259
+ * Copy an eSIM's whole stored purchase history onto its wallet, over as many
260
+ * transactions as that takes. `onlyESIMWalletAdmin`.
261
+ *
262
+ * Resumable for the same reason as the deployment: the cursor lives on chain, so
263
+ * a partly copied eSIM is continued rather than restarted.
264
+ *
265
+ * The history cursor is per eSIM and the deploy cursor is per device, so this can
266
+ * run against an eSIM whose wallet has landed while its siblings are still
267
+ * undeployed.
268
+ *
269
+ * @param maxEntries entries per transaction, 1 to `MAX_HISTORY_ENTRIES_PER_CALL`.
270
+ */
271
+ export const _setHistoryForLazyWalletAllBatches = async (client, eSIMIdentifier, maxEntries = DEFAULT_HISTORY_ENTRIES_PER_CALL) => {
272
+ const values = await _resolve(client);
273
+ if (!client.account)
274
+ throw new MissingEOAWalletError();
275
+ const publicClient = client.extend(publicActions);
276
+ const lazyRegistryAddress = values.factoryAddresses.LAZY_WALLET_REGISTRY;
277
+ if (maxEntries < 1n || maxEntries > MAX_HISTORY_ENTRIES_PER_CALL) {
278
+ throw new BatchSizeOutOfRangeError("maxEntries", maxEntries, MAX_HISTORY_ENTRIES_PER_CALL);
279
+ }
280
+ // The same lookup the contract authorises on. Checking it here turns a
281
+ // reverted transaction into a typed error.
282
+ const eSIMWallet = await _lazyDeployedESIMWallet(client, eSIMIdentifier);
283
+ if (eSIMWallet === ZERO_ADDRESS)
284
+ throw new ESIMWalletNotLazyDeployedError(eSIMIdentifier);
285
+ const finished = await _isFinished(publicClient, {
286
+ address: lazyRegistryAddress,
287
+ abi: LazyWalletRegistry,
288
+ functionName: "setHistoryForLazyWallet",
289
+ args: [eSIMIdentifier, maxEntries],
290
+ account: client.account.address,
291
+ }, "HistoryAlreadyCopied");
292
+ if (finished)
293
+ return { eSIMWallet, copied: 0n, batches: [], alreadyComplete: true };
294
+ const batches = [];
295
+ let copied = 0n;
296
+ let outstanding = true;
297
+ while (outstanding) {
298
+ const hash = await _setHistoryForLazyWallet(client, eSIMIdentifier, maxEntries);
299
+ const batch = await _batchEvent(publicClient, lazyRegistryAddress, hash, "LazyHistoryCopied");
300
+ if (batch._copied === 0n)
301
+ throw new StalledBatchError(hash, batch._remaining);
302
+ batches.push({ hash, copied: batch._copied, remaining: batch._remaining });
303
+ copied += batch._copied;
304
+ outstanding = batch._remaining > 0n;
305
+ }
306
+ return { eSIMWallet, copied, batches, alreadyComplete: false };
307
+ };
308
+ // ---------------------------------------------------------------------------
309
+ // Owner payloads - only reachable through schedule
310
+ // ---------------------------------------------------------------------------
311
+ // Both are `onlyOwner`, and on the live deployment the owner is the timelock, so
312
+ // they exist as something to schedule rather than to send. Each returns the
313
+ // `OwnerCall` to hand to `protocolAdmin.schedule`.
314
+ /**
315
+ * Offer ownership to a new address. Pass the result to `schedule`.
316
+ *
317
+ * Ownable2Step, so the offer changes nothing until the named address calls
318
+ * `acceptOwnership`. Until then the current owner keeps every power.
319
+ */
320
+ export const _transferOwnershipCall = async (client, newOwner) => {
321
+ const chainID = await client.getChainId();
322
+ const rpcURL = client.transport.url;
323
+ const values = _getChainSpecificConstants(chainID, rpcURL);
324
+ return {
325
+ address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
326
+ abi: LazyWalletRegistry,
327
+ functionName: 'transferOwnership',
328
+ args: [newOwner],
329
+ };
330
+ };
331
+ /**
332
+ * Point the proxy at a new implementation. Builds `upgradeToAndCall`. Pass the
333
+ * result to `schedule`.
334
+ *
335
+ * This contract holds every fiat user's unclaimed purchase history, so a layout
336
+ * change here strands data that has no other copy. Diff the storage layout
337
+ * before scheduling. `data` runs on the proxy straight after the swap and is
338
+ * where a `reinitializer` goes.
339
+ */
340
+ export const _upgradeCall = async (client, newImplementation, data = '0x') => {
341
+ const chainID = await client.getChainId();
342
+ const rpcURL = client.transport.url;
343
+ const values = _getChainSpecificConstants(chainID, rpcURL);
344
+ return {
345
+ address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
346
+ abi: LazyWalletRegistry,
347
+ functionName: 'upgradeToAndCall',
348
+ args: [newImplementation, data],
349
+ };
350
+ };
351
+ /**
352
+ * Take ownership after a `transferOwnership` named this client. `msg.sender`
353
+ * must equal `pendingOwner`, so the `client` is the incoming owner.
354
+ *
355
+ * Where the incoming owner is the timelock, use
356
+ * `protocolAdmin.acceptOwnershipBatch` instead, which accepts for every contract
357
+ * at once.
358
+ */
359
+ export const _acceptOwnership = async (client) => {
49
360
  const chainID = await client.getChainId();
50
361
  const rpcURL = client.transport.url;
51
362
  const values = _getChainSpecificConstants(chainID, rpcURL);
52
363
  if (!client.account)
53
364
  throw new MissingEOAWalletError();
54
- return client.writeContract({
365
+ return writeContractOrThrow(client, {
55
366
  address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
56
367
  chain: values.chain,
57
368
  account: client.account.address,
58
369
  abi: LazyWalletRegistry,
59
- functionName: 'switchESIMIdentifierToNewDeviceIdentifier',
60
- args: [eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier]
370
+ functionName: 'acceptOwnership',
371
+ args: []
61
372
  });
62
373
  };