kokio-sdk 0.1.3 → 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 +18 -2
- package/dist/esm/interface/constantsClass.js +33 -10
- 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 +78 -27
- 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 +14 -2
- package/dist/types/interface/P256VerifierClass.d.ts +2 -1
- package/dist/types/interface/constantsClass.d.ts +23 -3
- 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 +17 -4
- package/dist/esm/interface/utilsClass.js +0 -13
- package/dist/types/interface/utilsClass.d.ts +0 -2567
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _deployESIMWalletWithUserOp, _getCurrentESIMWalletImplementation } from "../logic/eSIMWalletFactory.js";
|
|
2
2
|
export class ESIMWalletFactorySubPackage {
|
|
3
3
|
smartAccountClient;
|
|
4
4
|
walletClient;
|
|
@@ -6,16 +6,10 @@ export class ESIMWalletFactorySubPackage {
|
|
|
6
6
|
this.smartAccountClient = smartAccountClient;
|
|
7
7
|
this.walletClient = walletClient;
|
|
8
8
|
}
|
|
9
|
-
deployESIMWalletWithEOA(deviceWalletAddress, salt) {
|
|
10
|
-
return _deployESIMWalletWithEOA(this.walletClient, deviceWalletAddress, salt);
|
|
11
|
-
}
|
|
12
9
|
deployESIMWalletWithUserOp(deviceWalletAddress, salt) {
|
|
13
10
|
return _deployESIMWalletWithUserOp(this.smartAccountClient, deviceWalletAddress, salt);
|
|
14
11
|
}
|
|
15
|
-
|
|
16
|
-
return _addRegistryAddress(this.smartAccountClient, registryContractAddress);
|
|
17
|
-
}
|
|
18
|
-
_getCurrentESIMWalletImplementation() {
|
|
12
|
+
getCurrentESIMWalletImplementation() {
|
|
19
13
|
return _getCurrentESIMWalletImplementation(this.smartAccountClient);
|
|
20
14
|
}
|
|
21
15
|
}
|
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _isLazyWalletDeployed } from "../logic/lazyWalletRegistry.js";
|
|
2
2
|
export class LazyWalletRegistrySubPackage {
|
|
3
3
|
client;
|
|
4
4
|
constructor(client) {
|
|
5
5
|
this.client = client;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
return _batchPopulateHistory(this.client, deviceUniqueIdentifiers, eSIMUniqueIdentifiers, dataBundleDetails);
|
|
9
|
-
}
|
|
10
|
-
_deployLazyWalletAndSetESIMIdentifier(deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount) {
|
|
11
|
-
return _deployLazyWalletAndSetESIMIdentifier(this.client, deviceOwnerPublicKey, deviceUniqueIdentifier, salt, depositAmount);
|
|
12
|
-
}
|
|
13
|
-
_isLazyWalletDeployed(deviceUniqueIdentifier) {
|
|
7
|
+
isLazyWalletDeployed(deviceUniqueIdentifier) {
|
|
14
8
|
return _isLazyWalletDeployed(this.client, deviceUniqueIdentifier);
|
|
15
9
|
}
|
|
16
|
-
_switchESIMIdentifierToNewDeviceIdentifier(eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier) {
|
|
17
|
-
return _switchESIMIdentifierToNewDeviceIdentifier(this.client, eSIMIdentifier, oldDeviceIdentifier, newDeviceIdentifier);
|
|
18
|
-
}
|
|
19
10
|
}
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { _getChainSpecificConstants, customErrors } from "./constants.js";
|
|
1
|
+
import { _getChainSpecificConstants } from "./constants.js";
|
|
3
2
|
import { P256Verifier } from "../abis/index.js";
|
|
3
|
+
// `verifySignature` is a `view` - read it directly instead of spending a userOp
|
|
4
|
+
// (the previous userOp form returned a userOp hash, never the boolean result).
|
|
4
5
|
export const _verifySignature = async (client, message, requireMessageVerification, webAuthnSignature, x, y) => {
|
|
5
6
|
const chainID = await client.getChainId();
|
|
6
7
|
const rpcURL = client.transport.url;
|
|
7
8
|
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
uo: {
|
|
14
|
-
target: values.factoryAddresses.P256VERIFIER,
|
|
15
|
-
data: encodeFunctionData({
|
|
16
|
-
abi: P256Verifier,
|
|
17
|
-
functionName: "verifySignature",
|
|
18
|
-
args: [message, requireMessageVerification, webAuthnSignature, x, y]
|
|
19
|
-
})
|
|
20
|
-
}
|
|
9
|
+
return client.readContract({
|
|
10
|
+
address: values.factoryAddresses.P256VERIFIER,
|
|
11
|
+
abi: P256Verifier,
|
|
12
|
+
functionName: "verifySignature",
|
|
13
|
+
args: [message, requireMessageVerification, webAuthnSignature, x, y]
|
|
21
14
|
});
|
|
22
15
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createSmartAccountClient, getEntryPoint, toSmartContractAccount, split } from "@aa-sdk/core";
|
|
2
|
-
import { http, encodeFunctionData, encodePacked, encodeAbiParameters, parseAbiParameters, getContract, concat, keccak256, getContractAddress, getAddress, hashMessage,
|
|
1
|
+
import { createSmartAccountClient, getEntryPoint, toSmartContractAccount, split, erc7677Middleware } from "@aa-sdk/core";
|
|
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
|
-
import { alchemyGasManagerMiddleware } from "@account-kit/infra";
|
|
7
7
|
import { isoBase64URL } from "@simplewebauthn/server/helpers";
|
|
8
8
|
import { Passkey } from "react-native-passkey";
|
|
9
9
|
import { p256 } from "@noble/curves/nist.js";
|
|
@@ -16,6 +16,22 @@ var AuthenticatorTransport;
|
|
|
16
16
|
AuthenticatorTransport["hybrid"] = "hybrid";
|
|
17
17
|
AuthenticatorTransport["internal"] = "internal";
|
|
18
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";
|
|
19
35
|
/*
|
|
20
36
|
** Stamp is client-side authentication. Since the passkeys are one the user's mobile device
|
|
21
37
|
** react-native-passkey helps fetch passkey for the user (provided credentialId, rpId).
|
|
@@ -23,7 +39,10 @@ var AuthenticatorTransport;
|
|
|
23
39
|
*/
|
|
24
40
|
export const _stamp = async (credentialId, rpId, payload) => {
|
|
25
41
|
const signingOptions = {
|
|
26
|
-
|
|
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))),
|
|
27
46
|
allowCredentials: [{
|
|
28
47
|
id: credentialId,
|
|
29
48
|
type: "public-key",
|
|
@@ -120,7 +139,7 @@ const _encodeBatchExecute = async (txs) => {
|
|
|
120
139
|
args: [new_txs]
|
|
121
140
|
});
|
|
122
141
|
};
|
|
123
|
-
const _getAccountInitCode = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
142
|
+
export const _getAccountInitCode = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
124
143
|
// To send with user operations
|
|
125
144
|
const chainID = await client.getChainId();
|
|
126
145
|
const rpcURL = client.transport.url;
|
|
@@ -132,7 +151,7 @@ const _getAccountInitCode = async (client, deviceUniqueIdentifier, deviceWalletO
|
|
|
132
151
|
});
|
|
133
152
|
return values.factoryAddresses.DEVICE_WALLET_FACTORY.concat(_remove0x(callData));
|
|
134
153
|
};
|
|
135
|
-
const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey) => {
|
|
154
|
+
export const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey) => {
|
|
136
155
|
const chainID = await client.getChainId();
|
|
137
156
|
const rpcURL = client.transport.url;
|
|
138
157
|
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
@@ -145,7 +164,7 @@ const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwner
|
|
|
145
164
|
address: deviceWalletFactoryAddress,
|
|
146
165
|
client
|
|
147
166
|
});
|
|
148
|
-
const beacon = await deviceWalletFactory.read.beacon(
|
|
167
|
+
const beacon = await deviceWalletFactory.read.beacon();
|
|
149
168
|
// Encode the DeviceWallet.init with the init params
|
|
150
169
|
const deviceWalletInitData = encodeFunctionData({
|
|
151
170
|
abi: DeviceWallet,
|
|
@@ -157,14 +176,13 @@ const getInitCodeHash = async (client, deviceUniqueIdentifier, deviceWalletOwner
|
|
|
157
176
|
eSIMWalletFactoryAddress
|
|
158
177
|
]
|
|
159
178
|
});
|
|
160
|
-
const beaconProxyBytecode = "0x60a06040908082526104a8803803809161001982856102ae565b8339810182828203126101e95761002f826102e7565b60208084015191939091906001600160401b0382116101e9570182601f820112156101e957805190610060826102fb565b9361006d875195866102ae565b8285528383830101116101e957829060005b83811061029a57505060009184010152823b1561027a577fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b038581169182179092558551635c60da1b60e01b8082529194928482600481895afa91821561026f57600092610238575b50813b1561021f5750508551847f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e600080a282511561020057508290600487518096819382525afa9283156101f5576000936101b3575b5091600080848461019096519101845af4903d156101aa573d610174816102fb565b90610181885192836102ae565b8152600081943d92013e610316565b505b6080525161012e908161037a82396080518160180152f35b60609250610316565b92508183813d83116101ee575b6101ca81836102ae565b810103126101e9576000806101e1610190956102e7565b945050610152565b600080fd5b503d6101c0565b85513d6000823e3d90fd5b9350505050346102105750610192565b63b398979f60e01b8152600490fd5b8751634c9c8ce360e01b81529116600482015260249150fd5b9091508481813d8311610268575b61025081836102ae565b810103126101e957610261906102e7565b90386100fb565b503d610246565b88513d6000823e3d90fd5b8351631933b43b60e21b81526001600160a01b0384166004820152602490fd5b81810183015186820184015284920161007f565b601f909101601f19168101906001600160401b038211908210176102d157604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101e957565b6001600160401b0381116102d157601f01601f191660200190565b9061033d575080511561032b57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580610370575b61034e575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561034656fe60806040819052635c60da1b60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811560a9576000916054575b5060da565b905060203d60201160a3575b601f8101601f191682019167ffffffffffffffff831181841017608d576088926040520160b5565b38604f565b634e487b7160e01b600052604160045260246000fd5b503d6060565b6040513d6000823e3d90fd5b602090607f19011260d5576080516001600160a01b038116810360d55790565b600080fd5b6000808092368280378136915af43d82803e1560f4573d90f35b3d90fdfea264697066735822122099ba460fd62b3e22c737d15959887e6cae3498f3495d31e43e2bcf1283aec7d264736f6c63430008190033";
|
|
161
179
|
// Encode BeaconProxy constructor args
|
|
162
180
|
const beaconProxyConstructorArgs = encodeAbiParameters(parseAbiParameters("address, bytes"), [beacon, deviceWalletInitData]);
|
|
163
181
|
// Compute initCode
|
|
164
|
-
const initCode = concat([
|
|
182
|
+
const initCode = concat([BEACON_PROXY_CREATION_CODE, beaconProxyConstructorArgs]);
|
|
165
183
|
return keccak256(initCode);
|
|
166
184
|
};
|
|
167
|
-
const getCounterFactualAddress = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
185
|
+
export const getCounterFactualAddress = async (client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt) => {
|
|
168
186
|
const chainID = await client.getChainId();
|
|
169
187
|
const rpcURL = client.transport.url;
|
|
170
188
|
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
@@ -180,7 +198,41 @@ const getCounterFactualAddress = async (client, deviceUniqueIdentifier, deviceWa
|
|
|
180
198
|
});
|
|
181
199
|
return getAddress(create2Address);
|
|
182
200
|
};
|
|
183
|
-
|
|
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) => {
|
|
184
236
|
const encodedWebAuthnSignatureBytes = encodeAbiParameters([
|
|
185
237
|
{
|
|
186
238
|
type: "tuple",
|
|
@@ -201,30 +253,30 @@ const _encodeSignature = async (webAuthnSignature, validUntil) => {
|
|
|
201
253
|
return signature;
|
|
202
254
|
};
|
|
203
255
|
// message here is the original message data (string or Uint8Array) directly from the app
|
|
204
|
-
const _signMessage = async (message, credentialId, rpId) => {
|
|
256
|
+
export const _signMessage = async (message, credentialId, rpId) => {
|
|
205
257
|
const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
|
|
206
|
-
|
|
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);
|
|
207
263
|
// The original message is passed to the stamp and sign function.
|
|
208
264
|
// The stamp and sign function creates the EIP-191 digest hash using its hashMessage function
|
|
209
265
|
// The result of the hashMessage(message) will be the `payload` used as a challenge
|
|
210
266
|
const webAuthnSignature = await _stamp(credentialId, rpId, payload);
|
|
211
267
|
return _encodeSignature(webAuthnSignature, validUntil);
|
|
212
268
|
};
|
|
213
|
-
const _signTypedData = async (typedData,
|
|
269
|
+
export const _signTypedData = async (typedData, credentialId, rpId) => {
|
|
214
270
|
// signature valid until, UNIX timestamp in seconds
|
|
215
271
|
const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
typeIndex: BigInt(0),
|
|
222
|
-
r: BigInt(0),
|
|
223
|
-
s: BigInt(0)
|
|
224
|
-
};
|
|
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);
|
|
225
277
|
return _encodeSignature(webAuthnSignature, validUntil);
|
|
226
278
|
};
|
|
227
|
-
const _signUserOperationHash = async (credentialId, rpId, userOpHash) => {
|
|
279
|
+
export const _signUserOperationHash = async (credentialId, rpId, userOpHash) => {
|
|
228
280
|
const validUntil = Math.floor(Date.now() / 1000) + SIGNATURE_VALIDITY_SECONDS;
|
|
229
281
|
const messagePrecursor = encodePacked(["uint8", "uint48", "bytes32"], [
|
|
230
282
|
1,
|
|
@@ -241,7 +293,6 @@ export const _getSmartWallet = async (client, credentialId, rpId, organiationId,
|
|
|
241
293
|
const values = _getChainSpecificConstants(chainID, rpcURL);
|
|
242
294
|
if (!client.account)
|
|
243
295
|
throw new Error('Error: No signer account found with WalletClient');
|
|
244
|
-
const signWith = client.account.address;
|
|
245
296
|
return toSmartContractAccount({
|
|
246
297
|
/// REQUIRED PARAMS ///
|
|
247
298
|
source: "MyAccount",
|
|
@@ -256,7 +307,7 @@ export const _getSmartWallet = async (client, credentialId, rpId, organiationId,
|
|
|
256
307
|
// given a UO in the form of {target, data, value} should output the calldata for calling your contract's execution method
|
|
257
308
|
encodeExecute: async (uo) => _encodeExecute(uo),
|
|
258
309
|
signMessage: async ({ message }) => _signMessage(message, credentialId, rpId),
|
|
259
|
-
signTypedData: async (typedData) => _signTypedData(typedData,
|
|
310
|
+
signTypedData: async (typedData) => _signTypedData(typedData, credentialId, rpId),
|
|
260
311
|
/// OPTIONAL PARAMS ///
|
|
261
312
|
// if you already know your account's address, pass that in here to avoid generating a new counterfactual
|
|
262
313
|
accountAddress: await getCounterFactualAddress(client, deviceUniqueIdentifier, deviceWalletOwnerKey, salt),
|
|
@@ -294,6 +345,6 @@ export const _getSmartWalletClient = async (client, pimlicoAPIKey, gasPolicyId,
|
|
|
294
345
|
fallback: http(values.rpcURL),
|
|
295
346
|
}),
|
|
296
347
|
// transport: http(values.rpcURL),
|
|
297
|
-
...
|
|
348
|
+
...erc7677Middleware({ context: { policyId: gasPolicyId } })
|
|
298
349
|
});
|
|
299
350
|
};
|
|
@@ -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
|
+
};
|