kokio-sdk 0.1.4 → 1.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 +185 -1
- package/dist/esm/admin/config-admin.js +85 -0
- package/dist/esm/admin/interface/deviceWalletClass.js +34 -0
- package/dist/esm/admin/interface/deviceWalletFactoryClass.js +57 -0
- package/dist/esm/admin/interface/eSIMWalletClass.js +31 -0
- package/dist/esm/admin/interface/eSIMWalletFactoryClass.js +22 -0
- package/dist/esm/admin/interface/lazyWalletRegistryClass.js +33 -0
- package/dist/esm/admin/interface/registryClass.js +43 -0
- package/dist/esm/config.js +4 -0
- package/dist/esm/interface/deviceWalletClass.js +1 -13
- package/dist/esm/interface/eSIMWalletClass.js +2 -8
- package/dist/esm/interface/eSIMWalletFactoryClass.js +2 -8
- package/dist/esm/interface/lazyWalletRegistryClass.js +2 -11
- package/dist/esm/logic/P256Verifier.js +8 -15
- package/dist/esm/logic/account-kit/createSmartAccount.js +76 -24
- package/dist/esm/logic/admin/deviceWallet.eoa.js +42 -0
- package/dist/esm/logic/admin/deviceWalletFactory.eoa.js +133 -0
- package/dist/esm/logic/admin/eSIMWallet.eoa.js +30 -0
- package/dist/esm/logic/admin/eSIMWalletFactory.eoa.js +43 -0
- package/dist/esm/logic/admin/lazyWalletRegistry.eoa.js +62 -0
- package/dist/esm/logic/admin/reads/deviceWallet.reads.js +45 -0
- package/dist/esm/logic/admin/reads/deviceWalletFactory.reads.js +87 -0
- package/dist/esm/logic/admin/reads/eSIMWallet.reads.js +44 -0
- package/dist/esm/logic/admin/reads/eSIMWalletFactory.reads.js +32 -0
- package/dist/esm/logic/admin/reads/lazyWalletRegistry.reads.js +62 -0
- package/dist/esm/logic/admin/reads/registry.reads.js +136 -0
- package/dist/esm/logic/admin/registry.eoa.js +23 -0
- package/dist/esm/logic/constants.js +31 -71
- package/dist/esm/logic/deviceWallet.js +28 -91
- package/dist/esm/logic/deviceWalletFactory.js +21 -30
- package/dist/esm/logic/eSIMWallet.js +25 -57
- package/dist/esm/logic/eSIMWalletFactory.js +17 -50
- package/dist/esm/logic/errors.js +118 -0
- package/dist/esm/logic/lazyWalletRegistry.js +12 -72
- package/dist/esm/logic/utils.js +3 -3
- package/dist/types/abis/BeaconProxy.d.ts +58 -2
- package/dist/types/abis/DeviceWallet.d.ts +702 -2
- package/dist/types/abis/DeviceWalletFactory.d.ts +634 -2
- package/dist/types/abis/ESIMWallet.d.ts +375 -2
- package/dist/types/abis/ESIMWalletFactory.d.ts +355 -2
- package/dist/types/abis/LazyWalletRegistry.d.ts +565 -2
- package/dist/types/abis/P256Verifier.d.ts +56 -2
- package/dist/types/abis/Registry.d.ts +623 -2
- package/dist/types/abis/RegistryHelper.d.ts +295 -2
- package/dist/types/admin/config-admin.d.ts +55 -0
- package/dist/types/admin/interface/deviceWalletClass.d.ts +17 -0
- package/dist/types/admin/interface/deviceWalletFactoryClass.d.ts +25 -0
- package/dist/types/admin/interface/eSIMWalletClass.d.ts +17 -0
- package/dist/types/admin/interface/eSIMWalletFactoryClass.d.ts +10 -0
- package/dist/types/admin/interface/lazyWalletRegistryClass.d.ts +14 -0
- package/dist/types/admin/interface/registryClass.d.ts +17 -0
- package/dist/types/config.d.ts +2 -0
- package/dist/types/interface/P256VerifierClass.d.ts +2 -1
- package/dist/types/interface/deviceWalletClass.d.ts +24 -28
- package/dist/types/interface/deviceWalletFactoryClass.d.ts +27 -26
- package/dist/types/interface/eSIMWalletClass.d.ts +2 -4
- package/dist/types/interface/eSIMWalletFactoryClass.d.ts +24 -26
- package/dist/types/interface/lazyWalletRegistryClass.d.ts +1 -6
- package/dist/types/interface/smartAccountClass.d.ts +23 -23
- package/dist/types/logic/P256Verifier.d.ts +2 -1
- package/dist/types/logic/account-kit/createSmartAccount.d.ts +38 -1
- package/dist/types/logic/admin/deviceWallet.eoa.d.ts +12 -0
- package/dist/types/logic/admin/deviceWalletFactory.eoa.d.ts +33 -0
- package/dist/types/logic/admin/eSIMWallet.eoa.d.ts +14 -0
- package/dist/types/logic/admin/eSIMWalletFactory.eoa.d.ts +13 -0
- package/dist/types/logic/admin/lazyWalletRegistry.eoa.d.ts +18 -0
- package/dist/types/logic/admin/reads/deviceWallet.reads.d.ts +16 -0
- package/dist/types/logic/admin/reads/deviceWalletFactory.reads.d.ts +26 -0
- package/dist/types/logic/admin/reads/eSIMWallet.reads.d.ts +15 -0
- package/dist/types/logic/admin/reads/eSIMWalletFactory.reads.d.ts +10 -0
- package/dist/types/logic/admin/reads/lazyWalletRegistry.reads.d.ts +20 -0
- package/dist/types/logic/admin/reads/registry.reads.d.ts +34 -0
- package/dist/types/logic/admin/registry.eoa.d.ts +7 -0
- package/dist/types/logic/deviceWallet.d.ts +1 -5
- package/dist/types/logic/deviceWalletFactory.d.ts +5 -4
- package/dist/types/logic/eSIMWallet.d.ts +1 -3
- package/dist/types/logic/eSIMWalletFactory.d.ts +2 -4
- package/dist/types/logic/errors.d.ts +63 -0
- package/dist/types/logic/lazyWalletRegistry.d.ts +1 -6
- package/dist/types/logic/utils.d.ts +8 -1
- package/dist/types/types.d.ts +1 -1
- package/package.json +12 -3
- package/dist/esm/interface/utilsClass.js +0 -13
- package/dist/types/interface/utilsClass.d.ts +0 -2567
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createSmartAccountClient, getEntryPoint, toSmartContractAccount, split, erc7677Middleware } from "@aa-sdk/core";
|
|
2
|
-
import { http, encodeFunctionData, encodePacked, encodeAbiParameters, parseAbiParameters, getContract, concat, keccak256, getContractAddress, getAddress, hashMessage,
|
|
2
|
+
import { http, encodeFunctionData, encodePacked, encodeAbiParameters, parseAbiParameters, getContract, concat, keccak256, getContractAddress, getAddress, hashMessage, toHex, hashTypedData, hexToBytes, bytesToHex } from "viem";
|
|
3
3
|
import { _getChainSpecificConstants, ZERO, SIGNATURE_VALIDITY_SECONDS } from "../constants.js";
|
|
4
|
+
import { CounterfactualMismatchError } from "../errors.js";
|
|
4
5
|
import { _remove0x } from "../utils.js";
|
|
5
6
|
import { DeviceWallet, DeviceWalletFactory } from "../../abis/index.js";
|
|
6
7
|
import { isoBase64URL } from "@simplewebauthn/server/helpers";
|
|
@@ -15,6 +16,22 @@ var AuthenticatorTransport;
|
|
|
15
16
|
AuthenticatorTransport["hybrid"] = "hybrid";
|
|
16
17
|
AuthenticatorTransport["internal"] = "internal";
|
|
17
18
|
})(AuthenticatorTransport || (AuthenticatorTransport = {}));
|
|
19
|
+
/**
|
|
20
|
+
* BeaconProxy creation bytecode, used to compute the CREATE2 counterfactual
|
|
21
|
+
* DeviceWallet address off-chain (initCode = creationCode ++ abi.encode(beacon, initData)).
|
|
22
|
+
*
|
|
23
|
+
* PINNED - this MUST byte-for-byte match the BeaconProxy the on-chain
|
|
24
|
+
* DeviceWalletFactory deploys, or the computed address will diverge from the
|
|
25
|
+
* deployed one. Source of truth:
|
|
26
|
+
* OpenZeppelin Contracts v5.0.0 - proxy/beacon/BeaconProxy.sol
|
|
27
|
+
* compiled by Hardhat (smart-contract-suite `artifacts/@openzeppelin/contracts/
|
|
28
|
+
* proxy/beacon/BeaconProxy.sol/BeaconProxy.json`), solc 0.8.25+commit.b61c2a91,
|
|
29
|
+
* optimizer { enabled: true, runs: 200 }, viaIR: true.
|
|
30
|
+
* NOTE: the Foundry `out/` artifact (different optimizer settings) produces a
|
|
31
|
+
* DIFFERENT bytecode - do not swap it in without re-verifying the counterfactual.
|
|
32
|
+
* `_assertCounterfactualMatchesOnChain` guards against drift at runtime.
|
|
33
|
+
*/
|
|
34
|
+
export const BEACON_PROXY_CREATION_CODE = "0x60a06040908082526104a8803803809161001982856102ae565b8339810182828203126101e95761002f826102e7565b60208084015191939091906001600160401b0382116101e9570182601f820112156101e957805190610060826102fb565b9361006d875195866102ae565b8285528383830101116101e957829060005b83811061029a57505060009184010152823b1561027a577fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b038581169182179092558551635c60da1b60e01b8082529194928482600481895afa91821561026f57600092610238575b50813b1561021f5750508551847f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e600080a282511561020057508290600487518096819382525afa9283156101f5576000936101b3575b5091600080848461019096519101845af4903d156101aa573d610174816102fb565b90610181885192836102ae565b8152600081943d92013e610316565b505b6080525161012e908161037a82396080518160180152f35b60609250610316565b92508183813d83116101ee575b6101ca81836102ae565b810103126101e9576000806101e1610190956102e7565b945050610152565b600080fd5b503d6101c0565b85513d6000823e3d90fd5b9350505050346102105750610192565b63b398979f60e01b8152600490fd5b8751634c9c8ce360e01b81529116600482015260249150fd5b9091508481813d8311610268575b61025081836102ae565b810103126101e957610261906102e7565b90386100fb565b503d610246565b88513d6000823e3d90fd5b8351631933b43b60e21b81526001600160a01b0384166004820152602490fd5b81810183015186820184015284920161007f565b601f909101601f19168101906001600160401b038211908210176102d157604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101e957565b6001600160401b0381116102d157601f01601f191660200190565b9061033d575080511561032b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580610370575b61034e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561034656fe60806040819052635c60da1b60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811560a9576000916054575b5060da565b905060203d60201160a3575b601f8101601f191682019167ffffffffffffffff831181841017608d576088926040520160b5565b38604f565b634e487b7160e01b600052604160045260246000fd5b503d6060565b6040513d6000823e3d90fd5b602090607f19011260d5576080516001600160a01b038116810360d55790565b600080fd5b6000808092368280378136915af43d82803e1560f4573d90f35b3d90fdfea264697066735822122099ba460fd62b3e22c737d15959887e6cae3498f3495d31e43e2bcf1283aec7d264736f6c63430008190033";
|
|
18
35
|
/*
|
|
19
36
|
** Stamp is client-side authentication. Since the passkeys are one the user's mobile device
|
|
20
37
|
** react-native-passkey helps fetch passkey for the user (provided credentialId, rpId).
|
|
@@ -22,7 +39,10 @@ var AuthenticatorTransport;
|
|
|
22
39
|
*/
|
|
23
40
|
export const _stamp = async (credentialId, rpId, payload) => {
|
|
24
41
|
const signingOptions = {
|
|
25
|
-
|
|
42
|
+
// `Uint8Array.from` gives a fresh ArrayBuffer-backed view, matching the
|
|
43
|
+
// `Uint8Array<ArrayBuffer>` that `fromBuffer` expects (viem's `hexToBytes`
|
|
44
|
+
// is typed over the wider `ArrayBufferLike`).
|
|
45
|
+
challenge: isoBase64URL.fromBuffer(Uint8Array.from(hexToBytes(payload))),
|
|
26
46
|
allowCredentials: [{
|
|
27
47
|
id: credentialId,
|
|
28
48
|
type: "public-key",
|
|
@@ -119,7 +139,7 @@ const _encodeBatchExecute = async (txs) => {
|
|
|
119
139
|
args: [new_txs]
|
|
120
140
|
});
|
|
121
141
|
};
|
|
122
|
-
const _getAccountInitCode = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
142
|
+
export const _getAccountInitCode = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
123
143
|
// To send with user operations
|
|
124
144
|
const chainID = await client.getChainId();
|
|
125
145
|
const rpcURL = client.transport.url;
|
|
@@ -131,7 +151,7 @@ const _getAccountInitCode = async (client, deviceUniqueIdentifier, deviceWalletO
|
|
|
131
151
|
});
|
|
132
152
|
return values.factoryAddresses.DEVICE_WALLET_FACTORY.concat(_remove0x(callData));
|
|
133
153
|
};
|
|
134
|
-
const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey) => {
|
|
154
|
+
export const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey) => {
|
|
135
155
|
const chainID = await client.getChainId();
|
|
136
156
|
const rpcURL = client.transport.url;
|
|
137
157
|
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
@@ -144,7 +164,7 @@ const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwner
|
|
|
144
164
|
address: deviceWalletFactoryAddress,
|
|
145
165
|
client
|
|
146
166
|
});
|
|
147
|
-
const beacon = await deviceWalletFactory.read.beacon(
|
|
167
|
+
const beacon = await deviceWalletFactory.read.beacon();
|
|
148
168
|
// Encode the DeviceWallet.init with the init params
|
|
149
169
|
const deviceWalletInitData = encodeFunctionData({
|
|
150
170
|
abi: DeviceWallet,
|
|
@@ -156,14 +176,13 @@ const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwner
|
|
|
156
176
|
eSIMWalletFactoryAddress
|
|
157
177
|
]
|
|
158
178
|
});
|
|
159
|
-
const beaconProxyBytecode = "0x60a06040908082526104a8803803809161001982856102ae565b8339810182828203126101e95761002f826102e7565b60208084015191939091906001600160401b0382116101e9570182601f820112156101e957805190610060826102fb565b9361006d875195866102ae565b8285528383830101116101e957829060005b83811061029a57505060009184010152823b1561027a577fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b038581169182179092558551635c60da1b60e01b8082529194928482600481895afa91821561026f57600092610238575b50813b1561021f5750508551847f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e600080a282511561020057508290600487518096819382525afa9283156101f5576000936101b3575b5091600080848461019096519101845af4903d156101aa573d610174816102fb565b90610181885192836102ae565b8152600081943d92013e610316565b505b6080525161012e908161037a82396080518160180152f35b60609250610316565b92508183813d83116101ee575b6101ca81836102ae565b810103126101e9576000806101e1610190956102e7565b945050610152565b600080fd5b503d6101c0565b85513d6000823e3d90fd5b9350505050346102105750610192565b63b398979f60e01b8152600490fd5b8751634c9c8ce360e01b81529116600482015260249150fd5b9091508481813d8311610268575b61025081836102ae565b810103126101e957610261906102e7565b90386100fb565b503d610246565b88513d6000823e3d90fd5b8351631933b43b60e21b81526001600160a01b0384166004820152602490fd5b81810183015186820184015284920161007f565b601f909101601f19168101906001600160401b038211908210176102d157604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101e957565b6001600160401b0381116102d157601f01601f191660200190565b9061033d575080511561032b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580610370575b61034e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561034656fe60806040819052635c60da1b60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811560a9576000916054575b5060da565b905060203d60201160a3575b601f8101601f191682019167ffffffffffffffff831181841017608d576088926040520160b5565b38604f565b634e487b7160e01b600052604160045260246000fd5b503d6060565b6040513d6000823e3d90fd5b602090607f19011260d5576080516001600160a01b038116810360d55790565b600080fd5b6000808092368280378136915af43d82803e1560f4573d90f35b3d90fdfea264697066735822122099ba460fd62b3e22c737d15959887e6cae3498f3495d31e43e2bcf1283aec7d264736f6c63430008190033";
|
|
160
179
|
// Encode BeaconProxy constructor args
|
|
161
180
|
const beaconProxyConstructorArgs = encodeAbiParameters(parseAbiParameters("address, bytes"), [beacon, deviceWalletInitData]);
|
|
162
181
|
// Compute initCode
|
|
163
|
-
const initCode = concat([
|
|
182
|
+
const initCode = concat([BEACON_PROXY_CREATION_CODE, beaconProxyConstructorArgs]);
|
|
164
183
|
return keccak256(initCode);
|
|
165
184
|
};
|
|
166
|
-
const getCounterFactualAddress = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
185
|
+
export const getCounterFactualAddress = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
167
186
|
const chainID = await client.getChainId();
|
|
168
187
|
const rpcURL = client.transport.url;
|
|
169
188
|
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
@@ -179,7 +198,41 @@ const getCounterFactualAddress = async (client, deviceUniqueIdentifier, deviceWa
|
|
|
179
198
|
});
|
|
180
199
|
return getAddress(create2Address);
|
|
181
200
|
};
|
|
182
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Optional drift guard. Recomputes the counterfactual address off-chain (using
|
|
203
|
+
* the pinned {@link BEACON_PROXY_CREATION_CODE}) and compares it against the
|
|
204
|
+
* on-chain `DeviceWalletFactory.getCounterFactualAddress` view - which derives
|
|
205
|
+
* the address from the BeaconProxy the factory ACTUALLY deploys. A mismatch
|
|
206
|
+
* means the pinned proxy bytecode (or init encoding) has drifted from the
|
|
207
|
+
* deployed contract, so this throws early instead of letting a UserOp deploy to,
|
|
208
|
+
* or fund, the wrong address.
|
|
209
|
+
*
|
|
210
|
+
* Not wired into the default account-creation path (it costs one extra RPC);
|
|
211
|
+
* call it explicitly in environments where you want the extra safety, e.g.
|
|
212
|
+
* after a contract redeploy or on first use against a new chain.
|
|
213
|
+
*/
|
|
214
|
+
export const _assertCounterfactualMatchesOnChain = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
215
|
+
const chainID = await client.getChainId();
|
|
216
|
+
const rpcURL = client.transport.url;
|
|
217
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
218
|
+
const offChain = await getCounterFactualAddress(client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt);
|
|
219
|
+
const deviceWalletFactory = getContract({
|
|
220
|
+
abi: DeviceWalletFactory,
|
|
221
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
222
|
+
client,
|
|
223
|
+
});
|
|
224
|
+
// on-chain view arg order is (ownerKey, uid, salt) - differs from createAccount
|
|
225
|
+
const onChain = await deviceWalletFactory.read.getCounterFactualAddress([
|
|
226
|
+
deviceWalletOwnerKey,
|
|
227
|
+
deviceUniqueIdentifier,
|
|
228
|
+
salt,
|
|
229
|
+
]);
|
|
230
|
+
if (getAddress(offChain) !== getAddress(onChain)) {
|
|
231
|
+
throw new CounterfactualMismatchError(getAddress(offChain), getAddress(onChain));
|
|
232
|
+
}
|
|
233
|
+
return offChain;
|
|
234
|
+
};
|
|
235
|
+
export const _encodeSignature = async (webAuthnSignature, validUntil) => {
|
|
183
236
|
const encodedWebAuthnSignatureBytes = encodeAbiParameters([
|
|
184
237
|
{
|
|
185
238
|
type: "tuple",
|
|
@@ -200,30 +253,30 @@ const _encodeSignature = async (webAuthnSignature, validUntil) => {
|
|
|
200
253
|
return signature;
|
|
201
254
|
};
|
|
202
255
|
// message here is the original message data (string or Uint8Array) directly from the app
|
|
203
|
-
const _signMessage = async (message, credentialId, rpId) => {
|
|
256
|
+
export const _signMessage = async (message, credentialId, rpId) => {
|
|
204
257
|
const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
|
|
205
|
-
|
|
258
|
+
// viem's SignableMessage is `string | { raw: Hex | ByteArray }`. A plain
|
|
259
|
+
// string is a UTF-8 message; the `{ raw }` form is already-serialized bytes
|
|
260
|
+
// (possibly a pre-computed digest). hashMessage handles both natively, so
|
|
261
|
+
// forward the message as-is rather than force-casting it to a string.
|
|
262
|
+
const payload = hashMessage(message);
|
|
206
263
|
// The original message is passed to the stamp and sign function.
|
|
207
264
|
// The stamp and sign function creates the EIP-191 digest hash using its hashMessage function
|
|
208
265
|
// The result of the hashMessage(message) will be the `payload` used as a challenge
|
|
209
266
|
const webAuthnSignature = await _stamp(credentialId, rpId, payload);
|
|
210
267
|
return _encodeSignature(webAuthnSignature, validUntil);
|
|
211
268
|
};
|
|
212
|
-
const _signTypedData = async (typedData,
|
|
269
|
+
export const _signTypedData = async (typedData, credentialId, rpId) => {
|
|
213
270
|
// signature valid until, UNIX timestamp in seconds
|
|
214
271
|
const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
typeIndex: BigInt(0),
|
|
221
|
-
r: BigInt(0),
|
|
222
|
-
s: BigInt(0)
|
|
223
|
-
};
|
|
272
|
+
// EIP-712 digest is the WebAuthn challenge, mirroring _signMessage's use of
|
|
273
|
+
// the EIP-191 digest. The contract's isValidSignature receives this same
|
|
274
|
+
// hashTypedData result and verifies the passkey signature against it.
|
|
275
|
+
const payload = hashTypedData(typedData);
|
|
276
|
+
const webAuthnSignature = await _stamp(credentialId, rpId, payload);
|
|
224
277
|
return _encodeSignature(webAuthnSignature, validUntil);
|
|
225
278
|
};
|
|
226
|
-
const _signUserOperationHash = async (credentialId, rpId, userOpHash) => {
|
|
279
|
+
export const _signUserOperationHash = async (credentialId, rpId, userOpHash) => {
|
|
227
280
|
const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
|
|
228
281
|
const messagePrecursor = encodePacked(["uint8", "uint48", "bytes32"], [
|
|
229
282
|
1,
|
|
@@ -240,7 +293,6 @@ export const _getSmartWallet = async (client, credentialId, rpId, organiationId,
|
|
|
240
293
|
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
241
294
|
if (!client.account)
|
|
242
295
|
throw new Error('Error: No signer account found with WalletClient');
|
|
243
|
-
const signWith = client.account.address;
|
|
244
296
|
return toSmartContractAccount({
|
|
245
297
|
/// REQUIRED PARAMS ///
|
|
246
298
|
source: "MyAccount",
|
|
@@ -255,7 +307,7 @@ export const _getSmartWallet = async (client, credentialId, rpId, organiationId,
|
|
|
255
307
|
// given a UO in the form of {target, data, value} should output the calldata for calling your contract's execution method
|
|
256
308
|
encodeExecute: async (uo) => _encodeExecute(uo),
|
|
257
309
|
signMessage: async ({ message }) => _signMessage(message, credentialId, rpId),
|
|
258
|
-
signTypedData: async (typedData) => _signTypedData(typedData,
|
|
310
|
+
signTypedData: async (typedData) => _signTypedData(typedData, credentialId, rpId),
|
|
259
311
|
/// OPTIONAL PARAMS ///
|
|
260
312
|
// if you already know your account's address, pass that in here to avoid generating a new counterfactual
|
|
261
313
|
accountAddress: await getCounterFactualAddress(client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt),
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { _getChainSpecificConstants } from "../constants.js";
|
|
2
|
+
import { MissingEOAWalletError } from "../errors.js";
|
|
3
|
+
import { DeviceWallet } from "../../abis/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Admin-EOA logic targeting a specific `DeviceWallet` instance (its address is
|
|
6
|
+
* passed in - there is no single factory address). Both functions are admin
|
|
7
|
+
* gated on chain (`deployESIMWallet` is `onlyESIMWalletAdmin`,
|
|
8
|
+
* `setESIMUniqueIdentifierForAnESIMWallet` is `onlyESIMWalletAdminOrRegistry`),
|
|
9
|
+
* so they cannot be driven from a device-wallet userOp and live on the EOA surface.
|
|
10
|
+
*/
|
|
11
|
+
/** Deploy a new eSIM wallet under a device wallet. `onlyESIMWalletAdmin`. */
|
|
12
|
+
export const _deployESIMWallet = async (client, deviceWalletAddress, hasAccessToETH, salt) => {
|
|
13
|
+
const chainID = await client.getChainId();
|
|
14
|
+
const rpcURL = client.transport.url;
|
|
15
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
16
|
+
if (!client.account)
|
|
17
|
+
throw new MissingEOAWalletError();
|
|
18
|
+
return client.writeContract({
|
|
19
|
+
address: deviceWalletAddress,
|
|
20
|
+
chain: values.chain,
|
|
21
|
+
account: client.account.address,
|
|
22
|
+
abi: DeviceWallet,
|
|
23
|
+
functionName: 'deployESIMWallet',
|
|
24
|
+
args: [hasAccessToETH, salt]
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
/** Bind an eSIM's unique identifier to its wallet. `onlyESIMWalletAdminOrRegistry`. */
|
|
28
|
+
export const _setESIMUniqueIdentifierForAnESIMWallet = async (client, deviceWalletAddress, eSIMWalletAddress, eSIMUniqueIdentifier) => {
|
|
29
|
+
const chainID = await client.getChainId();
|
|
30
|
+
const rpcURL = client.transport.url;
|
|
31
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
32
|
+
if (!client.account)
|
|
33
|
+
throw new MissingEOAWalletError();
|
|
34
|
+
return client.writeContract({
|
|
35
|
+
address: deviceWalletAddress,
|
|
36
|
+
chain: values.chain,
|
|
37
|
+
account: client.account.address,
|
|
38
|
+
abi: DeviceWallet,
|
|
39
|
+
functionName: 'setESIMUniqueIdentifierForAnESIMWallet',
|
|
40
|
+
args: [eSIMWalletAddress, eSIMUniqueIdentifier]
|
|
41
|
+
});
|
|
42
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { _getChainSpecificConstants } from "../constants.js";
|
|
2
|
+
import { MissingEOAWalletError } from "../errors.js";
|
|
3
|
+
import { DeviceWalletFactory } from "../../abis/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Admin-EOA logic for `DeviceWalletFactory`.
|
|
6
|
+
*
|
|
7
|
+
* Every function here is `onlyAdmin` / `onlyAdminOrRegistry` / `onlyOwner` on
|
|
8
|
+
* chain, i.e. the caller must be the `eSIMWalletAdmin` (or `upgradeManager`)
|
|
9
|
+
* EOA - never a device-wallet userOp. They therefore live on the EOA surface
|
|
10
|
+
* (`KokioAdmin`) and use `writeContract`, mirroring `_createAccountWithEOA`
|
|
11
|
+
* (which is reused as-is from `../deviceWalletFactory.js`).
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Batch-deploy device wallets for lazy/fiat users. `onlyAdminOrRegistry`,
|
|
15
|
+
* `payable`: `value` is the total ETH pot from which each `depositAmounts[i]`
|
|
16
|
+
* is drawn; any surplus is refunded to the caller on chain.
|
|
17
|
+
*/
|
|
18
|
+
export const _deployDeviceWalletForUsers = async (client, deviceUniqueIdentifiers, deviceWalletOwnersKey, salts, depositAmounts, value) => {
|
|
19
|
+
const chainID = await client.getChainId();
|
|
20
|
+
const rpcURL = client.transport.url;
|
|
21
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
22
|
+
if (!client.account)
|
|
23
|
+
throw new MissingEOAWalletError();
|
|
24
|
+
return client.writeContract({
|
|
25
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
26
|
+
chain: values.chain,
|
|
27
|
+
account: client.account.address,
|
|
28
|
+
abi: DeviceWalletFactory,
|
|
29
|
+
functionName: 'deployDeviceWalletForUsers',
|
|
30
|
+
args: [deviceUniqueIdentifiers, deviceWalletOwnersKey, salts, depositAmounts],
|
|
31
|
+
value
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
/** Register a freshly created device wallet with the factory. `onlyAdminOrRegistry`. */
|
|
35
|
+
export const _postCreateAccount = async (client, deviceWallet, deviceUniqueIdentifier, deviceWalletOwnerKey) => {
|
|
36
|
+
const chainID = await client.getChainId();
|
|
37
|
+
const rpcURL = client.transport.url;
|
|
38
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
39
|
+
if (!client.account)
|
|
40
|
+
throw new MissingEOAWalletError();
|
|
41
|
+
return client.writeContract({
|
|
42
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
43
|
+
chain: values.chain,
|
|
44
|
+
account: client.account.address,
|
|
45
|
+
abi: DeviceWalletFactory,
|
|
46
|
+
functionName: 'postCreateAccount',
|
|
47
|
+
args: [deviceWallet, deviceUniqueIdentifier, deviceWalletOwnerKey]
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
/** One-time wiring of the registry into the factory. `onlyAdmin`. */
|
|
51
|
+
export const _addRegistryAddress = async (client, registryContractAddress) => {
|
|
52
|
+
const chainID = await client.getChainId();
|
|
53
|
+
const rpcURL = client.transport.url;
|
|
54
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
55
|
+
if (!client.account)
|
|
56
|
+
throw new MissingEOAWalletError();
|
|
57
|
+
return client.writeContract({
|
|
58
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
59
|
+
chain: values.chain,
|
|
60
|
+
account: client.account.address,
|
|
61
|
+
abi: DeviceWalletFactory,
|
|
62
|
+
functionName: 'addRegistryAddress',
|
|
63
|
+
args: [registryContractAddress]
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
/** Update the vault that receives eSIM payments. `onlyAdmin`. */
|
|
67
|
+
export const _updateVaultAddress = async (client, newVaultAddress) => {
|
|
68
|
+
const chainID = await client.getChainId();
|
|
69
|
+
const rpcURL = client.transport.url;
|
|
70
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
71
|
+
if (!client.account)
|
|
72
|
+
throw new MissingEOAWalletError();
|
|
73
|
+
return client.writeContract({
|
|
74
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
75
|
+
chain: values.chain,
|
|
76
|
+
account: client.account.address,
|
|
77
|
+
abi: DeviceWalletFactory,
|
|
78
|
+
functionName: 'updateVaultAddress',
|
|
79
|
+
args: [newVaultAddress]
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
/** Step 1 of the 2-step admin handover: propose a new admin. `onlyAdmin`. */
|
|
83
|
+
export const _requestAdminUpdate = async (client, newAdmin) => {
|
|
84
|
+
const chainID = await client.getChainId();
|
|
85
|
+
const rpcURL = client.transport.url;
|
|
86
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
87
|
+
if (!client.account)
|
|
88
|
+
throw new MissingEOAWalletError();
|
|
89
|
+
return client.writeContract({
|
|
90
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
91
|
+
chain: values.chain,
|
|
92
|
+
account: client.account.address,
|
|
93
|
+
abi: DeviceWalletFactory,
|
|
94
|
+
functionName: 'requestAdminUpdate',
|
|
95
|
+
args: [newAdmin]
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Step 2 of the 2-step admin handover: the proposed admin accepts. The chain
|
|
100
|
+
* requires `msg.sender` to equal the pending admin, so the `client` here must
|
|
101
|
+
* be the newly proposed admin EOA.
|
|
102
|
+
*/
|
|
103
|
+
export const _acceptAdminUpdate = async (client) => {
|
|
104
|
+
const chainID = await client.getChainId();
|
|
105
|
+
const rpcURL = client.transport.url;
|
|
106
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
107
|
+
if (!client.account)
|
|
108
|
+
throw new MissingEOAWalletError();
|
|
109
|
+
return client.writeContract({
|
|
110
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
111
|
+
chain: values.chain,
|
|
112
|
+
account: client.account.address,
|
|
113
|
+
abi: DeviceWalletFactory,
|
|
114
|
+
functionName: 'acceptAdminUpdate',
|
|
115
|
+
args: []
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
/** Point the device-wallet beacon at a new implementation. `onlyOwner` (upgradeManager). */
|
|
119
|
+
export const _updateDeviceWalletImplementation = async (client, newDeviceImpl) => {
|
|
120
|
+
const chainID = await client.getChainId();
|
|
121
|
+
const rpcURL = client.transport.url;
|
|
122
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
123
|
+
if (!client.account)
|
|
124
|
+
throw new MissingEOAWalletError();
|
|
125
|
+
return client.writeContract({
|
|
126
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
127
|
+
chain: values.chain,
|
|
128
|
+
account: client.account.address,
|
|
129
|
+
abi: DeviceWalletFactory,
|
|
130
|
+
functionName: 'updateDeviceWalletImplementation',
|
|
131
|
+
args: [newDeviceImpl]
|
|
132
|
+
});
|
|
133
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { _getChainSpecificConstants } from "../constants.js";
|
|
2
|
+
import { MissingEOAWalletError } from "../errors.js";
|
|
3
|
+
import { ESIMWallet } from "../../abis/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Admin-EOA logic targeting a specific `ESIMWallet` instance (address passed in).
|
|
6
|
+
* `buyDataBundle` is `onlyDeviceWalletOrESIMWalletAdmin`, so the admin EOA can
|
|
7
|
+
* call it directly.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Buy a data bundle for an eSIM wallet. `onlyDeviceWalletOrESIMWalletAdmin`,
|
|
11
|
+
* `payable`. `value` is optional: the contract pulls any shortfall from the
|
|
12
|
+
* device wallet's balance, so an admin can pass `0n` when the wallet is funded,
|
|
13
|
+
* or forward `dataBundlePrice` to pay directly.
|
|
14
|
+
*/
|
|
15
|
+
export const _buyDataBundle = async (client, eSIMWalletAddress, dataBundleDetails, value = 0n) => {
|
|
16
|
+
const chainID = await client.getChainId();
|
|
17
|
+
const rpcURL = client.transport.url;
|
|
18
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
19
|
+
if (!client.account)
|
|
20
|
+
throw new MissingEOAWalletError();
|
|
21
|
+
return client.writeContract({
|
|
22
|
+
address: eSIMWalletAddress,
|
|
23
|
+
chain: values.chain,
|
|
24
|
+
account: client.account.address,
|
|
25
|
+
abi: ESIMWallet,
|
|
26
|
+
functionName: 'buyDataBundle',
|
|
27
|
+
args: [dataBundleDetails],
|
|
28
|
+
value
|
|
29
|
+
});
|
|
30
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { _getChainSpecificConstants } from "../constants.js";
|
|
2
|
+
import { MissingEOAWalletError } from "../errors.js";
|
|
3
|
+
import { ESIMWalletFactory } from "../../abis/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Admin-EOA logic for `ESIMWalletFactory`. Both functions are owner-gated
|
|
6
|
+
* (`addRegistryAddress` requires `msg.sender == owner()`, `updateESIMWalletImplementation`
|
|
7
|
+
* is `onlyOwner`), so the `client` must carry the `upgradeManager` EOA.
|
|
8
|
+
*
|
|
9
|
+
* Note: `ESIMWalletFactory.deployESIMWallet` is intentionally NOT exposed - it is
|
|
10
|
+
* `onlyRegistryOrDeviceWalletFactoryOrDeviceWallet`, so a bare EOA always reverts.
|
|
11
|
+
*/
|
|
12
|
+
/** One-time wiring of the registry into the eSIM factory. Owner only. */
|
|
13
|
+
export const _addRegistryAddress = async (client, registryContractAddress) => {
|
|
14
|
+
const chainID = await client.getChainId();
|
|
15
|
+
const rpcURL = client.transport.url;
|
|
16
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
17
|
+
if (!client.account)
|
|
18
|
+
throw new MissingEOAWalletError();
|
|
19
|
+
return client.writeContract({
|
|
20
|
+
address: values.factoryAddresses.ESIM_WALLET_FACTORY,
|
|
21
|
+
chain: values.chain,
|
|
22
|
+
account: client.account.address,
|
|
23
|
+
abi: ESIMWalletFactory,
|
|
24
|
+
functionName: 'addRegistryAddress',
|
|
25
|
+
args: [registryContractAddress]
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
/** Point the eSIM-wallet beacon at a new implementation. `onlyOwner`. */
|
|
29
|
+
export const _updateESIMWalletImplementation = async (client, eSIMWalletImpl) => {
|
|
30
|
+
const chainID = await client.getChainId();
|
|
31
|
+
const rpcURL = client.transport.url;
|
|
32
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
33
|
+
if (!client.account)
|
|
34
|
+
throw new MissingEOAWalletError();
|
|
35
|
+
return client.writeContract({
|
|
36
|
+
address: values.factoryAddresses.ESIM_WALLET_FACTORY,
|
|
37
|
+
chain: values.chain,
|
|
38
|
+
account: client.account.address,
|
|
39
|
+
abi: ESIMWalletFactory,
|
|
40
|
+
functionName: 'updateESIMWalletImplementation',
|
|
41
|
+
args: [eSIMWalletImpl]
|
|
42
|
+
});
|
|
43
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { _getChainSpecificConstants } from "../constants.js";
|
|
2
|
+
import { MissingEOAWalletError } from "../errors.js";
|
|
3
|
+
import { LazyWalletRegistry } from "../../abis/index.js";
|
|
4
|
+
/**
|
|
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.
|
|
9
|
+
*/
|
|
10
|
+
/** Record fiat/lazy purchase history for a batch of devices. `onlyESIMWalletAdmin`. */
|
|
11
|
+
export const _batchPopulateHistory = async (client, deviceUniqueIdentifiers, eSIMUniqueIdentifiers, dataBundleDetails) => {
|
|
12
|
+
const chainID = await client.getChainId();
|
|
13
|
+
const rpcURL = client.transport.url;
|
|
14
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
15
|
+
if (!client.account)
|
|
16
|
+
throw new MissingEOAWalletError();
|
|
17
|
+
return client.writeContract({
|
|
18
|
+
address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
|
|
19
|
+
chain: values.chain,
|
|
20
|
+
account: client.account.address,
|
|
21
|
+
abi: LazyWalletRegistry,
|
|
22
|
+
functionName: 'batchPopulateHistory',
|
|
23
|
+
args: [deviceUniqueIdentifiers, eSIMUniqueIdentifiers, dataBundleDetails]
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
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.
|
|
30
|
+
*/
|
|
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);
|
|
35
|
+
if (!client.account)
|
|
36
|
+
throw new MissingEOAWalletError();
|
|
37
|
+
return client.writeContract({
|
|
38
|
+
address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
|
|
39
|
+
chain: values.chain,
|
|
40
|
+
account: client.account.address,
|
|
41
|
+
abi: LazyWalletRegistry,
|
|
42
|
+
functionName: 'deployLazyWalletAndSetESIMIdentifier',
|
|
43
|
+
args: [deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount],
|
|
44
|
+
value: depositAmount
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
/** Re-point an eSIM identifier from an old device to a new one. `onlyESIMWalletAdmin`. */
|
|
48
|
+
export const _switchESIMIdentifierToNewDeviceIdentifier = async (client, eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier) => {
|
|
49
|
+
const chainID = await client.getChainId();
|
|
50
|
+
const rpcURL = client.transport.url;
|
|
51
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
52
|
+
if (!client.account)
|
|
53
|
+
throw new MissingEOAWalletError();
|
|
54
|
+
return client.writeContract({
|
|
55
|
+
address: values.factoryAddresses.LAZY_WALLET_REGISTRY,
|
|
56
|
+
chain: values.chain,
|
|
57
|
+
account: client.account.address,
|
|
58
|
+
abi: LazyWalletRegistry,
|
|
59
|
+
functionName: 'switchESIMIdentifierToNewDeviceIdentifier',
|
|
60
|
+
args: [eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier]
|
|
61
|
+
});
|
|
62
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { publicActions } from "viem";
|
|
2
|
+
import { DeviceWallet } from "../../../abis/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read-only admin logic targeting a specific `DeviceWallet` instance (its address
|
|
5
|
+
* is passed in). Surfaces the instance's public storage getters + `getVaultAddress`
|
|
6
|
+
* view for the backend. Each read extends the `WalletClient` with `publicActions`;
|
|
7
|
+
* no EOA account is required, and the target is the instance address (not a
|
|
8
|
+
* factory address, so no chain-constants lookup is needed).
|
|
9
|
+
*/
|
|
10
|
+
/** The device's unique identifier string. */
|
|
11
|
+
export const _deviceUniqueIdentifier = async (client, deviceWalletAddress) => {
|
|
12
|
+
return client.extend(publicActions).readContract({
|
|
13
|
+
address: deviceWalletAddress,
|
|
14
|
+
abi: DeviceWallet,
|
|
15
|
+
functionName: "deviceUniqueIdentifier",
|
|
16
|
+
args: []
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
/** Whether an eSIM wallet is a valid child of this device wallet. */
|
|
20
|
+
export const _isValidESIMWallet = async (client, deviceWalletAddress, eSIMWallet) => {
|
|
21
|
+
return client.extend(publicActions).readContract({
|
|
22
|
+
address: deviceWalletAddress,
|
|
23
|
+
abi: DeviceWallet,
|
|
24
|
+
functionName: "isValidESIMWallet",
|
|
25
|
+
args: [eSIMWallet]
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
/** Whether an eSIM wallet is allowed to pull ETH from this device wallet. */
|
|
29
|
+
export const _canPullETH = async (client, deviceWalletAddress, eSIMWallet) => {
|
|
30
|
+
return client.extend(publicActions).readContract({
|
|
31
|
+
address: deviceWalletAddress,
|
|
32
|
+
abi: DeviceWallet,
|
|
33
|
+
functionName: "canPullETH",
|
|
34
|
+
args: [eSIMWallet]
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
/** The vault address this device wallet pays eSIM purchases to. */
|
|
38
|
+
export const _getVaultAddress = async (client, deviceWalletAddress) => {
|
|
39
|
+
return client.extend(publicActions).readContract({
|
|
40
|
+
address: deviceWalletAddress,
|
|
41
|
+
abi: DeviceWallet,
|
|
42
|
+
functionName: "getVaultAddress",
|
|
43
|
+
args: []
|
|
44
|
+
});
|
|
45
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { publicActions } from "viem";
|
|
2
|
+
import { _getChainSpecificConstants } from "../../constants.js";
|
|
3
|
+
import { DeviceWalletFactory } from "../../../abis/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Read-only admin logic for `DeviceWalletFactory` - the contract's public
|
|
6
|
+
* storage getters and `view` functions, surfaced for the backend.
|
|
7
|
+
*
|
|
8
|
+
* A viem `WalletClient` carries no public actions, so each read extends it with
|
|
9
|
+
* `publicActions` (reusing the same transport, so it also works under an anvil
|
|
10
|
+
* fork) before calling `readContract`. Reads need no EOA account, so there is no
|
|
11
|
+
* `MissingEOAWalletError` guard.
|
|
12
|
+
*/
|
|
13
|
+
/** The admin EOA (`eSIMWalletAdmin`) currently set on the factory. */
|
|
14
|
+
export const _eSIMWalletAdmin = async (client) => {
|
|
15
|
+
const chainID = await client.getChainId();
|
|
16
|
+
const rpcURL = client.transport.url;
|
|
17
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
18
|
+
return client.extend(publicActions).readContract({
|
|
19
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
20
|
+
abi: DeviceWalletFactory,
|
|
21
|
+
functionName: "eSIMWalletAdmin",
|
|
22
|
+
args: []
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
/** The vault EOA that receives eSIM payments. */
|
|
26
|
+
export const _vault = async (client) => {
|
|
27
|
+
const chainID = await client.getChainId();
|
|
28
|
+
const rpcURL = client.transport.url;
|
|
29
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
30
|
+
return client.extend(publicActions).readContract({
|
|
31
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
32
|
+
abi: DeviceWalletFactory,
|
|
33
|
+
functionName: "vault",
|
|
34
|
+
args: []
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
/** The pending admin proposed via `requestAdminUpdate` (zero address if none). */
|
|
38
|
+
export const _newRequestedAdmin = async (client) => {
|
|
39
|
+
const chainID = await client.getChainId();
|
|
40
|
+
const rpcURL = client.transport.url;
|
|
41
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
42
|
+
return client.extend(publicActions).readContract({
|
|
43
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
44
|
+
abi: DeviceWalletFactory,
|
|
45
|
+
functionName: "newRequestedAdmin",
|
|
46
|
+
args: []
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
/** Whether a device wallet has been registered with the factory. */
|
|
50
|
+
export const _deviceWalletInfoAdded = async (client, deviceWallet) => {
|
|
51
|
+
const chainID = await client.getChainId();
|
|
52
|
+
const rpcURL = client.transport.url;
|
|
53
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
54
|
+
return client.extend(publicActions).readContract({
|
|
55
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
56
|
+
abi: DeviceWalletFactory,
|
|
57
|
+
functionName: "deviceWalletInfoAdded",
|
|
58
|
+
args: [deviceWallet]
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
/** The current device-wallet beacon implementation. */
|
|
62
|
+
export const _getCurrentDeviceWalletImplementation = async (client) => {
|
|
63
|
+
const chainID = await client.getChainId();
|
|
64
|
+
const rpcURL = client.transport.url;
|
|
65
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
66
|
+
return client.extend(publicActions).readContract({
|
|
67
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
68
|
+
abi: DeviceWalletFactory,
|
|
69
|
+
functionName: "getCurrentDeviceWalletImplementation",
|
|
70
|
+
args: []
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* The counterfactual (CREATE2) device-wallet address for an owner key. On-chain
|
|
75
|
+
* arg order is `(ownerKey, uid, salt)` - note this differs from `createAccount`.
|
|
76
|
+
*/
|
|
77
|
+
export const _getCounterFactualAddress = async (client, deviceWalletOwnerKey, deviceUniqueIdentifier, salt) => {
|
|
78
|
+
const chainID = await client.getChainId();
|
|
79
|
+
const rpcURL = client.transport.url;
|
|
80
|
+
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
81
|
+
return client.extend(publicActions).readContract({
|
|
82
|
+
address: values.factoryAddresses.DEVICE_WALLET_FACTORY,
|
|
83
|
+
abi: DeviceWalletFactory,
|
|
84
|
+
functionName: "getCounterFactualAddress",
|
|
85
|
+
args: [deviceWalletOwnerKey, deviceUniqueIdentifier, salt]
|
|
86
|
+
});
|
|
87
|
+
};
|