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.
- 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 +24 -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 +23 -12
- package/dist/esm/logic/admin/deviceWalletFactory.eoa.js +63 -42
- package/dist/esm/logic/admin/eSIMWallet.eoa.js +3 -5
- package/dist/esm/logic/admin/eSIMWalletFactory.eoa.js +76 -8
- package/dist/esm/logic/admin/lazyWalletRegistry.eoa.js +330 -19
- 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 +274 -4
- 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 +64 -0
- 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 +16 -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/constantsClass.d.ts +2 -2
- 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 +45 -0
- 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,27 +1,39 @@
|
|
|
1
|
-
import { encodeFunctionData } from "viem";
|
|
1
|
+
import { encodeFunctionData, maxUint256 } from "viem";
|
|
2
2
|
import { MissingSmartWalletError } from "./errors.js";
|
|
3
3
|
import { ESIMWallet } from "../abis/index.js";
|
|
4
|
+
import { _defaultDataBundlePriceCap } from "./registry.js";
|
|
4
5
|
// Not exposed on this surface:
|
|
5
|
-
// - populateHistory
|
|
6
|
+
// - populateHistory and setESIMUniqueIdentifier are `onlyRegistry` - callable
|
|
7
|
+
// only by the registry contract. Naming an eSIM goes through
|
|
8
|
+
// `admin.registry.assignESIMIdentifier` instead.
|
|
6
9
|
// - transferOwnership is a `pure` override that always reverts
|
|
7
10
|
// ("Use acceptOwnershipTransfer instead."); use requestTransferOwnership /
|
|
8
11
|
// acceptOwnershipTransfer instead.
|
|
9
12
|
// The functions below are `onlyDeviceWallet` (the eSIM wallet's owner IS the device
|
|
10
13
|
// wallet) or otherwise satisfiable by the device-wallet userOp sender, so they succeed.
|
|
11
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Cap what this eSIM wallet may be charged for one data bundle. Zero hands it
|
|
16
|
+
* back to the registry's ceiling.
|
|
17
|
+
*
|
|
18
|
+
* `onlyDeviceWallet`, so it needs the user's own signature. That is the point:
|
|
19
|
+
* the admin names the price on `buyDataBundle`, so it must not be able to raise
|
|
20
|
+
* the ceiling on that price too. A handover clears the cap, and the new owner has
|
|
21
|
+
* to set it again.
|
|
22
|
+
*/
|
|
23
|
+
export const _setDataBundlePriceCap = async (client, address, cap) => {
|
|
12
24
|
if (!client.account)
|
|
13
25
|
throw new MissingSmartWalletError();
|
|
14
26
|
// UserOp - `onlyDeviceWallet`.
|
|
15
27
|
return client.sendUserOperation({
|
|
16
28
|
account: client.account,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
calls: [{
|
|
30
|
+
to: address,
|
|
31
|
+
data: encodeFunctionData({
|
|
32
|
+
abi: ESIMWallet,
|
|
33
|
+
functionName: "setDataBundlePriceCap",
|
|
34
|
+
args: [cap]
|
|
35
|
+
})
|
|
36
|
+
}]
|
|
25
37
|
});
|
|
26
38
|
};
|
|
27
39
|
export const _buyDataBundle = async (client, address, dataBundleDetails) => {
|
|
@@ -30,14 +42,14 @@ export const _buyDataBundle = async (client, address, dataBundleDetails) => {
|
|
|
30
42
|
// UserOp - `onlyDeviceWalletOrESIMWalletAdmin`; the owning device wallet may buy.
|
|
31
43
|
return client.sendUserOperation({
|
|
32
44
|
account: client.account,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
calls: [{
|
|
46
|
+
to: address,
|
|
47
|
+
data: encodeFunctionData({
|
|
48
|
+
abi: ESIMWallet,
|
|
49
|
+
functionName: "buyDataBundle",
|
|
50
|
+
args: [dataBundleDetails]
|
|
51
|
+
})
|
|
52
|
+
}]
|
|
41
53
|
});
|
|
42
54
|
};
|
|
43
55
|
// `owner()` is a `view` - read it directly instead of spending a userOp.
|
|
@@ -49,20 +61,78 @@ export const _owner = async (client, address) => {
|
|
|
49
61
|
args: []
|
|
50
62
|
});
|
|
51
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* The ceiling that actually applies to this wallet's next purchase, in wei.
|
|
66
|
+
* Read it before naming a price on `buyDataBundle`, since a price above the
|
|
67
|
+
* ceiling reverts.
|
|
68
|
+
*
|
|
69
|
+
* Resolved the way the contract resolves it. The wallet's own cap wins when it
|
|
70
|
+
* has one. Zero there means "follow the registry", which is where a fresh wallet
|
|
71
|
+
* and a newly handed-over wallet both start. A zero on both means no ceiling at
|
|
72
|
+
* all, so this returns `maxUint256` rather than a zero that reads as "you may
|
|
73
|
+
* not spend anything".
|
|
74
|
+
*
|
|
75
|
+
* That last case cannot happen on a live deployment: the registry refuses a zero
|
|
76
|
+
* cap in both `initialize` and `setDefaultDataBundlePriceCap`. It is handled
|
|
77
|
+
* because the contract's own check treats zero as unlimited, not because the
|
|
78
|
+
* state is reachable.
|
|
79
|
+
*/
|
|
80
|
+
export const _dataBundlePriceCap = async (client, address) => {
|
|
81
|
+
const walletCap = await client.readContract({
|
|
82
|
+
address,
|
|
83
|
+
abi: ESIMWallet,
|
|
84
|
+
functionName: "dataBundlePriceCap",
|
|
85
|
+
args: []
|
|
86
|
+
});
|
|
87
|
+
if (walletCap !== 0n)
|
|
88
|
+
return walletCap;
|
|
89
|
+
const registryCap = await _defaultDataBundlePriceCap(client);
|
|
90
|
+
return registryCap === 0n ? maxUint256 : registryCap;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* The device wallet this eSIM wallet belongs to. Tracks `owner`, but it is its
|
|
94
|
+
* own storage slot with its own getter, so read whichever one you mean.
|
|
95
|
+
*/
|
|
96
|
+
export const _deviceWallet = async (client, address) => {
|
|
97
|
+
return client.readContract({
|
|
98
|
+
address,
|
|
99
|
+
abi: ESIMWallet,
|
|
100
|
+
functionName: "deviceWallet",
|
|
101
|
+
args: []
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* One data bundle purchase, by position. Holds every purchase this wallet has
|
|
106
|
+
* made, and for a wallet that came off the fiat path it also holds the
|
|
107
|
+
* pre-deployment purchases the lazy registry copies in.
|
|
108
|
+
*
|
|
109
|
+
* There is no length getter on the contract. Read upwards from zero until a call
|
|
110
|
+
* reverts, or track the count from the `DataBundleBought` and
|
|
111
|
+
* `TransactionHistoryPopulated` events.
|
|
112
|
+
*/
|
|
113
|
+
export const _transactionHistory = async (client, address, index) => {
|
|
114
|
+
const [dataBundleID, dataBundlePrice] = await client.readContract({
|
|
115
|
+
address,
|
|
116
|
+
abi: ESIMWallet,
|
|
117
|
+
functionName: "transactionHistory",
|
|
118
|
+
args: [index]
|
|
119
|
+
});
|
|
120
|
+
return { dataBundleID, dataBundlePrice };
|
|
121
|
+
};
|
|
52
122
|
export const _requestTransferOwnership = async (client, address, newOwner) => {
|
|
53
123
|
if (!client.account)
|
|
54
124
|
throw new MissingSmartWalletError();
|
|
55
125
|
// UserOp - `onlyDeviceWallet`; the owning device wallet requests the transfer.
|
|
56
126
|
return client.sendUserOperation({
|
|
57
127
|
account: client.account,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
128
|
+
calls: [{
|
|
129
|
+
to: address,
|
|
130
|
+
data: encodeFunctionData({
|
|
131
|
+
abi: ESIMWallet,
|
|
132
|
+
functionName: "requestTransferOwnership",
|
|
133
|
+
args: [newOwner]
|
|
134
|
+
})
|
|
135
|
+
}]
|
|
66
136
|
});
|
|
67
137
|
};
|
|
68
138
|
export const _acceptOwnershipTransfer = async (client, address) => {
|
|
@@ -71,14 +141,14 @@ export const _acceptOwnershipTransfer = async (client, address) => {
|
|
|
71
141
|
// UserOp - the caller must be the pending `newRequestedOwner` (the new device wallet).
|
|
72
142
|
return client.sendUserOperation({
|
|
73
143
|
account: client.account,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
144
|
+
calls: [{
|
|
145
|
+
to: address,
|
|
146
|
+
data: encodeFunctionData({
|
|
147
|
+
abi: ESIMWallet,
|
|
148
|
+
functionName: "acceptOwnershipTransfer",
|
|
149
|
+
args: []
|
|
150
|
+
})
|
|
151
|
+
}]
|
|
82
152
|
});
|
|
83
153
|
};
|
|
84
154
|
export const _sendETHToDeviceWallet = async (client, address, amount) => {
|
|
@@ -87,13 +157,13 @@ export const _sendETHToDeviceWallet = async (client, address, amount) => {
|
|
|
87
157
|
// UserOp - `onlyDeviceWallet`.
|
|
88
158
|
return client.sendUserOperation({
|
|
89
159
|
account: client.account,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
160
|
+
calls: [{
|
|
161
|
+
to: address,
|
|
162
|
+
data: encodeFunctionData({
|
|
163
|
+
abi: ESIMWallet,
|
|
164
|
+
functionName: "sendETHToDeviceWallet",
|
|
165
|
+
args: [amount]
|
|
166
|
+
})
|
|
167
|
+
}]
|
|
98
168
|
});
|
|
99
169
|
};
|
|
@@ -18,14 +18,14 @@ export const _deployESIMWalletWithUserOp = async (client, deviceWalletAddress, s
|
|
|
18
18
|
// UserOp - the device-wallet sender is a valid device wallet per the registry.
|
|
19
19
|
return client.sendUserOperation({
|
|
20
20
|
account: client.account,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
calls: [{
|
|
22
|
+
to: values.factoryAddresses.ESIM_WALLET_FACTORY,
|
|
23
|
+
data: encodeFunctionData({
|
|
24
|
+
abi: ESIMWalletFactory,
|
|
25
|
+
functionName: "deployESIMWallet",
|
|
26
|
+
args: [deviceWalletAddress, salt]
|
|
27
|
+
})
|
|
28
|
+
}]
|
|
29
29
|
});
|
|
30
30
|
};
|
|
31
31
|
export const _getCurrentESIMWalletImplementation = async (client) => {
|
package/dist/esm/logic/errors.js
CHANGED
|
@@ -68,6 +68,70 @@ export class CounterfactualMismatchError extends KokioError {
|
|
|
68
68
|
this.onChain = onChain;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* A batch size outside what the contract accepts. Both paginated calls refuse a
|
|
73
|
+
* request above their cap rather than clamping it, so this is caught locally to
|
|
74
|
+
* save the caller a reverted transaction.
|
|
75
|
+
*/
|
|
76
|
+
export class BatchSizeOutOfRangeError extends KokioError {
|
|
77
|
+
requested;
|
|
78
|
+
max;
|
|
79
|
+
constructor(what, requested, max) {
|
|
80
|
+
super("BATCH_SIZE_OUT_OF_RANGE", `${what} must be between 1 and ${max}, got ${requested}.`);
|
|
81
|
+
this.requested = requested;
|
|
82
|
+
this.max = max;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A deposit was passed to a lazy deployment that turned out to be a resume. Only
|
|
87
|
+
* the first batch is payable and it already took the deposit, so carrying on
|
|
88
|
+
* would fund the device with less than the caller asked for.
|
|
89
|
+
*/
|
|
90
|
+
export class DepositOnResumeError extends KokioError {
|
|
91
|
+
deviceUniqueIdentifier;
|
|
92
|
+
depositAmount;
|
|
93
|
+
constructor(deviceUniqueIdentifier, depositAmount) {
|
|
94
|
+
super("DEPOSIT_ON_RESUME", `Device ${deviceUniqueIdentifier} is already part-deployed, so its deposit was taken by ` +
|
|
95
|
+
`the first batch. Retry with a deposit of 0 rather than ${depositAmount}.`);
|
|
96
|
+
this.deviceUniqueIdentifier = deviceUniqueIdentifier;
|
|
97
|
+
this.depositAmount = depositAmount;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* History was aimed at an eSIM this registry never deployed a wallet for. That
|
|
102
|
+
* lookup is the whole authorisation on chain, so it cannot be worked around.
|
|
103
|
+
*/
|
|
104
|
+
export class ESIMWalletNotLazyDeployedError extends KokioError {
|
|
105
|
+
eSIMIdentifier;
|
|
106
|
+
constructor(eSIMIdentifier) {
|
|
107
|
+
super("ESIM_WALLET_NOT_LAZY_DEPLOYED", `No lazily deployed eSIM wallet for identifier ${eSIMIdentifier}.`);
|
|
108
|
+
this.eSIMIdentifier = eSIMIdentifier;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A batch landed but its receipt carried no event from the lazy registry. The
|
|
113
|
+
* loop reads its position from that event, so it cannot continue without one.
|
|
114
|
+
*/
|
|
115
|
+
export class MissingBatchEventError extends KokioError {
|
|
116
|
+
hash;
|
|
117
|
+
constructor(eventName, hash) {
|
|
118
|
+
super("MISSING_BATCH_EVENT", `Transaction ${hash} emitted no ${eventName} event from the lazy registry.`);
|
|
119
|
+
this.hash = hash;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A batch reported work outstanding but did none of it. Nothing on chain should
|
|
124
|
+
* produce this; it stops the loop rather than letting it spin.
|
|
125
|
+
*/
|
|
126
|
+
export class StalledBatchError extends KokioError {
|
|
127
|
+
hash;
|
|
128
|
+
remaining;
|
|
129
|
+
constructor(hash, remaining) {
|
|
130
|
+
super("STALLED_BATCH", `Transaction ${hash} made no progress with ${remaining} still outstanding.`);
|
|
131
|
+
this.hash = hash;
|
|
132
|
+
this.remaining = remaining;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
71
135
|
// Every ABI that can surface a custom error from an on-chain revert. viem's
|
|
72
136
|
// `decodeErrorResult` walks each ABI's `error` fragments to match the 4-byte
|
|
73
137
|
// selector in the revert data.
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { _getChainSpecificConstants } from "./constants.js";
|
|
3
|
+
import { Registry } from "../abis/index.js";
|
|
4
|
+
import { MissingSmartWalletError } from "./errors.js";
|
|
5
|
+
// A userOp from a device wallet arrives at the registry with msg.sender set to the
|
|
6
|
+
// device wallet, which is what `onlyDeviceWallet` wants. Those three functions are
|
|
7
|
+
// the only writes this surface can reach; everything else is `onlyOwner`,
|
|
8
|
+
// `onlyESIMWalletAdmin`, `onlyDeviceWalletFactory` or `onlyLazyWalletRegistry` and
|
|
9
|
+
// lives on `KokioAdmin.registry` or behind the lazy registry wrappers.
|
|
10
|
+
//
|
|
11
|
+
// updateDeviceWalletOwnerKey is the exception among the three. It is
|
|
12
|
+
// `onlyDeviceWallet`, so a userOp reaches it, but calling it on its own writes a
|
|
13
|
+
// key into the registry that the wallet is not actually using.
|
|
14
|
+
// `deviceWallet.transferOwnership` rotates the key and updates the registry in one
|
|
15
|
+
// call, so that is the only way this surface offers to move it.
|
|
16
|
+
/**
|
|
17
|
+
* Take on an eSIM wallet and clear any standby flag left by a transfer.
|
|
18
|
+
*
|
|
19
|
+
* The registry only accepts the calling device wallet as the new holder, so the
|
|
20
|
+
* SDK fills that in and there is nothing to pass. The eSIM wallet's `owner()`
|
|
21
|
+
* has to already be this device wallet: accept the ownership transfer first,
|
|
22
|
+
* then bind.
|
|
23
|
+
*
|
|
24
|
+
* Reverts while a transfer is still pending on the eSIM wallet, and for any
|
|
25
|
+
* address the eSIM wallet factory did not deploy.
|
|
26
|
+
*/
|
|
27
|
+
export const _bindESIMWallet = async (client, eSIMWalletAddress) => {
|
|
28
|
+
if (!client.account)
|
|
29
|
+
throw new MissingSmartWalletError();
|
|
30
|
+
const chainID = await client.getChainId();
|
|
31
|
+
const rpcURL = client.transport.url;
|
|
32
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
33
|
+
return client.sendUserOperation({
|
|
34
|
+
account: client.account,
|
|
35
|
+
calls: [{
|
|
36
|
+
to: values.factoryAddresses.REGISTRY,
|
|
37
|
+
data: encodeFunctionData({
|
|
38
|
+
abi: Registry,
|
|
39
|
+
functionName: "bindESIMWallet",
|
|
40
|
+
args: [eSIMWalletAddress, client.account.address]
|
|
41
|
+
})
|
|
42
|
+
}]
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Flag an eSIM wallet as mid-transfer, or clear the flag when the move settles or
|
|
47
|
+
* is called off.
|
|
48
|
+
*
|
|
49
|
+
* Only the flag moves. The registry keeps naming this device wallet as the eSIM
|
|
50
|
+
* wallet's holder either way, so raising standby on a wallet still held here is
|
|
51
|
+
* the ordinary case rather than a contradiction.
|
|
52
|
+
*/
|
|
53
|
+
export const _toggleESIMWalletStandbyStatus = async (client, eSIMWalletAddress, isOnStandby) => {
|
|
54
|
+
if (!client.account)
|
|
55
|
+
throw new MissingSmartWalletError();
|
|
56
|
+
const chainID = await client.getChainId();
|
|
57
|
+
const rpcURL = client.transport.url;
|
|
58
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
59
|
+
return client.sendUserOperation({
|
|
60
|
+
account: client.account,
|
|
61
|
+
calls: [{
|
|
62
|
+
to: values.factoryAddresses.REGISTRY,
|
|
63
|
+
data: encodeFunctionData({
|
|
64
|
+
abi: Registry,
|
|
65
|
+
functionName: "toggleESIMWalletStandbyStatus",
|
|
66
|
+
args: [eSIMWalletAddress, isOnStandby]
|
|
67
|
+
})
|
|
68
|
+
}]
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* True once the device has a wallet on chain. Note this is not the same question
|
|
73
|
+
* as `LazyWalletRegistry.isDeviceIdentifierReserved`, which only says whether
|
|
74
|
+
* history has been recorded for the device, and is true well before anything is
|
|
75
|
+
* deployed.
|
|
76
|
+
*/
|
|
77
|
+
export const _isDeviceIdentifierAlreadyUsed = async (client, deviceUniqueIdentifier) => {
|
|
78
|
+
const chainID = await client.getChainId();
|
|
79
|
+
const rpcURL = client.transport.url;
|
|
80
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
81
|
+
// A `view` - read it directly instead of spending a userOp.
|
|
82
|
+
return client.readContract({
|
|
83
|
+
address: values.factoryAddresses.REGISTRY,
|
|
84
|
+
abi: Registry,
|
|
85
|
+
functionName: "isDeviceIdentifierAlreadyUsed",
|
|
86
|
+
args: [deviceUniqueIdentifier]
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Whether the protocol is paused. While true, every ETH-moving path on the device
|
|
91
|
+
* wallets and eSIM wallets reverts, so check this before offering a purchase.
|
|
92
|
+
*/
|
|
93
|
+
export const _paused = async (client) => {
|
|
94
|
+
const chainID = await client.getChainId();
|
|
95
|
+
const rpcURL = client.transport.url;
|
|
96
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
97
|
+
return client.readContract({
|
|
98
|
+
address: values.factoryAddresses.REGISTRY,
|
|
99
|
+
abi: Registry,
|
|
100
|
+
functionName: "paused",
|
|
101
|
+
args: []
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* The same pause check the wallets themselves run, which throws rather than
|
|
106
|
+
* returning false. Use `_paused` to branch on it; use this when you want the
|
|
107
|
+
* failure to carry the protocol's own revert reason.
|
|
108
|
+
*/
|
|
109
|
+
export const _requireNotPaused = async (client) => {
|
|
110
|
+
const chainID = await client.getChainId();
|
|
111
|
+
const rpcURL = client.transport.url;
|
|
112
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
113
|
+
await client.readContract({
|
|
114
|
+
address: values.factoryAddresses.REGISTRY,
|
|
115
|
+
abi: Registry,
|
|
116
|
+
functionName: "requireNotPaused",
|
|
117
|
+
args: []
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The device wallet holding an eSIM wallet, zero if it was never registered.
|
|
122
|
+
* Despite the name this returns an address, not a boolean, and it keeps naming
|
|
123
|
+
* the last holder after a release, so a non-zero answer is not proof anyone
|
|
124
|
+
* holds it now. Ask `deviceWallet.isValidESIMWallet` for that.
|
|
125
|
+
*/
|
|
126
|
+
export const _isESIMWalletValid = async (client, eSIMWalletAddress) => {
|
|
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.REGISTRY,
|
|
132
|
+
abi: Registry,
|
|
133
|
+
functionName: "isESIMWalletValid",
|
|
134
|
+
args: [eSIMWalletAddress]
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Whether a transfer is outstanding on an eSIM wallet. `bindESIMWallet` clears
|
|
139
|
+
* it once the new device wallet takes the eSIM wallet on.
|
|
140
|
+
*
|
|
141
|
+
* Independent of `isESIMWalletValid`, and neither implies the other. A `true`
|
|
142
|
+
* here is not a claim the wallet left the protocol, and it is normal for the
|
|
143
|
+
* association to still name the device wallet that raised the flag.
|
|
144
|
+
*/
|
|
145
|
+
export const _isESIMWalletOnStandby = async (client, eSIMWalletAddress) => {
|
|
146
|
+
const chainID = await client.getChainId();
|
|
147
|
+
const rpcURL = client.transport.url;
|
|
148
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
149
|
+
return client.readContract({
|
|
150
|
+
address: values.factoryAddresses.REGISTRY,
|
|
151
|
+
abi: Registry,
|
|
152
|
+
functionName: "isESIMWalletOnStandby",
|
|
153
|
+
args: [eSIMWalletAddress]
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
/** Whether a device wallet is registered with the protocol. */
|
|
157
|
+
export const _isDeviceWalletValid = async (client, deviceWalletAddress) => {
|
|
158
|
+
const chainID = await client.getChainId();
|
|
159
|
+
const rpcURL = client.transport.url;
|
|
160
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
161
|
+
return client.readContract({
|
|
162
|
+
address: values.factoryAddresses.REGISTRY,
|
|
163
|
+
abi: Registry,
|
|
164
|
+
functionName: "isDeviceWalletValid",
|
|
165
|
+
args: [deviceWalletAddress]
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
/** The device wallet registered for a device identifier, zero if none. */
|
|
169
|
+
export const _uniqueIdentifierToDeviceWallet = async (client, deviceUniqueIdentifier) => {
|
|
170
|
+
const chainID = await client.getChainId();
|
|
171
|
+
const rpcURL = client.transport.url;
|
|
172
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
173
|
+
return client.readContract({
|
|
174
|
+
address: values.factoryAddresses.REGISTRY,
|
|
175
|
+
abi: Registry,
|
|
176
|
+
functionName: "uniqueIdentifierToDeviceWallet",
|
|
177
|
+
args: [deviceUniqueIdentifier]
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
/** Whether an eSIM identifier is already held by a wallet. */
|
|
181
|
+
export const _isESIMIdentifierClaimed = async (client, eSIMUniqueIdentifier) => {
|
|
182
|
+
const chainID = await client.getChainId();
|
|
183
|
+
const rpcURL = client.transport.url;
|
|
184
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
185
|
+
return client.readContract({
|
|
186
|
+
address: values.factoryAddresses.REGISTRY,
|
|
187
|
+
abi: Registry,
|
|
188
|
+
functionName: "isESIMIdentifierClaimed",
|
|
189
|
+
args: [eSIMUniqueIdentifier]
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* The one eSIM wallet holding an eSIM identifier, zero if nobody holds it. Set
|
|
194
|
+
* once and never cleared, an ownership transfer included, because the eSIM
|
|
195
|
+
* belongs to the wallet rather than to whichever device is holding it.
|
|
196
|
+
*/
|
|
197
|
+
export const _eSIMWalletForIdentifier = async (client, eSIMUniqueIdentifier) => {
|
|
198
|
+
const chainID = await client.getChainId();
|
|
199
|
+
const rpcURL = client.transport.url;
|
|
200
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
201
|
+
return client.readContract({
|
|
202
|
+
address: values.factoryAddresses.REGISTRY,
|
|
203
|
+
abi: Registry,
|
|
204
|
+
functionName: "eSIMWalletForIdentifier",
|
|
205
|
+
args: [eSIMUniqueIdentifier]
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
/** The fallback price ceiling in wei for a wallet holding no cap of its own. */
|
|
209
|
+
export const _defaultDataBundlePriceCap = async (client) => {
|
|
210
|
+
const chainID = await client.getChainId();
|
|
211
|
+
const rpcURL = client.transport.url;
|
|
212
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
213
|
+
return client.readContract({
|
|
214
|
+
address: values.factoryAddresses.REGISTRY,
|
|
215
|
+
abi: Registry,
|
|
216
|
+
functionName: "defaultDataBundlePriceCap",
|
|
217
|
+
args: []
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Throws if a fiat user's eSIMs are already waiting on this device identifier.
|
|
222
|
+
* Worth calling before a deployment: taking a reserved identifier strands the
|
|
223
|
+
* lazy user, since the history copy, the wallet deployment and the device switch
|
|
224
|
+
* all then refuse it.
|
|
225
|
+
*/
|
|
226
|
+
export const _requireDeviceIdentifierNotReserved = async (client, deviceUniqueIdentifier) => {
|
|
227
|
+
const chainID = await client.getChainId();
|
|
228
|
+
const rpcURL = client.transport.url;
|
|
229
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
230
|
+
await client.readContract({
|
|
231
|
+
address: values.factoryAddresses.REGISTRY,
|
|
232
|
+
abi: Registry,
|
|
233
|
+
functionName: "requireDeviceIdentifierNotReserved",
|
|
234
|
+
args: [deviceUniqueIdentifier]
|
|
235
|
+
});
|
|
236
|
+
};
|
package/dist/esm/logic/utils.js
CHANGED
|
@@ -54,7 +54,8 @@ export function parseDEREncodedSignature(signature) {
|
|
|
54
54
|
let offset = 0;
|
|
55
55
|
if (signature[offset++] !== 0x30)
|
|
56
56
|
throw new Error("Invalid DER sequence");
|
|
57
|
-
|
|
57
|
+
// Sequence length byte. Skipped, because r and s each carry their own length.
|
|
58
|
+
offset++;
|
|
58
59
|
if (signature[offset++] !== 0x02)
|
|
59
60
|
throw new Error("Expected integer for r");
|
|
60
61
|
const rLen = signature[offset++];
|
|
@@ -1,59 +1,47 @@
|
|
|
1
1
|
declare const BeaconProxy: readonly [{
|
|
2
|
+
readonly type: "fallback";
|
|
3
|
+
readonly stateMutability: "payable";
|
|
4
|
+
}, {
|
|
5
|
+
readonly type: "event";
|
|
6
|
+
readonly name: "BeaconUpgraded";
|
|
2
7
|
readonly inputs: readonly [{
|
|
3
|
-
readonly internalType: "address";
|
|
4
8
|
readonly name: "beacon";
|
|
5
9
|
readonly type: "address";
|
|
6
|
-
|
|
7
|
-
readonly internalType: "
|
|
8
|
-
readonly name: "data";
|
|
9
|
-
readonly type: "bytes";
|
|
10
|
+
readonly indexed: true;
|
|
11
|
+
readonly internalType: "address";
|
|
10
12
|
}];
|
|
11
|
-
readonly
|
|
12
|
-
readonly type: "constructor";
|
|
13
|
+
readonly anonymous: false;
|
|
13
14
|
}, {
|
|
15
|
+
readonly type: "error";
|
|
16
|
+
readonly name: "AddressEmptyCode";
|
|
14
17
|
readonly inputs: readonly [{
|
|
15
|
-
readonly internalType: "address";
|
|
16
18
|
readonly name: "target";
|
|
17
19
|
readonly type: "address";
|
|
20
|
+
readonly internalType: "address";
|
|
18
21
|
}];
|
|
19
|
-
readonly name: "AddressEmptyCode";
|
|
20
|
-
readonly type: "error";
|
|
21
22
|
}, {
|
|
23
|
+
readonly type: "error";
|
|
24
|
+
readonly name: "ERC1967InvalidBeacon";
|
|
22
25
|
readonly inputs: readonly [{
|
|
23
|
-
readonly internalType: "address";
|
|
24
26
|
readonly name: "beacon";
|
|
25
27
|
readonly type: "address";
|
|
28
|
+
readonly internalType: "address";
|
|
26
29
|
}];
|
|
27
|
-
readonly name: "ERC1967InvalidBeacon";
|
|
28
|
-
readonly type: "error";
|
|
29
30
|
}, {
|
|
31
|
+
readonly type: "error";
|
|
32
|
+
readonly name: "ERC1967InvalidImplementation";
|
|
30
33
|
readonly inputs: readonly [{
|
|
31
|
-
readonly internalType: "address";
|
|
32
34
|
readonly name: "implementation";
|
|
33
35
|
readonly type: "address";
|
|
36
|
+
readonly internalType: "address";
|
|
34
37
|
}];
|
|
35
|
-
readonly name: "ERC1967InvalidImplementation";
|
|
36
|
-
readonly type: "error";
|
|
37
38
|
}, {
|
|
38
|
-
readonly inputs: readonly [];
|
|
39
|
-
readonly name: "ERC1967NonPayable";
|
|
40
39
|
readonly type: "error";
|
|
41
|
-
|
|
40
|
+
readonly name: "ERC1967NonPayable";
|
|
42
41
|
readonly inputs: readonly [];
|
|
43
|
-
readonly name: "FailedInnerCall";
|
|
44
|
-
readonly type: "error";
|
|
45
42
|
}, {
|
|
46
|
-
readonly
|
|
47
|
-
readonly
|
|
48
|
-
|
|
49
|
-
readonly internalType: "address";
|
|
50
|
-
readonly name: "beacon";
|
|
51
|
-
readonly type: "address";
|
|
52
|
-
}];
|
|
53
|
-
readonly name: "BeaconUpgraded";
|
|
54
|
-
readonly type: "event";
|
|
55
|
-
}, {
|
|
56
|
-
readonly stateMutability: "payable";
|
|
57
|
-
readonly type: "fallback";
|
|
43
|
+
readonly type: "error";
|
|
44
|
+
readonly name: "FailedCall";
|
|
45
|
+
readonly inputs: readonly [];
|
|
58
46
|
}];
|
|
59
47
|
export default BeaconProxy;
|