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.
- package/README.md +68 -19
- package/dist/esm/abis/BeaconProxy.js +30 -46
- package/dist/esm/abis/DeviceWallet.js +546 -535
- package/dist/esm/abis/DeviceWalletFactory.js +537 -544
- package/dist/esm/abis/ESIMWallet.js +440 -299
- package/dist/esm/abis/ESIMWalletFactory.js +372 -289
- package/dist/esm/abis/LazyWalletRegistry.js +941 -421
- package/dist/esm/abis/P256Verifier.js +29 -29
- package/dist/esm/abis/ProtocolAdmin.js +1228 -0
- package/dist/esm/abis/Registry.js +1207 -466
- package/dist/esm/abis/RegistryHelper.js +414 -20
- package/dist/esm/abis/index.js +2 -1
- package/dist/esm/admin/config-admin.js +7 -0
- package/dist/esm/admin/interface/deviceWalletClass.js +27 -6
- package/dist/esm/admin/interface/deviceWalletFactoryClass.js +41 -19
- package/dist/esm/admin/interface/eSIMWalletClass.js +10 -1
- package/dist/esm/admin/interface/eSIMWalletFactoryClass.js +24 -2
- package/dist/esm/admin/interface/lazyWalletRegistryClass.js +83 -4
- package/dist/esm/admin/interface/protocolAdminClass.js +195 -0
- package/dist/esm/admin/interface/registryClass.js +93 -2
- package/dist/esm/config.js +42 -7
- package/dist/esm/interface/deviceWalletClass.js +45 -5
- package/dist/esm/interface/deviceWalletFactoryClass.js +20 -1
- package/dist/esm/interface/eSIMWalletClass.js +12 -3
- package/dist/esm/interface/registryClass.js +47 -0
- package/dist/esm/interface/smartAccountClass.js +2 -4
- package/dist/esm/logic/account-kit/createSmartAccount.js +156 -102
- package/dist/esm/logic/admin/deviceWallet.eoa.js +26 -15
- package/dist/esm/logic/admin/deviceWalletFactory.eoa.js +69 -48
- package/dist/esm/logic/admin/eSIMWallet.eoa.js +5 -7
- package/dist/esm/logic/admin/eSIMWalletFactory.eoa.js +79 -11
- package/dist/esm/logic/admin/lazyWalletRegistry.eoa.js +333 -22
- package/dist/esm/logic/admin/protocolAdmin.eoa.js +524 -0
- package/dist/esm/logic/admin/reads/deviceWallet.reads.js +82 -7
- package/dist/esm/logic/admin/reads/deviceWalletFactory.reads.js +82 -23
- package/dist/esm/logic/admin/reads/eSIMWallet.reads.js +50 -6
- package/dist/esm/logic/admin/reads/eSIMWalletFactory.reads.js +63 -5
- package/dist/esm/logic/admin/reads/lazyWalletRegistry.reads.js +171 -10
- package/dist/esm/logic/admin/reads/protocolAdmin.reads.js +154 -0
- package/dist/esm/logic/admin/reads/registry.reads.js +289 -9
- package/dist/esm/logic/admin/registry.eoa.js +276 -6
- package/dist/esm/logic/constants.js +53 -26
- package/dist/esm/logic/deviceWallet.js +224 -31
- package/dist/esm/logic/deviceWalletFactory.js +89 -0
- package/dist/esm/logic/eSIMWallet.js +113 -43
- package/dist/esm/logic/eSIMWalletFactory.js +8 -8
- package/dist/esm/logic/errors.js +94 -1
- package/dist/esm/logic/registry.js +236 -0
- package/dist/esm/logic/utils.js +2 -1
- package/dist/types/abis/BeaconProxy.d.ts +21 -33
- package/dist/types/abis/DeviceWallet.d.ts +372 -365
- package/dist/types/abis/DeviceWalletFactory.d.ts +438 -448
- package/dist/types/abis/ESIMWallet.d.ts +352 -245
- package/dist/types/abis/ESIMWalletFactory.d.ts +278 -216
- package/dist/types/abis/LazyWalletRegistry.d.ts +710 -317
- package/dist/types/abis/P256Verifier.d.ts +16 -16
- package/dist/types/abis/ProtocolAdmin.d.ts +947 -0
- package/dist/types/abis/Registry.d.ts +960 -393
- package/dist/types/abis/RegistryHelper.d.ts +317 -16
- package/dist/types/abis/index.d.ts +2 -1
- package/dist/types/admin/config-admin.d.ts +3 -0
- package/dist/types/admin/interface/deviceWalletClass.d.ts +10 -3
- package/dist/types/admin/interface/deviceWalletFactoryClass.d.ts +14 -7
- package/dist/types/admin/interface/eSIMWalletClass.d.ts +3 -0
- package/dist/types/admin/interface/eSIMWalletFactoryClass.d.ts +8 -1
- package/dist/types/admin/interface/lazyWalletRegistryClass.d.ts +38 -2
- package/dist/types/admin/interface/protocolAdminClass.d.ts +95 -0
- package/dist/types/admin/interface/registryClass.d.ts +30 -0
- package/dist/types/config.d.ts +26 -5
- package/dist/types/interface/P256VerifierClass.d.ts +3 -4
- package/dist/types/interface/deviceWalletClass.d.ts +22 -2569
- package/dist/types/interface/deviceWalletFactoryClass.d.ts +10 -2564
- package/dist/types/interface/eSIMWalletClass.d.ts +11 -8
- package/dist/types/interface/eSIMWalletFactoryClass.d.ts +5 -2565
- package/dist/types/interface/registryClass.d.ts +19 -0
- package/dist/types/interface/smartAccountClass.d.ts +6 -2568
- package/dist/types/logic/P256Verifier.d.ts +2 -2
- package/dist/types/logic/account-kit/createSmartAccount.d.ts +43 -19
- package/dist/types/logic/admin/deviceWallet.eoa.d.ts +15 -9
- package/dist/types/logic/admin/deviceWalletFactory.eoa.d.ts +34 -23
- package/dist/types/logic/admin/eSIMWallet.eoa.d.ts +0 -5
- package/dist/types/logic/admin/eSIMWalletFactory.eoa.d.ts +27 -9
- package/dist/types/logic/admin/lazyWalletRegistry.eoa.d.ts +102 -10
- package/dist/types/logic/admin/protocolAdmin.eoa.d.ts +163 -0
- package/dist/types/logic/admin/reads/deviceWallet.reads.d.ts +28 -8
- package/dist/types/logic/admin/reads/deviceWalletFactory.reads.d.ts +45 -14
- package/dist/types/logic/admin/reads/eSIMWallet.reads.d.ts +25 -6
- package/dist/types/logic/admin/reads/eSIMWalletFactory.reads.d.ts +21 -6
- package/dist/types/logic/admin/reads/lazyWalletRegistry.reads.d.ts +44 -11
- package/dist/types/logic/admin/reads/protocolAdmin.reads.d.ts +53 -0
- package/dist/types/logic/admin/reads/registry.reads.d.ts +105 -9
- package/dist/types/logic/admin/registry.eoa.d.ts +102 -5
- package/dist/types/logic/constants.d.ts +2 -0
- package/dist/types/logic/deviceWallet.d.ts +78 -6
- package/dist/types/logic/deviceWalletFactory.d.ts +32 -3
- package/dist/types/logic/eSIMWallet.d.ts +48 -7
- package/dist/types/logic/eSIMWalletFactory.d.ts +3 -3
- package/dist/types/logic/errors.d.ts +61 -1
- package/dist/types/logic/registry.d.ts +78 -0
- package/dist/types/types-export.d.ts +1 -1
- package/dist/types/types.d.ts +111 -1
- package/package.json +11 -13
- package/dist/esm/interface/lazyWalletRegistryClass.js +0 -10
- package/dist/esm/logic/lazyWalletRegistry.js +0 -19
- package/dist/types/interface/lazyWalletRegistryClass.d.ts +0 -6
- 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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
|
|
11
|
-
export const
|
|
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
|
-
|
|
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
|
|
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
|
|
28
|
-
* `onlyESIMWalletAdmin`, `payable`: the contract requires
|
|
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
|
|
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
|
|
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
|
|
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: '
|
|
60
|
-
args: [
|
|
370
|
+
functionName: 'acceptOwnership',
|
|
371
|
+
args: []
|
|
61
372
|
});
|
|
62
373
|
};
|