@indigo-labs/indigo-sdk 0.4.4 → 0.5.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/dist/index.d.mts +102 -40
- package/dist/index.d.ts +102 -40
- package/dist/index.js +900 -801
- package/dist/index.mjs +339 -256
- package/package.json +2 -2
- package/src/contracts/cdp/helpers.ts +7 -6
- package/src/contracts/cdp/transactions.ts +8 -29
- package/src/contracts/gov/transactions.ts +12 -16
- package/src/contracts/iasset/helpers.ts +2 -7
- package/src/contracts/initialize/actions.ts +0 -2
- package/src/contracts/initialize/helpers.ts +0 -4
- package/src/contracts/interest-collection/transactions.ts +2 -5
- package/src/contracts/interest-oracle/helpers.ts +4 -0
- package/src/contracts/interest-oracle/transactions.ts +1 -4
- package/src/contracts/price-oracle/helpers.ts +5 -11
- package/src/contracts/price-oracle/transactions.ts +2 -7
- package/src/contracts/rob/transactions.ts +0 -2
- package/src/contracts/rob-leverage/transactions.ts +1 -4
- package/src/contracts/stability-pool/transactions.ts +2 -8
- package/src/contracts/stableswap/helpers.ts +369 -1
- package/src/contracts/stableswap/transactions.ts +43 -191
- package/src/contracts/staking/transactions.ts +2 -7
- package/tests/cdp/actions.ts +0 -11
- package/tests/cdp/cdp-helpers.ts +2 -2
- package/tests/cdp/cdp-queries.ts +1 -3
- package/tests/cdp/cdp.test.ts +409 -620
- package/tests/cdp/transactions-mutated.ts +30 -25
- package/tests/endpoints/initialize.ts +0 -2
- package/tests/gov/actions.ts +7 -32
- package/tests/gov/gov.test.ts +169 -401
- package/tests/indigo-test-helpers.ts +0 -1
- package/tests/initialize.test.ts +15 -20
- package/tests/interest-collection/interest-collection.test.ts +0 -4
- package/tests/interest-oracle.test.ts +1 -8
- package/tests/price-oracle/actions.ts +6 -8
- package/tests/price-oracle/price-oracle.test.ts +1 -13
- package/tests/price-oracle/transactions-mutated.ts +1 -4
- package/tests/pyth/pyth-indigo.test.ts +8 -12
- package/tests/pyth/pyth.test.ts +1 -2
- package/tests/rob/actions.ts +0 -2
- package/tests/rob/rob-leverage.test.ts +164 -220
- package/tests/rob/rob.test.ts +158 -263
- package/tests/rob/transactions-mutated.ts +7 -18
- package/tests/stability-pool/actions.ts +4 -8
- package/tests/stability-pool.test.ts +164 -255
- package/tests/stableswap/stableswap-actions.ts +0 -1
- package/tests/stableswap/stableswap.test.ts +226 -4
- package/tests/staking.test.ts +2 -13
- package/tests/treasury/treasury.test.ts +6 -30
package/tests/initialize.test.ts
CHANGED
|
@@ -40,29 +40,24 @@ beforeEach<MyContext>(async (context: MyContext) => {
|
|
|
40
40
|
test<MyContext>('Initialize Protocol - can initialize', async ({
|
|
41
41
|
lucid,
|
|
42
42
|
users,
|
|
43
|
-
emulator,
|
|
44
43
|
}: MyContext) => {
|
|
45
44
|
lucid.selectWallet.fromSeed(users.admin.seedPhrase);
|
|
46
45
|
|
|
47
|
-
await init(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
]),
|
|
63
|
-
],
|
|
64
|
-
emulator.slot,
|
|
65
|
-
);
|
|
46
|
+
await init(lucid, [
|
|
47
|
+
iusdInitialAssetCfg(DEFAULT_INTEREST, [
|
|
48
|
+
{
|
|
49
|
+
collateralAsset: EXAMPLE_TOKEN_1,
|
|
50
|
+
collateralToIassetRatio: rationalFromInt(1n),
|
|
51
|
+
feeManager: undefined,
|
|
52
|
+
minMintOrderAmount: 0n,
|
|
53
|
+
minRedemptionOrderAmount: 0n,
|
|
54
|
+
mintingEnabled: true,
|
|
55
|
+
redemptionEnabled: true,
|
|
56
|
+
mintingFeeRatio: { numerator: 1n, denominator: 100n },
|
|
57
|
+
redemptionFeeRatio: { numerator: 1n, denominator: 100n },
|
|
58
|
+
},
|
|
59
|
+
]),
|
|
60
|
+
]);
|
|
66
61
|
});
|
|
67
62
|
|
|
68
63
|
test<MyContext>('Validate Lucid protocol parameters match Mainnet', ({
|
|
@@ -314,7 +314,6 @@ describe('Interest Collection', () => {
|
|
|
314
314
|
priceOracleUtxo!,
|
|
315
315
|
rationalFromInt(1n),
|
|
316
316
|
iAssetConfig.collateralAssets[0].oracleParams!,
|
|
317
|
-
context.emulator.slot,
|
|
318
317
|
),
|
|
319
318
|
);
|
|
320
319
|
|
|
@@ -327,7 +326,6 @@ describe('Interest Collection', () => {
|
|
|
327
326
|
cdpsInfo.map((cdp) => cdp.utxo),
|
|
328
327
|
context.systemParams,
|
|
329
328
|
context.lucid,
|
|
330
|
-
context.emulator.slot,
|
|
331
329
|
),
|
|
332
330
|
context.lucid,
|
|
333
331
|
context.emulator,
|
|
@@ -406,7 +404,6 @@ describe('Interest Collection', () => {
|
|
|
406
404
|
priceOracleUtxo!,
|
|
407
405
|
rationalFromInt(1n),
|
|
408
406
|
iAssetConfig.collateralAssets[0].oracleParams!,
|
|
409
|
-
context.emulator.slot,
|
|
410
407
|
),
|
|
411
408
|
);
|
|
412
409
|
|
|
@@ -419,7 +416,6 @@ describe('Interest Collection', () => {
|
|
|
419
416
|
cdpsInfo.map((cdp) => cdp.utxo),
|
|
420
417
|
context.systemParams,
|
|
421
418
|
context.lucid,
|
|
422
|
-
context.emulator.slot,
|
|
423
419
|
),
|
|
424
420
|
);
|
|
425
421
|
});
|
|
@@ -86,14 +86,7 @@ test<InterestOracleTestContext>('Interest Oracle - Update', async ({
|
|
|
86
86
|
|
|
87
87
|
await benchmarkAndAwaitTx(
|
|
88
88
|
'Interest Oracle - Update',
|
|
89
|
-
await feedInterestOracle(
|
|
90
|
-
interestParams,
|
|
91
|
-
500_000n,
|
|
92
|
-
lucid,
|
|
93
|
-
emulator.slot,
|
|
94
|
-
undefined,
|
|
95
|
-
utxo,
|
|
96
|
-
),
|
|
89
|
+
await feedInterestOracle(interestParams, 500_000n, lucid, undefined, utxo),
|
|
97
90
|
lucid,
|
|
98
91
|
emulator,
|
|
99
92
|
);
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
} from '../cdp/cdp-queries';
|
|
17
17
|
import { feedPriceOracleTx } from '../../src/contracts/price-oracle/transactions';
|
|
18
18
|
import { findCollateralAsset } from '../queries/iasset-queries';
|
|
19
|
-
import { unixTimeToSlot } from '@lucid-evolution/lucid';
|
|
20
19
|
import { findPriceOracle } from './price-oracle-queries';
|
|
21
20
|
import { match, P } from 'ts-pattern';
|
|
22
21
|
import { parsePriceOracleDatum } from '../../src/contracts/price-oracle/types-new';
|
|
@@ -65,7 +64,6 @@ export async function runFeedPriceToOracle(
|
|
|
65
64
|
priceOracleUtxo!,
|
|
66
65
|
price,
|
|
67
66
|
collateralInfo.oracleParams!,
|
|
68
|
-
context.emulator.slot,
|
|
69
67
|
),
|
|
70
68
|
);
|
|
71
69
|
|
|
@@ -120,7 +118,6 @@ export async function refreshPriceOracle(
|
|
|
120
118
|
priceOracleUtxo!,
|
|
121
119
|
price,
|
|
122
120
|
collateralInfo.oracleParams!,
|
|
123
|
-
context.emulator.slot,
|
|
124
121
|
),
|
|
125
122
|
);
|
|
126
123
|
|
|
@@ -147,15 +144,16 @@ export async function waitForOracleExpiration(
|
|
|
147
144
|
|
|
148
145
|
const oracle = parsePriceOracleDatum(getInlineDatumOrThrow(priceOracle));
|
|
149
146
|
|
|
150
|
-
const targetSlot = unixTimeToSlot(
|
|
151
|
-
context.lucid.config().network!,
|
|
147
|
+
const targetSlot = context.lucid.unixTimeToSlot(
|
|
152
148
|
Number(oracle.expirationTime),
|
|
153
149
|
);
|
|
154
150
|
|
|
155
|
-
if (targetSlot > context.
|
|
156
|
-
expect(targetSlot).toBeGreaterThan(context.
|
|
151
|
+
if (targetSlot > context.lucid.currentSlot()) {
|
|
152
|
+
expect(targetSlot).toBeGreaterThan(context.lucid.currentSlot());
|
|
157
153
|
|
|
158
|
-
context.emulator.awaitSlot(
|
|
154
|
+
context.emulator.awaitSlot(
|
|
155
|
+
targetSlot - context.lucid.currentSlot() + 5,
|
|
156
|
+
);
|
|
159
157
|
}
|
|
160
158
|
})
|
|
161
159
|
// otherwise no need to await
|
|
@@ -52,7 +52,6 @@ describe('Rational Price Oracle', () => {
|
|
|
52
52
|
'ORACLE_NFT',
|
|
53
53
|
rationalFromInt(1n),
|
|
54
54
|
params,
|
|
55
|
-
context.emulator.slot,
|
|
56
55
|
);
|
|
57
56
|
|
|
58
57
|
await runAndAwaitTxBuilder(context.lucid, tx);
|
|
@@ -70,7 +69,6 @@ describe('Rational Price Oracle', () => {
|
|
|
70
69
|
'ORACLE_NFT',
|
|
71
70
|
rationalFromInt(1n),
|
|
72
71
|
params,
|
|
73
|
-
context.emulator.slot,
|
|
74
72
|
);
|
|
75
73
|
|
|
76
74
|
const startTxHash = await runAndAwaitTxBuilder(context.lucid, startTx);
|
|
@@ -80,7 +78,6 @@ describe('Rational Price Oracle', () => {
|
|
|
80
78
|
{ txHash: startTxHash, outputIndex: 0 },
|
|
81
79
|
rationalFromInt(2n),
|
|
82
80
|
params,
|
|
83
|
-
context.emulator.slot,
|
|
84
81
|
);
|
|
85
82
|
|
|
86
83
|
await runAndAwaitTxBuilder(context.lucid, feedTx);
|
|
@@ -98,7 +95,6 @@ describe('Rational Price Oracle', () => {
|
|
|
98
95
|
'ORACLE_NFT',
|
|
99
96
|
rationalFromInt(1n),
|
|
100
97
|
params,
|
|
101
|
-
context.emulator.slot,
|
|
102
98
|
);
|
|
103
99
|
|
|
104
100
|
const startTxHash = await runAndAwaitTxBuilder(context.lucid, startTx);
|
|
@@ -110,7 +106,6 @@ describe('Rational Price Oracle', () => {
|
|
|
110
106
|
{ txHash: startTxHash, outputIndex: 0 },
|
|
111
107
|
rationalFromInt(-2n),
|
|
112
108
|
params,
|
|
113
|
-
context.emulator.slot,
|
|
114
109
|
),
|
|
115
110
|
);
|
|
116
111
|
});
|
|
@@ -127,7 +122,6 @@ describe('Rational Price Oracle', () => {
|
|
|
127
122
|
'ORACLE_NFT',
|
|
128
123
|
rationalFromInt(1n),
|
|
129
124
|
params,
|
|
130
|
-
context.emulator.slot,
|
|
131
125
|
);
|
|
132
126
|
|
|
133
127
|
const startTxHash = await runAndAwaitTxBuilder(context.lucid, startTx);
|
|
@@ -139,7 +133,6 @@ describe('Rational Price Oracle', () => {
|
|
|
139
133
|
{ txHash: startTxHash, outputIndex: 0 },
|
|
140
134
|
rationalFromInt(2n),
|
|
141
135
|
params,
|
|
142
|
-
context.emulator.slot,
|
|
143
136
|
),
|
|
144
137
|
);
|
|
145
138
|
});
|
|
@@ -156,7 +149,6 @@ describe('Rational Price Oracle', () => {
|
|
|
156
149
|
'ORACLE_NFT',
|
|
157
150
|
rationalFromInt(1n),
|
|
158
151
|
params,
|
|
159
|
-
context.emulator.slot,
|
|
160
152
|
);
|
|
161
153
|
|
|
162
154
|
const startTxHash = await runAndAwaitTxBuilder(context.lucid, startTx);
|
|
@@ -168,7 +160,6 @@ describe('Rational Price Oracle', () => {
|
|
|
168
160
|
{ txHash: startTxHash, outputIndex: 0 },
|
|
169
161
|
{ numerator: 2n, denominator: 0n },
|
|
170
162
|
params,
|
|
171
|
-
context.emulator.slot,
|
|
172
163
|
),
|
|
173
164
|
);
|
|
174
165
|
});
|
|
@@ -185,7 +176,6 @@ describe('Rational Price Oracle', () => {
|
|
|
185
176
|
'ORACLE_NFT',
|
|
186
177
|
rationalFromInt(1n),
|
|
187
178
|
params,
|
|
188
|
-
context.emulator.slot,
|
|
189
179
|
);
|
|
190
180
|
|
|
191
181
|
const startTxHash = await runAndAwaitTxBuilder(context.lucid, startTx);
|
|
@@ -201,7 +191,6 @@ describe('Rational Price Oracle', () => {
|
|
|
201
191
|
denominator: BigInt(Number.MAX_SAFE_INTEGER),
|
|
202
192
|
},
|
|
203
193
|
params,
|
|
204
|
-
context.emulator.slot,
|
|
205
194
|
),
|
|
206
195
|
);
|
|
207
196
|
});
|
|
@@ -218,7 +207,6 @@ describe('Rational Price Oracle', () => {
|
|
|
218
207
|
'ORACLE_NFT',
|
|
219
208
|
rationalFromInt(1n),
|
|
220
209
|
params,
|
|
221
|
-
context.emulator.slot,
|
|
222
210
|
);
|
|
223
211
|
|
|
224
212
|
const startTxHash = await runAndAwaitTxBuilder(context.lucid, startTx);
|
|
@@ -230,7 +218,7 @@ describe('Rational Price Oracle', () => {
|
|
|
230
218
|
{ txHash: startTxHash, outputIndex: 0 },
|
|
231
219
|
rationalFromInt(1n),
|
|
232
220
|
params,
|
|
233
|
-
|
|
221
|
+
|
|
234
222
|
Core.Data.fromCBORHex(
|
|
235
223
|
'd8799f1b0180e51d1ae19514d8799f1a00030d40ff1b00000194ce33c598ff',
|
|
236
224
|
),
|
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
Data,
|
|
3
3
|
LucidEvolution,
|
|
4
4
|
OutRef,
|
|
5
|
-
slotToUnixTime,
|
|
6
5
|
TxBuilder,
|
|
7
6
|
} from '@lucid-evolution/lucid';
|
|
8
7
|
import {
|
|
@@ -22,10 +21,8 @@ export async function feedPriceOracleTxStealNft(
|
|
|
22
21
|
oracleOref: OutRef,
|
|
23
22
|
newPrice: Rational,
|
|
24
23
|
oracleParams: PriceOracleParams,
|
|
25
|
-
currentSlot: number,
|
|
26
24
|
): Promise<TxBuilder> {
|
|
27
|
-
const
|
|
28
|
-
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
|
|
25
|
+
const currentTime = BigInt(lucid.slotToUnixTime(lucid.currentSlot()));
|
|
29
26
|
|
|
30
27
|
const priceOracleUtxo = matchSingle(
|
|
31
28
|
await lucid.utxosByOutRef([oracleOref]),
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
generateEmulatorAccount,
|
|
15
15
|
generateEmulatorAccountFromPrivateKey,
|
|
16
16
|
Lucid,
|
|
17
|
-
slotToUnixTime,
|
|
18
17
|
toHex,
|
|
19
18
|
} from '@lucid-evolution/lucid';
|
|
20
19
|
import {
|
|
@@ -89,7 +88,6 @@ describe('Pyth > Indigo', () => {
|
|
|
89
88
|
const [systemParams, assetConfigs] = await init(
|
|
90
89
|
context.lucid,
|
|
91
90
|
[],
|
|
92
|
-
context.emulator.slot,
|
|
93
91
|
(pythStateNft: AssetClass) => [
|
|
94
92
|
iusdInitialAssetCfgWithPyth(pythStateNft, (pythStatePolicyId) => [
|
|
95
93
|
mkBaseCollateralAsset(
|
|
@@ -142,7 +140,7 @@ describe('Pyth > Indigo', () => {
|
|
|
142
140
|
|
|
143
141
|
test('Open CDP - Direct Price Value (ada collateral)', async (context: IndigoTestContext) => {
|
|
144
142
|
const currentTime = BigInt(
|
|
145
|
-
|
|
143
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
146
144
|
);
|
|
147
145
|
|
|
148
146
|
const iUsdFeed: ParsedFeedPayload = {
|
|
@@ -170,7 +168,7 @@ describe('Pyth > Indigo', () => {
|
|
|
170
168
|
|
|
171
169
|
test('Open CDP - Direct Price Value (non-ADA collateral)', async (context: IndigoTestContext) => {
|
|
172
170
|
const currentTime = BigInt(
|
|
173
|
-
|
|
171
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
174
172
|
);
|
|
175
173
|
|
|
176
174
|
const iEthFeed: ParsedFeedPayload = {
|
|
@@ -199,7 +197,7 @@ describe('Pyth > Indigo', () => {
|
|
|
199
197
|
|
|
200
198
|
test('Open CDP - Divide Price Value', async (context: IndigoTestContext) => {
|
|
201
199
|
const currentTime = BigInt(
|
|
202
|
-
|
|
200
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
203
201
|
);
|
|
204
202
|
|
|
205
203
|
const feed1: ParsedFeedPayload = {
|
|
@@ -235,7 +233,7 @@ describe('Pyth > Indigo', () => {
|
|
|
235
233
|
|
|
236
234
|
test('Open CDP - Fails if missing feed price', async (context: IndigoTestContext) => {
|
|
237
235
|
const currentTime = BigInt(
|
|
238
|
-
|
|
236
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
239
237
|
);
|
|
240
238
|
|
|
241
239
|
// This feed doesn't include a price for feedId 2, which is used by the iBTC asset
|
|
@@ -261,7 +259,7 @@ describe('Pyth > Indigo', () => {
|
|
|
261
259
|
|
|
262
260
|
test('Withdraw CDP - Direct Price Value', async (context: IndigoTestContext) => {
|
|
263
261
|
const currentTime = BigInt(
|
|
264
|
-
|
|
262
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
265
263
|
);
|
|
266
264
|
|
|
267
265
|
const iUsdFeed: ParsedFeedPayload = {
|
|
@@ -302,7 +300,7 @@ describe('Pyth > Indigo', () => {
|
|
|
302
300
|
|
|
303
301
|
test('Freeze CDP - Direct Price Value', async (context: IndigoTestContext) => {
|
|
304
302
|
const currentTime = BigInt(
|
|
305
|
-
|
|
303
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
306
304
|
);
|
|
307
305
|
{
|
|
308
306
|
const iUsdFeed: ParsedFeedPayload = {
|
|
@@ -355,7 +353,7 @@ describe('Pyth > Indigo', () => {
|
|
|
355
353
|
const [ownPkh, _] = await addrDetails(context.lucid);
|
|
356
354
|
|
|
357
355
|
const currentTime = BigInt(
|
|
358
|
-
|
|
356
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
359
357
|
);
|
|
360
358
|
const iUsdFeed: ParsedFeedPayload = {
|
|
361
359
|
priceFeedId: 1,
|
|
@@ -413,7 +411,6 @@ describe('Pyth > Indigo', () => {
|
|
|
413
411
|
[[robUtxo, redemptionIAssetAmt]],
|
|
414
412
|
'iUSD',
|
|
415
413
|
adaAssetClass,
|
|
416
|
-
context.emulator.slot,
|
|
417
414
|
toHex(message),
|
|
418
415
|
),
|
|
419
416
|
context.lucid,
|
|
@@ -425,7 +422,7 @@ describe('Pyth > Indigo', () => {
|
|
|
425
422
|
const [ownPkh, _] = await addrDetails(context.lucid);
|
|
426
423
|
|
|
427
424
|
const currentTime = BigInt(
|
|
428
|
-
|
|
425
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
429
426
|
);
|
|
430
427
|
const iUsdFeed: ParsedFeedPayload = {
|
|
431
428
|
priceFeedId: 1,
|
|
@@ -499,7 +496,6 @@ describe('Pyth > Indigo', () => {
|
|
|
499
496
|
[[robUtxo, payoutCollateralAmt]],
|
|
500
497
|
'iUSD',
|
|
501
498
|
adaAssetClass,
|
|
502
|
-
context.emulator.slot,
|
|
503
499
|
toHex(message),
|
|
504
500
|
),
|
|
505
501
|
context.lucid,
|
package/tests/pyth/pyth.test.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
generateEmulatorAccount,
|
|
8
8
|
Lucid,
|
|
9
9
|
scriptHashToCredential,
|
|
10
|
-
slotToUnixTime,
|
|
11
10
|
toHex,
|
|
12
11
|
validatorToScriptHash,
|
|
13
12
|
} from '@lucid-evolution/lucid';
|
|
@@ -140,7 +139,7 @@ describe('Pyth > Initialization', () => {
|
|
|
140
139
|
);
|
|
141
140
|
|
|
142
141
|
const currentTime = BigInt(
|
|
143
|
-
|
|
142
|
+
context.lucid.slotToUnixTime(context.lucid.currentSlot()),
|
|
144
143
|
);
|
|
145
144
|
|
|
146
145
|
// This is to test the transaction validity when using a timestamp different than the
|
package/tests/rob/actions.ts
CHANGED
|
@@ -12,7 +12,6 @@ export async function runRedeemRob(
|
|
|
12
12
|
redemptionRobsData: [RobOutput, bigint][],
|
|
13
13
|
iasset: string,
|
|
14
14
|
collateralAsset: AssetClass,
|
|
15
|
-
currentSlot: number,
|
|
16
15
|
pythMessage?: string,
|
|
17
16
|
): Promise<TxBuilder> {
|
|
18
17
|
if (redemptionRobsData.length === 0) throw new Error('No ROBs to redeem');
|
|
@@ -51,7 +50,6 @@ export async function runRedeemRob(
|
|
|
51
50
|
collateral.utxo,
|
|
52
51
|
context.lucid,
|
|
53
52
|
sysParams,
|
|
54
|
-
currentSlot,
|
|
55
53
|
pythMessage,
|
|
56
54
|
pythStateOutRef,
|
|
57
55
|
);
|