kokio-sdk 3.1.0 → 3.2.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/dist/esm/admin/config-admin.js +5 -0
- package/dist/esm/admin/interface/callsClass.js +30 -0
- package/dist/esm/interface/eSIMWalletClass.js +9 -1
- package/dist/esm/logic/admin/lazyWalletRegistry.eoa.js +18 -4
- package/dist/esm/logic/calls/eSIMWallet.calls.js +72 -0
- package/dist/esm/logic/eSIMWallet.js +20 -36
- package/dist/types/admin/config-admin.d.ts +3 -0
- package/dist/types/admin/interface/callsClass.d.ts +26 -0
- package/dist/types/interface/eSIMWalletClass.d.ts +8 -0
- package/dist/types/logic/calls/eSIMWallet.calls.d.ts +25 -0
- package/dist/types/logic/eSIMWallet.d.ts +8 -0
- package/dist/types/types.d.ts +2 -2
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ import { AdminProtocolAdminSubPackage } from "./interface/protocolAdminClass.js"
|
|
|
7
7
|
import { AdminDeviceWalletSubPackage } from "./interface/deviceWalletClass.js";
|
|
8
8
|
import { AdminESIMWalletSubPackage } from "./interface/eSIMWalletClass.js";
|
|
9
9
|
import { AdminPaymentAdapterSubPackage } from "./interface/paymentAdapterClass.js";
|
|
10
|
+
import { AdminCallsSubPackage } from "./interface/callsClass.js";
|
|
10
11
|
// Re-export the typed error surface so backend consumers can `instanceof
|
|
11
12
|
// KokioError` (or a subclass) and decode reverts without reaching into internal
|
|
12
13
|
// module paths - mirroring `config.ts`.
|
|
@@ -42,6 +43,8 @@ export class KokioAdmin {
|
|
|
42
43
|
lazyWalletRegistry;
|
|
43
44
|
protocolAdmin;
|
|
44
45
|
paymentAdapter;
|
|
46
|
+
/** Calls for the app to sign as a user operation, built here so the backend holds the purchase logic. */
|
|
47
|
+
calls;
|
|
45
48
|
// Instance-scoped surfaces - undefined until their address is known.
|
|
46
49
|
deviceWallet;
|
|
47
50
|
eSIMWallet;
|
|
@@ -56,6 +59,7 @@ export class KokioAdmin {
|
|
|
56
59
|
this.lazyWalletRegistry = new AdminLazyWalletRegistrySubPackage(walletClient);
|
|
57
60
|
this.protocolAdmin = new AdminProtocolAdminSubPackage(walletClient);
|
|
58
61
|
this.paymentAdapter = new AdminPaymentAdapterSubPackage(walletClient);
|
|
62
|
+
this.calls = new AdminCallsSubPackage(walletClient);
|
|
59
63
|
this.deviceWallet = deviceWalletAddress ? new AdminDeviceWalletSubPackage(walletClient, deviceWalletAddress) : undefined;
|
|
60
64
|
this.eSIMWallet = eSIMWalletAddress ? new AdminESIMWalletSubPackage(walletClient, eSIMWalletAddress) : undefined;
|
|
61
65
|
}
|
|
@@ -106,6 +110,7 @@ export class KokioAdmin {
|
|
|
106
110
|
this.lazyWalletRegistry = new AdminLazyWalletRegistrySubPackage(walletClient);
|
|
107
111
|
this.protocolAdmin = new AdminProtocolAdminSubPackage(walletClient);
|
|
108
112
|
this.paymentAdapter = new AdminPaymentAdapterSubPackage(walletClient);
|
|
113
|
+
this.calls = new AdminCallsSubPackage(walletClient);
|
|
109
114
|
this.deviceWallet = this.deviceWalletAddress ? new AdminDeviceWalletSubPackage(walletClient, this.deviceWalletAddress) : undefined;
|
|
110
115
|
this.eSIMWallet = this.eSIMWalletAddress ? new AdminESIMWalletSubPackage(walletClient, this.eSIMWalletAddress) : undefined;
|
|
111
116
|
return this;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { publicActions } from "viem";
|
|
2
|
+
import { _acceptAndBindESIMWalletCalls, _buyDataBundleWithTransferCalls } from "../../logic/calls/eSIMWallet.calls.js";
|
|
3
|
+
/**
|
|
4
|
+
* Builds the calls a user's device wallet signs as one user operation. Nothing
|
|
5
|
+
* is signed or sent here: hand the result to the app, which passes it to
|
|
6
|
+
* `deviceWallet.sendUserOperation`. Addresses are passed per call, since one
|
|
7
|
+
* backend builds calls for many users.
|
|
8
|
+
*/
|
|
9
|
+
export class AdminCallsSubPackage {
|
|
10
|
+
walletClient;
|
|
11
|
+
constructor(walletClient) {
|
|
12
|
+
this.walletClient = walletClient;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The calls `kokio.eSIMWallet.buyDataBundleWithTransfer` sends: a token
|
|
16
|
+
* transfer from the device wallet for whatever the eSIM wallet is short of,
|
|
17
|
+
* then the purchase. The purchase emits `DataBundleBoughtWithToken` as usual.
|
|
18
|
+
*/
|
|
19
|
+
buyDataBundleWithTransfer(eSIMWalletAddress, dataBundleDetails, asset, maxAmountIn, paymentReference) {
|
|
20
|
+
return _buyDataBundleWithTransferCalls(this.walletClient.extend(publicActions), eSIMWalletAddress, dataBundleDetails, asset, maxAmountIn, paymentReference);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The calls `kokio.eSIMWallet.acceptAndBindESIMWallet` sends, for the device
|
|
24
|
+
* wallet named in `requestTransferOwnership` to sign. Build them once the
|
|
25
|
+
* `OwnershipTransferRequested` event names that device wallet as `_newOwner`.
|
|
26
|
+
*/
|
|
27
|
+
acceptAndBindESIMWallet(eSIMWalletAddress, newDeviceWalletAddress, options = {}) {
|
|
28
|
+
return _acceptAndBindESIMWalletCalls(eSIMWalletAddress, newDeviceWalletAddress, options.grantAccessToFunds ?? false);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _acceptOwnershipTransfer, _buyDataBundleWithToken, _buyDataBundleWithTransfer, _priceCapUSDCents, _deviceWallet, _owner, _requestTransferOwnership, _sendETHToDeviceWallet, _sendTokenToDeviceWallet, _setPriceCapUSDCents, _transactionHistory } from "../logic/eSIMWallet.js";
|
|
1
|
+
import { _acceptAndBindESIMWallet, _acceptOwnershipTransfer, _buyDataBundleWithToken, _buyDataBundleWithTransfer, _priceCapUSDCents, _deviceWallet, _owner, _requestTransferOwnership, _sendETHToDeviceWallet, _sendTokenToDeviceWallet, _setPriceCapUSDCents, _transactionHistory } from "../logic/eSIMWallet.js";
|
|
2
2
|
export class ESIMWalletSubPackage {
|
|
3
3
|
client;
|
|
4
4
|
address;
|
|
@@ -9,6 +9,14 @@ export class ESIMWalletSubPackage {
|
|
|
9
9
|
acceptOwnershipTransfer() {
|
|
10
10
|
return _acceptOwnershipTransfer(this.client, this.address);
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Accept this eSIM wallet's transfer and bind it to the signing device
|
|
14
|
+
* wallet in one user operation, optionally granting it access to that
|
|
15
|
+
* wallet's tokens too.
|
|
16
|
+
*/
|
|
17
|
+
acceptAndBindESIMWallet(options = {}) {
|
|
18
|
+
return _acceptAndBindESIMWallet(this.client, this.address, options.grantAccessToFunds ?? false);
|
|
19
|
+
}
|
|
12
20
|
buyDataBundleWithToken(dataBundleDetails, asset, maxAmountIn, paymentReference) {
|
|
13
21
|
return _buyDataBundleWithToken(this.client, this.address, dataBundleDetails, asset, maxAmountIn, paymentReference);
|
|
14
22
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseError, ContractFunctionRevertedError, isAddressEqual, parseEventLog
|
|
|
2
2
|
import { _chainId, _getChainSpecificConstants } from "../constants.js";
|
|
3
3
|
import { BatchSizeOutOfRangeError, DepositOnResumeError, ESIMWalletNotLazyDeployedError, MissingBatchEventError, MissingEOAWalletError, StalledBatchError, writeContractOrThrow, } from "../errors.js";
|
|
4
4
|
import { LazyWalletRegistry, Registry } from "../../abis/index.js";
|
|
5
|
-
import { _eSIMWalletsDeployed, _lazyDeployedESIMWallet } from "./reads/lazyWalletRegistry.reads.js";
|
|
5
|
+
import { _eSIMIdentifiersAssociatedWithDeviceIdentifier, _eSIMWalletsDeployed, _lazyDeployedESIMWallet, } from "./reads/lazyWalletRegistry.reads.js";
|
|
6
6
|
// Admin-EOA logic for `LazyWalletRegistry`. Every function here is
|
|
7
7
|
// `onlyESIMWalletAdmin` on chain, so they can only succeed from the admin EOA -
|
|
8
8
|
// a device-wallet userOp (whose sender is the smart account) always reverts.
|
|
@@ -199,6 +199,7 @@ export const _deployLazyWalletAllBatches = async (client, deviceOwnerPublicKey,
|
|
|
199
199
|
}
|
|
200
200
|
const alreadyDeployed = await _eSIMWalletsDeployed(client, deviceUniqueIdentifier);
|
|
201
201
|
const batches = [];
|
|
202
|
+
let earlier = { eSIMWallets: [], eSIMIdentifiers: [] };
|
|
202
203
|
let deviceWallet;
|
|
203
204
|
let outstanding;
|
|
204
205
|
if (alreadyDeployed === 0n) {
|
|
@@ -216,6 +217,9 @@ export const _deployLazyWalletAllBatches = async (client, deviceOwnerPublicKey,
|
|
|
216
217
|
else {
|
|
217
218
|
if (depositAmount !== 0n)
|
|
218
219
|
throw new DepositOnResumeError(deviceUniqueIdentifier, depositAmount);
|
|
220
|
+
// Wallets an earlier call deployed. Without them a resume would report only its
|
|
221
|
+
// own batches, and a caller walking the result would skip the rest of the device.
|
|
222
|
+
earlier = await _readDeployedESIMWallets(client, deviceUniqueIdentifier, alreadyDeployed);
|
|
219
223
|
deviceWallet = await publicClient.readContract({
|
|
220
224
|
address: values.factoryAddresses.REGISTRY,
|
|
221
225
|
abi: Registry,
|
|
@@ -230,7 +234,7 @@ export const _deployLazyWalletAllBatches = async (client, deviceOwnerPublicKey,
|
|
|
230
234
|
account: client.account,
|
|
231
235
|
}, "AllESIMWalletsDeployed");
|
|
232
236
|
if (finished) {
|
|
233
|
-
return { deviceWallet,
|
|
237
|
+
return { deviceWallet, ...earlier, batches: [], alreadyComplete: true };
|
|
234
238
|
}
|
|
235
239
|
outstanding = true;
|
|
236
240
|
}
|
|
@@ -249,12 +253,22 @@ export const _deployLazyWalletAllBatches = async (client, deviceOwnerPublicKey,
|
|
|
249
253
|
}
|
|
250
254
|
return {
|
|
251
255
|
deviceWallet,
|
|
252
|
-
eSIMWallets: batches.flatMap((batch) => [...batch.eSIMWallets]),
|
|
253
|
-
eSIMIdentifiers: batches.flatMap((batch) => [...batch.eSIMIdentifiers]),
|
|
256
|
+
eSIMWallets: [...earlier.eSIMWallets, ...batches.flatMap((batch) => [...batch.eSIMWallets])],
|
|
257
|
+
eSIMIdentifiers: [...earlier.eSIMIdentifiers, ...batches.flatMap((batch) => [...batch.eSIMIdentifiers])],
|
|
254
258
|
batches,
|
|
255
259
|
alreadyComplete: false,
|
|
256
260
|
};
|
|
257
261
|
};
|
|
262
|
+
/**
|
|
263
|
+
* The first `count` eSIM wallets deployed for a device, in deploy order. The
|
|
264
|
+
* deploy walks the device's identifier list from the start, so the first
|
|
265
|
+
* `count` identifiers are exactly the ones with wallets.
|
|
266
|
+
*/
|
|
267
|
+
const _readDeployedESIMWallets = async (client, deviceUniqueIdentifier, count) => {
|
|
268
|
+
const eSIMIdentifiers = await Promise.all(Array.from({ length: Number(count) }, (_, i) => _eSIMIdentifiersAssociatedWithDeviceIdentifier(client, deviceUniqueIdentifier, BigInt(i))));
|
|
269
|
+
const eSIMWallets = await Promise.all(eSIMIdentifiers.map((id) => _lazyDeployedESIMWallet(client, id)));
|
|
270
|
+
return { eSIMWallets, eSIMIdentifiers };
|
|
271
|
+
};
|
|
258
272
|
/**
|
|
259
273
|
* Copy an eSIM's whole stored purchase history onto its wallet, over as many
|
|
260
274
|
* transactions as that takes. `onlyESIMWalletAdmin`.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { encodeFunctionData, erc20Abi } from "viem";
|
|
2
|
+
import { DeviceWallet, ESIMWallet, PaymentAdapter, Registry } from "../../abis/index.js";
|
|
3
|
+
import { _chainId, _getChainSpecificConstants } from "../constants.js";
|
|
4
|
+
/**
|
|
5
|
+
* The calls for buying a data bundle with tokens the device wallet sends over
|
|
6
|
+
* in the same user operation, so the eSIM wallet needs no access to the device
|
|
7
|
+
* wallet's funds.
|
|
8
|
+
*
|
|
9
|
+
* Only the shortfall is sent: the quote for the bundle minus what the eSIM
|
|
10
|
+
* wallet already holds of `asset`, worked out when this runs. If that balance
|
|
11
|
+
* or the quote changes before the operation lands, it reverts, so build the
|
|
12
|
+
* calls again rather than resending old ones.
|
|
13
|
+
*/
|
|
14
|
+
export const _buyDataBundleWithTransferCalls = async (client, eSIMWalletAddress, dataBundleDetails, asset, maxAmountIn, paymentReference) => {
|
|
15
|
+
const chainID = await _chainId(client);
|
|
16
|
+
const values = _getChainSpecificConstants(chainID, client.transport.url);
|
|
17
|
+
// The eSIM wallet pays through whichever adapter the registry names, so read it there.
|
|
18
|
+
const adapter = await client.readContract({
|
|
19
|
+
address: values.factoryAddresses.REGISTRY, abi: Registry, functionName: "paymentAdapter"
|
|
20
|
+
});
|
|
21
|
+
const [{ token }, amountIn] = await Promise.all([
|
|
22
|
+
client.readContract({
|
|
23
|
+
address: adapter, abi: PaymentAdapter, functionName: "resolveAsset", args: [asset]
|
|
24
|
+
}),
|
|
25
|
+
client.readContract({
|
|
26
|
+
address: adapter, abi: PaymentAdapter, functionName: "quote", args: [asset, dataBundleDetails.priceUSDCents]
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
const held = await client.readContract({
|
|
30
|
+
address: token, abi: erc20Abi, functionName: "balanceOf", args: [eSIMWalletAddress]
|
|
31
|
+
});
|
|
32
|
+
const buy = {
|
|
33
|
+
to: eSIMWalletAddress,
|
|
34
|
+
data: encodeFunctionData({
|
|
35
|
+
abi: ESIMWallet,
|
|
36
|
+
functionName: "buyDataBundleWithToken",
|
|
37
|
+
args: [dataBundleDetails, asset, maxAmountIn, paymentReference]
|
|
38
|
+
})
|
|
39
|
+
};
|
|
40
|
+
if (held >= amountIn)
|
|
41
|
+
return [buy];
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
to: token,
|
|
45
|
+
data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [eSIMWalletAddress, amountIn - held] })
|
|
46
|
+
},
|
|
47
|
+
buy
|
|
48
|
+
];
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* The calls for the new device wallet to take over an eSIM wallet another
|
|
52
|
+
* device wallet asked to hand it: accept the transfer, then bind it, which also
|
|
53
|
+
* tells the registry and clears the standby flag.
|
|
54
|
+
*
|
|
55
|
+
* Accepting first is what lets the bind through: it makes this device wallet
|
|
56
|
+
* the owner and clears the pending transfer. Fund access cannot be granted at
|
|
57
|
+
* bind time, so `grantAccessToFunds` adds a `toggleAccessToFunds` after it.
|
|
58
|
+
*/
|
|
59
|
+
export const _acceptAndBindESIMWalletCalls = (eSIMWalletAddress, deviceWalletAddress, grantAccessToFunds) => {
|
|
60
|
+
const self = (functionName, hasAccessToFunds) => ({
|
|
61
|
+
to: deviceWalletAddress,
|
|
62
|
+
data: encodeFunctionData({ abi: DeviceWallet, functionName, args: [eSIMWalletAddress, hasAccessToFunds] })
|
|
63
|
+
});
|
|
64
|
+
return [
|
|
65
|
+
{
|
|
66
|
+
to: eSIMWalletAddress,
|
|
67
|
+
data: encodeFunctionData({ abi: ESIMWallet, functionName: "acceptOwnershipTransfer", args: [] })
|
|
68
|
+
},
|
|
69
|
+
self("addESIMWallet", false),
|
|
70
|
+
...(grantAccessToFunds ? [self("toggleAccessToFunds", true)] : [])
|
|
71
|
+
];
|
|
72
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { encodeFunctionData,
|
|
1
|
+
import { encodeFunctionData, maxUint256 } from "viem";
|
|
2
2
|
import { MissingSmartWalletError } from "./errors.js";
|
|
3
|
-
import { ESIMWallet
|
|
4
|
-
import { _chainId, _getChainSpecificConstants } from "./constants.js";
|
|
3
|
+
import { ESIMWallet } from "../abis/index.js";
|
|
5
4
|
import { _defaultPriceCapUSDCents } from "./registry.js";
|
|
5
|
+
import { _acceptAndBindESIMWalletCalls, _buyDataBundleWithTransferCalls } from "./calls/eSIMWallet.calls.js";
|
|
6
6
|
// Not exposed on this surface:
|
|
7
7
|
// - populateHistory and setESIMUniqueIdentifier are `onlyRegistry` - callable
|
|
8
8
|
// only by the registry contract. Naming an eSIM goes through
|
|
@@ -68,45 +68,14 @@ export const _buyDataBundleWithToken = async (client, address, dataBundleDetails
|
|
|
68
68
|
*
|
|
69
69
|
* Only the shortfall is sent: the quote for the bundle minus what this eSIM
|
|
70
70
|
* wallet already holds of `asset`. Arguments are as for `buyDataBundleWithToken`.
|
|
71
|
+
* The backend builds the same calls with `admin.calls.buyDataBundleWithTransfer`.
|
|
71
72
|
*/
|
|
72
73
|
export const _buyDataBundleWithTransfer = async (client, address, dataBundleDetails, asset, maxAmountIn, paymentReference) => {
|
|
73
|
-
const chainID = await _chainId(client);
|
|
74
|
-
const rpcURL = client.transport.url;
|
|
75
|
-
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
76
74
|
if (!client.account)
|
|
77
75
|
throw new MissingSmartWalletError();
|
|
78
|
-
// The eSIM wallet pays through whichever adapter the registry names, so read it there.
|
|
79
|
-
const adapter = await client.readContract({
|
|
80
|
-
address: values.factoryAddresses.REGISTRY, abi: Registry, functionName: "paymentAdapter"
|
|
81
|
-
});
|
|
82
|
-
const [{ token }, amountIn] = await Promise.all([
|
|
83
|
-
client.readContract({
|
|
84
|
-
address: adapter, abi: PaymentAdapter, functionName: "resolveAsset", args: [asset]
|
|
85
|
-
}),
|
|
86
|
-
client.readContract({
|
|
87
|
-
address: adapter, abi: PaymentAdapter, functionName: "quote", args: [asset, dataBundleDetails.priceUSDCents]
|
|
88
|
-
}),
|
|
89
|
-
]);
|
|
90
|
-
const held = await client.readContract({
|
|
91
|
-
address: token, abi: erc20Abi, functionName: "balanceOf", args: [address]
|
|
92
|
-
});
|
|
93
|
-
const buy = {
|
|
94
|
-
to: address,
|
|
95
|
-
data: encodeFunctionData({
|
|
96
|
-
abi: ESIMWallet,
|
|
97
|
-
functionName: "buyDataBundleWithToken",
|
|
98
|
-
args: [dataBundleDetails, asset, maxAmountIn, paymentReference]
|
|
99
|
-
})
|
|
100
|
-
};
|
|
101
76
|
return client.sendUserOperation({
|
|
102
77
|
account: client.account,
|
|
103
|
-
calls:
|
|
104
|
-
{
|
|
105
|
-
to: token,
|
|
106
|
-
data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [address, amountIn - held] })
|
|
107
|
-
},
|
|
108
|
-
buy
|
|
109
|
-
]
|
|
78
|
+
calls: await _buyDataBundleWithTransferCalls(client, address, dataBundleDetails, asset, maxAmountIn, paymentReference)
|
|
110
79
|
});
|
|
111
80
|
};
|
|
112
81
|
/**
|
|
@@ -228,6 +197,21 @@ export const _acceptOwnershipTransfer = async (client, address) => {
|
|
|
228
197
|
}]
|
|
229
198
|
});
|
|
230
199
|
};
|
|
200
|
+
/**
|
|
201
|
+
* Accept an eSIM wallet another device wallet asked to hand over, and bind it,
|
|
202
|
+
* in one user operation. `grantAccessToFunds` also lets it pull this device
|
|
203
|
+
* wallet's tokens. The backend builds the same calls with
|
|
204
|
+
* `admin.calls.acceptAndBindESIMWallet`.
|
|
205
|
+
*/
|
|
206
|
+
export const _acceptAndBindESIMWallet = async (client, address, grantAccessToFunds) => {
|
|
207
|
+
if (!client.account)
|
|
208
|
+
throw new MissingSmartWalletError();
|
|
209
|
+
// UserOp - the sender is the pending `newRequestedOwner`, and then the owner the bind needs.
|
|
210
|
+
return client.sendUserOperation({
|
|
211
|
+
account: client.account,
|
|
212
|
+
calls: _acceptAndBindESIMWalletCalls(address, client.account.address, grantAccessToFunds)
|
|
213
|
+
});
|
|
214
|
+
};
|
|
231
215
|
export const _sendETHToDeviceWallet = async (client, address, amount) => {
|
|
232
216
|
if (!client.account)
|
|
233
217
|
throw new MissingSmartWalletError();
|
|
@@ -8,6 +8,7 @@ import { AdminProtocolAdminSubPackage } from "./interface/protocolAdminClass.js"
|
|
|
8
8
|
import { AdminDeviceWalletSubPackage } from "./interface/deviceWalletClass.js";
|
|
9
9
|
import { AdminESIMWalletSubPackage } from "./interface/eSIMWalletClass.js";
|
|
10
10
|
import { AdminPaymentAdapterSubPackage } from "./interface/paymentAdapterClass.js";
|
|
11
|
+
import { AdminCallsSubPackage } from "./interface/callsClass.js";
|
|
11
12
|
export { KokioError, NullOrUndefinedValueError, MissingSmartWalletError, MissingEOAWalletError, InvalidClientError, UnsupportedChainError, UnconfiguredChainError, CounterfactualMismatchError, BatchSizeOutOfRangeError, DepositOnResumeError, ESIMWalletNotLazyDeployedError, MissingBatchEventError, StalledBatchError, ContractRevertError, decodeContractRevert, } from "../logic/errors.js";
|
|
12
13
|
export type { DecodedRevert } from "../logic/errors.js";
|
|
13
14
|
export { OperationState } from "../logic/admin/reads/protocolAdmin.reads.js";
|
|
@@ -38,6 +39,8 @@ export declare class KokioAdmin {
|
|
|
38
39
|
lazyWalletRegistry: AdminLazyWalletRegistrySubPackage;
|
|
39
40
|
protocolAdmin: AdminProtocolAdminSubPackage;
|
|
40
41
|
paymentAdapter: AdminPaymentAdapterSubPackage;
|
|
42
|
+
/** Calls for the app to sign as a user operation, built here so the backend holds the purchase logic. */
|
|
43
|
+
calls: AdminCallsSubPackage;
|
|
41
44
|
deviceWallet?: AdminDeviceWalletSubPackage;
|
|
42
45
|
eSIMWallet?: AdminESIMWalletSubPackage;
|
|
43
46
|
constructor(walletClient: WalletClient, deviceWalletAddress?: Address, eSIMWalletAddress?: Address);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Address, Hex, WalletClient } from "viem";
|
|
2
|
+
import { DataBundleDetails } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Builds the calls a user's device wallet signs as one user operation. Nothing
|
|
5
|
+
* is signed or sent here: hand the result to the app, which passes it to
|
|
6
|
+
* `deviceWallet.sendUserOperation`. Addresses are passed per call, since one
|
|
7
|
+
* backend builds calls for many users.
|
|
8
|
+
*/
|
|
9
|
+
export declare class AdminCallsSubPackage {
|
|
10
|
+
walletClient: WalletClient;
|
|
11
|
+
constructor(walletClient: WalletClient);
|
|
12
|
+
/**
|
|
13
|
+
* The calls `kokio.eSIMWallet.buyDataBundleWithTransfer` sends: a token
|
|
14
|
+
* transfer from the device wallet for whatever the eSIM wallet is short of,
|
|
15
|
+
* then the purchase. The purchase emits `DataBundleBoughtWithToken` as usual.
|
|
16
|
+
*/
|
|
17
|
+
buyDataBundleWithTransfer(eSIMWalletAddress: Address, dataBundleDetails: DataBundleDetails, asset: Hex, maxAmountIn: bigint, paymentReference: Hex): Promise<import("../../types.js").Call[]>;
|
|
18
|
+
/**
|
|
19
|
+
* The calls `kokio.eSIMWallet.acceptAndBindESIMWallet` sends, for the device
|
|
20
|
+
* wallet named in `requestTransferOwnership` to sign. Build them once the
|
|
21
|
+
* `OwnershipTransferRequested` event names that device wallet as `_newOwner`.
|
|
22
|
+
*/
|
|
23
|
+
acceptAndBindESIMWallet(eSIMWalletAddress: Address, newDeviceWalletAddress: Address, options?: {
|
|
24
|
+
grantAccessToFunds?: boolean;
|
|
25
|
+
}): import("../../types.js").Call[];
|
|
26
|
+
}
|
|
@@ -6,6 +6,14 @@ export declare class ESIMWalletSubPackage {
|
|
|
6
6
|
address: `0x${string}`;
|
|
7
7
|
constructor(client: KokioSmartAccountClient, address: Address);
|
|
8
8
|
acceptOwnershipTransfer(): Promise<`0x${string}`>;
|
|
9
|
+
/**
|
|
10
|
+
* Accept this eSIM wallet's transfer and bind it to the signing device
|
|
11
|
+
* wallet in one user operation, optionally granting it access to that
|
|
12
|
+
* wallet's tokens too.
|
|
13
|
+
*/
|
|
14
|
+
acceptAndBindESIMWallet(options?: {
|
|
15
|
+
grantAccessToFunds?: boolean;
|
|
16
|
+
}): Promise<`0x${string}`>;
|
|
9
17
|
buyDataBundleWithToken(dataBundleDetails: DataBundleDetails, asset: Hex, maxAmountIn: bigint, paymentReference: Hex): Promise<`0x${string}`>;
|
|
10
18
|
/**
|
|
11
19
|
* Same purchase as `buyDataBundleWithToken`, with the device wallet sending
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Address, Client, Hex, PublicActions } from "viem";
|
|
2
|
+
import { Call, DataBundleDetails } from "../../types.js";
|
|
3
|
+
/** Any client that can read contracts: the mobile smart account client, or a wallet client extended with `publicActions`. */
|
|
4
|
+
export type CallBuilderClient = Pick<PublicActions, "readContract" | "getChainId"> & Pick<Client, "transport">;
|
|
5
|
+
/**
|
|
6
|
+
* The calls for buying a data bundle with tokens the device wallet sends over
|
|
7
|
+
* in the same user operation, so the eSIM wallet needs no access to the device
|
|
8
|
+
* wallet's funds.
|
|
9
|
+
*
|
|
10
|
+
* Only the shortfall is sent: the quote for the bundle minus what the eSIM
|
|
11
|
+
* wallet already holds of `asset`, worked out when this runs. If that balance
|
|
12
|
+
* or the quote changes before the operation lands, it reverts, so build the
|
|
13
|
+
* calls again rather than resending old ones.
|
|
14
|
+
*/
|
|
15
|
+
export declare const _buyDataBundleWithTransferCalls: (client: CallBuilderClient, eSIMWalletAddress: Address, dataBundleDetails: DataBundleDetails, asset: Hex, maxAmountIn: bigint, paymentReference: Hex) => Promise<Call[]>;
|
|
16
|
+
/**
|
|
17
|
+
* The calls for the new device wallet to take over an eSIM wallet another
|
|
18
|
+
* device wallet asked to hand it: accept the transfer, then bind it, which also
|
|
19
|
+
* tells the registry and clears the standby flag.
|
|
20
|
+
*
|
|
21
|
+
* Accepting first is what lets the bind through: it makes this device wallet
|
|
22
|
+
* the owner and clears the pending transfer. Fund access cannot be granted at
|
|
23
|
+
* bind time, so `grantAccessToFunds` adds a `toggleAccessToFunds` after it.
|
|
24
|
+
*/
|
|
25
|
+
export declare const _acceptAndBindESIMWalletCalls: (eSIMWalletAddress: Address, deviceWalletAddress: Address, grantAccessToFunds: boolean) => Call[];
|
|
@@ -27,6 +27,7 @@ export declare const _buyDataBundleWithToken: (client: KokioSmartAccountClient,
|
|
|
27
27
|
*
|
|
28
28
|
* Only the shortfall is sent: the quote for the bundle minus what this eSIM
|
|
29
29
|
* wallet already holds of `asset`. Arguments are as for `buyDataBundleWithToken`.
|
|
30
|
+
* The backend builds the same calls with `admin.calls.buyDataBundleWithTransfer`.
|
|
30
31
|
*/
|
|
31
32
|
export declare const _buyDataBundleWithTransfer: (client: KokioSmartAccountClient, address: Address, dataBundleDetails: DataBundleDetails, asset: Hex, maxAmountIn: bigint, paymentReference: Hex) => Promise<`0x${string}`>;
|
|
32
33
|
/**
|
|
@@ -69,4 +70,11 @@ export declare const _deviceWallet: (client: KokioSmartAccountClient, address: A
|
|
|
69
70
|
export declare const _transactionHistory: (client: KokioSmartAccountClient, address: Address, index: bigint) => Promise<DataBundleDetails>;
|
|
70
71
|
export declare const _requestTransferOwnership: (client: KokioSmartAccountClient, address: Address, newOwner: Address) => Promise<`0x${string}`>;
|
|
71
72
|
export declare const _acceptOwnershipTransfer: (client: KokioSmartAccountClient, address: Address) => Promise<`0x${string}`>;
|
|
73
|
+
/**
|
|
74
|
+
* Accept an eSIM wallet another device wallet asked to hand over, and bind it,
|
|
75
|
+
* in one user operation. `grantAccessToFunds` also lets it pull this device
|
|
76
|
+
* wallet's tokens. The backend builds the same calls with
|
|
77
|
+
* `admin.calls.acceptAndBindESIMWallet`.
|
|
78
|
+
*/
|
|
79
|
+
export declare const _acceptAndBindESIMWallet: (client: KokioSmartAccountClient, address: Address, grantAccessToFunds: boolean) => Promise<`0x${string}`>;
|
|
72
80
|
export declare const _sendETHToDeviceWallet: (client: KokioSmartAccountClient, address: Address, amount: bigint) => Promise<`0x${string}`>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -127,8 +127,8 @@ export type LazyDeploymentBatch = {
|
|
|
127
127
|
};
|
|
128
128
|
/**
|
|
129
129
|
* What a fully paginated lazy deployment did. `eSIMWallets` and `eSIMIdentifiers`
|
|
130
|
-
* cover
|
|
131
|
-
*
|
|
130
|
+
* cover the device's whole set, including wallets an earlier call deployed, so a
|
|
131
|
+
* resume can be walked like a fresh deploy. `batches` holds only what this call sent.
|
|
132
132
|
*/
|
|
133
133
|
export type LazyDeployment = {
|
|
134
134
|
deviceWallet: Address;
|