@indigo-labs/indigo-sdk 0.1.6 → 0.1.8
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/.github/workflows/ci.yml +62 -0
- package/.github/workflows/test.yml +44 -0
- package/.husky/pre-commit +1 -0
- package/.nvmrc +1 -0
- package/.prettierrc +6 -0
- package/dist/index.d.mts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +81 -6
- package/dist/index.mjs +78 -6
- package/eslint.config.mjs +36 -0
- package/package.json +2 -5
- package/src/contracts/cdp.ts +741 -0
- package/src/contracts/collector.ts +98 -0
- package/src/contracts/gov.ts +1 -0
- package/src/contracts/interest-oracle.ts +149 -0
- package/src/contracts/lrp.ts +315 -0
- package/src/contracts/one-shot.ts +67 -0
- package/src/contracts/stability-pool.ts +684 -0
- package/src/contracts/staking.ts +348 -0
- package/src/contracts/treasury.ts +112 -0
- package/src/helpers/asset-helpers.ts +57 -0
- package/src/helpers/helper-txs.ts +30 -0
- package/src/helpers/helpers.ts +38 -0
- package/src/helpers/indigo-helpers.ts +19 -0
- package/src/helpers/interest-oracle.ts +57 -0
- package/src/helpers/lucid-utils.ts +70 -0
- package/src/helpers/price-oracle-helpers.ts +36 -0
- package/src/helpers/stability-pool-helpers.ts +207 -0
- package/src/helpers/staking-helpers.ts +94 -0
- package/src/helpers/time-helpers.ts +4 -0
- package/src/helpers/value-helpers.ts +27 -0
- package/src/index.ts +34 -0
- package/src/scripts/always-fail-validator.ts +7 -0
- package/src/scripts/auth-token-policy.ts +23 -0
- package/src/scripts/cdp-creator-validator.ts +53 -0
- package/src/scripts/cdp-validator.ts +9 -0
- package/src/scripts/collector-validator.ts +8 -0
- package/src/scripts/execute-validator.ts +52 -0
- package/src/scripts/gov-validator.ts +44 -0
- package/src/scripts/iasset-policy.ts +22 -0
- package/src/scripts/interest-oracle-validator.ts +23 -0
- package/src/scripts/lrp-validator.ts +40 -0
- package/src/scripts/one-shot-policy.ts +62 -0
- package/src/scripts/poll-manager-validator.ts +52 -0
- package/src/scripts/poll-shard-validator.ts +47 -0
- package/src/scripts/price-oracle-validator.ts +26 -0
- package/src/scripts/stability-pool-validator.ts +60 -0
- package/src/scripts/staking-validator.ts +8 -0
- package/src/scripts/treasury-validator.ts +8 -0
- package/src/scripts/version-record-policy.ts +26 -0
- package/src/scripts/version-registry.ts +15 -0
- package/src/types/generic.ts +106 -0
- package/src/types/indigo/cdp-creator.ts +46 -0
- package/src/types/indigo/cdp.ts +88 -0
- package/src/types/indigo/execute.ts +21 -0
- package/src/types/indigo/gov.ts +51 -0
- package/src/types/indigo/interest-oracle.ts +55 -0
- package/src/types/indigo/lrp.ts +59 -0
- package/src/types/indigo/poll-manager.ts +21 -0
- package/src/types/indigo/poll-shard.ts +16 -0
- package/src/types/indigo/price-oracle.ts +38 -0
- package/src/types/indigo/stability-pool.ts +233 -0
- package/src/types/indigo/staking.ts +99 -0
- package/src/types/indigo/version-record.ts +17 -0
- package/src/types/on-chain-decimal.ts +23 -0
- package/src/types/one-shot.ts +22 -0
- package/src/types/system-params.ts +256 -0
- package/tests/data/system-params.json +1012 -0
- package/tests/datums.test.ts +286 -0
- package/tests/endpoints/initialize.ts +1013 -0
- package/tests/hash-checks.test.ts +80 -0
- package/tests/indigo-test-helpers.ts +115 -0
- package/tests/initialize.test.ts +27 -0
- package/tests/interest-calculations.test.ts +120 -0
- package/tests/interest-oracle.test.ts +90 -0
- package/tests/lrp.test.ts +777 -0
- package/tests/queries/governance-queries.ts +31 -0
- package/tests/queries/iasset-queries.ts +39 -0
- package/tests/queries/interest-oracle-queries.ts +13 -0
- package/tests/queries/lrp-queries.ts +39 -0
- package/tests/queries/price-oracle-queries.ts +27 -0
- package/tests/queries/stability-pool-queries.ts +75 -0
- package/tests/queries/staking-queries.ts +43 -0
- package/tests/stability-pool.test.ts +364 -0
- package/tests/staking.test.ts +105 -0
- package/tests/test-helpers.ts +38 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
import { assert, describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
Emulator,
|
|
4
|
+
fromText,
|
|
5
|
+
generateEmulatorAccount,
|
|
6
|
+
Lucid,
|
|
7
|
+
LucidEvolution,
|
|
8
|
+
Network,
|
|
9
|
+
paymentCredentialOf,
|
|
10
|
+
toText,
|
|
11
|
+
UTxO,
|
|
12
|
+
validatorToScriptHash,
|
|
13
|
+
} from '@lucid-evolution/lucid';
|
|
14
|
+
import { LRPParams, parseLrpDatum } from '../src/types/indigo/lrp';
|
|
15
|
+
import { mkLrpValidator } from '../src/scripts/lrp-validator';
|
|
16
|
+
import { runCreateScriptRefTx } from '../src/helpers/helper-txs';
|
|
17
|
+
import { runOneShotMintTx } from '../src/contracts/one-shot';
|
|
18
|
+
import {
|
|
19
|
+
adjustLrp,
|
|
20
|
+
cancelLrp,
|
|
21
|
+
claimLrp,
|
|
22
|
+
openLrp,
|
|
23
|
+
redeemLrp,
|
|
24
|
+
} from '../src/contracts/lrp';
|
|
25
|
+
import { findLrp } from './queries/lrp-queries';
|
|
26
|
+
import { addrDetails, getInlineDatumOrThrow } from '../src/helpers/lucid-utils';
|
|
27
|
+
import { runAndAwaitTx } from './test-helpers';
|
|
28
|
+
import { matchSingle } from '../src/helpers/helpers';
|
|
29
|
+
import { runCreateIAsset, runStartPriceOracle } from './indigo-test-helpers';
|
|
30
|
+
import { mkPriceOracleValidator } from '../src/scripts/price-oracle-validator';
|
|
31
|
+
import { AssetClass, OracleAssetNft, PriceOracleParams } from '../src';
|
|
32
|
+
import { alwaysFailValidator } from '../src/scripts/always-fail-validator';
|
|
33
|
+
import {
|
|
34
|
+
OCD_ONE,
|
|
35
|
+
OCD_ZERO,
|
|
36
|
+
OnChainDecimal,
|
|
37
|
+
} from '../src/types/on-chain-decimal';
|
|
38
|
+
import { findPriceOracle } from './queries/price-oracle-queries';
|
|
39
|
+
import { findIAsset } from './queries/iasset-queries';
|
|
40
|
+
import { assetClassValueOf, lovelacesAmt } from '../src/helpers/value-helpers';
|
|
41
|
+
import { strictEqual } from 'assert';
|
|
42
|
+
|
|
43
|
+
type LRPTestContext = {
|
|
44
|
+
iassetAc: AssetClass;
|
|
45
|
+
oracleNft: OracleAssetNft;
|
|
46
|
+
iassetNft: AssetClass;
|
|
47
|
+
iassetValHash: string;
|
|
48
|
+
oracleParams: PriceOracleParams;
|
|
49
|
+
oracleValHash: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
async function initTest(
|
|
53
|
+
/** The admin account lucid instance */
|
|
54
|
+
lucid: LucidEvolution,
|
|
55
|
+
network: Network,
|
|
56
|
+
iassetTokenName: string,
|
|
57
|
+
initialMint: bigint,
|
|
58
|
+
iassetPrice: OnChainDecimal,
|
|
59
|
+
): Promise<LRPTestContext> {
|
|
60
|
+
const utxos = await lucid.wallet().getUtxos();
|
|
61
|
+
const iassetPolicyId = await runOneShotMintTx(lucid, {
|
|
62
|
+
referenceOutRef: {
|
|
63
|
+
txHash: utxos[0].txHash,
|
|
64
|
+
outputIdx: BigInt(utxos[0].outputIndex),
|
|
65
|
+
},
|
|
66
|
+
mintAmounts: [{ tokenName: iassetTokenName, amount: initialMint }],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const [ownPkh, _] = await addrDetails(lucid);
|
|
70
|
+
|
|
71
|
+
const priceOracleParams: PriceOracleParams = {
|
|
72
|
+
owner: ownPkh.hash,
|
|
73
|
+
// 1 minute
|
|
74
|
+
biasTime: 1n * 60n * 1000n,
|
|
75
|
+
// 10 minutes
|
|
76
|
+
expiration: 10n * 60n * 1000n,
|
|
77
|
+
};
|
|
78
|
+
const oracleValidator = mkPriceOracleValidator(priceOracleParams);
|
|
79
|
+
const oracleValidatorHash = validatorToScriptHash(oracleValidator);
|
|
80
|
+
const oracleNft = await runStartPriceOracle(
|
|
81
|
+
lucid,
|
|
82
|
+
oracleValidatorHash,
|
|
83
|
+
priceOracleParams,
|
|
84
|
+
network,
|
|
85
|
+
fromText('ORACLE_IBTC'),
|
|
86
|
+
iassetPrice,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const iassetValHash = validatorToScriptHash(alwaysFailValidator);
|
|
90
|
+
const iassetNft = await runCreateIAsset(lucid, network, iassetValHash, {
|
|
91
|
+
assetName: iassetTokenName,
|
|
92
|
+
price: { Oracle: oracleNft },
|
|
93
|
+
interestOracleNft: { currencySymbol: '', tokenName: '' },
|
|
94
|
+
redemptionRatio: OCD_ONE,
|
|
95
|
+
maintenanceRatio: OCD_ONE,
|
|
96
|
+
liquidationRatio: OCD_ONE,
|
|
97
|
+
debtMintingFeePercentage: OCD_ZERO,
|
|
98
|
+
liquidationProcessingFeePercentage: OCD_ZERO,
|
|
99
|
+
stabilityPoolWithdrawalFeePercentage: OCD_ZERO,
|
|
100
|
+
redemptionReimbursementPercentage: OCD_ONE,
|
|
101
|
+
redemptionProcessingFeePercentage: OCD_ZERO,
|
|
102
|
+
interestCollectorPortionPercentage: OCD_ZERO,
|
|
103
|
+
firstIAsset: true,
|
|
104
|
+
nextIAsset: null,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
oracleNft: oracleNft,
|
|
109
|
+
iassetAc: { currencySymbol: iassetPolicyId, tokenName: iassetTokenName },
|
|
110
|
+
iassetNft: iassetNft,
|
|
111
|
+
iassetValHash: iassetValHash,
|
|
112
|
+
oracleParams: priceOracleParams,
|
|
113
|
+
oracleValHash: oracleValidatorHash,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
describe('LRP', () => {
|
|
118
|
+
it('adjust positive and negative', async () => {
|
|
119
|
+
const network: Network = 'Custom';
|
|
120
|
+
const account1 = generateEmulatorAccount({
|
|
121
|
+
lovelace: 80_000_000_000n, // 80,000 ADA
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const emulator = new Emulator([account1]);
|
|
125
|
+
const lucid = await Lucid(emulator, network);
|
|
126
|
+
|
|
127
|
+
lucid.selectWallet.fromSeed(account1.seedPhrase);
|
|
128
|
+
|
|
129
|
+
const iassetTokenName = fromText('iBTC');
|
|
130
|
+
const testCtx = await initTest(
|
|
131
|
+
lucid,
|
|
132
|
+
network,
|
|
133
|
+
iassetTokenName,
|
|
134
|
+
10_000_000n,
|
|
135
|
+
OCD_ONE,
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const [ownPkh, _] = await addrDetails(lucid);
|
|
139
|
+
|
|
140
|
+
const lrpParams: LRPParams = {
|
|
141
|
+
versionRecordToken: {
|
|
142
|
+
currencySymbol: fromText('smth'),
|
|
143
|
+
tokenName: fromText('version_record'),
|
|
144
|
+
},
|
|
145
|
+
iassetNft: testCtx.iassetNft,
|
|
146
|
+
iassetPolicyId: testCtx.iassetAc.currencySymbol,
|
|
147
|
+
minRedemptionLovelacesAmt: 1_000_000n,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const lrpValidator = mkLrpValidator(lrpParams);
|
|
151
|
+
const lrpValidatorHash = validatorToScriptHash(lrpValidator);
|
|
152
|
+
const lrpRefScriptOutRef = await runCreateScriptRefTx(
|
|
153
|
+
lucid,
|
|
154
|
+
lrpValidator,
|
|
155
|
+
network,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const findSingleOwnLrp = async (): Promise<UTxO> => {
|
|
159
|
+
return matchSingle(
|
|
160
|
+
await findLrp(
|
|
161
|
+
lucid,
|
|
162
|
+
network,
|
|
163
|
+
lrpValidatorHash,
|
|
164
|
+
ownPkh.hash,
|
|
165
|
+
iassetTokenName,
|
|
166
|
+
),
|
|
167
|
+
(res) =>
|
|
168
|
+
new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
await runAndAwaitTx(
|
|
173
|
+
lucid,
|
|
174
|
+
openLrp(
|
|
175
|
+
iassetTokenName,
|
|
176
|
+
20_000_000n,
|
|
177
|
+
{ getOnChainInt: 1_000_000n },
|
|
178
|
+
lucid,
|
|
179
|
+
lrpValidatorHash,
|
|
180
|
+
network,
|
|
181
|
+
),
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
await runAndAwaitTx(
|
|
185
|
+
lucid,
|
|
186
|
+
findSingleOwnLrp().then((lrp) =>
|
|
187
|
+
adjustLrp(lucid, lrp, -1_000_000n, lrpRefScriptOutRef, lrpParams),
|
|
188
|
+
),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const adjustedUtxo1 = await findSingleOwnLrp();
|
|
192
|
+
|
|
193
|
+
assert(
|
|
194
|
+
parseLrpDatum(getInlineDatumOrThrow(adjustedUtxo1)).lovelacesToSpend ===
|
|
195
|
+
20_000_000n - 1_000_000n,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
expect(
|
|
199
|
+
lovelacesAmt(adjustedUtxo1.assets) >=
|
|
200
|
+
parseLrpDatum(getInlineDatumOrThrow(adjustedUtxo1)).lovelacesToSpend,
|
|
201
|
+
'Lovelaces to spend has to be smaller than actual lovelaces in UTXO',
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
await runAndAwaitTx(
|
|
205
|
+
lucid,
|
|
206
|
+
adjustLrp(
|
|
207
|
+
lucid,
|
|
208
|
+
adjustedUtxo1,
|
|
209
|
+
5_000_000n,
|
|
210
|
+
lrpRefScriptOutRef,
|
|
211
|
+
lrpParams,
|
|
212
|
+
),
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const adjustedUtxo2 = matchSingle(
|
|
216
|
+
await findLrp(
|
|
217
|
+
lucid,
|
|
218
|
+
network,
|
|
219
|
+
lrpValidatorHash,
|
|
220
|
+
ownPkh.hash,
|
|
221
|
+
iassetTokenName,
|
|
222
|
+
),
|
|
223
|
+
(res) => new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const expectedResultAdaAmt = 20_000_000n - 1_000_000n + 5_000_000n;
|
|
227
|
+
|
|
228
|
+
strictEqual(
|
|
229
|
+
parseLrpDatum(getInlineDatumOrThrow(adjustedUtxo2)).lovelacesToSpend,
|
|
230
|
+
expectedResultAdaAmt,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(
|
|
234
|
+
lovelacesAmt(adjustedUtxo2.assets) >=
|
|
235
|
+
parseLrpDatum(getInlineDatumOrThrow(adjustedUtxo2)).lovelacesToSpend,
|
|
236
|
+
'Lovelaces to spend has to be smaller than actual lovelaces in UTXO',
|
|
237
|
+
);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('claim', async () => {
|
|
241
|
+
const network: Network = 'Custom';
|
|
242
|
+
const account1 = generateEmulatorAccount({
|
|
243
|
+
lovelace: 80_000_000_000n, // 80,000 ADA
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const emulator = new Emulator([account1]);
|
|
247
|
+
const lucid = await Lucid(emulator, network);
|
|
248
|
+
|
|
249
|
+
lucid.selectWallet.fromSeed(account1.seedPhrase);
|
|
250
|
+
|
|
251
|
+
const iassetTokenName = fromText('iBTC');
|
|
252
|
+
const testCtx = await initTest(
|
|
253
|
+
lucid,
|
|
254
|
+
network,
|
|
255
|
+
iassetTokenName,
|
|
256
|
+
10_000_000n,
|
|
257
|
+
OCD_ONE,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const [ownPkh, _] = await addrDetails(lucid);
|
|
261
|
+
|
|
262
|
+
const lrpParams: LRPParams = {
|
|
263
|
+
versionRecordToken: {
|
|
264
|
+
currencySymbol: fromText('smth'),
|
|
265
|
+
tokenName: fromText('version_record'),
|
|
266
|
+
},
|
|
267
|
+
iassetNft: testCtx.iassetNft,
|
|
268
|
+
iassetPolicyId: testCtx.iassetAc.currencySymbol,
|
|
269
|
+
minRedemptionLovelacesAmt: 1_000_000n,
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const lrpValidator = mkLrpValidator(lrpParams);
|
|
273
|
+
const lrpValidatorHash = validatorToScriptHash(lrpValidator);
|
|
274
|
+
const lrpRefScriptOutRef = await runCreateScriptRefTx(
|
|
275
|
+
lucid,
|
|
276
|
+
lrpValidator,
|
|
277
|
+
network,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const findSingleOwnLrp = async (): Promise<UTxO> => {
|
|
281
|
+
return matchSingle(
|
|
282
|
+
await findLrp(
|
|
283
|
+
lucid,
|
|
284
|
+
network,
|
|
285
|
+
lrpValidatorHash,
|
|
286
|
+
ownPkh.hash,
|
|
287
|
+
iassetTokenName,
|
|
288
|
+
),
|
|
289
|
+
(res) =>
|
|
290
|
+
new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
291
|
+
);
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
await runAndAwaitTx(
|
|
295
|
+
lucid,
|
|
296
|
+
openLrp(
|
|
297
|
+
iassetTokenName,
|
|
298
|
+
20_000_000n,
|
|
299
|
+
{ getOnChainInt: 1_000_000n },
|
|
300
|
+
lucid,
|
|
301
|
+
lrpValidatorHash,
|
|
302
|
+
network,
|
|
303
|
+
),
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
const lrpUtxo = await findSingleOwnLrp();
|
|
307
|
+
|
|
308
|
+
const redemptionAsset: AssetClass = {
|
|
309
|
+
currencySymbol: testCtx.iassetAc.currencySymbol,
|
|
310
|
+
tokenName: iassetTokenName,
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
strictEqual(
|
|
314
|
+
assetClassValueOf(lrpUtxo.assets, redemptionAsset),
|
|
315
|
+
0n,
|
|
316
|
+
'LRP should have no iassets before redemption',
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
const redemptionIAssetAmt = 5_000_000n;
|
|
320
|
+
|
|
321
|
+
await runAndAwaitTx(
|
|
322
|
+
lucid,
|
|
323
|
+
redeemLrp(
|
|
324
|
+
[[lrpUtxo, redemptionIAssetAmt]],
|
|
325
|
+
lrpRefScriptOutRef,
|
|
326
|
+
await findPriceOracle(
|
|
327
|
+
lucid,
|
|
328
|
+
network,
|
|
329
|
+
testCtx.oracleValHash,
|
|
330
|
+
testCtx.oracleNft,
|
|
331
|
+
),
|
|
332
|
+
await findIAsset(
|
|
333
|
+
lucid,
|
|
334
|
+
testCtx.iassetValHash,
|
|
335
|
+
testCtx.iassetNft,
|
|
336
|
+
toText(iassetTokenName),
|
|
337
|
+
),
|
|
338
|
+
lucid,
|
|
339
|
+
lrpParams,
|
|
340
|
+
testCtx.oracleParams,
|
|
341
|
+
network,
|
|
342
|
+
emulator.slot,
|
|
343
|
+
),
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
const redeemedLrp = await findSingleOwnLrp();
|
|
347
|
+
|
|
348
|
+
strictEqual(
|
|
349
|
+
assetClassValueOf(redeemedLrp.assets, redemptionAsset),
|
|
350
|
+
redemptionIAssetAmt,
|
|
351
|
+
'LRP has wrong number of iassets after redemption',
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
await runAndAwaitTx(
|
|
355
|
+
lucid,
|
|
356
|
+
claimLrp(lucid, redeemedLrp, lrpRefScriptOutRef, lrpParams),
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
const claimedLrp = await findSingleOwnLrp();
|
|
360
|
+
|
|
361
|
+
strictEqual(
|
|
362
|
+
assetClassValueOf(claimedLrp.assets, redemptionAsset),
|
|
363
|
+
0n,
|
|
364
|
+
'LRP has to have 0 redemption assets after claim',
|
|
365
|
+
);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('claim using adjust', async () => {
|
|
369
|
+
const network: Network = 'Custom';
|
|
370
|
+
const account1 = generateEmulatorAccount({
|
|
371
|
+
lovelace: 80_000_000_000n, // 80,000 ADA
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
const emulator = new Emulator([account1]);
|
|
375
|
+
const lucid = await Lucid(emulator, network);
|
|
376
|
+
|
|
377
|
+
lucid.selectWallet.fromSeed(account1.seedPhrase);
|
|
378
|
+
|
|
379
|
+
const iassetTokenName = fromText('iBTC');
|
|
380
|
+
const testCtx = await initTest(
|
|
381
|
+
lucid,
|
|
382
|
+
network,
|
|
383
|
+
iassetTokenName,
|
|
384
|
+
10_000_000n,
|
|
385
|
+
OCD_ONE,
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
const [ownPkh, _] = await addrDetails(lucid);
|
|
389
|
+
|
|
390
|
+
const lrpParams: LRPParams = {
|
|
391
|
+
versionRecordToken: {
|
|
392
|
+
currencySymbol: fromText('smth'),
|
|
393
|
+
tokenName: fromText('version_record'),
|
|
394
|
+
},
|
|
395
|
+
iassetNft: testCtx.iassetNft,
|
|
396
|
+
iassetPolicyId: testCtx.iassetAc.currencySymbol,
|
|
397
|
+
minRedemptionLovelacesAmt: 1_000_000n,
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const lrpValidator = mkLrpValidator(lrpParams);
|
|
401
|
+
const lrpValidatorHash = validatorToScriptHash(lrpValidator);
|
|
402
|
+
const lrpRefScriptOutRef = await runCreateScriptRefTx(
|
|
403
|
+
lucid,
|
|
404
|
+
lrpValidator,
|
|
405
|
+
network,
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
const findSingleOwnLrp = async (): Promise<UTxO> => {
|
|
409
|
+
return matchSingle(
|
|
410
|
+
await findLrp(
|
|
411
|
+
lucid,
|
|
412
|
+
network,
|
|
413
|
+
lrpValidatorHash,
|
|
414
|
+
ownPkh.hash,
|
|
415
|
+
iassetTokenName,
|
|
416
|
+
),
|
|
417
|
+
(res) =>
|
|
418
|
+
new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
419
|
+
);
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
await runAndAwaitTx(
|
|
423
|
+
lucid,
|
|
424
|
+
openLrp(
|
|
425
|
+
iassetTokenName,
|
|
426
|
+
20_000_000n,
|
|
427
|
+
{ getOnChainInt: 1_000_000n },
|
|
428
|
+
lucid,
|
|
429
|
+
lrpValidatorHash,
|
|
430
|
+
network,
|
|
431
|
+
),
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const lrpUtxo = await findSingleOwnLrp();
|
|
435
|
+
|
|
436
|
+
const redemptionAsset: AssetClass = {
|
|
437
|
+
currencySymbol: testCtx.iassetAc.currencySymbol,
|
|
438
|
+
tokenName: iassetTokenName,
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
strictEqual(
|
|
442
|
+
assetClassValueOf(lrpUtxo.assets, redemptionAsset),
|
|
443
|
+
0n,
|
|
444
|
+
'LRP should have no iassets before redemption',
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
const redemptionIAssetAmt = 5_000_000n;
|
|
448
|
+
|
|
449
|
+
await runAndAwaitTx(
|
|
450
|
+
lucid,
|
|
451
|
+
redeemLrp(
|
|
452
|
+
[[lrpUtxo, redemptionIAssetAmt]],
|
|
453
|
+
lrpRefScriptOutRef,
|
|
454
|
+
await findPriceOracle(
|
|
455
|
+
lucid,
|
|
456
|
+
network,
|
|
457
|
+
testCtx.oracleValHash,
|
|
458
|
+
testCtx.oracleNft,
|
|
459
|
+
),
|
|
460
|
+
await findIAsset(
|
|
461
|
+
lucid,
|
|
462
|
+
testCtx.iassetValHash,
|
|
463
|
+
testCtx.iassetNft,
|
|
464
|
+
toText(iassetTokenName),
|
|
465
|
+
),
|
|
466
|
+
lucid,
|
|
467
|
+
lrpParams,
|
|
468
|
+
testCtx.oracleParams,
|
|
469
|
+
network,
|
|
470
|
+
emulator.slot,
|
|
471
|
+
),
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
const redeemedLrp = await findSingleOwnLrp();
|
|
475
|
+
|
|
476
|
+
strictEqual(
|
|
477
|
+
assetClassValueOf(redeemedLrp.assets, redemptionAsset),
|
|
478
|
+
redemptionIAssetAmt,
|
|
479
|
+
'LRP has wrong number of iassets after redemption',
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
await runAndAwaitTx(
|
|
483
|
+
lucid,
|
|
484
|
+
adjustLrp(lucid, redeemedLrp, -1_000_000n, lrpRefScriptOutRef, lrpParams),
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
const adjustedLrp = await findSingleOwnLrp();
|
|
488
|
+
|
|
489
|
+
strictEqual(
|
|
490
|
+
assetClassValueOf(adjustedLrp.assets, redemptionAsset),
|
|
491
|
+
0n,
|
|
492
|
+
'LRP has to have 0 redemption assets after adjust',
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
strictEqual(
|
|
496
|
+
parseLrpDatum(getInlineDatumOrThrow(adjustedLrp)).lovelacesToSpend,
|
|
497
|
+
// 20mil start, 5mil redeemer at price 1:1, -1mil adjusted
|
|
498
|
+
14_000_000n,
|
|
499
|
+
);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
it('single redemption and cancel', async () => {
|
|
503
|
+
const network: Network = 'Custom';
|
|
504
|
+
const account1 = generateEmulatorAccount({
|
|
505
|
+
lovelace: 80_000_000_000n, // 80,000 ADA
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
const emulator = new Emulator([account1]);
|
|
509
|
+
const lucid = await Lucid(emulator, network);
|
|
510
|
+
|
|
511
|
+
lucid.selectWallet.fromSeed(account1.seedPhrase);
|
|
512
|
+
|
|
513
|
+
const iassetTokenName = fromText('iBTC');
|
|
514
|
+
const testCtx = await initTest(
|
|
515
|
+
lucid,
|
|
516
|
+
network,
|
|
517
|
+
iassetTokenName,
|
|
518
|
+
10_000_000n,
|
|
519
|
+
OCD_ONE,
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
const [ownPkh, _] = await addrDetails(lucid);
|
|
523
|
+
|
|
524
|
+
const lrpParams: LRPParams = {
|
|
525
|
+
versionRecordToken: {
|
|
526
|
+
currencySymbol: fromText('smth'),
|
|
527
|
+
tokenName: fromText('version_record'),
|
|
528
|
+
},
|
|
529
|
+
iassetNft: testCtx.iassetNft,
|
|
530
|
+
iassetPolicyId: testCtx.iassetAc.currencySymbol,
|
|
531
|
+
minRedemptionLovelacesAmt: 1_000_000n,
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
const lrpValidator = mkLrpValidator(lrpParams);
|
|
535
|
+
const lrpValidatorHash = validatorToScriptHash(lrpValidator);
|
|
536
|
+
const lrpRefScriptOutRef = await runCreateScriptRefTx(
|
|
537
|
+
lucid,
|
|
538
|
+
lrpValidator,
|
|
539
|
+
network,
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
const findSingleOwnLrp = async (): Promise<UTxO> => {
|
|
543
|
+
return matchSingle(
|
|
544
|
+
await findLrp(
|
|
545
|
+
lucid,
|
|
546
|
+
network,
|
|
547
|
+
lrpValidatorHash,
|
|
548
|
+
ownPkh.hash,
|
|
549
|
+
iassetTokenName,
|
|
550
|
+
),
|
|
551
|
+
(res) =>
|
|
552
|
+
new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
553
|
+
);
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
await runAndAwaitTx(
|
|
557
|
+
lucid,
|
|
558
|
+
openLrp(
|
|
559
|
+
iassetTokenName,
|
|
560
|
+
20_000_000n,
|
|
561
|
+
{ getOnChainInt: 1_000_000n },
|
|
562
|
+
lucid,
|
|
563
|
+
lrpValidatorHash,
|
|
564
|
+
network,
|
|
565
|
+
),
|
|
566
|
+
);
|
|
567
|
+
|
|
568
|
+
const lrpUtxo = await findSingleOwnLrp();
|
|
569
|
+
|
|
570
|
+
const redemptionAsset: AssetClass = {
|
|
571
|
+
currencySymbol: testCtx.iassetAc.currencySymbol,
|
|
572
|
+
tokenName: iassetTokenName,
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
strictEqual(
|
|
576
|
+
assetClassValueOf(lrpUtxo.assets, redemptionAsset),
|
|
577
|
+
0n,
|
|
578
|
+
'LRP should have no iassets before redemption',
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
const redemptionIAssetAmt = 5_000_000n;
|
|
582
|
+
|
|
583
|
+
await runAndAwaitTx(
|
|
584
|
+
lucid,
|
|
585
|
+
redeemLrp(
|
|
586
|
+
[[lrpUtxo, redemptionIAssetAmt]],
|
|
587
|
+
lrpRefScriptOutRef,
|
|
588
|
+
await findPriceOracle(
|
|
589
|
+
lucid,
|
|
590
|
+
network,
|
|
591
|
+
testCtx.oracleValHash,
|
|
592
|
+
testCtx.oracleNft,
|
|
593
|
+
),
|
|
594
|
+
await findIAsset(
|
|
595
|
+
lucid,
|
|
596
|
+
testCtx.iassetValHash,
|
|
597
|
+
testCtx.iassetNft,
|
|
598
|
+
toText(iassetTokenName),
|
|
599
|
+
),
|
|
600
|
+
lucid,
|
|
601
|
+
lrpParams,
|
|
602
|
+
testCtx.oracleParams,
|
|
603
|
+
network,
|
|
604
|
+
emulator.slot,
|
|
605
|
+
),
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
const redeemedLrp = await findSingleOwnLrp();
|
|
609
|
+
|
|
610
|
+
strictEqual(
|
|
611
|
+
assetClassValueOf(redeemedLrp.assets, redemptionAsset),
|
|
612
|
+
redemptionIAssetAmt,
|
|
613
|
+
'LRP has wrong number of iassets after redemption',
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
await runAndAwaitTx(
|
|
617
|
+
lucid,
|
|
618
|
+
cancelLrp(redeemedLrp, lrpRefScriptOutRef, lucid),
|
|
619
|
+
);
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
it('multi redemption case', async () => {
|
|
623
|
+
const network: Network = 'Custom';
|
|
624
|
+
const account1 = generateEmulatorAccount({
|
|
625
|
+
lovelace: 80_000_000_000n, // 80,000 ADA
|
|
626
|
+
});
|
|
627
|
+
const account2 = generateEmulatorAccount({
|
|
628
|
+
lovelace: 80_000_000_000n, // 80,000 ADA
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
const emulator = new Emulator([account1, account2]);
|
|
632
|
+
const lucid = await Lucid(emulator, network);
|
|
633
|
+
|
|
634
|
+
lucid.selectWallet.fromSeed(account1.seedPhrase);
|
|
635
|
+
|
|
636
|
+
const iassetTokenName = fromText('TEST_IBTC');
|
|
637
|
+
const testCtx = await initTest(
|
|
638
|
+
lucid,
|
|
639
|
+
network,
|
|
640
|
+
iassetTokenName,
|
|
641
|
+
100_000_000n,
|
|
642
|
+
OCD_ONE,
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
const lrpParams: LRPParams = {
|
|
646
|
+
versionRecordToken: {
|
|
647
|
+
currencySymbol: fromText('smth'),
|
|
648
|
+
tokenName: fromText('version_record'),
|
|
649
|
+
},
|
|
650
|
+
iassetNft: testCtx.iassetNft,
|
|
651
|
+
iassetPolicyId: testCtx.iassetAc.currencySymbol,
|
|
652
|
+
minRedemptionLovelacesAmt: 1_000_000n,
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
const lrpValidator = mkLrpValidator(lrpParams);
|
|
656
|
+
const lrpValidatorHash = validatorToScriptHash(lrpValidator);
|
|
657
|
+
const lrpRefScriptOutRef = await runCreateScriptRefTx(
|
|
658
|
+
lucid,
|
|
659
|
+
lrpValidator,
|
|
660
|
+
network,
|
|
661
|
+
);
|
|
662
|
+
|
|
663
|
+
await runAndAwaitTx(
|
|
664
|
+
lucid,
|
|
665
|
+
openLrp(
|
|
666
|
+
iassetTokenName,
|
|
667
|
+
20_000_000n,
|
|
668
|
+
{ getOnChainInt: 1_000_000n },
|
|
669
|
+
lucid,
|
|
670
|
+
lrpValidatorHash,
|
|
671
|
+
network,
|
|
672
|
+
),
|
|
673
|
+
);
|
|
674
|
+
|
|
675
|
+
lucid.selectWallet.fromSeed(account2.seedPhrase);
|
|
676
|
+
|
|
677
|
+
await runAndAwaitTx(
|
|
678
|
+
lucid,
|
|
679
|
+
openLrp(
|
|
680
|
+
iassetTokenName,
|
|
681
|
+
20_000_000n,
|
|
682
|
+
{ getOnChainInt: 1_100_000n },
|
|
683
|
+
lucid,
|
|
684
|
+
lrpValidatorHash,
|
|
685
|
+
network,
|
|
686
|
+
),
|
|
687
|
+
);
|
|
688
|
+
|
|
689
|
+
const lrpUtxo2 = matchSingle(
|
|
690
|
+
await findLrp(
|
|
691
|
+
lucid,
|
|
692
|
+
network,
|
|
693
|
+
lrpValidatorHash,
|
|
694
|
+
await addrDetails(lucid).then((d) => d[0].hash),
|
|
695
|
+
iassetTokenName,
|
|
696
|
+
),
|
|
697
|
+
(res) => new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
lucid.selectWallet.fromSeed(account1.seedPhrase);
|
|
701
|
+
|
|
702
|
+
const lrpUtxo1 = matchSingle(
|
|
703
|
+
await findLrp(
|
|
704
|
+
lucid,
|
|
705
|
+
network,
|
|
706
|
+
lrpValidatorHash,
|
|
707
|
+
await addrDetails(lucid).then((d) => d[0].hash),
|
|
708
|
+
iassetTokenName,
|
|
709
|
+
),
|
|
710
|
+
(res) => new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
711
|
+
);
|
|
712
|
+
|
|
713
|
+
await runAndAwaitTx(
|
|
714
|
+
lucid,
|
|
715
|
+
redeemLrp(
|
|
716
|
+
[
|
|
717
|
+
[lrpUtxo1, 5_000_000n],
|
|
718
|
+
[lrpUtxo2, 4_000_000n],
|
|
719
|
+
],
|
|
720
|
+
lrpRefScriptOutRef,
|
|
721
|
+
await findPriceOracle(
|
|
722
|
+
lucid,
|
|
723
|
+
network,
|
|
724
|
+
testCtx.oracleValHash,
|
|
725
|
+
testCtx.oracleNft,
|
|
726
|
+
),
|
|
727
|
+
await findIAsset(
|
|
728
|
+
lucid,
|
|
729
|
+
testCtx.iassetValHash,
|
|
730
|
+
testCtx.iassetNft,
|
|
731
|
+
toText(iassetTokenName),
|
|
732
|
+
),
|
|
733
|
+
lucid,
|
|
734
|
+
lrpParams,
|
|
735
|
+
testCtx.oracleParams,
|
|
736
|
+
network,
|
|
737
|
+
emulator.slot,
|
|
738
|
+
),
|
|
739
|
+
);
|
|
740
|
+
|
|
741
|
+
const resultLrpUtxo1 = matchSingle(
|
|
742
|
+
await findLrp(
|
|
743
|
+
lucid,
|
|
744
|
+
network,
|
|
745
|
+
lrpValidatorHash,
|
|
746
|
+
paymentCredentialOf(account1.address).hash,
|
|
747
|
+
iassetTokenName,
|
|
748
|
+
),
|
|
749
|
+
(res) => new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
750
|
+
);
|
|
751
|
+
const resultLrpUtxo2 = matchSingle(
|
|
752
|
+
await findLrp(
|
|
753
|
+
lucid,
|
|
754
|
+
network,
|
|
755
|
+
lrpValidatorHash,
|
|
756
|
+
paymentCredentialOf(account2.address).hash,
|
|
757
|
+
iassetTokenName,
|
|
758
|
+
),
|
|
759
|
+
(res) => new Error('Expected a single LRP UTXO.: ' + JSON.stringify(res)),
|
|
760
|
+
);
|
|
761
|
+
|
|
762
|
+
assert(
|
|
763
|
+
assetClassValueOf(resultLrpUtxo1.assets, {
|
|
764
|
+
currencySymbol: testCtx.iassetAc.currencySymbol,
|
|
765
|
+
tokenName: iassetTokenName,
|
|
766
|
+
}) === 5_000_000n,
|
|
767
|
+
'LRP1 has wrong number of iassets after redemption',
|
|
768
|
+
);
|
|
769
|
+
assert(
|
|
770
|
+
assetClassValueOf(resultLrpUtxo2.assets, {
|
|
771
|
+
currencySymbol: testCtx.iassetAc.currencySymbol,
|
|
772
|
+
tokenName: iassetTokenName,
|
|
773
|
+
}) === 4_000_000n,
|
|
774
|
+
'LRP2 has wrong number of iassets after redemption',
|
|
775
|
+
);
|
|
776
|
+
});
|
|
777
|
+
});
|