@indigo-labs/indigo-sdk 0.2.1 → 0.2.4

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.
@@ -1,11 +1,8 @@
1
1
  import {
2
2
  LucidEvolution,
3
- Network,
4
- ScriptHash,
5
3
  TxBuilder,
6
4
  Credential,
7
5
  OutRef,
8
- UTxO,
9
6
  addAssets,
10
7
  unixTimeToSlot,
11
8
  slotToUnixTime,
@@ -15,39 +12,39 @@ import {
15
12
  createScriptAddress,
16
13
  getInlineDatumOrThrow,
17
14
  } from '../../utils/lucid-utils';
18
- import { match, P } from 'ts-pattern';
19
15
  import { unzip, zip } from 'fp-ts/lib/Array';
20
- import { reduceWithIndex } from 'fp-ts/lib/Array';
21
16
  import {
22
17
  LRPDatum,
23
- LRPParams,
24
- parseLrpDatum,
18
+ parseLrpDatumOrThrow,
25
19
  serialiseLrpDatum,
26
20
  serialiseLrpRedeemer,
27
21
  } from './types';
28
22
  import { parsePriceOracleDatum } from '../price-oracle/types';
29
- import { ocdMul, OnChainDecimal } from '../../types/on-chain-decimal';
23
+ import { OnChainDecimal } from '../../types/on-chain-decimal';
30
24
  import { parseIAssetDatumOrThrow } from '../cdp/types';
31
25
  import {
32
26
  assetClassValueOf,
33
27
  mkAssetsOf,
34
28
  mkLovelacesOf,
35
29
  } from '../../utils/value-helpers';
36
- import { calculateFeeFromPercentage } from '../../utils/indigo-helpers';
37
30
  import { matchSingle } from '../../utils/utils';
38
31
  import { AssetClass } from '../../types/generic';
39
-
40
- const MIN_UTXO_COLLATERAL_AMT = 2_000_000n;
32
+ import {
33
+ fromSystemParamsScriptRef,
34
+ SystemParams,
35
+ } from '../../types/system-params';
36
+ import { buildRedemptionsTx, MIN_LRP_COLLATERAL_AMT } from './helpers';
41
37
 
42
38
  export async function openLrp(
43
39
  assetTokenName: string,
44
40
  lovelacesAmt: bigint,
45
41
  maxPrice: OnChainDecimal,
46
42
  lucid: LucidEvolution,
47
- lrpScriptHash: ScriptHash,
48
- network: Network,
43
+ sysParams: SystemParams,
49
44
  lrpStakeCredential?: Credential,
50
45
  ): Promise<TxBuilder> {
46
+ const network = lucid.config().network!;
47
+
51
48
  const [ownPkh, _] = await addrDetails(lucid);
52
49
 
53
50
  const newDatum: LRPDatum = {
@@ -58,22 +55,28 @@ export async function openLrp(
58
55
  };
59
56
 
60
57
  return lucid.newTx().pay.ToContract(
61
- createScriptAddress(network, lrpScriptHash, lrpStakeCredential),
58
+ createScriptAddress(
59
+ network,
60
+ sysParams.validatorHashes.lrpHash,
61
+ lrpStakeCredential,
62
+ ),
62
63
  {
63
64
  kind: 'inline',
64
65
  value: serialiseLrpDatum(newDatum),
65
66
  },
66
- { lovelace: lovelacesAmt + MIN_UTXO_COLLATERAL_AMT },
67
+ { lovelace: lovelacesAmt + MIN_LRP_COLLATERAL_AMT },
67
68
  );
68
69
  }
69
70
 
70
71
  export async function cancelLrp(
71
72
  lrpOutRef: OutRef,
72
- lrpRefScriptOutRef: OutRef,
73
+ sysParams: SystemParams,
73
74
  lucid: LucidEvolution,
74
75
  ): Promise<TxBuilder> {
75
76
  const lrpScriptRefUtxo = matchSingle(
76
- await lucid.utxosByOutRef([lrpRefScriptOutRef]),
77
+ await lucid.utxosByOutRef([
78
+ fromSystemParamsScriptRef(sysParams.scriptReferences.lrpValidatorRef),
79
+ ]),
77
80
  (_) => new Error('Expected a single LRP Ref Script UTXO'),
78
81
  );
79
82
 
@@ -82,7 +85,7 @@ export async function cancelLrp(
82
85
  (_) => new Error('Expected a single LRP UTXO.'),
83
86
  );
84
87
 
85
- const lrpDatum = parseLrpDatum(getInlineDatumOrThrow(lrpUtxo));
88
+ const lrpDatum = parseLrpDatumOrThrow(getInlineDatumOrThrow(lrpUtxo));
86
89
 
87
90
  return lucid
88
91
  .newTx()
@@ -94,15 +97,17 @@ export async function cancelLrp(
94
97
  export async function redeemLrp(
95
98
  /** The tuple represents the LRP outref and the amount of iAssets to redeem against it. */
96
99
  redemptionLrpsData: [OutRef, bigint][],
97
- lrpRefScriptOutRef: OutRef,
98
100
  priceOracleOutRef: OutRef,
99
101
  iassetOutRef: OutRef,
100
102
  lucid: LucidEvolution,
101
- lrpParams: LRPParams,
102
- network: Network,
103
+ sysParams: SystemParams,
103
104
  ): Promise<TxBuilder> {
105
+ const network = lucid.config().network!;
106
+
104
107
  const lrpScriptRefUtxo = matchSingle(
105
- await lucid.utxosByOutRef([lrpRefScriptOutRef]),
108
+ await lucid.utxosByOutRef([
109
+ fromSystemParamsScriptRef(sysParams.scriptReferences.lrpValidatorRef),
110
+ ]),
106
111
  (_) => new Error('Expected a single LRP Ref Script UTXO'),
107
112
  );
108
113
 
@@ -131,81 +136,14 @@ export async function redeemLrp(
131
136
  .utxosByOutRef(lrpsToRedeemOutRefs)
132
137
  .then((val) => zip(val, lrpRedemptionIAssetAmt));
133
138
 
134
- const [[mainLrpUtxo, _], __] = match(redemptionLrps)
135
- .with(
136
- [P._, ...P.array()],
137
- ([[firstLrp, _], ...rest]): [[UTxO, bigint], [UTxO, bigint][]] => [
138
- [firstLrp, _],
139
- rest,
140
- ],
141
- )
142
- .otherwise(() => {
143
- throw new Error('Expects at least 1 UTXO to redeem.');
144
- });
145
-
146
- const mainLrpDatum = parseLrpDatum(getInlineDatumOrThrow(mainLrpUtxo));
147
-
148
- const tx = reduceWithIndex<[UTxO, bigint], TxBuilder>(
139
+ const tx = buildRedemptionsTx(
140
+ redemptionLrps,
141
+ priceOracleDatum.price,
142
+ iassetDatum.redemptionReimbursementPercentage,
143
+ sysParams,
149
144
  lucid.newTx(),
150
- (idx, acc, [lrpUtxo, redeemIAssetAmt]) => {
151
- const lovelacesForRedemption = ocdMul(
152
- {
153
- getOnChainInt: redeemIAssetAmt,
154
- },
155
- priceOracleDatum.price,
156
- ).getOnChainInt;
157
- const reimburstmentLovelaces = calculateFeeFromPercentage(
158
- iassetDatum.redemptionReimbursementPercentage,
159
- lovelacesForRedemption,
160
- );
161
-
162
- const lrpDatum = parseLrpDatum(getInlineDatumOrThrow(lrpUtxo));
163
-
164
- return acc
165
- .collectFrom(
166
- [lrpUtxo],
167
- serialiseLrpRedeemer(
168
- idx === 0
169
- ? { Redeem: { continuingOutputIdx: 0n } }
170
- : {
171
- RedeemAuxiliary: {
172
- continuingOutputIdx: BigInt(idx),
173
- mainRedeemOutRef: {
174
- txHash: { hash: mainLrpUtxo.txHash },
175
- outputIndex: BigInt(mainLrpUtxo.outputIndex),
176
- },
177
- asset: mainLrpDatum.iasset,
178
- assetPrice: priceOracleDatum.price,
179
- redemptionReimbursementPercentage:
180
- iassetDatum.redemptionReimbursementPercentage,
181
- },
182
- },
183
- ),
184
- )
185
- .pay.ToContract(
186
- lrpUtxo.address,
187
- {
188
- kind: 'inline',
189
- value: serialiseLrpDatum({
190
- ...lrpDatum,
191
- lovelacesToSpend:
192
- lrpDatum.lovelacesToSpend - lovelacesForRedemption,
193
- }),
194
- },
195
- addAssets(
196
- lrpUtxo.assets,
197
- mkLovelacesOf(-lovelacesForRedemption + reimburstmentLovelaces),
198
- mkAssetsOf(
199
- {
200
- currencySymbol: lrpParams.iassetPolicyId,
201
- tokenName: mainLrpDatum.iasset,
202
- },
203
- redeemIAssetAmt,
204
- ),
205
- ),
206
- );
207
- },
208
- )(redemptionLrps);
145
+ 0n,
146
+ );
209
147
 
210
148
  return (
211
149
  lucid
@@ -235,11 +173,12 @@ export async function adjustLrp(
235
173
  * and a negative amount takes lovelaces from the LRP.
236
174
  */
237
175
  lovelacesAdjustAmt: bigint,
238
- lrpRefScriptOutRef: OutRef,
239
- lrpParams: LRPParams,
176
+ sysParams: SystemParams,
240
177
  ): Promise<TxBuilder> {
241
178
  const lrpScriptRefUtxo = matchSingle(
242
- await lucid.utxosByOutRef([lrpRefScriptOutRef]),
179
+ await lucid.utxosByOutRef([
180
+ fromSystemParamsScriptRef(sysParams.scriptReferences.lrpValidatorRef),
181
+ ]),
243
182
  (_) => new Error('Expected a single LRP Ref Script UTXO'),
244
183
  );
245
184
 
@@ -248,10 +187,10 @@ export async function adjustLrp(
248
187
  (_) => new Error('Expected a single LRP UTXO.'),
249
188
  );
250
189
 
251
- const lrpDatum = parseLrpDatum(getInlineDatumOrThrow(lrpUtxo));
190
+ const lrpDatum = parseLrpDatumOrThrow(getInlineDatumOrThrow(lrpUtxo));
252
191
 
253
192
  const rewardAssetClass: AssetClass = {
254
- currencySymbol: lrpParams.iassetPolicyId,
193
+ currencySymbol: sysParams.lrpParams.iassetPolicyId.unCurrencySymbol,
255
194
  tokenName: lrpDatum.iasset,
256
195
  };
257
196
  const rewardAssetsAmt = assetClassValueOf(lrpUtxo.assets, rewardAssetClass);
@@ -301,8 +240,7 @@ export async function adjustLrp(
301
240
  export async function claimLrp(
302
241
  lucid: LucidEvolution,
303
242
  lrpOutRef: OutRef,
304
- lrpRefScriptOutRef: OutRef,
305
- lrpParams: LRPParams,
243
+ sysParams: SystemParams,
306
244
  ): Promise<TxBuilder> {
307
- return adjustLrp(lucid, lrpOutRef, 0n, lrpRefScriptOutRef, lrpParams);
245
+ return adjustLrp(lucid, lrpOutRef, 0n, sysParams);
308
246
  }
@@ -1,6 +1,7 @@
1
- import { Data, Datum, Redeemer } from '@lucid-evolution/lucid';
1
+ import { Data, Datum, Redeemer, UTxO } from '@lucid-evolution/lucid';
2
2
  import { AssetClassSchema, OutputReferenceSchema } from '../../types/generic';
3
3
  import { OnChainDecimalSchema } from '../../types/on-chain-decimal';
4
+ import { option as O, function as F } from 'fp-ts';
4
5
 
5
6
  export const LRPParamsSchema = Data.Object({
6
7
  versionRecordToken: AssetClassSchema,
@@ -42,8 +43,21 @@ export const LRPRedeemerSchema = Data.Enum([
42
43
  export type LRPRedeemer = Data.Static<typeof LRPRedeemerSchema>;
43
44
  const LRPRedeemer = LRPRedeemerSchema as unknown as LRPRedeemer;
44
45
 
45
- export function parseLrpDatum(datum: Datum): LRPDatum {
46
- return Data.from<LRPDatum>(datum, LRPDatum);
46
+ export function parseLrpDatum(datum: Datum): O.Option<LRPDatum> {
47
+ try {
48
+ return O.some(Data.from<LRPDatum>(datum, LRPDatum));
49
+ } catch (_) {
50
+ return O.none;
51
+ }
52
+ }
53
+
54
+ export function parseLrpDatumOrThrow(datum: Datum): LRPDatum {
55
+ return F.pipe(
56
+ parseLrpDatum(datum),
57
+ O.match(() => {
58
+ throw new Error('Expected an LRP datum.');
59
+ }, F.identity),
60
+ );
47
61
  }
48
62
 
49
63
  export function serialiseLrpDatum(datum: LRPDatum): Datum {
@@ -57,3 +71,5 @@ export function serialiseLrpRedeemer(redeemer: LRPRedeemer): Redeemer {
57
71
  export function castLrpParams(params: LRPParams): Data {
58
72
  return Data.castTo(params, LRPParams);
59
73
  }
74
+
75
+ export type LrpOutput = { datum: LRPDatum; utxo: UTxO };
@@ -461,10 +461,6 @@ export async function processSpRequest(
461
461
  newPoolSum,
462
462
  );
463
463
 
464
- console.log('balanceChange', balanceChange);
465
- console.log('withdrawalFee', withdrawalFee);
466
- console.log('rewardLovelacesFee', rewardLovelacesFee);
467
- console.log('reward', reward);
468
464
  if (rewardLovelacesFee > 0n) {
469
465
  await collectorFeeTx(
470
466
  rewardLovelacesFee,
@@ -15,6 +15,7 @@ import {
15
15
  } from './types-new';
16
16
  import { createScriptAddress } from '../../utils/lucid-utils';
17
17
  import { mkStakingValidatorFromSP } from './scripts';
18
+ import { OCD_DECIMAL_UNIT } from '../../types/on-chain-decimal';
18
19
 
19
20
  export type StakingPositionOutput = {
20
21
  utxo: UTxO;
@@ -114,3 +115,13 @@ export function findStakingPositionByOutRef(
114
115
  return result;
115
116
  });
116
117
  }
118
+
119
+ export const rewardSnapshotPrecision = OCD_DECIMAL_UNIT * OCD_DECIMAL_UNIT;
120
+
121
+ export function distributeReward(
122
+ snapshotAda: bigint,
123
+ adaReward: bigint,
124
+ totalStake: bigint,
125
+ ): bigint {
126
+ return snapshotAda + (adaReward * rewardSnapshotPrecision) / totalStake;
127
+ }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ addAssets,
2
3
  Constr,
3
4
  Data,
4
5
  fromHex,
@@ -12,19 +13,25 @@ import {
12
13
  fromSystemParamsScriptRef,
13
14
  SystemParams,
14
15
  } from '../../types/system-params';
15
- import { addrDetails } from '../../utils/lucid-utils';
16
+ import { addrDetails, getInlineDatumOrThrow } from '../../utils/lucid-utils';
16
17
  import {
18
+ distributeReward,
17
19
  findStakingManager,
18
20
  findStakingManagerByOutRef,
19
21
  findStakingPositionByOutRef,
22
+ rewardSnapshotPrecision,
20
23
  updateStakingLockedAmount,
21
24
  } from './helpers';
22
25
  import {
26
+ parseStakingManagerDatum,
23
27
  serialiseStakingDatum,
24
28
  StakingManager,
25
29
  StakingPosition,
26
30
  } from './types-new';
27
31
  import { matchSingle } from '../../utils/utils';
32
+ import { serialiseStakingRedeemer } from './types';
33
+ import { serialiseCollectorRedeemer } from '../collector/types';
34
+ import { mkLovelacesOf } from '../../utils/value-helpers';
28
35
 
29
36
  export async function openStakingPosition(
30
37
  amount: bigint,
@@ -147,7 +154,7 @@ export async function adjustStakingPosition(
147
154
  const oldSnapshotAda = stakingPositionOut.datum.positionSnapshot.snapshotAda;
148
155
  const adaReward =
149
156
  ((currentSnapshotAda - oldSnapshotAda) * existingIndyAmount) /
150
- (1000000n * 1000000n);
157
+ rewardSnapshotPrecision;
151
158
 
152
159
  const newLockedAmount = updateStakingLockedAmount(
153
160
  stakingPositionOut.datum.lockedAmount,
@@ -158,8 +165,16 @@ export async function adjustStakingPosition(
158
165
  .newTx()
159
166
  .validFrom(Date.now())
160
167
  .readFrom([stakingRefScriptUtxo])
161
- .collectFrom([stakingPositionOut.utxo], Data.to(new Constr(3, [amount])))
162
- .collectFrom([stakingManagerOut.utxo], Data.to(new Constr(1, [])))
168
+ .collectFrom(
169
+ [stakingPositionOut.utxo],
170
+ serialiseStakingRedeemer({
171
+ AdjustStakedAmount: { adjustAmount: amount },
172
+ }),
173
+ )
174
+ .collectFrom(
175
+ [stakingManagerOut.utxo],
176
+ serialiseStakingRedeemer('UpdateTotalStake'),
177
+ )
163
178
  .pay.ToContract(
164
179
  stakingManagerOut.utxo.address,
165
180
  {
@@ -266,3 +281,78 @@ export async function closeStakingPosition(
266
281
  )
267
282
  .addSignerKey(toHex(stakingPositionOut.datum.owner));
268
283
  }
284
+
285
+ const MIN_UTXO_AMOUNT = 2_000_000n;
286
+
287
+ export async function distributeAda(
288
+ stakingManagerRef: OutRef,
289
+ collectorRefs: OutRef[],
290
+ params: SystemParams,
291
+ lucid: LucidEvolution,
292
+ ): Promise<TxBuilder> {
293
+ const [stakingManagerUtxo] = await lucid.utxosByOutRef([stakingManagerRef]);
294
+ const stakingManagerDatum = parseStakingManagerDatum(
295
+ getInlineDatumOrThrow(stakingManagerUtxo),
296
+ );
297
+ const collectorUtxos = (await lucid.utxosByOutRef(collectorRefs))
298
+ .filter((utxo) => utxo.datum && utxo.datum === Data.void())
299
+ .filter((utxo) => utxo.assets.lovelace > MIN_UTXO_AMOUNT);
300
+
301
+ if (collectorUtxos.length === 0) {
302
+ throw new Error('No available collectors found');
303
+ }
304
+
305
+ const adaRewardCollected = collectorUtxos.reduce(
306
+ (acc, utxo) => acc + utxo.assets.lovelace - MIN_UTXO_AMOUNT,
307
+ 0n,
308
+ );
309
+ const newSnapshot = distributeReward(
310
+ stakingManagerDatum.managerSnapshot.snapshotAda,
311
+ adaRewardCollected,
312
+ stakingManagerDatum.totalStake,
313
+ );
314
+
315
+ const stakingRefScriptUtxo = matchSingle(
316
+ await lucid.utxosByOutRef([
317
+ fromSystemParamsScriptRef(params.scriptReferences.stakingValidatorRef),
318
+ ]),
319
+ (_) => new Error('Expected a single staking Ref Script UTXO'),
320
+ );
321
+
322
+ const collectorRefScriptUtxo = matchSingle(
323
+ await lucid.utxosByOutRef([
324
+ fromSystemParamsScriptRef(params.scriptReferences.collectorValidatorRef),
325
+ ]),
326
+ (_) => new Error('Expected a single staking Ref Script UTXO'),
327
+ );
328
+
329
+ const tx = lucid
330
+ .newTx()
331
+ .readFrom([stakingRefScriptUtxo, collectorRefScriptUtxo])
332
+ .collectFrom([stakingManagerUtxo], serialiseStakingRedeemer('Distribute'))
333
+ .collectFrom(
334
+ collectorUtxos,
335
+ serialiseCollectorRedeemer('DistributeToStakers'),
336
+ )
337
+ .pay.ToContract(
338
+ stakingManagerUtxo.address,
339
+ {
340
+ kind: 'inline',
341
+ value: serialiseStakingDatum({
342
+ ...stakingManagerDatum,
343
+ managerSnapshot: { snapshotAda: newSnapshot },
344
+ }),
345
+ },
346
+ addAssets(stakingManagerUtxo.assets, mkLovelacesOf(adaRewardCollected)),
347
+ );
348
+
349
+ for (const collectorUtxo of collectorUtxos) {
350
+ tx.pay.ToContract(
351
+ collectorUtxo.address,
352
+ { kind: 'inline', value: Data.void() },
353
+ mkLovelacesOf(MIN_UTXO_AMOUNT),
354
+ );
355
+ }
356
+
357
+ return tx;
358
+ }
package/src/index.ts CHANGED
@@ -11,13 +11,14 @@ export * from './contracts/gov/types';
11
11
  export * from './contracts/stability-pool/transactions';
12
12
  export * from './contracts/stability-pool/types-new';
13
13
  export * from './contracts/staking/transactions';
14
+ export * from './contracts/staking/types';
15
+ export * from './contracts/staking/types-new';
14
16
  export * from './contracts/interest-oracle/transactions';
15
17
  export * from './contracts/interest-oracle/types';
16
18
  export * from './contracts/interest-oracle/scripts';
17
19
  export * from './contracts/version-registry/types';
18
20
  export * from './contracts/version-registry/scripts';
19
21
  export * from './contracts/treasury/transactions';
20
- export * from './utils/utils';
21
22
  export * from './utils/lucid-utils';
22
23
  export * from './contracts/stability-pool/helpers';
23
24
  export * from './utils/time-helpers';
@@ -28,14 +29,18 @@ export * from './contracts/execute/types';
28
29
  export * from './contracts/execute/scripts';
29
30
  export * from './contracts/price-oracle/types';
30
31
  export * from './contracts/stability-pool/types';
31
- export * from './contracts/lrp/types';
32
32
  export * from './contracts/poll/types-poll-shard';
33
33
  export * from './contracts/poll/types-poll-manager';
34
34
  export * from './types/generic';
35
35
  export * from './types/system-params';
36
+ export * from './contracts/lrp/helpers';
36
37
  export * from './contracts/lrp/transactions';
37
38
  export * from './contracts/lrp/scripts';
39
+ export * from './contracts/lrp/types';
38
40
  export * from './utils/helper-txs';
39
41
  export * from './contracts/one-shot/transactions';
40
42
  export * from './utils/utils';
43
+ export * from './utils/array-utils';
41
44
  export * from './utils/value-helpers';
45
+ export * from './contracts/leverage/transactions';
46
+ export * from './contracts/leverage/helpers';
@@ -13,6 +13,10 @@ export function ocdCeil(a: OnChainDecimal): bigint {
13
13
  return a.getOnChainInt > whole * OCD_DECIMAL_UNIT ? whole + 1n : whole;
14
14
  }
15
15
 
16
+ export function ocdFloor(a: OnChainDecimal): bigint {
17
+ return a.getOnChainInt / OCD_DECIMAL_UNIT;
18
+ }
19
+
16
20
  export function ocdNegate(a: OnChainDecimal): OnChainDecimal {
17
21
  return { getOnChainInt: -a.getOnChainInt };
18
22
  }
@@ -0,0 +1,39 @@
1
+ import { array as A, ord as Ord } from 'fp-ts';
2
+
3
+ export function shuffle<T>(arr: T[]): T[] {
4
+ const source = [...arr];
5
+ for (let i = source.length - 1; i > 0; i--) {
6
+ const j = Math.floor(Math.random() * (i + 1));
7
+ [source[i], source[j]] = [source[j], source[i]];
8
+ }
9
+
10
+ return source;
11
+ }
12
+
13
+ /**
14
+ * The parameter `arr` should be sorted for correct results.
15
+ */
16
+ export function insertSorted<T>(arr: T[], item: T, ord: Ord.Ord<T>): T[] {
17
+ if (arr.length === 0) {
18
+ return [item];
19
+ }
20
+
21
+ const arrOrd = ord.compare(arr[0], arr[arr.length - 1]);
22
+ // Array containing the same items
23
+ if (arrOrd === 0) {
24
+ if (ord.compare(arr[0], item) === -1) {
25
+ return [...arr, item];
26
+ } else {
27
+ return [item, ...arr];
28
+ }
29
+ }
30
+
31
+ // TODO: could be improved with binary search
32
+ for (let i = 0; i < arr.length; i++) {
33
+ if (ord.compare(arr[i], item) !== arrOrd) {
34
+ return [...A.takeLeft(i)(arr), item, ...A.takeRight(arr.length - i)(arr)];
35
+ }
36
+ }
37
+
38
+ return [...arr, item];
39
+ }
@@ -1,3 +1,6 @@
1
+ import Decimal from 'decimal.js';
2
+ import { array as A, ord as Ord } from 'fp-ts';
3
+
1
4
  export function bigintMax(a: bigint, b: bigint): bigint {
2
5
  return a > b ? a : b;
3
6
  }
@@ -5,3 +8,16 @@ export function bigintMax(a: bigint, b: bigint): bigint {
5
8
  export function bigintMin(a: bigint, b: bigint): bigint {
6
9
  return a < b ? a : b;
7
10
  }
11
+
12
+ export function sum(arr: bigint[]): bigint {
13
+ return A.reduce<bigint, bigint>(0n, (acc, val) => acc + val)(arr);
14
+ }
15
+
16
+ export function fromDecimal(val: Decimal): bigint {
17
+ return BigInt(val.toString());
18
+ }
19
+
20
+ export const BigIntOrd: Ord.Ord<bigint> = {
21
+ equals: (x, y) => x === y,
22
+ compare: (first, second) => (first < second ? -1 : first > second ? 1 : 0),
23
+ };
@@ -0,0 +1,92 @@
1
+ import { expect, test } from 'vitest';
2
+ import { insertSorted, shuffle } from '../src/utils/array-utils';
3
+ import { BigIntOrd } from '../src/utils/bigint-utils';
4
+ import { ord as Ord, number as Num, array as A } from 'fp-ts';
5
+
6
+ test('Shuffle', () => {
7
+ const arr = [1, 2, 34, 45, -1, 20, 35];
8
+ const shuffled = shuffle(arr);
9
+
10
+ expect(shuffled.length).toBe(arr.length);
11
+ expect(A.sort(Num.Ord)(shuffled)).toEqual(A.sort(Num.Ord)(arr));
12
+ });
13
+
14
+ test('insert sorted 1', () => {
15
+ const arr = [0n, 2n, 3n];
16
+ expect(insertSorted(arr, 1n, BigIntOrd)).toEqual([0n, 1n, 2n, 3n]);
17
+ });
18
+ test('insert sorted 2', () => {
19
+ const arr = [0n, 2n, 4n];
20
+ expect(insertSorted(arr, 3n, BigIntOrd)).toEqual([0n, 2n, 3n, 4n]);
21
+ });
22
+ test('insert sorted at start', () => {
23
+ const arr = [0n, 2n, 3n];
24
+ expect(insertSorted(arr, -1n, BigIntOrd)).toEqual([-1n, 0n, 2n, 3n]);
25
+ });
26
+ test('insert sorted at end', () => {
27
+ const arr = [0n, 2n, 3n];
28
+ expect(insertSorted(arr, 5n, BigIntOrd)).toEqual([0n, 2n, 3n, 5n]);
29
+ });
30
+ test('insert sorted at start when array all equal', () => {
31
+ const arr = [0n, 0n, 0n];
32
+ expect(insertSorted(arr, -1n, BigIntOrd)).toEqual([-1n, 0n, 0n, 0n]);
33
+ });
34
+ test('insert sorted at end when array all equal', () => {
35
+ const arr = [0n, 0n, 0n];
36
+ expect(insertSorted(arr, 1n, BigIntOrd)).toEqual([0n, 0n, 0n, 1n]);
37
+ });
38
+
39
+ test('insert sorted reversed 1', () => {
40
+ const arr = [3n, 2n, 0n];
41
+ expect(insertSorted(arr, 1n, Ord.reverse(BigIntOrd))).toEqual([
42
+ 3n,
43
+ 2n,
44
+ 1n,
45
+ 0n,
46
+ ]);
47
+ });
48
+ test('insert sorted reversed 2', () => {
49
+ const arr = [4n, 2n, 0n];
50
+ expect(insertSorted(arr, 3n, Ord.reverse(BigIntOrd))).toEqual([
51
+ 4n,
52
+ 3n,
53
+ 2n,
54
+ 0n,
55
+ ]);
56
+ });
57
+ test('insert sorted eversed at start', () => {
58
+ const arr = [3n, 2n, 0n];
59
+ expect(insertSorted(arr, 4n, Ord.reverse(BigIntOrd))).toEqual([
60
+ 4n,
61
+ 3n,
62
+ 2n,
63
+ 0n,
64
+ ]);
65
+ });
66
+ test('insert sorted reversed at end', () => {
67
+ const arr = [3n, 2n, 0n];
68
+ expect(insertSorted(arr, -1n, Ord.reverse(BigIntOrd))).toEqual([
69
+ 3n,
70
+ 2n,
71
+ 0n,
72
+ -1n,
73
+ ]);
74
+ });
75
+ test('insert sorted reversed at end when array all equal', () => {
76
+ const arr = [0n, 0n, 0n];
77
+ expect(insertSorted(arr, -1n, Ord.reverse(BigIntOrd))).toEqual([
78
+ 0n,
79
+ 0n,
80
+ 0n,
81
+ -1n,
82
+ ]);
83
+ });
84
+ test('insert sorted reversed at start when array all equal', () => {
85
+ const arr = [0n, 0n, 0n];
86
+ expect(insertSorted(arr, 1n, Ord.reverse(BigIntOrd))).toEqual([
87
+ 1n,
88
+ 0n,
89
+ 0n,
90
+ 0n,
91
+ ]);
92
+ });