x402z-shared 0.0.1 → 0.0.3

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 CHANGED
@@ -53,6 +53,10 @@ const result = await viewConfidentialBalance({
53
53
  console.log(result.balance?.toString());
54
54
  ```
55
55
 
56
+ Notes:
57
+ - Balance decryption is allowed for the account or its `observer` (ERC7984ObserverAccess).
58
+ - Unauthorized observer errors throw `confidentialErrorCodes.observerNotAuthorized` (`ConfidentialErrorCode`).
59
+
56
60
  ## Transfer amount helper (Node)
57
61
 
58
62
  ```ts
@@ -70,6 +74,39 @@ const transfers = await viewConfidentialTransferAmounts({
70
74
  console.log(transfers[0]?.amount?.toString());
71
75
  ```
72
76
 
77
+ Notes:
78
+ - Transfer amount decryption is allowed for `holder`, `payee`, or an `observer` set via `ERC7984ObserverAccess`.
79
+ - Unauthorized observer errors throw `confidentialErrorCodes.observerNotAuthorized` (`ConfidentialErrorCode`).
80
+
81
+ ## Observer helper (Node)
82
+
83
+ ```ts
84
+ import { setObserver } from "x402z-shared";
85
+
86
+ const txHash = await setObserver({
87
+ rpcUrl: "https://sepolia.infura.io/v3/...",
88
+ tokenAddress: "0xToken",
89
+ account: "0xHolder",
90
+ observer: "0xObserver",
91
+ signer,
92
+ });
93
+ console.log(txHash);
94
+ ```
95
+
96
+ ## Observer helper (Browser)
97
+
98
+ ```ts
99
+ import { setObserverWeb } from "x402z-shared/web";
100
+
101
+ const txHash = await setObserverWeb({
102
+ tokenAddress: "0xToken",
103
+ account: "0xHolder",
104
+ observer: "0xObserver",
105
+ walletClient,
106
+ });
107
+ console.log(txHash);
108
+ ```
109
+
73
110
  ## Balance helper (Browser)
74
111
 
75
112
  ```ts
@@ -0,0 +1,156 @@
1
+ // src/abi.ts
2
+ var confidentialTokenAbi = [
3
+ {
4
+ inputs: [
5
+ {
6
+ components: [
7
+ { internalType: "address", name: "holder", type: "address" },
8
+ { internalType: "address", name: "payee", type: "address" },
9
+ { internalType: "uint256", name: "maxClearAmount", type: "uint256" },
10
+ { internalType: "bytes32", name: "resourceHash", type: "bytes32" },
11
+ { internalType: "uint48", name: "validAfter", type: "uint48" },
12
+ { internalType: "uint48", name: "validBefore", type: "uint48" },
13
+ { internalType: "bytes32", name: "nonce", type: "bytes32" },
14
+ { internalType: "bytes32", name: "encryptedAmountHash", type: "bytes32" }
15
+ ],
16
+ internalType: "struct FHEToken.ConfidentialPayment",
17
+ name: "p",
18
+ type: "tuple"
19
+ },
20
+ { internalType: "externalEuint64", name: "encryptedAmountInput", type: "bytes32" },
21
+ { internalType: "bytes", name: "inputProof", type: "bytes" },
22
+ { internalType: "bytes", name: "sig", type: "bytes" }
23
+ ],
24
+ name: "confidentialTransferWithAuthorization",
25
+ outputs: [{ internalType: "euint64", name: "transferred", type: "bytes32" }],
26
+ stateMutability: "nonpayable",
27
+ type: "function"
28
+ },
29
+ {
30
+ anonymous: false,
31
+ inputs: [
32
+ { indexed: true, internalType: "address", name: "holder", type: "address" },
33
+ { indexed: true, internalType: "address", name: "payee", type: "address" },
34
+ { indexed: false, internalType: "uint256", name: "maxClearAmount", type: "uint256" },
35
+ { indexed: true, internalType: "bytes32", name: "resourceHash", type: "bytes32" },
36
+ { indexed: false, internalType: "bytes32", name: "nonce", type: "bytes32" },
37
+ { indexed: false, internalType: "bytes32", name: "transferredAmount", type: "bytes32" }
38
+ ],
39
+ name: "ConfidentialPaymentExecuted",
40
+ type: "event"
41
+ },
42
+ {
43
+ inputs: [
44
+ { internalType: "address", name: "", type: "address" },
45
+ { internalType: "bytes32", name: "", type: "bytes32" }
46
+ ],
47
+ name: "usedNonces",
48
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
49
+ stateMutability: "view",
50
+ type: "function"
51
+ },
52
+ {
53
+ inputs: [{ internalType: "address", name: "account", type: "address" }],
54
+ name: "observer",
55
+ outputs: [{ internalType: "address", name: "", type: "address" }],
56
+ stateMutability: "view",
57
+ type: "function"
58
+ },
59
+ {
60
+ inputs: [
61
+ { internalType: "address", name: "account", type: "address" },
62
+ { internalType: "address", name: "newObserver", type: "address" }
63
+ ],
64
+ name: "setObserver",
65
+ outputs: [],
66
+ stateMutability: "nonpayable",
67
+ type: "function"
68
+ }
69
+ ];
70
+
71
+ // src/constants.ts
72
+ var confidentialPaymentTypes = {
73
+ ConfidentialPayment: [
74
+ { name: "holder", type: "address" },
75
+ { name: "payee", type: "address" },
76
+ { name: "maxClearAmount", type: "uint256" },
77
+ { name: "resourceHash", type: "bytes32" },
78
+ { name: "validAfter", type: "uint48" },
79
+ { name: "validBefore", type: "uint48" },
80
+ { name: "nonce", type: "bytes32" },
81
+ { name: "encryptedAmountHash", type: "bytes32" }
82
+ ]
83
+ };
84
+ var confidentialErrorCodes = {
85
+ observerNotAuthorized: "observer_not_authorized"
86
+ };
87
+
88
+ // src/utils.ts
89
+ import { encodeAbiParameters, keccak256, toHex } from "viem";
90
+ function createNonce() {
91
+ const cryptoObj = typeof globalThis.crypto !== "undefined" ? globalThis.crypto : globalThis.crypto;
92
+ if (!cryptoObj) {
93
+ throw new Error("Crypto API not available");
94
+ }
95
+ return toHex(cryptoObj.getRandomValues(new Uint8Array(32)));
96
+ }
97
+ function hashEncryptedAmountInput(encryptedAmountInput) {
98
+ return keccak256(
99
+ encodeAbiParameters([{ type: "bytes32" }], [encryptedAmountInput])
100
+ );
101
+ }
102
+ function normalizeAmount(amount) {
103
+ if (typeof amount === "string") {
104
+ return amount;
105
+ }
106
+ if (typeof amount === "number") {
107
+ if (!Number.isFinite(amount)) {
108
+ throw new Error("Invalid amount");
109
+ }
110
+ return Math.trunc(amount).toString();
111
+ }
112
+ return amount.toString();
113
+ }
114
+
115
+ // src/observer.ts
116
+ import { createPublicClient, getAddress, http, isAddress } from "viem";
117
+ async function setObserver(options) {
118
+ if (!isAddress(options.tokenAddress)) {
119
+ throw new Error(`Invalid token address: ${options.tokenAddress}`);
120
+ }
121
+ if (!isAddress(options.account)) {
122
+ throw new Error(`Invalid account address: ${options.account}`);
123
+ }
124
+ if (!isAddress(options.observer)) {
125
+ throw new Error(`Invalid observer address: ${options.observer}`);
126
+ }
127
+ const tokenAddress = getAddress(options.tokenAddress);
128
+ const account = getAddress(options.account);
129
+ const observer = getAddress(options.observer);
130
+ const publicClient = createPublicClient({ transport: http(options.rpcUrl) });
131
+ const existing = await publicClient.readContract({
132
+ address: tokenAddress,
133
+ abi: confidentialTokenAbi,
134
+ functionName: "observer",
135
+ args: [account]
136
+ });
137
+ if (existing && isAddress(existing) && getAddress(existing) === observer) {
138
+ return "0x" + "00".repeat(32);
139
+ }
140
+ return options.signer.writeContract({
141
+ address: tokenAddress,
142
+ abi: confidentialTokenAbi,
143
+ functionName: "setObserver",
144
+ args: [account, observer]
145
+ });
146
+ }
147
+
148
+ export {
149
+ confidentialTokenAbi,
150
+ confidentialPaymentTypes,
151
+ confidentialErrorCodes,
152
+ createNonce,
153
+ hashEncryptedAmountInput,
154
+ normalizeAmount,
155
+ setObserver
156
+ };
package/dist/index.d.mts CHANGED
@@ -1,38 +1,7 @@
1
- export { C as ConfidentialPaymentAuthorization, f as ConfidentialPaymentInput, d as ConfidentialPaymentPayload, e as ConfidentialRequirementsExtra, a as confidentialPaymentTypes, c as confidentialTokenAbi, b as createNonce, h as hashEncryptedAmountInput, n as normalizeAmount } from './types-RdcpJuhT.mjs';
2
- import { createInstance } from '@zama-fhe/relayer-sdk/node';
3
- export { SepoliaConfig } from '@zama-fhe/relayer-sdk/node';
1
+ import { R as RelayerInstance, a as RelayerSigner } from './types-gx3OAvqG.mjs';
2
+ export { C as ConfidentialErrorCode, i as ConfidentialPaymentAuthorization, l as ConfidentialPaymentInput, j as ConfidentialPaymentPayload, k as ConfidentialRequirementsExtra, S as SetObserverOptions, d as confidentialErrorCodes, b as confidentialPaymentTypes, c as confidentialTokenAbi, g as createEncryptedAmountInput, e as createNonce, f as createRelayerInstance, h as hashEncryptedAmountInput, n as normalizeAmount, p as publicDecrypt, s as setObserver, u as userDecryptEuint64 } from './types-gx3OAvqG.mjs';
4
3
  export * from '@x402/core/types';
5
-
6
- type RelayerInstance = Awaited<ReturnType<typeof createInstance>>;
7
- type RelayerSigner = {
8
- address: string;
9
- signTypedData: ((domain: Record<string, unknown>, types: Record<string, Array<{
10
- name: string;
11
- type: string;
12
- }>>, message: Record<string, unknown>) => Promise<string>) | ((args: {
13
- domain: Record<string, unknown>;
14
- types: Record<string, Array<{
15
- name: string;
16
- type: string;
17
- }>>;
18
- primaryType: string;
19
- message: Record<string, unknown>;
20
- }) => Promise<string>);
21
- };
22
- declare function createRelayerInstance(config: unknown): Promise<RelayerInstance>;
23
-
24
- declare function createEncryptedAmountInput(relayer: RelayerInstance, contractAddress: string, senderAddress: string, amount: number): Promise<{
25
- handle: `0x${string}`;
26
- inputProof: `0x${string}`;
27
- }>;
28
- declare function userDecryptEuint64(relayer: RelayerInstance, handle: string, contractAddress: string, signer: RelayerSigner, options?: {
29
- durationDays?: string;
30
- startTimestamp?: string;
31
- }): Promise<bigint>;
32
- declare function publicDecrypt(relayer: RelayerInstance, handles: string[]): Promise<{
33
- clearValues: Record<string, bigint>;
34
- decryptionProof: string;
35
- }>;
4
+ export { FhevmInstanceConfig, SepoliaConfig } from '@zama-fhe/relayer-sdk/node';
36
5
 
37
6
  type ViewConfidentialBalanceOptions = {
38
7
  rpcUrl: string;
@@ -68,4 +37,4 @@ type ViewConfidentialTransferOptions = {
68
37
  };
69
38
  declare function viewConfidentialTransferAmounts(options: ViewConfidentialTransferOptions): Promise<ConfidentialTransferAmount[]>;
70
39
 
71
- export { type ConfidentialTransferAmount, type RelayerInstance, type RelayerSigner, type ViewConfidentialBalanceOptions, type ViewConfidentialTransferOptions, createEncryptedAmountInput, createRelayerInstance, publicDecrypt, userDecryptEuint64, viewConfidentialBalance, viewConfidentialTransferAmounts };
40
+ export { type ConfidentialTransferAmount, RelayerInstance, RelayerSigner, type ViewConfidentialBalanceOptions, type ViewConfidentialTransferOptions, viewConfidentialBalance, viewConfidentialTransferAmounts };
package/dist/index.d.ts CHANGED
@@ -1,38 +1,7 @@
1
- export { C as ConfidentialPaymentAuthorization, f as ConfidentialPaymentInput, d as ConfidentialPaymentPayload, e as ConfidentialRequirementsExtra, a as confidentialPaymentTypes, c as confidentialTokenAbi, b as createNonce, h as hashEncryptedAmountInput, n as normalizeAmount } from './types-RdcpJuhT.js';
2
- import { createInstance } from '@zama-fhe/relayer-sdk/node';
3
- export { SepoliaConfig } from '@zama-fhe/relayer-sdk/node';
1
+ import { R as RelayerInstance, a as RelayerSigner } from './types-gx3OAvqG.js';
2
+ export { C as ConfidentialErrorCode, i as ConfidentialPaymentAuthorization, l as ConfidentialPaymentInput, j as ConfidentialPaymentPayload, k as ConfidentialRequirementsExtra, S as SetObserverOptions, d as confidentialErrorCodes, b as confidentialPaymentTypes, c as confidentialTokenAbi, g as createEncryptedAmountInput, e as createNonce, f as createRelayerInstance, h as hashEncryptedAmountInput, n as normalizeAmount, p as publicDecrypt, s as setObserver, u as userDecryptEuint64 } from './types-gx3OAvqG.js';
4
3
  export * from '@x402/core/types';
5
-
6
- type RelayerInstance = Awaited<ReturnType<typeof createInstance>>;
7
- type RelayerSigner = {
8
- address: string;
9
- signTypedData: ((domain: Record<string, unknown>, types: Record<string, Array<{
10
- name: string;
11
- type: string;
12
- }>>, message: Record<string, unknown>) => Promise<string>) | ((args: {
13
- domain: Record<string, unknown>;
14
- types: Record<string, Array<{
15
- name: string;
16
- type: string;
17
- }>>;
18
- primaryType: string;
19
- message: Record<string, unknown>;
20
- }) => Promise<string>);
21
- };
22
- declare function createRelayerInstance(config: unknown): Promise<RelayerInstance>;
23
-
24
- declare function createEncryptedAmountInput(relayer: RelayerInstance, contractAddress: string, senderAddress: string, amount: number): Promise<{
25
- handle: `0x${string}`;
26
- inputProof: `0x${string}`;
27
- }>;
28
- declare function userDecryptEuint64(relayer: RelayerInstance, handle: string, contractAddress: string, signer: RelayerSigner, options?: {
29
- durationDays?: string;
30
- startTimestamp?: string;
31
- }): Promise<bigint>;
32
- declare function publicDecrypt(relayer: RelayerInstance, handles: string[]): Promise<{
33
- clearValues: Record<string, bigint>;
34
- decryptionProof: string;
35
- }>;
4
+ export { FhevmInstanceConfig, SepoliaConfig } from '@zama-fhe/relayer-sdk/node';
36
5
 
37
6
  type ViewConfidentialBalanceOptions = {
38
7
  rpcUrl: string;
@@ -68,4 +37,4 @@ type ViewConfidentialTransferOptions = {
68
37
  };
69
38
  declare function viewConfidentialTransferAmounts(options: ViewConfidentialTransferOptions): Promise<ConfidentialTransferAmount[]>;
70
39
 
71
- export { type ConfidentialTransferAmount, type RelayerInstance, type RelayerSigner, type ViewConfidentialBalanceOptions, type ViewConfidentialTransferOptions, createEncryptedAmountInput, createRelayerInstance, publicDecrypt, userDecryptEuint64, viewConfidentialBalance, viewConfidentialTransferAmounts };
40
+ export { type ConfidentialTransferAmount, RelayerInstance, RelayerSigner, type ViewConfidentialBalanceOptions, type ViewConfidentialTransferOptions, viewConfidentialBalance, viewConfidentialTransferAmounts };
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  SepoliaConfig: () => import_node.SepoliaConfig,
24
+ confidentialErrorCodes: () => confidentialErrorCodes,
24
25
  confidentialPaymentTypes: () => confidentialPaymentTypes,
25
26
  confidentialTokenAbi: () => confidentialTokenAbi,
26
27
  createEncryptedAmountInput: () => createEncryptedAmountInput,
@@ -29,6 +30,7 @@ __export(index_exports, {
29
30
  hashEncryptedAmountInput: () => hashEncryptedAmountInput,
30
31
  normalizeAmount: () => normalizeAmount,
31
32
  publicDecrypt: () => publicDecrypt,
33
+ setObserver: () => setObserver,
32
34
  userDecryptEuint64: () => userDecryptEuint64,
33
35
  viewConfidentialBalance: () => viewConfidentialBalance,
34
36
  viewConfidentialTransferAmounts: () => viewConfidentialTransferAmounts
@@ -85,6 +87,23 @@ var confidentialTokenAbi = [
85
87
  outputs: [{ internalType: "bool", name: "", type: "bool" }],
86
88
  stateMutability: "view",
87
89
  type: "function"
90
+ },
91
+ {
92
+ inputs: [{ internalType: "address", name: "account", type: "address" }],
93
+ name: "observer",
94
+ outputs: [{ internalType: "address", name: "", type: "address" }],
95
+ stateMutability: "view",
96
+ type: "function"
97
+ },
98
+ {
99
+ inputs: [
100
+ { internalType: "address", name: "account", type: "address" },
101
+ { internalType: "address", name: "newObserver", type: "address" }
102
+ ],
103
+ name: "setObserver",
104
+ outputs: [],
105
+ stateMutability: "nonpayable",
106
+ type: "function"
88
107
  }
89
108
  ];
90
109
 
@@ -101,6 +120,9 @@ var confidentialPaymentTypes = {
101
120
  { name: "encryptedAmountHash", type: "bytes32" }
102
121
  ]
103
122
  };
123
+ var confidentialErrorCodes = {
124
+ observerNotAuthorized: "observer_not_authorized"
125
+ };
104
126
 
105
127
  // src/utils.ts
106
128
  var import_viem = require("viem");
@@ -133,7 +155,11 @@ function normalizeAmount(amount) {
133
155
  var import_node = require("@zama-fhe/relayer-sdk/node");
134
156
  var import_viem2 = require("viem");
135
157
  async function createRelayerInstance(config) {
136
- return (0, import_node.createInstance)(config);
158
+ const instance = await (0, import_node.createInstance)(config);
159
+ if (typeof config.network === "string") {
160
+ instance.network = config.network;
161
+ }
162
+ return instance;
137
163
  }
138
164
  async function createEncryptedAmountInput(relayer, contractAddress, senderAddress, amount) {
139
165
  const normalizedContract = (0, import_viem2.getAddress)(contractAddress);
@@ -214,6 +240,18 @@ async function viewConfidentialBalance(options) {
214
240
  if (!options.signer) {
215
241
  throw new Error("Missing signer for decryption");
216
242
  }
243
+ const signerAddress = (0, import_viem3.getAddress)(options.signer.address);
244
+ if (!(0, import_viem3.isAddressEqual)(signerAddress, (0, import_viem3.getAddress)(account))) {
245
+ const observer = await publicClient.readContract({
246
+ address: options.tokenAddress,
247
+ abi: confidentialTokenAbi,
248
+ functionName: "observer",
249
+ args: [account]
250
+ });
251
+ if (!observer || !(0, import_viem3.isAddressEqual)(observer, signerAddress)) {
252
+ throw new Error(confidentialErrorCodes.observerNotAuthorized);
253
+ }
254
+ }
217
255
  if (handle === ZERO_HANDLE) {
218
256
  return { handle, balance: 0n };
219
257
  }
@@ -279,8 +317,27 @@ async function viewConfidentialTransferAmounts(options) {
279
317
  throw new Error("Missing signer for decryption");
280
318
  }
281
319
  const signerAddress = (0, import_viem4.getAddress)(options.signer.address);
282
- if (signerAddress !== (0, import_viem4.getAddress)(entry.holder) && signerAddress !== (0, import_viem4.getAddress)(entry.payee)) {
283
- throw new Error("Signer must be the holder or payee to decrypt transfer amount");
320
+ const holderAddress = (0, import_viem4.getAddress)(entry.holder);
321
+ const payeeAddress = (0, import_viem4.getAddress)(entry.payee);
322
+ if (!(0, import_viem4.isAddressEqual)(signerAddress, holderAddress) && !(0, import_viem4.isAddressEqual)(signerAddress, payeeAddress)) {
323
+ const [holderObserver, payeeObserver] = await Promise.all([
324
+ publicClient.readContract({
325
+ address: tokenAddress,
326
+ abi: confidentialTokenAbi,
327
+ functionName: "observer",
328
+ args: [holderAddress]
329
+ }),
330
+ publicClient.readContract({
331
+ address: tokenAddress,
332
+ abi: confidentialTokenAbi,
333
+ functionName: "observer",
334
+ args: [payeeAddress]
335
+ })
336
+ ]);
337
+ const allowed = holderObserver && (0, import_viem4.isAddressEqual)(holderObserver, signerAddress) || payeeObserver && (0, import_viem4.isAddressEqual)(payeeObserver, signerAddress);
338
+ if (!allowed) {
339
+ throw new Error(confidentialErrorCodes.observerNotAuthorized);
340
+ }
284
341
  }
285
342
  entry.amount = await userDecryptEuint64(
286
343
  options.relayer,
@@ -298,9 +355,43 @@ async function viewConfidentialTransferAmounts(options) {
298
355
  }
299
356
  return transfers;
300
357
  }
358
+
359
+ // src/observer.ts
360
+ var import_viem5 = require("viem");
361
+ async function setObserver(options) {
362
+ if (!(0, import_viem5.isAddress)(options.tokenAddress)) {
363
+ throw new Error(`Invalid token address: ${options.tokenAddress}`);
364
+ }
365
+ if (!(0, import_viem5.isAddress)(options.account)) {
366
+ throw new Error(`Invalid account address: ${options.account}`);
367
+ }
368
+ if (!(0, import_viem5.isAddress)(options.observer)) {
369
+ throw new Error(`Invalid observer address: ${options.observer}`);
370
+ }
371
+ const tokenAddress = (0, import_viem5.getAddress)(options.tokenAddress);
372
+ const account = (0, import_viem5.getAddress)(options.account);
373
+ const observer = (0, import_viem5.getAddress)(options.observer);
374
+ const publicClient = (0, import_viem5.createPublicClient)({ transport: (0, import_viem5.http)(options.rpcUrl) });
375
+ const existing = await publicClient.readContract({
376
+ address: tokenAddress,
377
+ abi: confidentialTokenAbi,
378
+ functionName: "observer",
379
+ args: [account]
380
+ });
381
+ if (existing && (0, import_viem5.isAddress)(existing) && (0, import_viem5.getAddress)(existing) === observer) {
382
+ return "0x" + "00".repeat(32);
383
+ }
384
+ return options.signer.writeContract({
385
+ address: tokenAddress,
386
+ abi: confidentialTokenAbi,
387
+ functionName: "setObserver",
388
+ args: [account, observer]
389
+ });
390
+ }
301
391
  // Annotate the CommonJS export names for ESM import in node:
302
392
  0 && (module.exports = {
303
393
  SepoliaConfig,
394
+ confidentialErrorCodes,
304
395
  confidentialPaymentTypes,
305
396
  confidentialTokenAbi,
306
397
  createEncryptedAmountInput,
@@ -309,6 +400,7 @@ async function viewConfidentialTransferAmounts(options) {
309
400
  hashEncryptedAmountInput,
310
401
  normalizeAmount,
311
402
  publicDecrypt,
403
+ setObserver,
312
404
  userDecryptEuint64,
313
405
  viewConfidentialBalance,
314
406
  viewConfidentialTransferAmounts
package/dist/index.mjs CHANGED
@@ -1,16 +1,22 @@
1
1
  import {
2
+ confidentialErrorCodes,
2
3
  confidentialPaymentTypes,
3
4
  confidentialTokenAbi,
4
5
  createNonce,
5
6
  hashEncryptedAmountInput,
6
- normalizeAmount
7
- } from "./chunk-V7Z3OAXS.mjs";
7
+ normalizeAmount,
8
+ setObserver
9
+ } from "./chunk-LTE4V3LT.mjs";
8
10
 
9
11
  // src/relayer.ts
10
12
  import { createInstance, SepoliaConfig } from "@zama-fhe/relayer-sdk/node";
11
13
  import { getAddress, toHex } from "viem";
12
14
  async function createRelayerInstance(config) {
13
- return createInstance(config);
15
+ const instance = await createInstance(config);
16
+ if (typeof config.network === "string") {
17
+ instance.network = config.network;
18
+ }
19
+ return instance;
14
20
  }
15
21
  async function createEncryptedAmountInput(relayer, contractAddress, senderAddress, amount) {
16
22
  const normalizedContract = getAddress(contractAddress);
@@ -58,7 +64,7 @@ async function publicDecrypt(relayer, handles) {
58
64
  }
59
65
 
60
66
  // src/balance.ts
61
- import { createPublicClient, http, isAddress } from "viem";
67
+ import { createPublicClient, getAddress as getAddress2, http, isAddress, isAddressEqual } from "viem";
62
68
  var ZERO_HANDLE = "0x" + "00".repeat(32);
63
69
  async function viewConfidentialBalance(options) {
64
70
  if (!isAddress(options.tokenAddress)) {
@@ -91,6 +97,18 @@ async function viewConfidentialBalance(options) {
91
97
  if (!options.signer) {
92
98
  throw new Error("Missing signer for decryption");
93
99
  }
100
+ const signerAddress = getAddress2(options.signer.address);
101
+ if (!isAddressEqual(signerAddress, getAddress2(account))) {
102
+ const observer = await publicClient.readContract({
103
+ address: options.tokenAddress,
104
+ abi: confidentialTokenAbi,
105
+ functionName: "observer",
106
+ args: [account]
107
+ });
108
+ if (!observer || !isAddressEqual(observer, signerAddress)) {
109
+ throw new Error(confidentialErrorCodes.observerNotAuthorized);
110
+ }
111
+ }
94
112
  if (handle === ZERO_HANDLE) {
95
113
  return { handle, balance: 0n };
96
114
  }
@@ -104,7 +122,7 @@ async function viewConfidentialBalance(options) {
104
122
  }
105
123
 
106
124
  // src/transfer.ts
107
- import { createPublicClient as createPublicClient2, decodeEventLog, getAddress as getAddress2, http as http2, isAddress as isAddress2, isHex } from "viem";
125
+ import { createPublicClient as createPublicClient2, decodeEventLog, getAddress as getAddress3, http as http2, isAddress as isAddress2, isHex, isAddressEqual as isAddressEqual2 } from "viem";
108
126
  async function viewConfidentialTransferAmounts(options) {
109
127
  if (!isAddress2(options.tokenAddress)) {
110
128
  throw new Error(`Invalid token address: ${options.tokenAddress}`);
@@ -122,10 +140,10 @@ async function viewConfidentialTransferAmounts(options) {
122
140
  const receipt = await publicClient.getTransactionReceipt({
123
141
  hash: options.txHash
124
142
  });
125
- const tokenAddress = getAddress2(options.tokenAddress);
126
- const fromFilter = options.from ? getAddress2(options.from) : void 0;
127
- const toFilter = options.to ? getAddress2(options.to) : void 0;
128
- const logs = receipt.logs.filter((log) => getAddress2(log.address) === tokenAddress);
143
+ const tokenAddress = getAddress3(options.tokenAddress);
144
+ const fromFilter = options.from ? getAddress3(options.from) : void 0;
145
+ const toFilter = options.to ? getAddress3(options.to) : void 0;
146
+ const logs = receipt.logs.filter((log) => getAddress3(log.address) === tokenAddress);
129
147
  const transfers = [];
130
148
  for (const log of logs) {
131
149
  try {
@@ -137,8 +155,8 @@ async function viewConfidentialTransferAmounts(options) {
137
155
  });
138
156
  const args = decoded.args;
139
157
  const entry = {
140
- holder: getAddress2(args.holder),
141
- payee: getAddress2(args.payee),
158
+ holder: getAddress3(args.holder),
159
+ payee: getAddress3(args.payee),
142
160
  maxClearAmount: BigInt(args.maxClearAmount),
143
161
  resourceHash: args.resourceHash,
144
162
  nonce: args.nonce,
@@ -155,9 +173,28 @@ async function viewConfidentialTransferAmounts(options) {
155
173
  if (!options.signer) {
156
174
  throw new Error("Missing signer for decryption");
157
175
  }
158
- const signerAddress = getAddress2(options.signer.address);
159
- if (signerAddress !== getAddress2(entry.holder) && signerAddress !== getAddress2(entry.payee)) {
160
- throw new Error("Signer must be the holder or payee to decrypt transfer amount");
176
+ const signerAddress = getAddress3(options.signer.address);
177
+ const holderAddress = getAddress3(entry.holder);
178
+ const payeeAddress = getAddress3(entry.payee);
179
+ if (!isAddressEqual2(signerAddress, holderAddress) && !isAddressEqual2(signerAddress, payeeAddress)) {
180
+ const [holderObserver, payeeObserver] = await Promise.all([
181
+ publicClient.readContract({
182
+ address: tokenAddress,
183
+ abi: confidentialTokenAbi,
184
+ functionName: "observer",
185
+ args: [holderAddress]
186
+ }),
187
+ publicClient.readContract({
188
+ address: tokenAddress,
189
+ abi: confidentialTokenAbi,
190
+ functionName: "observer",
191
+ args: [payeeAddress]
192
+ })
193
+ ]);
194
+ const allowed = holderObserver && isAddressEqual2(holderObserver, signerAddress) || payeeObserver && isAddressEqual2(payeeObserver, signerAddress);
195
+ if (!allowed) {
196
+ throw new Error(confidentialErrorCodes.observerNotAuthorized);
197
+ }
161
198
  }
162
199
  entry.amount = await userDecryptEuint64(
163
200
  options.relayer,
@@ -177,6 +214,7 @@ async function viewConfidentialTransferAmounts(options) {
177
214
  }
178
215
  export {
179
216
  SepoliaConfig,
217
+ confidentialErrorCodes,
180
218
  confidentialPaymentTypes,
181
219
  confidentialTokenAbi,
182
220
  createEncryptedAmountInput,
@@ -185,6 +223,7 @@ export {
185
223
  hashEncryptedAmountInput,
186
224
  normalizeAmount,
187
225
  publicDecrypt,
226
+ setObserver,
188
227
  userDecryptEuint64,
189
228
  viewConfidentialBalance,
190
229
  viewConfidentialTransferAmounts