@indigo-labs/indigo-sdk 0.1.7 → 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.
Files changed (89) hide show
  1. package/.github/workflows/ci.yml +62 -0
  2. package/.github/workflows/test.yml +44 -0
  3. package/.husky/pre-commit +1 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierrc +6 -0
  6. package/dist/index.d.mts +11 -1
  7. package/dist/index.d.ts +11 -1
  8. package/dist/index.js +15 -0
  9. package/dist/index.mjs +14 -0
  10. package/eslint.config.mjs +36 -0
  11. package/package.json +2 -5
  12. package/src/contracts/cdp.ts +741 -0
  13. package/src/contracts/collector.ts +98 -0
  14. package/src/contracts/gov.ts +1 -0
  15. package/src/contracts/interest-oracle.ts +149 -0
  16. package/src/contracts/lrp.ts +315 -0
  17. package/src/contracts/one-shot.ts +67 -0
  18. package/src/contracts/stability-pool.ts +684 -0
  19. package/src/contracts/staking.ts +348 -0
  20. package/src/contracts/treasury.ts +112 -0
  21. package/src/helpers/asset-helpers.ts +57 -0
  22. package/src/helpers/helper-txs.ts +30 -0
  23. package/src/helpers/helpers.ts +38 -0
  24. package/src/helpers/indigo-helpers.ts +19 -0
  25. package/src/helpers/interest-oracle.ts +57 -0
  26. package/src/helpers/lucid-utils.ts +70 -0
  27. package/src/helpers/price-oracle-helpers.ts +36 -0
  28. package/src/helpers/stability-pool-helpers.ts +207 -0
  29. package/src/helpers/staking-helpers.ts +94 -0
  30. package/src/helpers/time-helpers.ts +4 -0
  31. package/src/helpers/value-helpers.ts +27 -0
  32. package/src/index.ts +34 -0
  33. package/src/scripts/always-fail-validator.ts +7 -0
  34. package/src/scripts/auth-token-policy.ts +23 -0
  35. package/src/scripts/cdp-creator-validator.ts +53 -0
  36. package/src/scripts/cdp-validator.ts +9 -0
  37. package/src/scripts/collector-validator.ts +8 -0
  38. package/src/scripts/execute-validator.ts +52 -0
  39. package/src/scripts/gov-validator.ts +44 -0
  40. package/src/scripts/iasset-policy.ts +22 -0
  41. package/src/scripts/interest-oracle-validator.ts +23 -0
  42. package/src/scripts/lrp-validator.ts +40 -0
  43. package/src/scripts/one-shot-policy.ts +62 -0
  44. package/src/scripts/poll-manager-validator.ts +52 -0
  45. package/src/scripts/poll-shard-validator.ts +47 -0
  46. package/src/scripts/price-oracle-validator.ts +26 -0
  47. package/src/scripts/stability-pool-validator.ts +60 -0
  48. package/src/scripts/staking-validator.ts +8 -0
  49. package/src/scripts/treasury-validator.ts +8 -0
  50. package/src/scripts/version-record-policy.ts +26 -0
  51. package/src/scripts/version-registry.ts +15 -0
  52. package/src/types/generic.ts +106 -0
  53. package/src/types/indigo/cdp-creator.ts +46 -0
  54. package/src/types/indigo/cdp.ts +88 -0
  55. package/src/types/indigo/execute.ts +21 -0
  56. package/src/types/indigo/gov.ts +51 -0
  57. package/src/types/indigo/interest-oracle.ts +55 -0
  58. package/src/types/indigo/lrp.ts +59 -0
  59. package/src/types/indigo/poll-manager.ts +21 -0
  60. package/src/types/indigo/poll-shard.ts +16 -0
  61. package/src/types/indigo/price-oracle.ts +38 -0
  62. package/src/types/indigo/stability-pool.ts +233 -0
  63. package/src/types/indigo/staking.ts +99 -0
  64. package/src/types/indigo/version-record.ts +17 -0
  65. package/src/types/on-chain-decimal.ts +23 -0
  66. package/src/types/one-shot.ts +22 -0
  67. package/src/types/system-params.ts +256 -0
  68. package/tests/data/system-params.json +1012 -0
  69. package/tests/datums.test.ts +286 -0
  70. package/tests/endpoints/initialize.ts +1013 -0
  71. package/tests/hash-checks.test.ts +80 -0
  72. package/tests/indigo-test-helpers.ts +115 -0
  73. package/tests/initialize.test.ts +27 -0
  74. package/tests/interest-calculations.test.ts +120 -0
  75. package/tests/interest-oracle.test.ts +90 -0
  76. package/tests/lrp.test.ts +777 -0
  77. package/tests/queries/governance-queries.ts +31 -0
  78. package/tests/queries/iasset-queries.ts +39 -0
  79. package/tests/queries/interest-oracle-queries.ts +13 -0
  80. package/tests/queries/lrp-queries.ts +39 -0
  81. package/tests/queries/price-oracle-queries.ts +27 -0
  82. package/tests/queries/stability-pool-queries.ts +75 -0
  83. package/tests/queries/staking-queries.ts +43 -0
  84. package/tests/stability-pool.test.ts +364 -0
  85. package/tests/staking.test.ts +105 -0
  86. package/tests/test-helpers.ts +38 -0
  87. package/tsconfig.build.json +4 -0
  88. package/tsconfig.json +17 -0
  89. package/vitest.config.ts +9 -0
@@ -0,0 +1,98 @@
1
+ import {
2
+ Address,
3
+ applyParamsToScript,
4
+ Constr,
5
+ Data,
6
+ fromText,
7
+ LucidEvolution,
8
+ OutRef,
9
+ SpendingValidator,
10
+ TxBuilder,
11
+ UTxO,
12
+ validatorToAddress,
13
+ validatorToScriptHash,
14
+ } from '@lucid-evolution/lucid';
15
+ import { _collectorValidator } from '../scripts/collector-validator';
16
+ import {
17
+ CollectorParams,
18
+ ScriptReferences,
19
+ SystemParams,
20
+ } from '../types/system-params';
21
+ import { scriptRef } from '../helpers/lucid-utils';
22
+ import { getRandomElement } from '../helpers/helpers';
23
+
24
+ export class CollectorContract {
25
+ static async feeTx(
26
+ fee: bigint,
27
+ lucid: LucidEvolution,
28
+ params: SystemParams,
29
+ tx: TxBuilder,
30
+ collectorRef?: OutRef,
31
+ ): Promise<void> {
32
+ const collectorUtxo: UTxO = collectorRef
33
+ ? getRandomElement(await lucid.utxosByOutRef([collectorRef]))
34
+ : getRandomElement(
35
+ await lucid.utxosAt(
36
+ CollectorContract.address(params.collectorParams, lucid),
37
+ ),
38
+ );
39
+
40
+ const collectorScriptRefUtxo = await CollectorContract.scriptRef(
41
+ params.scriptReferences,
42
+ lucid,
43
+ );
44
+
45
+ tx.collectFrom([collectorUtxo], Data.to(new Constr(0, [])))
46
+ .pay.ToContract(
47
+ collectorUtxo.address,
48
+ { kind: 'inline', value: Data.to(new Constr(0, [])) },
49
+ {
50
+ ...collectorUtxo.assets,
51
+ lovelace: collectorUtxo.assets.lovelace + fee,
52
+ },
53
+ )
54
+ .readFrom([collectorScriptRefUtxo]);
55
+ }
56
+
57
+ // Collector Validator
58
+ static validator(params: CollectorParams): SpendingValidator {
59
+ return {
60
+ type: 'PlutusV2',
61
+ script: applyParamsToScript(_collectorValidator.cborHex, [
62
+ new Constr(0, [
63
+ new Constr(0, [
64
+ params.stakingManagerNFT[0].unCurrencySymbol,
65
+ fromText(params.stakingManagerNFT[1].unTokenName),
66
+ ]),
67
+ new Constr(0, [
68
+ params.stakingToken[0].unCurrencySymbol,
69
+ fromText(params.stakingToken[1].unTokenName),
70
+ ]),
71
+ new Constr(0, [
72
+ params.versionRecordToken[0].unCurrencySymbol,
73
+ fromText(params.versionRecordToken[1].unTokenName),
74
+ ]),
75
+ ]),
76
+ ]),
77
+ };
78
+ }
79
+
80
+ static validatorHash(params: CollectorParams): string {
81
+ return validatorToScriptHash(CollectorContract.validator(params));
82
+ }
83
+
84
+ static address(params: CollectorParams, lucid: LucidEvolution): Address {
85
+ const network = lucid.config().network;
86
+ if (!network) {
87
+ throw new Error('Network configuration is undefined');
88
+ }
89
+ return validatorToAddress(network, CollectorContract.validator(params));
90
+ }
91
+
92
+ static async scriptRef(
93
+ params: ScriptReferences,
94
+ lucid: LucidEvolution,
95
+ ): Promise<UTxO> {
96
+ return scriptRef(params.collectorValidatorRef, lucid);
97
+ }
98
+ }
@@ -0,0 +1 @@
1
+ export class GovContract {}
@@ -0,0 +1,149 @@
1
+ import {
2
+ fromText,
3
+ LucidEvolution,
4
+ OutRef,
5
+ toUnit,
6
+ TxBuilder,
7
+ UTxO,
8
+ validatorToAddress,
9
+ } from '@lucid-evolution/lucid';
10
+ import { AssetClass } from '../types/generic';
11
+ import {
12
+ InterestOracleParams,
13
+ parseInterestOracleDatum,
14
+ serialiseFeedInterestOracleRedeemer,
15
+ serialiseInterestOracleDatum,
16
+ } from '../types/indigo/interest-oracle';
17
+ import { oneShotMintTx } from './one-shot';
18
+ import { mkInterestOracleValidator } from '../scripts/interest-oracle-validator';
19
+ import { findInterestOracle } from '../../tests/queries/interest-oracle-queries';
20
+ import { ONE_SECOND } from '../helpers/time-helpers';
21
+ import { calculateUnitaryInterestSinceOracleLastUpdated } from '../helpers/interest-oracle';
22
+
23
+ export class InterestOracleContract {
24
+ static async startInterestOracle(
25
+ initialUnitaryInterest: bigint,
26
+ initialInterestRate: bigint,
27
+ initialLastInterestUpdate: bigint,
28
+ oracleParams: InterestOracleParams,
29
+ lucid: LucidEvolution,
30
+ withScriptRef: boolean = false,
31
+ refOutRef?: OutRef,
32
+ interestTokenName?: string,
33
+ ): Promise<[TxBuilder, AssetClass]> {
34
+ const tokenName = interestTokenName ?? 'INTEREST_ORACLE';
35
+ if (!refOutRef) {
36
+ refOutRef = (await lucid.wallet().getUtxos())[0];
37
+ }
38
+
39
+ const [tx, policyId] = await oneShotMintTx(lucid, {
40
+ referenceOutRef: {
41
+ txHash: refOutRef.txHash,
42
+ outputIdx: BigInt(refOutRef.outputIndex),
43
+ },
44
+ mintAmounts: [
45
+ {
46
+ tokenName: fromText(tokenName),
47
+ amount: 1n,
48
+ },
49
+ ],
50
+ });
51
+
52
+ const validator = mkInterestOracleValidator(oracleParams);
53
+
54
+ tx.pay.ToContract(
55
+ validatorToAddress(lucid.config().network, validator),
56
+ {
57
+ kind: 'inline',
58
+ value: serialiseInterestOracleDatum({
59
+ unitaryInterest: initialUnitaryInterest,
60
+ interestRate: {
61
+ getOnChainInt: initialInterestRate,
62
+ },
63
+ lastUpdated: initialLastInterestUpdate,
64
+ }),
65
+ },
66
+ {
67
+ lovelace: 2_500_000n,
68
+ [toUnit(policyId, fromText(tokenName))]: 1n,
69
+ },
70
+ );
71
+
72
+ if (withScriptRef) {
73
+ tx.pay.ToAddressWithData(
74
+ validatorToAddress(lucid.config().network, validator),
75
+ undefined,
76
+ undefined,
77
+ validator,
78
+ );
79
+ }
80
+
81
+ return [
82
+ tx,
83
+ {
84
+ currencySymbol: policyId,
85
+ tokenName: fromText(tokenName),
86
+ },
87
+ ];
88
+ }
89
+
90
+ static async feedInterestOracle(
91
+ params: InterestOracleParams,
92
+ newInterestRate: bigint,
93
+ lucid: LucidEvolution,
94
+ assetClass?: AssetClass,
95
+ utxo?: UTxO,
96
+ scriptRef?: UTxO,
97
+ ): Promise<TxBuilder> {
98
+ if (!assetClass && !utxo)
99
+ throw new Error('Either interest oracle nft or utxo must be provided');
100
+ if (assetClass && !utxo) {
101
+ const [ioUtxo, _datum] = await findInterestOracle(lucid, assetClass);
102
+ utxo = ioUtxo;
103
+ }
104
+
105
+ const now = BigInt(Date.now());
106
+ const tx = lucid.newTx();
107
+ const datum = parseInterestOracleDatum(utxo.datum);
108
+
109
+ if (scriptRef) {
110
+ tx.readFrom([scriptRef]);
111
+ } else {
112
+ tx.attach.Script(mkInterestOracleValidator(params));
113
+ }
114
+
115
+ tx.collectFrom(
116
+ [utxo],
117
+ serialiseFeedInterestOracleRedeemer({
118
+ newInterestRate: {
119
+ getOnChainInt: newInterestRate,
120
+ },
121
+ currentTime: now,
122
+ }),
123
+ );
124
+
125
+ tx.pay.ToContract(
126
+ utxo.address,
127
+ {
128
+ kind: 'inline',
129
+ value: serialiseInterestOracleDatum({
130
+ unitaryInterest:
131
+ datum.unitaryInterest +
132
+ calculateUnitaryInterestSinceOracleLastUpdated(now, datum),
133
+ interestRate: {
134
+ getOnChainInt: newInterestRate,
135
+ },
136
+ lastUpdated: now,
137
+ }),
138
+ },
139
+ utxo.assets,
140
+ );
141
+
142
+ tx.validFrom(Number(now) - ONE_SECOND);
143
+ tx.validTo(Number(now + params.biasTime) - ONE_SECOND);
144
+
145
+ tx.addSignerKey(params.owner);
146
+
147
+ return tx;
148
+ }
149
+ }
@@ -0,0 +1,315 @@
1
+ import {
2
+ LucidEvolution,
3
+ Network,
4
+ ScriptHash,
5
+ TxBuilder,
6
+ Credential,
7
+ OutRef,
8
+ UTxO,
9
+ addAssets,
10
+ } from '@lucid-evolution/lucid';
11
+ import {
12
+ addrDetails,
13
+ createScriptAddress,
14
+ getInlineDatumOrThrow,
15
+ } from '../helpers/lucid-utils';
16
+ import { match, P } from 'ts-pattern';
17
+ import { unzip, zip } from 'fp-ts/lib/Array';
18
+ import { reduceWithIndex } from 'fp-ts/lib/Array';
19
+ import {
20
+ LRPDatum,
21
+ LRPParams,
22
+ parseLrpDatum,
23
+ serialiseLrpDatum,
24
+ serialiseLrpRedeemer,
25
+ } from '../types/indigo/lrp';
26
+ import {
27
+ parsePriceOracleDatum,
28
+ PriceOracleParams,
29
+ } from '../types/indigo/price-oracle';
30
+ import { ocdMul, OnChainDecimal } from '../types/on-chain-decimal';
31
+ import { parseIAssetDatum } from '../types/indigo/cdp';
32
+ import {
33
+ assetClassValueOf,
34
+ mkAssetsOf,
35
+ mkLovelacesOf,
36
+ } from '../helpers/value-helpers';
37
+ import { oracleExpirationAwareValidity } from '../helpers/price-oracle-helpers';
38
+ import { calculateFeeFromPercentage } from '../helpers/indigo-helpers';
39
+ import { matchSingle } from '../helpers/helpers';
40
+ import { AssetClass } from '../types/generic';
41
+
42
+ const MIN_UTXO_COLLATERAL_AMT = 2_000_000n;
43
+
44
+ export async function openLrp(
45
+ assetTokenName: string,
46
+ lovelacesAmt: bigint,
47
+ maxPrice: OnChainDecimal,
48
+ lucid: LucidEvolution,
49
+ lrpScriptHash: ScriptHash,
50
+ network: Network,
51
+ lrpStakeCredential?: Credential,
52
+ ): Promise<TxBuilder> {
53
+ const [ownPkh, _] = await addrDetails(lucid);
54
+
55
+ const newDatum: LRPDatum = {
56
+ owner: ownPkh.hash,
57
+ iasset: assetTokenName,
58
+ maxPrice: maxPrice,
59
+ lovelacesToSpend: lovelacesAmt,
60
+ };
61
+
62
+ return lucid.newTx().pay.ToContract(
63
+ createScriptAddress(network, lrpScriptHash, lrpStakeCredential),
64
+ {
65
+ kind: 'inline',
66
+ value: serialiseLrpDatum(newDatum),
67
+ },
68
+ { lovelace: lovelacesAmt + MIN_UTXO_COLLATERAL_AMT },
69
+ );
70
+ }
71
+
72
+ export async function cancelLrp(
73
+ lrpOutRef: OutRef,
74
+ lrpRefScriptOutRef: OutRef,
75
+ lucid: LucidEvolution,
76
+ ): Promise<TxBuilder> {
77
+ const ownAddr = await lucid.wallet().address();
78
+ // TODO: use Promise.all
79
+ const lrpScriptRefUtxo = matchSingle(
80
+ await lucid.utxosByOutRef([lrpRefScriptOutRef]),
81
+ (_) => new Error('Expected a single LRP Ref Script UTXO'),
82
+ );
83
+
84
+ const lrpUtxo = matchSingle(
85
+ await lucid.utxosByOutRef([lrpOutRef]),
86
+ (_) => new Error('Expected a single LRP UTXO.'),
87
+ );
88
+
89
+ return lucid
90
+ .newTx()
91
+ .readFrom([lrpScriptRefUtxo])
92
+ .collectFrom([lrpUtxo], serialiseLrpRedeemer('Cancel'))
93
+ .addSigner(ownAddr);
94
+ }
95
+
96
+ export async function redeemLrp(
97
+ /** The tuple represents the LRP outref and the amount of iAssets to redeem against it. */
98
+ redemptionLrpsData: [OutRef, bigint][],
99
+ lrpRefScriptOutRef: OutRef,
100
+ priceOracleOutRef: OutRef,
101
+ iassetOutRef: OutRef,
102
+ lucid: LucidEvolution,
103
+ lrpParams: LRPParams,
104
+ priceOracleParams: PriceOracleParams,
105
+ network: Network,
106
+ currentSlot: number,
107
+ ): Promise<TxBuilder> {
108
+ const lrpScriptRefUtxo = matchSingle(
109
+ await lucid.utxosByOutRef([lrpRefScriptOutRef]),
110
+ (_) => new Error('Expected a single LRP Ref Script UTXO'),
111
+ );
112
+
113
+ const priceOracleUtxo = matchSingle(
114
+ await lucid.utxosByOutRef([priceOracleOutRef]),
115
+ (_) => new Error('Expected a single price oracle UTXO'),
116
+ );
117
+
118
+ const iassetUtxo = matchSingle(
119
+ await lucid.utxosByOutRef([iassetOutRef]),
120
+ (_) => new Error('Expected a single IAsset UTXO'),
121
+ );
122
+
123
+ const iassetDatum = parseIAssetDatum(getInlineDatumOrThrow(iassetUtxo));
124
+
125
+ const [lrpsToRedeemOutRefs, lrpRedemptionIAssetAmt] =
126
+ unzip(redemptionLrpsData);
127
+
128
+ const priceOracleDatum = parsePriceOracleDatum(
129
+ getInlineDatumOrThrow(priceOracleUtxo),
130
+ );
131
+
132
+ const redemptionLrps = await lucid
133
+ .utxosByOutRef(lrpsToRedeemOutRefs)
134
+ .then((val) => zip(val, lrpRedemptionIAssetAmt));
135
+
136
+ const [[mainLrpUtxo, _], __] = match(redemptionLrps)
137
+ .with(
138
+ [P._, ...P.array()],
139
+ ([[firstLrp, _], ...rest]): [[UTxO, bigint], [UTxO, bigint][]] => [
140
+ [firstLrp, _],
141
+ rest,
142
+ ],
143
+ )
144
+ .otherwise(() => {
145
+ throw new Error('Expects at least 1 UTXO to redeem.');
146
+ });
147
+
148
+ const mainLrpDatum = parseLrpDatum(getInlineDatumOrThrow(mainLrpUtxo));
149
+
150
+ const tx = reduceWithIndex<[UTxO, bigint], TxBuilder>(
151
+ lucid.newTx(),
152
+ (idx, acc, [lrpUtxo, redeemIAssetAmt]) => {
153
+ const lovelacesForRedemption = ocdMul(
154
+ {
155
+ getOnChainInt: redeemIAssetAmt,
156
+ },
157
+ priceOracleDatum.price,
158
+ ).getOnChainInt;
159
+ const reimburstmentLovelaces = calculateFeeFromPercentage(
160
+ iassetDatum.redemptionReimbursementPercentage,
161
+ lovelacesForRedemption,
162
+ );
163
+
164
+ const lrpDatum = parseLrpDatum(getInlineDatumOrThrow(lrpUtxo));
165
+
166
+ return acc
167
+ .collectFrom(
168
+ [lrpUtxo],
169
+ serialiseLrpRedeemer(
170
+ idx === 0
171
+ ? { Redeem: { continuingOutputIdx: 0n } }
172
+ : {
173
+ RedeemAuxiliary: {
174
+ continuingOutputIdx: BigInt(idx),
175
+ mainRedeemOutRef: {
176
+ txHash: { hash: mainLrpUtxo.txHash },
177
+ outputIndex: BigInt(mainLrpUtxo.outputIndex),
178
+ },
179
+ asset: mainLrpDatum.iasset,
180
+ assetPrice: priceOracleDatum.price,
181
+ redemptionReimbursementPercentage:
182
+ iassetDatum.redemptionReimbursementPercentage,
183
+ },
184
+ },
185
+ ),
186
+ )
187
+ .pay.ToContract(
188
+ lrpUtxo.address,
189
+ {
190
+ kind: 'inline',
191
+ value: serialiseLrpDatum({
192
+ ...lrpDatum,
193
+ lovelacesToSpend:
194
+ lrpDatum.lovelacesToSpend - lovelacesForRedemption,
195
+ }),
196
+ },
197
+ addAssets(
198
+ lrpUtxo.assets,
199
+ mkLovelacesOf(-(lovelacesForRedemption - reimburstmentLovelaces)),
200
+ mkAssetsOf(
201
+ {
202
+ currencySymbol: lrpParams.iassetPolicyId,
203
+ tokenName: mainLrpDatum.iasset,
204
+ },
205
+ redeemIAssetAmt,
206
+ ),
207
+ ),
208
+ );
209
+ },
210
+ )(redemptionLrps);
211
+
212
+ const txValidity = oracleExpirationAwareValidity(
213
+ currentSlot,
214
+ Number(priceOracleParams.biasTime),
215
+ Number(priceOracleDatum.expiration),
216
+ network,
217
+ );
218
+
219
+ return (
220
+ lucid
221
+ .newTx()
222
+ .validFrom(txValidity.validFrom)
223
+ .validTo(txValidity.validTo)
224
+ // Ref script
225
+ .readFrom([lrpScriptRefUtxo])
226
+ // Ref inputs
227
+ .readFrom([iassetUtxo, priceOracleUtxo])
228
+ .compose(tx)
229
+ );
230
+ }
231
+
232
+ /**
233
+ * Create Tx adjusting the LRP and claiming the received iAssets
234
+ */
235
+ export async function adjustLrp(
236
+ lucid: LucidEvolution,
237
+ lrpOutRef: OutRef,
238
+ /**
239
+ * A positive amount increases the lovelaces in the LRP,
240
+ * and a negative amount takes lovelaces from the LRP.
241
+ */
242
+ lovelacesAdjustAmt: bigint,
243
+ lrpRefScriptOutRef: OutRef,
244
+ lrpParams: LRPParams,
245
+ ): Promise<TxBuilder> {
246
+ const ownAddr = await lucid.wallet().address();
247
+
248
+ const lrpScriptRefUtxo = matchSingle(
249
+ await lucid.utxosByOutRef([lrpRefScriptOutRef]),
250
+ (_) => new Error('Expected a single LRP Ref Script UTXO'),
251
+ );
252
+
253
+ const lrpUtxo = matchSingle(
254
+ await lucid.utxosByOutRef([lrpOutRef]),
255
+ (_) => new Error('Expected a single LRP UTXO.'),
256
+ );
257
+
258
+ const lrpDatum = parseLrpDatum(getInlineDatumOrThrow(lrpUtxo));
259
+
260
+ const rewardAssetClass: AssetClass = {
261
+ currencySymbol: lrpParams.iassetPolicyId,
262
+ tokenName: lrpDatum.iasset,
263
+ };
264
+ const rewardAssetsAmt = assetClassValueOf(lrpUtxo.assets, rewardAssetClass);
265
+
266
+ // The claim case
267
+ if (lovelacesAdjustAmt === 0n && lrpDatum.lovelacesToSpend === 0n) {
268
+ throw new Error(
269
+ "When there's no more lovelaces to spend, use close instead of claim.",
270
+ );
271
+ }
272
+
273
+ // Negative adjust case
274
+ if (
275
+ lovelacesAdjustAmt < 0 &&
276
+ lrpDatum.lovelacesToSpend <= lovelacesAdjustAmt
277
+ ) {
278
+ throw new Error(
279
+ "Can't adjust negatively by more than available. Also, for adjusting by exactly the amount deposited, a close action should be used instead.",
280
+ );
281
+ }
282
+
283
+ return lucid
284
+ .newTx()
285
+ .readFrom([lrpScriptRefUtxo])
286
+ .collectFrom([lrpUtxo], serialiseLrpRedeemer('Cancel'))
287
+ .pay.ToContract(
288
+ lrpUtxo.address,
289
+ {
290
+ kind: 'inline',
291
+ value: serialiseLrpDatum({
292
+ ...lrpDatum,
293
+ lovelacesToSpend: lrpDatum.lovelacesToSpend + lovelacesAdjustAmt,
294
+ }),
295
+ },
296
+ addAssets(
297
+ lrpUtxo.assets,
298
+ mkAssetsOf(rewardAssetClass, -rewardAssetsAmt),
299
+ mkLovelacesOf(lovelacesAdjustAmt),
300
+ ),
301
+ )
302
+ .addSigner(ownAddr);
303
+ }
304
+
305
+ /**
306
+ * Create Tx claiming the received iAssets.
307
+ */
308
+ export async function claimLrp(
309
+ lucid: LucidEvolution,
310
+ lrpOutRef: OutRef,
311
+ lrpRefScriptOutRef: OutRef,
312
+ lrpParams: LRPParams,
313
+ ): Promise<TxBuilder> {
314
+ return adjustLrp(lucid, lrpOutRef, 0n, lrpRefScriptOutRef, lrpParams);
315
+ }
@@ -0,0 +1,67 @@
1
+ import {
2
+ addAssets,
3
+ Assets,
4
+ Constr,
5
+ Data,
6
+ LucidEvolution,
7
+ mintingPolicyToId,
8
+ PolicyId,
9
+ toUnit,
10
+ TxBuilder,
11
+ } from '@lucid-evolution/lucid';
12
+ import { OneShotParams } from '../types/one-shot';
13
+ import { matchSingle } from '../helpers/helpers';
14
+ import { mkOneShotPolicy } from '../scripts/one-shot-policy';
15
+ import { reduce } from 'fp-ts/lib/Array';
16
+
17
+ export async function oneShotMintTx(
18
+ lucid: LucidEvolution,
19
+ params: OneShotParams,
20
+ ): Promise<[TxBuilder, PolicyId]> {
21
+ const oneShotPolicy = mkOneShotPolicy(params);
22
+ const policyId = mintingPolicyToId(oneShotPolicy);
23
+
24
+ const refUtxo = matchSingle(
25
+ await lucid.utxosByOutRef([
26
+ {
27
+ txHash: params.referenceOutRef.txHash,
28
+ outputIndex: Number(params.referenceOutRef.outputIdx),
29
+ },
30
+ ]),
31
+ (_) => {
32
+ throw new Error('Cannot find the reference UTXO for one-shot.');
33
+ },
34
+ );
35
+
36
+ return [
37
+ lucid
38
+ .newTx()
39
+ .collectFrom([refUtxo])
40
+ .mintAssets(
41
+ reduce<{ tokenName: string; amount: bigint }, Assets>(
42
+ {},
43
+ (acc, entry) =>
44
+ addAssets(acc, {
45
+ [toUnit(policyId, entry.tokenName)]: entry.amount,
46
+ }),
47
+ )(params.mintAmounts),
48
+ Data.to(new Constr(0, [])),
49
+ )
50
+ .attach.MintingPolicy(oneShotPolicy),
51
+ policyId,
52
+ ];
53
+ }
54
+
55
+ export async function runOneShotMintTx(
56
+ lucid: LucidEvolution,
57
+ params: OneShotParams,
58
+ ): Promise<PolicyId> {
59
+ const [tx, policyId] = await oneShotMintTx(lucid, params);
60
+ const txHash = await tx
61
+ .complete()
62
+ .then((tx) => tx.sign.withWallet().complete())
63
+ .then((tx) => tx.submit());
64
+
65
+ await lucid.awaitTx(txHash);
66
+ return policyId;
67
+ }