x402z-shared 0.0.4 → 0.0.6
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 +17 -23
- package/dist/chunk-7OLOM2AQ.mjs +155 -0
- package/dist/index.d.mts +60 -13
- package/dist/index.d.ts +60 -13
- package/dist/index.js +214 -80
- package/dist/index.mjs +212 -79
- package/dist/types-I3K7qzdc.d.mts +274 -0
- package/dist/types-I3K7qzdc.d.ts +274 -0
- package/dist/web.d.mts +21 -23
- package/dist/web.d.ts +21 -23
- package/dist/web.js +231 -112
- package/dist/web.mjs +195 -76
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,18 +39,19 @@ const encrypted = await createEncryptedAmountInput(
|
|
|
39
39
|
);
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
##
|
|
42
|
+
## Token helper (Node)
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
|
-
import {
|
|
45
|
+
import { ConfidentialToken } from "x402z-shared";
|
|
46
46
|
|
|
47
|
-
const
|
|
47
|
+
const token = new ConfidentialToken({
|
|
48
48
|
rpcUrl: "https://sepolia.infura.io/v3/...",
|
|
49
49
|
tokenAddress: "0xToken",
|
|
50
50
|
relayer,
|
|
51
|
-
signer: { address, signTypedData },
|
|
51
|
+
signer: { address, signTypedData, writeContract },
|
|
52
52
|
});
|
|
53
|
-
|
|
53
|
+
const balance = await token.balanceOf("0xWallet");
|
|
54
|
+
console.log(balance.toString());
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
Notes:
|
|
@@ -81,45 +82,38 @@ Notes:
|
|
|
81
82
|
## Observer helper (Node)
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
|
-
import {
|
|
85
|
+
import { ConfidentialToken } from "x402z-shared";
|
|
85
86
|
|
|
86
|
-
const
|
|
87
|
+
const token = new ConfidentialToken({
|
|
87
88
|
rpcUrl: "https://sepolia.infura.io/v3/...",
|
|
88
89
|
tokenAddress: "0xToken",
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
signer,
|
|
90
|
+
relayer,
|
|
91
|
+
signer: { address, signTypedData, writeContract },
|
|
92
92
|
});
|
|
93
|
+
const txHash = await token.setObserver("0xHolder", "0xObserver");
|
|
93
94
|
console.log(txHash);
|
|
94
95
|
```
|
|
95
96
|
|
|
96
|
-
##
|
|
97
|
+
## Token helper (Browser)
|
|
97
98
|
|
|
98
99
|
```ts
|
|
99
|
-
import {
|
|
100
|
+
import { ConfidentialTokenWeb } from "x402z-shared/web";
|
|
100
101
|
|
|
101
|
-
const
|
|
102
|
+
const token = new ConfidentialTokenWeb({
|
|
103
|
+
rpcUrl: "https://sepolia.infura.io/v3/...",
|
|
102
104
|
tokenAddress: "0xToken",
|
|
103
|
-
|
|
104
|
-
observer: "0xObserver",
|
|
105
|
+
relayer,
|
|
105
106
|
walletClient,
|
|
106
107
|
});
|
|
108
|
+
const txHash = await token.setObserver("0xHolder", "0xObserver");
|
|
107
109
|
console.log(txHash);
|
|
108
110
|
```
|
|
109
111
|
|
|
110
|
-
## Balance helper (Browser)
|
|
111
|
-
|
|
112
|
-
```ts
|
|
113
|
-
import { viewConfidentialBalance } from "x402z-shared/web";
|
|
114
|
-
```
|
|
115
|
-
|
|
116
112
|
## Transfer amount helper (Browser)
|
|
117
113
|
|
|
118
114
|
```ts
|
|
119
115
|
import { viewConfidentialTransferAmounts } from "x402z-shared/web";
|
|
120
116
|
```
|
|
121
|
-
|
|
122
117
|
## Notes
|
|
123
118
|
|
|
124
119
|
- Scheme name: `erc7984-mind-v1`
|
|
125
|
-
- `viewConfidentialBalance` can return handle-only if `decrypt: false`.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// src/abi.ts
|
|
2
|
+
var confidentialTokenAbi = [
|
|
3
|
+
{
|
|
4
|
+
inputs: [
|
|
5
|
+
{ internalType: "address", name: "to", type: "address" },
|
|
6
|
+
{ internalType: "bytes32", name: "encryptedAmountInput", type: "bytes32" },
|
|
7
|
+
{ internalType: "bytes", name: "inputProof", type: "bytes" }
|
|
8
|
+
],
|
|
9
|
+
name: "confidentialTransfer",
|
|
10
|
+
outputs: [{ internalType: "euint64", name: "transferred", type: "bytes32" }],
|
|
11
|
+
stateMutability: "nonpayable",
|
|
12
|
+
type: "function"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
inputs: [
|
|
16
|
+
{
|
|
17
|
+
components: [
|
|
18
|
+
{ internalType: "address", name: "holder", type: "address" },
|
|
19
|
+
{ internalType: "address", name: "payee", type: "address" },
|
|
20
|
+
{ internalType: "uint256", name: "maxClearAmount", type: "uint256" },
|
|
21
|
+
{ internalType: "bytes32", name: "resourceHash", type: "bytes32" },
|
|
22
|
+
{ internalType: "uint48", name: "validAfter", type: "uint48" },
|
|
23
|
+
{ internalType: "uint48", name: "validBefore", type: "uint48" },
|
|
24
|
+
{ internalType: "bytes32", name: "nonce", type: "bytes32" },
|
|
25
|
+
{ internalType: "bytes32", name: "encryptedAmountHash", type: "bytes32" }
|
|
26
|
+
],
|
|
27
|
+
internalType: "struct FHEToken.ConfidentialPayment",
|
|
28
|
+
name: "p",
|
|
29
|
+
type: "tuple"
|
|
30
|
+
},
|
|
31
|
+
{ internalType: "externalEuint64", name: "encryptedAmountInput", type: "bytes32" },
|
|
32
|
+
{ internalType: "bytes", name: "inputProof", type: "bytes" },
|
|
33
|
+
{ internalType: "bytes", name: "sig", type: "bytes" }
|
|
34
|
+
],
|
|
35
|
+
name: "confidentialTransferWithAuthorization",
|
|
36
|
+
outputs: [{ internalType: "euint64", name: "transferred", type: "bytes32" }],
|
|
37
|
+
stateMutability: "nonpayable",
|
|
38
|
+
type: "function"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
inputs: [
|
|
42
|
+
{ internalType: "address", name: "to", type: "address" },
|
|
43
|
+
{ internalType: "uint256", name: "amount", type: "uint256" }
|
|
44
|
+
],
|
|
45
|
+
name: "wrap",
|
|
46
|
+
outputs: [],
|
|
47
|
+
stateMutability: "nonpayable",
|
|
48
|
+
type: "function"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
inputs: [
|
|
52
|
+
{ internalType: "address", name: "from", type: "address" },
|
|
53
|
+
{ internalType: "address", name: "to", type: "address" },
|
|
54
|
+
{ internalType: "bytes32", name: "encryptedAmountInput", type: "bytes32" },
|
|
55
|
+
{ internalType: "bytes", name: "inputProof", type: "bytes" }
|
|
56
|
+
],
|
|
57
|
+
name: "unwrap",
|
|
58
|
+
outputs: [],
|
|
59
|
+
stateMutability: "nonpayable",
|
|
60
|
+
type: "function"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
anonymous: false,
|
|
64
|
+
inputs: [
|
|
65
|
+
{ indexed: true, internalType: "address", name: "holder", type: "address" },
|
|
66
|
+
{ indexed: true, internalType: "address", name: "payee", type: "address" },
|
|
67
|
+
{ indexed: false, internalType: "uint256", name: "maxClearAmount", type: "uint256" },
|
|
68
|
+
{ indexed: true, internalType: "bytes32", name: "resourceHash", type: "bytes32" },
|
|
69
|
+
{ indexed: false, internalType: "bytes32", name: "nonce", type: "bytes32" },
|
|
70
|
+
{ indexed: false, internalType: "bytes32", name: "transferredAmount", type: "bytes32" }
|
|
71
|
+
],
|
|
72
|
+
name: "ConfidentialPaymentExecuted",
|
|
73
|
+
type: "event"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
inputs: [
|
|
77
|
+
{ internalType: "address", name: "", type: "address" },
|
|
78
|
+
{ internalType: "bytes32", name: "", type: "bytes32" }
|
|
79
|
+
],
|
|
80
|
+
name: "usedNonces",
|
|
81
|
+
outputs: [{ internalType: "bool", name: "", type: "bool" }],
|
|
82
|
+
stateMutability: "view",
|
|
83
|
+
type: "function"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
inputs: [{ internalType: "address", name: "account", type: "address" }],
|
|
87
|
+
name: "observer",
|
|
88
|
+
outputs: [{ internalType: "address", name: "", type: "address" }],
|
|
89
|
+
stateMutability: "view",
|
|
90
|
+
type: "function"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
inputs: [
|
|
94
|
+
{ internalType: "address", name: "account", type: "address" },
|
|
95
|
+
{ internalType: "address", name: "newObserver", type: "address" }
|
|
96
|
+
],
|
|
97
|
+
name: "setObserver",
|
|
98
|
+
outputs: [],
|
|
99
|
+
stateMutability: "nonpayable",
|
|
100
|
+
type: "function"
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
// src/constants.ts
|
|
105
|
+
var confidentialPaymentTypes = {
|
|
106
|
+
ConfidentialPayment: [
|
|
107
|
+
{ name: "holder", type: "address" },
|
|
108
|
+
{ name: "payee", type: "address" },
|
|
109
|
+
{ name: "maxClearAmount", type: "uint256" },
|
|
110
|
+
{ name: "resourceHash", type: "bytes32" },
|
|
111
|
+
{ name: "validAfter", type: "uint48" },
|
|
112
|
+
{ name: "validBefore", type: "uint48" },
|
|
113
|
+
{ name: "nonce", type: "bytes32" },
|
|
114
|
+
{ name: "encryptedAmountHash", type: "bytes32" }
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
var confidentialErrorCodes = {
|
|
118
|
+
observerNotAuthorized: "observer_not_authorized"
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/utils.ts
|
|
122
|
+
import { encodeAbiParameters, keccak256, toHex } from "viem";
|
|
123
|
+
function createNonce() {
|
|
124
|
+
const cryptoObj = typeof globalThis.crypto !== "undefined" ? globalThis.crypto : globalThis.crypto;
|
|
125
|
+
if (!cryptoObj) {
|
|
126
|
+
throw new Error("Crypto API not available");
|
|
127
|
+
}
|
|
128
|
+
return toHex(cryptoObj.getRandomValues(new Uint8Array(32)));
|
|
129
|
+
}
|
|
130
|
+
function hashEncryptedAmountInput(encryptedAmountInput) {
|
|
131
|
+
return keccak256(
|
|
132
|
+
encodeAbiParameters([{ type: "bytes32" }], [encryptedAmountInput])
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
function normalizeAmount(amount) {
|
|
136
|
+
if (typeof amount === "string") {
|
|
137
|
+
return amount;
|
|
138
|
+
}
|
|
139
|
+
if (typeof amount === "number") {
|
|
140
|
+
if (!Number.isFinite(amount)) {
|
|
141
|
+
throw new Error("Invalid amount");
|
|
142
|
+
}
|
|
143
|
+
return Math.trunc(amount).toString();
|
|
144
|
+
}
|
|
145
|
+
return amount.toString();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export {
|
|
149
|
+
confidentialTokenAbi,
|
|
150
|
+
confidentialPaymentTypes,
|
|
151
|
+
confidentialErrorCodes,
|
|
152
|
+
createNonce,
|
|
153
|
+
hashEncryptedAmountInput,
|
|
154
|
+
normalizeAmount
|
|
155
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { C as ConfidentialErrorCode,
|
|
3
|
-
|
|
1
|
+
import { c as confidentialTokenAbi } from './types-I3K7qzdc.mjs';
|
|
2
|
+
export { C as ConfidentialErrorCode, e as ConfidentialPaymentAuthorization, i as ConfidentialPaymentInput, f as ConfidentialPaymentPayload, g as ConfidentialRequirementsExtra, b as confidentialErrorCodes, a as confidentialPaymentTypes, d as createNonce, h as hashEncryptedAmountInput, n as normalizeAmount } from './types-I3K7qzdc.mjs';
|
|
3
|
+
import { FhevmInstanceConfig, createInstance } from '@zama-fhe/relayer-sdk/node';
|
|
4
4
|
export { FhevmInstanceConfig, SepoliaConfig } from '@zama-fhe/relayer-sdk/node';
|
|
5
|
+
export * from '@x402/core/types';
|
|
5
6
|
|
|
6
|
-
type
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
type RelayerInstance = Awaited<ReturnType<typeof createInstance>>;
|
|
8
|
+
type RelayerSigner = {
|
|
9
|
+
address: string;
|
|
10
|
+
signTypedData: ((domain: Record<string, unknown>, types: Record<string, Array<{
|
|
11
|
+
name: string;
|
|
12
|
+
type: string;
|
|
13
|
+
}>>, message: Record<string, unknown>) => Promise<string>) | ((args: {
|
|
14
|
+
domain: Record<string, unknown>;
|
|
15
|
+
types: Record<string, Array<{
|
|
16
|
+
name: string;
|
|
17
|
+
type: string;
|
|
18
|
+
}>>;
|
|
19
|
+
primaryType: string;
|
|
20
|
+
message: Record<string, unknown>;
|
|
21
|
+
}) => Promise<string>);
|
|
13
22
|
};
|
|
14
|
-
|
|
23
|
+
|
|
24
|
+
declare function createRelayerInstance(config: FhevmInstanceConfig): Promise<RelayerInstance>;
|
|
25
|
+
|
|
26
|
+
declare function createEncryptedAmountInput(relayer: RelayerInstance, contractAddress: string, senderAddress: string, amount: number): Promise<{
|
|
15
27
|
handle: `0x${string}`;
|
|
16
|
-
|
|
28
|
+
inputProof: `0x${string}`;
|
|
29
|
+
}>;
|
|
30
|
+
declare function userDecryptEuint64(relayer: RelayerInstance, handle: string, contractAddress: string, signer: RelayerSigner, options?: {
|
|
31
|
+
durationDays?: string;
|
|
32
|
+
startTimestamp?: string;
|
|
33
|
+
}): Promise<bigint>;
|
|
34
|
+
declare function publicDecrypt(relayer: RelayerInstance, handles: string[]): Promise<{
|
|
35
|
+
clearValues: Record<string, bigint>;
|
|
36
|
+
decryptionProof: string;
|
|
17
37
|
}>;
|
|
18
38
|
|
|
19
39
|
type ConfidentialTransferAmount = {
|
|
@@ -37,4 +57,31 @@ type ViewConfidentialTransferOptions = {
|
|
|
37
57
|
};
|
|
38
58
|
declare function viewConfidentialTransferAmounts(options: ViewConfidentialTransferOptions): Promise<ConfidentialTransferAmount[]>;
|
|
39
59
|
|
|
40
|
-
|
|
60
|
+
type TokenWriteSigner = RelayerSigner & {
|
|
61
|
+
writeContract?: (args: {
|
|
62
|
+
address: `0x${string}`;
|
|
63
|
+
abi: typeof confidentialTokenAbi;
|
|
64
|
+
functionName: "confidentialTransfer" | "wrap" | "unwrap" | "setObserver";
|
|
65
|
+
args: readonly unknown[];
|
|
66
|
+
}) => Promise<`0x${string}`>;
|
|
67
|
+
};
|
|
68
|
+
type ConfidentialTokenConfig = {
|
|
69
|
+
rpcUrl: string;
|
|
70
|
+
tokenAddress: `0x${string}`;
|
|
71
|
+
relayer: RelayerInstance;
|
|
72
|
+
signer: TokenWriteSigner;
|
|
73
|
+
};
|
|
74
|
+
declare class ConfidentialToken {
|
|
75
|
+
private readonly rpcUrl;
|
|
76
|
+
private readonly tokenAddress;
|
|
77
|
+
private readonly relayer;
|
|
78
|
+
private readonly signer;
|
|
79
|
+
constructor(config: ConfidentialTokenConfig);
|
|
80
|
+
balanceOf(account?: `0x${string}`): Promise<bigint>;
|
|
81
|
+
setObserver(account: `0x${string}`, observer: `0x${string}`): Promise<`0x${string}`>;
|
|
82
|
+
transfer(to: `0x${string}`, amount: number): Promise<`0x${string}`>;
|
|
83
|
+
wrap(to: `0x${string}`, amount: string | number | bigint): Promise<`0x${string}`>;
|
|
84
|
+
unwrap(from: `0x${string}`, to: `0x${string}`, amount: number): Promise<`0x${string}`>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { ConfidentialToken, type ConfidentialTokenConfig, type ConfidentialTransferAmount, type RelayerInstance, type RelayerSigner, type ViewConfidentialTransferOptions, ConfidentialToken as confidentialToken, confidentialTokenAbi, createEncryptedAmountInput, createRelayerInstance, publicDecrypt, userDecryptEuint64, viewConfidentialTransferAmounts };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { C as ConfidentialErrorCode,
|
|
3
|
-
|
|
1
|
+
import { c as confidentialTokenAbi } from './types-I3K7qzdc.js';
|
|
2
|
+
export { C as ConfidentialErrorCode, e as ConfidentialPaymentAuthorization, i as ConfidentialPaymentInput, f as ConfidentialPaymentPayload, g as ConfidentialRequirementsExtra, b as confidentialErrorCodes, a as confidentialPaymentTypes, d as createNonce, h as hashEncryptedAmountInput, n as normalizeAmount } from './types-I3K7qzdc.js';
|
|
3
|
+
import { FhevmInstanceConfig, createInstance } from '@zama-fhe/relayer-sdk/node';
|
|
4
4
|
export { FhevmInstanceConfig, SepoliaConfig } from '@zama-fhe/relayer-sdk/node';
|
|
5
|
+
export * from '@x402/core/types';
|
|
5
6
|
|
|
6
|
-
type
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
type RelayerInstance = Awaited<ReturnType<typeof createInstance>>;
|
|
8
|
+
type RelayerSigner = {
|
|
9
|
+
address: string;
|
|
10
|
+
signTypedData: ((domain: Record<string, unknown>, types: Record<string, Array<{
|
|
11
|
+
name: string;
|
|
12
|
+
type: string;
|
|
13
|
+
}>>, message: Record<string, unknown>) => Promise<string>) | ((args: {
|
|
14
|
+
domain: Record<string, unknown>;
|
|
15
|
+
types: Record<string, Array<{
|
|
16
|
+
name: string;
|
|
17
|
+
type: string;
|
|
18
|
+
}>>;
|
|
19
|
+
primaryType: string;
|
|
20
|
+
message: Record<string, unknown>;
|
|
21
|
+
}) => Promise<string>);
|
|
13
22
|
};
|
|
14
|
-
|
|
23
|
+
|
|
24
|
+
declare function createRelayerInstance(config: FhevmInstanceConfig): Promise<RelayerInstance>;
|
|
25
|
+
|
|
26
|
+
declare function createEncryptedAmountInput(relayer: RelayerInstance, contractAddress: string, senderAddress: string, amount: number): Promise<{
|
|
15
27
|
handle: `0x${string}`;
|
|
16
|
-
|
|
28
|
+
inputProof: `0x${string}`;
|
|
29
|
+
}>;
|
|
30
|
+
declare function userDecryptEuint64(relayer: RelayerInstance, handle: string, contractAddress: string, signer: RelayerSigner, options?: {
|
|
31
|
+
durationDays?: string;
|
|
32
|
+
startTimestamp?: string;
|
|
33
|
+
}): Promise<bigint>;
|
|
34
|
+
declare function publicDecrypt(relayer: RelayerInstance, handles: string[]): Promise<{
|
|
35
|
+
clearValues: Record<string, bigint>;
|
|
36
|
+
decryptionProof: string;
|
|
17
37
|
}>;
|
|
18
38
|
|
|
19
39
|
type ConfidentialTransferAmount = {
|
|
@@ -37,4 +57,31 @@ type ViewConfidentialTransferOptions = {
|
|
|
37
57
|
};
|
|
38
58
|
declare function viewConfidentialTransferAmounts(options: ViewConfidentialTransferOptions): Promise<ConfidentialTransferAmount[]>;
|
|
39
59
|
|
|
40
|
-
|
|
60
|
+
type TokenWriteSigner = RelayerSigner & {
|
|
61
|
+
writeContract?: (args: {
|
|
62
|
+
address: `0x${string}`;
|
|
63
|
+
abi: typeof confidentialTokenAbi;
|
|
64
|
+
functionName: "confidentialTransfer" | "wrap" | "unwrap" | "setObserver";
|
|
65
|
+
args: readonly unknown[];
|
|
66
|
+
}) => Promise<`0x${string}`>;
|
|
67
|
+
};
|
|
68
|
+
type ConfidentialTokenConfig = {
|
|
69
|
+
rpcUrl: string;
|
|
70
|
+
tokenAddress: `0x${string}`;
|
|
71
|
+
relayer: RelayerInstance;
|
|
72
|
+
signer: TokenWriteSigner;
|
|
73
|
+
};
|
|
74
|
+
declare class ConfidentialToken {
|
|
75
|
+
private readonly rpcUrl;
|
|
76
|
+
private readonly tokenAddress;
|
|
77
|
+
private readonly relayer;
|
|
78
|
+
private readonly signer;
|
|
79
|
+
constructor(config: ConfidentialTokenConfig);
|
|
80
|
+
balanceOf(account?: `0x${string}`): Promise<bigint>;
|
|
81
|
+
setObserver(account: `0x${string}`, observer: `0x${string}`): Promise<`0x${string}`>;
|
|
82
|
+
transfer(to: `0x${string}`, amount: number): Promise<`0x${string}`>;
|
|
83
|
+
wrap(to: `0x${string}`, amount: string | number | bigint): Promise<`0x${string}`>;
|
|
84
|
+
unwrap(from: `0x${string}`, to: `0x${string}`, amount: number): Promise<`0x${string}`>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { ConfidentialToken, type ConfidentialTokenConfig, type ConfidentialTransferAmount, type RelayerInstance, type RelayerSigner, type ViewConfidentialTransferOptions, ConfidentialToken as confidentialToken, confidentialTokenAbi, createEncryptedAmountInput, createRelayerInstance, publicDecrypt, userDecryptEuint64, viewConfidentialTransferAmounts };
|