@indigo-labs/indigo-sdk 0.2.42 → 0.3.1

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 (202) hide show
  1. package/.github/workflows/ci.yml +4 -2
  2. package/README.md +88 -15
  3. package/dist/index.d.mts +3012 -2194
  4. package/dist/index.d.ts +3012 -2194
  5. package/dist/index.js +9849 -6198
  6. package/dist/index.mjs +8733 -4933
  7. package/package.json +14 -3
  8. package/src/contracts/cdp/helpers.ts +68 -72
  9. package/src/contracts/cdp/scripts.ts +50 -13
  10. package/src/contracts/cdp/transactions.ts +841 -546
  11. package/src/contracts/cdp/types-new.ts +256 -0
  12. package/src/contracts/cdp/types.ts +26 -144
  13. package/src/contracts/cdp-creator/scripts.ts +15 -9
  14. package/src/contracts/cdp-creator/types-new.ts +50 -0
  15. package/src/contracts/cdp-creator/types.ts +5 -31
  16. package/src/contracts/collector/scripts.ts +1 -1
  17. package/src/contracts/collector/transactions.ts +23 -13
  18. package/src/contracts/collector/types-new.ts +17 -0
  19. package/src/contracts/execute/scripts.ts +19 -10
  20. package/src/contracts/execute/types-new.ts +44 -0
  21. package/src/contracts/execute/types.ts +5 -38
  22. package/src/contracts/gov/helpers.ts +187 -51
  23. package/src/contracts/gov/scripts.ts +17 -10
  24. package/src/contracts/gov/transactions.ts +599 -271
  25. package/src/contracts/gov/types-new.ts +253 -100
  26. package/src/contracts/gov/types.ts +4 -71
  27. package/src/contracts/iasset/helpers.ts +172 -0
  28. package/src/contracts/iasset/scripts.ts +38 -0
  29. package/src/contracts/iasset/types.ts +154 -0
  30. package/src/contracts/initialize/actions.ts +768 -0
  31. package/src/contracts/initialize/helpers.ts +611 -36
  32. package/src/contracts/initialize/types.ts +102 -28
  33. package/src/contracts/interest-collection/helpers.ts +19 -0
  34. package/src/contracts/interest-collection/scripts.ts +44 -0
  35. package/src/contracts/interest-collection/transactions.ts +436 -0
  36. package/src/contracts/interest-collection/types-new.ts +50 -0
  37. package/src/contracts/interest-collection/types.ts +26 -0
  38. package/src/contracts/interest-oracle/helpers.ts +2 -30
  39. package/src/contracts/interest-oracle/scripts.ts +1 -1
  40. package/src/contracts/interest-oracle/transactions.ts +21 -16
  41. package/src/contracts/interest-oracle/types-new.ts +32 -0
  42. package/src/contracts/interest-oracle/types.ts +1 -40
  43. package/src/contracts/one-shot/transactions.ts +1 -2
  44. package/src/contracts/poll/helpers.ts +5 -23
  45. package/src/contracts/poll/scripts.ts +12 -13
  46. package/src/contracts/poll/types-poll-manager.ts +1 -19
  47. package/src/contracts/poll/types-poll-new.ts +170 -0
  48. package/src/contracts/poll/types-poll-shard.ts +2 -24
  49. package/src/contracts/price-oracle/helpers.ts +1 -4
  50. package/src/contracts/price-oracle/scripts.ts +3 -8
  51. package/src/contracts/price-oracle/transactions.ts +32 -25
  52. package/src/contracts/price-oracle/types-new.ts +50 -0
  53. package/src/contracts/price-oracle/types.ts +2 -36
  54. package/src/contracts/pyth-feed/helpers.ts +58 -0
  55. package/src/contracts/pyth-feed/scripts.ts +15 -0
  56. package/src/contracts/pyth-feed/types.ts +181 -0
  57. package/src/contracts/rob/helpers.ts +405 -0
  58. package/src/contracts/rob/scripts.ts +35 -0
  59. package/src/contracts/rob/transactions.ts +410 -0
  60. package/src/contracts/rob/types-new.ts +128 -0
  61. package/src/contracts/rob/types.ts +16 -0
  62. package/src/contracts/rob-leverage/helpers.ts +424 -0
  63. package/src/contracts/{leverage → rob-leverage}/transactions.ts +68 -48
  64. package/src/contracts/stability-pool/helpers.ts +714 -230
  65. package/src/contracts/stability-pool/scripts.ts +20 -15
  66. package/src/contracts/stability-pool/transactions.ts +628 -496
  67. package/src/contracts/stability-pool/types-new.ts +247 -100
  68. package/src/contracts/stability-pool/types.ts +5 -22
  69. package/src/contracts/stableswap/helpers.ts +22 -0
  70. package/src/contracts/stableswap/scripts.ts +37 -0
  71. package/src/contracts/stableswap/transactions.ts +647 -0
  72. package/src/contracts/stableswap/types-new.ts +131 -0
  73. package/src/contracts/stableswap/types.ts +17 -0
  74. package/src/contracts/staking/helpers.ts +49 -34
  75. package/src/contracts/staking/scripts.ts +1 -1
  76. package/src/contracts/staking/transactions.ts +85 -130
  77. package/src/contracts/staking/types-new.ts +60 -28
  78. package/src/contracts/staking/types.ts +1 -28
  79. package/src/contracts/treasury/helpers.ts +21 -0
  80. package/src/contracts/treasury/scripts.ts +16 -26
  81. package/src/contracts/treasury/transactions.ts +256 -27
  82. package/src/contracts/treasury/types-new.ts +69 -0
  83. package/src/contracts/treasury/types.ts +2 -43
  84. package/src/contracts/version-registry/scripts.ts +2 -2
  85. package/src/contracts/version-registry/types-new.ts +6 -7
  86. package/src/index.ts +37 -20
  87. package/src/scripts/auth-token-policy.ts +3 -2
  88. package/src/scripts/iasset-policy.ts +3 -2
  89. package/src/types/evolution-schema-options.ts +3 -3
  90. package/src/types/generic.ts +17 -89
  91. package/src/types/multisig.ts +48 -0
  92. package/src/types/on-chain-decimal.ts +14 -7
  93. package/src/types/rational.ts +61 -0
  94. package/src/types/system-params.ts +237 -41
  95. package/src/utils/array-utils.ts +70 -1
  96. package/src/utils/bigint-utils.ts +12 -0
  97. package/src/utils/indigo-helpers.ts +8 -10
  98. package/src/utils/lucid-utils.ts +47 -40
  99. package/src/utils/oracle-helpers.ts +62 -0
  100. package/src/utils/pyth/decode.ts +223 -0
  101. package/src/utils/pyth/encode.ts +262 -0
  102. package/src/utils/pyth/index.ts +14 -0
  103. package/src/utils/pyth/types.ts +87 -0
  104. package/src/validators/always-succeed-validator.ts +6 -0
  105. package/src/validators/cdp-creator-validator.ts +2 -2
  106. package/src/validators/cdp-redeem-validator.ts +7 -0
  107. package/src/validators/cdp-validator.ts +2 -2
  108. package/src/validators/collector-validator.ts +2 -2
  109. package/src/validators/execute-validator.ts +2 -2
  110. package/src/validators/governance-validator.ts +2 -2
  111. package/src/validators/iasset-validator.ts +7 -0
  112. package/src/validators/interest-collection-validator.ts +7 -0
  113. package/src/validators/interest-oracle-validator.ts +2 -2
  114. package/src/validators/poll-manager-validator.ts +2 -2
  115. package/src/validators/poll-shard-validator.ts +2 -2
  116. package/src/validators/price-oracle-validator.ts +7 -0
  117. package/src/validators/pyth-feed-validator.ts +7 -0
  118. package/src/validators/rob-validator.ts +7 -0
  119. package/src/validators/stability-pool-validator.ts +2 -2
  120. package/src/validators/stableswap-validator.ts +7 -0
  121. package/src/validators/staking-validator.ts +2 -2
  122. package/src/validators/treasury-validator.ts +2 -2
  123. package/src/validators/version-record-policy.ts +2 -2
  124. package/src/validators/version-registry-validator.ts +2 -2
  125. package/tests/always-succeed/script.ts +7 -0
  126. package/tests/bigint-utils.test.ts +41 -0
  127. package/tests/cdp/actions.ts +610 -0
  128. package/tests/cdp/cdp-helpers.ts +55 -0
  129. package/tests/cdp/cdp-queries.ts +440 -0
  130. package/tests/cdp/cdp.test.ts +6087 -0
  131. package/tests/cdp/transactions-mutated.ts +1729 -0
  132. package/tests/data/system-params.json +177 -34
  133. package/tests/datums.test.ts +209 -210
  134. package/tests/endpoints/initialize.ts +68 -0
  135. package/tests/endpoints/interest-collector.ts +37 -0
  136. package/tests/endpoints/treasury.ts +70 -0
  137. package/tests/gov/actions.ts +406 -0
  138. package/tests/gov/gov.test.ts +4450 -0
  139. package/tests/{queries → gov}/governance-queries.ts +6 -3
  140. package/tests/hash-checks.test.ts +38 -11
  141. package/tests/indigo-test-helpers.ts +100 -0
  142. package/tests/initialize.test.ts +61 -9
  143. package/tests/interest-collection/interest-collection.test.ts +892 -0
  144. package/tests/interest-collection/interest-collector-queries.ts +49 -0
  145. package/tests/interest-collection/transactions-mutated.ts +260 -0
  146. package/tests/interest-oracle.test.ts +43 -35
  147. package/tests/mock/assets-mock.ts +234 -23
  148. package/tests/mock/protocol-params-mock.ts +21 -0
  149. package/tests/price-oracle/actions.ts +163 -0
  150. package/tests/price-oracle/price-oracle-queries.ts +12 -0
  151. package/tests/price-oracle/price-oracle.test.ts +240 -0
  152. package/tests/price-oracle/transactions-mutated.ts +62 -0
  153. package/tests/pyth/endpoints.ts +96 -0
  154. package/tests/pyth/helpers.ts +37 -0
  155. package/tests/pyth/pyth-encoding.test.ts +376 -0
  156. package/tests/pyth/pyth-indigo.test.ts +509 -0
  157. package/tests/pyth/pyth.test.ts +300 -0
  158. package/tests/queries/execute-queries.ts +6 -5
  159. package/tests/queries/iasset-queries.ts +175 -5
  160. package/tests/queries/interest-oracle-queries.ts +4 -2
  161. package/tests/queries/poll-queries.ts +8 -9
  162. package/tests/queries/stability-pool-queries.ts +95 -48
  163. package/tests/queries/staking-queries.ts +4 -2
  164. package/tests/queries/treasury-queries.ts +80 -5
  165. package/tests/rob/actions.ts +58 -0
  166. package/tests/{lrp-leverage.test.ts → rob/rob-leverage.test.ts} +393 -296
  167. package/tests/rob/rob-queries.ts +95 -0
  168. package/tests/rob/rob.test.ts +3762 -0
  169. package/tests/rob/transactions-mutated.ts +853 -0
  170. package/tests/script-size.test.ts +240 -0
  171. package/tests/setup.ts +135 -0
  172. package/tests/stability-pool/actions.ts +220 -0
  173. package/tests/stability-pool.test.ts +6121 -667
  174. package/tests/stableswap/stableswap-actions.ts +84 -0
  175. package/tests/stableswap/stableswap-queries.ts +89 -0
  176. package/tests/stableswap/stableswap.test.ts +3891 -0
  177. package/tests/stableswap/transactions-mutated.ts +348 -0
  178. package/tests/staking.test.ts +82 -99
  179. package/tests/test-helpers.ts +58 -11
  180. package/tests/treasury.test.ts +242 -0
  181. package/tests/utils/asserts.ts +74 -0
  182. package/tests/utils/benchmark-utils.ts +81 -0
  183. package/tests/utils/index.ts +122 -4
  184. package/tsconfig.json +9 -1
  185. package/vitest.config.ts +3 -1
  186. package/src/contracts/collector/types.ts +0 -16
  187. package/src/contracts/initialize/transactions.ts +0 -891
  188. package/src/contracts/leverage/helpers.ts +0 -424
  189. package/src/contracts/lrp/helpers.ts +0 -294
  190. package/src/contracts/lrp/scripts.ts +0 -27
  191. package/src/contracts/lrp/transactions.ts +0 -250
  192. package/src/contracts/lrp/types.ts +0 -131
  193. package/src/contracts/poll/types-poll.ts +0 -88
  194. package/src/contracts/vesting/helpers.ts +0 -218
  195. package/src/utils/value-helpers.ts +0 -37
  196. package/src/validators/lrp-validator.ts +0 -7
  197. package/tests/cdp.test.ts +0 -1528
  198. package/tests/gov.test.ts +0 -2011
  199. package/tests/lrp.test.ts +0 -673
  200. package/tests/queries/cdp-queries.ts +0 -220
  201. package/tests/queries/lrp-queries.ts +0 -76
  202. package/tests/queries/price-oracle-queries.ts +0 -10
@@ -1,5 +1,4 @@
1
1
  import {
2
- Constr,
3
2
  fromText,
4
3
  LucidEvolution,
5
4
  TxBuilder,
@@ -9,70 +8,83 @@ import {
9
8
  credentialToAddress,
10
9
  fromHex,
11
10
  toHex,
11
+ addAssets,
12
+ OutRef,
13
+ slotToUnixTime,
12
14
  } from '@lucid-evolution/lucid';
13
- import { ActionReturnDatum } from './types';
14
- import { fromSystemParamsAsset, SystemParams } from '../../types/system-params';
15
15
  import {
16
- addrDetails,
17
- getInlineDatumOrThrow,
18
- scriptRef,
19
- UtxoOrOutRef,
20
- } from '../../utils/lucid-utils';
16
+ fromSystemParamsAsset,
17
+ fromSystemParamsScriptRef,
18
+ SystemParams,
19
+ } from '../../types/system-params';
20
+ import { addrDetails, getInlineDatumOrThrow } from '../../utils/lucid-utils';
21
21
  import { mkStabilityPoolValidatorFromSP } from './scripts';
22
22
  import {
23
- adjustmentHelper,
24
- setSumInEpochToScaleToSum,
25
- updatePoolSnapshotWithdrawalFee,
23
+ BASE_MAX_TX_FEE,
24
+ createProcessRequestAccountRedeemer,
25
+ findRelevantE2s2sIdxs,
26
+ initSpState,
27
+ liquidationHelper,
28
+ mkStabilityPoolAddr,
29
+ partitionEpochToScaleToSums,
30
+ updateAccount,
31
+ updatePoolStateWhenWithdrawalFee,
26
32
  } from './helpers';
27
- import { calculateFeeFromPercentage } from '../../utils/indigo-helpers';
28
- import { GovDatum, parseGovDatumOrThrow } from '../gov/types';
29
- import { IAssetContent, parseIAssetDatumOrThrow } from '../cdp/types';
30
- import {
31
- addressFromBech32,
32
- addressToBech32,
33
- } from '@3rd-eye-labs/cardano-offchain-common';
33
+ import { calculateFeeFromRatio } from '../../utils/indigo-helpers';
34
34
  import {
35
35
  AccountAction,
36
36
  AccountContent,
37
- EpochToScaleToSum,
38
37
  fromSPInteger,
39
38
  mkSPInteger,
40
- parseAccountDatum,
41
- parseStabilityPoolDatum,
39
+ parseAccountDatumOrThrow,
40
+ parseStabilityPoolDatumOrThrow,
41
+ serialiseActionReturnDatum,
42
42
  serialiseStabilityPoolDatum,
43
43
  serialiseStabilityPoolRedeemer,
44
44
  spAdd,
45
- spDiv,
46
- spMul,
47
45
  spSub,
48
- StabilityPoolRedeemer,
49
- StabilityPoolSnapshot,
46
+ spZeroNegatives,
50
47
  } from './types-new';
51
- import { collectorFeeTx } from '../collector/transactions';
52
- import { mkAssetsOf } from '../../utils/value-helpers';
48
+ import {
49
+ adaAssetClass,
50
+ addressFromBech32,
51
+ addressToBech32,
52
+ AssetClass,
53
+ assetClassValueOf,
54
+ estimateUtxoMinLovelace,
55
+ lovelacesAmt,
56
+ matchSingle,
57
+ mkAssetsOf,
58
+ mkLovelacesOf,
59
+ negateAssets,
60
+ } from '@3rd-eye-labs/cardano-offchain-common';
61
+ import { parseIAssetDatumOrThrow } from '../iasset/types';
62
+ import { match, P } from 'ts-pattern';
63
+ import { bigintMax, zeroNegatives } from '../../utils/bigint-utils';
53
64
 
54
- export async function createSpAccount(
55
- asset: string,
65
+ export async function requestSpAccountCreation(
66
+ assetAscii: string,
56
67
  amount: bigint,
57
- params: SystemParams,
68
+ sysParams: SystemParams,
58
69
  lucid: LucidEvolution,
59
70
  ): Promise<TxBuilder> {
60
71
  const [pkh, _skh] = await addrDetails(lucid);
61
- const minLovelaces = BigInt(
62
- params.stabilityPoolParams.accountCreateFeeLovelaces +
63
- params.stabilityPoolParams.requestCollateralLovelaces,
64
- );
72
+
73
+ const iasset = fromHex(fromText(assetAscii));
74
+ const iassetAssetClass = {
75
+ currencySymbol: fromHex(
76
+ sysParams.stabilityPoolParams.assetSymbol.unCurrencySymbol,
77
+ ),
78
+ tokenName: iasset,
79
+ };
80
+
65
81
  const datum: AccountContent = {
66
82
  owner: fromHex(pkh.hash),
67
- asset: fromHex(fromText(asset)),
68
- accountSnapshot: {
69
- productVal: { value: 0n },
70
- depositVal: { value: 0n },
71
- sumVal: { value: 0n },
72
- epoch: 0n,
73
- scale: 0n,
74
- },
83
+ iasset: iasset,
84
+ state: initSpState,
85
+ assetSums: [],
75
86
  request: 'Create',
87
+ lastRequestProcessingTime: 0n,
76
88
  };
77
89
 
78
90
  return lucid
@@ -80,7 +92,7 @@ export async function createSpAccount(
80
92
  .pay.ToContract(
81
93
  credentialToAddress(lucid.config().network!, {
82
94
  hash: validatorToScriptHash(
83
- mkStabilityPoolValidatorFromSP(params.stabilityPoolParams),
95
+ mkStabilityPoolValidatorFromSP(sysParams.stabilityPoolParams),
84
96
  ),
85
97
  type: 'Script',
86
98
  }),
@@ -88,30 +100,35 @@ export async function createSpAccount(
88
100
  kind: 'inline',
89
101
  value: serialiseStabilityPoolDatum({ Account: datum }),
90
102
  },
91
- {
92
- lovelace: minLovelaces,
93
- [params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
94
- fromText(asset)]: amount,
95
- },
103
+ addAssets(
104
+ mkAssetsOf(iassetAssetClass, amount),
105
+ mkLovelacesOf(
106
+ // TODO: Calculate a more accurate amount to just cover costs.
107
+ 5_000_000n,
108
+ ),
109
+ ),
96
110
  )
97
111
  .addSignerKey(pkh.hash);
98
112
  }
99
113
 
100
- export async function adjustSpAccount(
101
- asset: string,
114
+ export async function requestSpAccountAdjustment(
102
115
  amount: bigint,
103
116
  accountUtxo: UTxO,
104
- params: SystemParams,
117
+ sysParams: SystemParams,
105
118
  lucid: LucidEvolution,
106
119
  ): Promise<TxBuilder> {
107
120
  const myAddress = await lucid.wallet().address();
108
121
 
109
- const stabilityPoolScriptRef = await scriptRef(
110
- params.scriptReferences.stabilityPoolValidatorRef,
111
- lucid,
122
+ const stabilityPoolScriptRef = matchSingle(
123
+ await lucid.utxosByOutRef([
124
+ fromSystemParamsScriptRef(
125
+ sysParams.scriptReferences.stabilityPoolValidatorRef,
126
+ ),
127
+ ]),
128
+ (_) => new Error('Expected a single stability pool Ref Script UTXO'),
112
129
  );
113
130
 
114
- const oldAccountDatum: AccountContent = parseAccountDatum(
131
+ const oldAccountDatum: AccountContent = parseAccountDatumOrThrow(
115
132
  getInlineDatumOrThrow(accountUtxo),
116
133
  );
117
134
 
@@ -125,21 +142,6 @@ export async function adjustSpAccount(
125
142
  },
126
143
  };
127
144
 
128
- const value = {
129
- lovelace: BigInt(
130
- params.stabilityPoolParams.requestCollateralLovelaces +
131
- params.stabilityPoolParams.accountAdjustmentFeeLovelaces,
132
- ),
133
- [params.stabilityPoolParams.accountToken[0].unCurrencySymbol +
134
- fromText(params.stabilityPoolParams.accountToken[1].unTokenName)]: 1n,
135
- };
136
-
137
- if (amount > 0n) {
138
- value[
139
- params.stabilityPoolParams.assetSymbol.unCurrencySymbol + fromText(asset)
140
- ] = amount;
141
- }
142
-
143
145
  return lucid
144
146
  .newTx()
145
147
  .readFrom([stabilityPoolScriptRef])
@@ -155,41 +157,62 @@ export async function adjustSpAccount(
155
157
  }),
156
158
  )
157
159
  .pay.ToContract(
158
- credentialToAddress(lucid.config().network!, {
159
- hash: validatorToScriptHash(
160
- mkStabilityPoolValidatorFromSP(params.stabilityPoolParams),
161
- ),
162
- type: 'Script',
163
- }),
160
+ accountUtxo.address,
164
161
  {
165
162
  kind: 'inline',
166
163
  value: serialiseStabilityPoolDatum({
167
164
  Account: newAccountDatum,
168
165
  }),
169
166
  },
170
- value,
167
+ addAssets(
168
+ mkLovelacesOf(
169
+ // TODO: Calculate a more accurate amount to just cover costs.
170
+ 7_000_000n,
171
+ ),
172
+ mkAssetsOf(
173
+ fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
174
+ 1n,
175
+ ),
176
+ amount > 0n
177
+ ? mkAssetsOf(
178
+ {
179
+ currencySymbol: fromHex(
180
+ sysParams.stabilityPoolParams.assetSymbol.unCurrencySymbol,
181
+ ),
182
+ tokenName: oldAccountDatum.iasset,
183
+ },
184
+ amount,
185
+ )
186
+ : {},
187
+ ),
171
188
  )
172
189
  .addSignerKey(toHex(oldAccountDatum.owner));
173
190
  }
174
191
 
175
- export async function closeSpAccount(
192
+ export async function requestSpAccountClosure(
176
193
  accountUtxo: UTxO,
177
- params: SystemParams,
194
+ sysParams: SystemParams,
178
195
  lucid: LucidEvolution,
196
+ maxTxFee: bigint = BASE_MAX_TX_FEE,
179
197
  ): Promise<TxBuilder> {
180
198
  const myAddress = await lucid.wallet().address();
181
199
 
182
- const stabilityPoolScriptRef = await scriptRef(
183
- params.scriptReferences.stabilityPoolValidatorRef,
184
- lucid,
200
+ const stabilityPoolScriptRef = matchSingle(
201
+ await lucid.utxosByOutRef([
202
+ fromSystemParamsScriptRef(
203
+ sysParams.scriptReferences.stabilityPoolValidatorRef,
204
+ ),
205
+ ]),
206
+ (_) => new Error('Expected a single stability pool Ref Script UTXO'),
185
207
  );
186
208
 
187
209
  const request: AccountAction = {
188
210
  Close: {
189
211
  outputAddress: addressFromBech32(myAddress),
212
+ maxTxFee: maxTxFee,
190
213
  },
191
214
  };
192
- const oldAccountDatum: AccountContent = parseAccountDatum(
215
+ const oldAccountDatum: AccountContent = parseAccountDatumOrThrow(
193
216
  getInlineDatumOrThrow(accountUtxo),
194
217
  );
195
218
  const newAccountDatum: AccountContent = {
@@ -205,460 +228,571 @@ export async function closeSpAccount(
205
228
  serialiseStabilityPoolRedeemer({ RequestAction: request }),
206
229
  )
207
230
  .pay.ToContract(
208
- credentialToAddress(lucid.config().network!, {
209
- hash: validatorToScriptHash(
210
- mkStabilityPoolValidatorFromSP(params.stabilityPoolParams),
211
- ),
212
- type: 'Script',
213
- }),
231
+ accountUtxo.address,
214
232
  {
215
233
  kind: 'inline',
216
234
  value: serialiseStabilityPoolDatum({ Account: newAccountDatum }),
217
235
  },
218
- {
219
- lovelace: BigInt(
220
- params.stabilityPoolParams.requestCollateralLovelaces +
221
- params.stabilityPoolParams.accountAdjustmentFeeLovelaces,
236
+ addAssets(
237
+ mkLovelacesOf(
238
+ // TODO: Calculate a more accurate amount to just cover costs.
239
+ 5_000_000n,
222
240
  ),
223
- [params.stabilityPoolParams.accountToken[0].unCurrencySymbol +
224
- fromText(params.stabilityPoolParams.accountToken[1].unTokenName)]: 1n,
225
- },
241
+ mkAssetsOf(
242
+ fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
243
+ 1n,
244
+ ),
245
+ ),
226
246
  )
227
247
  .addSignerKey(toHex(oldAccountDatum.owner));
228
248
  }
229
249
 
230
250
  export async function processSpRequest(
231
- asset: string,
232
251
  stabilityPoolUtxo: UTxO,
233
252
  accountUtxo: UTxO,
234
- govUtxo: UTxO,
235
253
  iAssetUtxo: UTxO,
236
- newSnapshotUtxo: UTxO | undefined,
237
- params: SystemParams,
254
+ /**
255
+ * For performance provide only the ones related to the pool's iAsset.
256
+ */
257
+ allE2s2sSnapshotOrefs: OutRef[],
258
+ sysParams: SystemParams,
238
259
  lucid: LucidEvolution,
239
- collector: UtxoOrOutRef,
260
+ currentSlot: number,
240
261
  ): Promise<TxBuilder> {
241
- const redeemer: StabilityPoolRedeemer = {
242
- ProcessRequest: {
243
- txHash: { hash: fromHex(accountUtxo.txHash) },
244
- outputIndex: BigInt(accountUtxo.outputIndex),
245
- },
246
- };
247
- const stabilityPoolScriptRef = await scriptRef(
248
- params.scriptReferences.stabilityPoolValidatorRef,
249
- lucid,
262
+ const network = lucid.config().network!;
263
+ const currentTime = BigInt(slotToUnixTime(network, currentSlot));
264
+
265
+ const stabilityPoolScriptRef = matchSingle(
266
+ await lucid.utxosByOutRef([
267
+ fromSystemParamsScriptRef(
268
+ sysParams.scriptReferences.stabilityPoolValidatorRef,
269
+ ),
270
+ ]),
271
+ (_) => new Error('Expected a single stability pool Ref Script UTXO'),
250
272
  );
251
273
 
252
- const accountDatum = parseAccountDatum(getInlineDatumOrThrow(accountUtxo));
274
+ const accountDatum = parseAccountDatumOrThrow(
275
+ getInlineDatumOrThrow(accountUtxo),
276
+ );
253
277
 
254
- const stabilityPoolDatum = parseStabilityPoolDatum(
278
+ const stabilityPoolDatum = parseStabilityPoolDatumOrThrow(
255
279
  getInlineDatumOrThrow(stabilityPoolUtxo),
256
280
  );
257
281
 
282
+ const baseRefInputs = [iAssetUtxo, stabilityPoolScriptRef];
283
+
284
+ const validFrom = slotToUnixTime(network, currentSlot - 1);
258
285
  const tx = lucid
259
286
  .newTx()
260
- .collectFrom([stabilityPoolUtxo], serialiseStabilityPoolRedeemer(redeemer))
261
- .collectFrom([accountUtxo], serialiseStabilityPoolRedeemer(redeemer))
262
- .readFrom([iAssetUtxo, govUtxo, stabilityPoolScriptRef]);
263
-
287
+ .validFrom(validFrom)
288
+ .validTo(validFrom + sysParams.stabilityPoolParams.accountProcessingBiasMs)
289
+ .readFrom(baseRefInputs)
290
+ .collectFrom([stabilityPoolUtxo], {
291
+ kind: 'selected',
292
+ inputs: [stabilityPoolUtxo, accountUtxo],
293
+ makeRedeemer: (indices) =>
294
+ serialiseStabilityPoolRedeemer({
295
+ ProcessRequestPool: {
296
+ poolInputIdx: indices[0],
297
+ accountInputIdx: indices[1],
298
+ },
299
+ }),
300
+ });
264
301
  if (!accountDatum.request) throw new Error('Account Request is null');
265
302
 
266
- if (accountDatum.request === 'Create') {
267
- const accountTokenScriptRef = await scriptRef(
268
- params.scriptReferences.authTokenPolicies.accountTokenRef,
269
- lucid,
270
- );
271
- tx.readFrom([accountTokenScriptRef]);
272
-
273
- const iassetUnit =
274
- params.stabilityPoolParams.assetSymbol.unCurrencySymbol + fromText(asset);
275
- const reqAmount = accountUtxo.assets[iassetUnit] ?? 0n;
276
-
277
- const newAccountSnapshot: StabilityPoolSnapshot = {
278
- ...stabilityPoolDatum.poolSnapshot,
279
- depositVal: {
280
- value: spAdd(
281
- accountDatum.accountSnapshot.depositVal,
282
- mkSPInteger(reqAmount),
283
- ).value,
284
- },
285
- };
303
+ const iassetAssetClass: AssetClass = {
304
+ currencySymbol: fromHex(
305
+ sysParams.stabilityPoolParams.assetSymbol.unCurrencySymbol,
306
+ ),
307
+ tokenName: stabilityPoolDatum.iasset,
308
+ };
286
309
 
287
- const newDeposit = spAdd(
288
- stabilityPoolDatum.poolSnapshot.depositVal,
289
- mkSPInteger(reqAmount),
290
- );
310
+ await match(accountDatum.request)
311
+ .with('Create', async (_) => {
312
+ const accountTokenScriptRef = matchSingle(
313
+ await lucid.utxosByOutRef([
314
+ fromSystemParamsScriptRef(
315
+ sysParams.scriptReferences.authTokenPolicies.accountTokenRef,
316
+ ),
317
+ ]),
318
+ (_) =>
319
+ new Error('Expected a single cdp auth token policy Ref Script UTXO'),
320
+ );
291
321
 
292
- const newSum = spAdd(
293
- stabilityPoolDatum.poolSnapshot.sumVal,
294
- spDiv(
295
- spMul(
296
- mkSPInteger(
297
- BigInt(params.stabilityPoolParams.accountCreateFeeLovelaces),
322
+ const requestDepositAmt = assetClassValueOf(
323
+ accountUtxo.assets,
324
+ iassetAssetClass,
325
+ );
326
+
327
+ const poolAddr = mkStabilityPoolAddr(lucid, sysParams);
328
+
329
+ tx.readFrom([accountTokenScriptRef])
330
+ .collectFrom([accountUtxo], {
331
+ kind: 'selected',
332
+ inputs: [stabilityPoolUtxo, accountUtxo],
333
+ makeRedeemer: (indices) =>
334
+ serialiseStabilityPoolRedeemer({
335
+ ProcessRequestAccount: {
336
+ poolInputIdx: indices[0],
337
+ accountInputIdx: indices[1],
338
+ e2s2sIdxs: [],
339
+ currentTime: currentTime,
340
+ },
341
+ }),
342
+ })
343
+ .mintAssets(
344
+ mkAssetsOf(
345
+ fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
346
+ 1n,
298
347
  ),
299
- stabilityPoolDatum.poolSnapshot.productVal,
348
+ Data.void(),
349
+ )
350
+ .pay.ToContract(
351
+ poolAddr,
352
+ {
353
+ kind: 'inline',
354
+ value: serialiseStabilityPoolDatum({
355
+ StabilityPool: liquidationHelper(
356
+ {
357
+ ...stabilityPoolDatum,
358
+ state: {
359
+ ...stabilityPoolDatum.state,
360
+ depositVal: spAdd(
361
+ stabilityPoolDatum.state.depositVal,
362
+ mkSPInteger(requestDepositAmt),
363
+ ),
364
+ },
365
+ },
366
+ adaAssetClass,
367
+ 0n,
368
+ BigInt(sysParams.stabilityPoolParams.accountCreateFeeLovelaces),
369
+ ),
370
+ }),
371
+ },
372
+ addAssets(
373
+ stabilityPoolUtxo.assets,
374
+ mkAssetsOf(iassetAssetClass, requestDepositAmt),
375
+ mkLovelacesOf(
376
+ BigInt(sysParams.stabilityPoolParams.accountCreateFeeLovelaces),
377
+ ),
378
+ ),
379
+ )
380
+ .pay.ToContract(
381
+ poolAddr,
382
+ {
383
+ kind: 'inline',
384
+ value: serialiseStabilityPoolDatum({
385
+ Account: {
386
+ owner: accountDatum.owner,
387
+ iasset: stabilityPoolDatum.iasset,
388
+ state: {
389
+ ...stabilityPoolDatum.state,
390
+ depositVal: mkSPInteger(requestDepositAmt),
391
+ },
392
+ assetSums: stabilityPoolDatum.assetStates.map(([key, val]) => [
393
+ key,
394
+ val.currentSumVal,
395
+ ]),
396
+ request: null,
397
+ lastRequestProcessingTime: currentTime,
398
+ },
399
+ }),
400
+ },
401
+ addAssets(
402
+ mkAssetsOf(
403
+ fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
404
+ 1n,
405
+ ),
406
+ mkLovelacesOf(lovelacesAmt(accountUtxo.assets)),
407
+ ),
408
+ );
409
+ })
410
+ .with({ Adjust: P.select() }, async (adjustContent) => {
411
+ const iassetDatum = parseIAssetDatumOrThrow(
412
+ getInlineDatumOrThrow(iAssetUtxo),
413
+ );
414
+
415
+ const accountDepositChange = adjustContent.amount;
416
+ const outputAddress = addressToBech32(
417
+ adjustContent.outputAddress,
418
+ lucid.config().network!,
419
+ );
420
+
421
+ const e2s2sIdxs = await findRelevantE2s2sIdxs(
422
+ lucid,
423
+ stabilityPoolDatum,
424
+ accountDatum.state,
425
+ allE2s2sSnapshotOrefs,
426
+ );
427
+
428
+ const { updatedAccountContent, reward } = updateAccount(
429
+ stabilityPoolDatum,
430
+ accountDatum,
431
+ e2s2sIdxs,
432
+ );
433
+
434
+ const isDepositOrRewardWithdrawal = accountDepositChange >= 0;
435
+
436
+ const accountBalanceChange = isDepositOrRewardWithdrawal
437
+ ? accountDepositChange
438
+ : bigintMax(
439
+ accountDepositChange,
440
+ -fromSPInteger(updatedAccountContent.state.depositVal),
441
+ );
442
+
443
+ const newPoolDepositExcludingFee = spZeroNegatives(
444
+ spAdd(
445
+ stabilityPoolDatum.state.depositVal,
446
+ mkSPInteger(accountBalanceChange),
300
447
  ),
301
- newDeposit,
302
- ),
303
- );
448
+ );
304
449
 
305
- const newStabilityPoolSnapshot: StabilityPoolSnapshot = {
306
- ...stabilityPoolDatum.poolSnapshot,
307
- depositVal: newDeposit,
308
- sumVal: newSum,
309
- };
310
-
311
- const newEpochToScaleToSum: EpochToScaleToSum = setSumInEpochToScaleToSum(
312
- stabilityPoolDatum.epochToScaleToSum,
313
- stabilityPoolDatum.poolSnapshot.epoch,
314
- stabilityPoolDatum.poolSnapshot.scale,
315
- newSum,
316
- );
450
+ const withdrawalFeeAmt =
451
+ isDepositOrRewardWithdrawal || newPoolDepositExcludingFee.value === 0n
452
+ ? 0n
453
+ : calculateFeeFromRatio(
454
+ iassetDatum.stabilityPoolWithdrawalFeeRatio,
455
+ -accountBalanceChange,
456
+ );
457
+
458
+ const newPoolState = updatePoolStateWhenWithdrawalFee(withdrawalFeeAmt, {
459
+ ...stabilityPoolDatum.state,
460
+ depositVal: newPoolDepositExcludingFee,
461
+ });
462
+
463
+ const { e2s2sRefInputs, mkProcessRequestAccountRedeemerContent } =
464
+ createProcessRequestAccountRedeemer(
465
+ e2s2sIdxs,
466
+ baseRefInputs,
467
+ currentTime,
468
+ );
469
+
470
+ if (e2s2sRefInputs.length > 0) {
471
+ tx.readFrom(e2s2sRefInputs);
472
+ }
473
+
474
+ tx.collectFrom([accountUtxo], {
475
+ kind: 'selected',
476
+ inputs: [stabilityPoolUtxo, accountUtxo],
477
+ makeRedeemer: (indices) => {
478
+ return serialiseStabilityPoolRedeemer({
479
+ ProcessRequestAccount: mkProcessRequestAccountRedeemerContent(
480
+ indices[0],
481
+ indices[1],
482
+ ),
483
+ });
484
+ },
485
+ }).pay.ToContract(
486
+ stabilityPoolUtxo.address,
487
+ {
488
+ kind: 'inline',
489
+ value: serialiseStabilityPoolDatum({
490
+ StabilityPool: {
491
+ ...stabilityPoolDatum,
492
+ state: newPoolState,
493
+ },
494
+ }),
495
+ },
496
+ addAssets(
497
+ stabilityPoolUtxo.assets,
498
+ negateAssets(reward),
499
+ mkAssetsOf(iassetAssetClass, accountBalanceChange + withdrawalFeeAmt),
500
+ ),
501
+ );
317
502
 
318
- const stabilityPoolAssetToken = stabilityPoolUtxo.assets[iassetUnit] ?? 0n;
319
- const poolOutputValue = {
320
- lovelace:
321
- stabilityPoolUtxo.assets.lovelace +
322
- BigInt(params.stabilityPoolParams.accountCreateFeeLovelaces),
323
- [params.stabilityPoolParams.stabilityPoolToken[0].unCurrencySymbol +
324
- fromText(params.stabilityPoolParams.stabilityPoolToken[1].unTokenName)]:
325
- 1n,
326
- [params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
327
- fromText(asset)]: stabilityPoolAssetToken + reqAmount,
328
- };
503
+ const theoreticalOwnerOutputVal = addAssets(
504
+ reward,
505
+ isDepositOrRewardWithdrawal
506
+ ? {}
507
+ : mkAssetsOf(
508
+ iassetAssetClass,
509
+ -accountBalanceChange - withdrawalFeeAmt,
510
+ ),
511
+ );
512
+ const ownerOutputDat = serialiseActionReturnDatum({
513
+ IndigoStabilityPoolAccountAdjustment: {
514
+ txHash: fromHex(accountUtxo.txHash),
515
+ outputIndex: BigInt(accountUtxo.outputIndex),
516
+ },
517
+ });
329
518
 
330
- tx.mintAssets(
331
- {
332
- [params.stabilityPoolParams.accountToken[0].unCurrencySymbol +
333
- fromText(params.stabilityPoolParams.accountToken[1].unTokenName)]: 1n,
334
- },
335
- Data.to(new Constr(0, [])),
336
- );
519
+ const ownerOutputMinUtxoLovelace = estimateUtxoMinLovelace(
520
+ lucid.config().protocolParameters!,
521
+ outputAddress,
522
+ theoreticalOwnerOutputVal,
523
+ { InlineDatum: { datum: ownerOutputDat } },
524
+ );
337
525
 
338
- tx.pay.ToContract(
339
- stabilityPoolUtxo.address,
340
- {
341
- kind: 'inline',
342
- value: serialiseStabilityPoolDatum({
343
- StabilityPool: {
344
- ...stabilityPoolDatum,
345
- poolSnapshot: newStabilityPoolSnapshot,
346
- epochToScaleToSum: newEpochToScaleToSum,
526
+ // Add extra lovelaces only when needed to reach minUTxo lovelaces.
527
+ const extraOwnerOutputLovelacesAmt =
528
+ lovelacesAmt(theoreticalOwnerOutputVal) >= ownerOutputMinUtxoLovelace
529
+ ? 0n
530
+ : ownerOutputMinUtxoLovelace -
531
+ lovelacesAmt(theoreticalOwnerOutputVal);
532
+
533
+ const actualOwnerOutputVal = addAssets(
534
+ theoreticalOwnerOutputVal,
535
+ mkLovelacesOf(extraOwnerOutputLovelacesAmt),
536
+ );
537
+
538
+ const accountOutputDat = serialiseStabilityPoolDatum({
539
+ Account: {
540
+ ...updatedAccountContent,
541
+ state: {
542
+ ...updatedAccountContent.state,
543
+ depositVal: spAdd(
544
+ updatedAccountContent.state.depositVal,
545
+ mkSPInteger(accountBalanceChange),
546
+ ),
347
547
  },
348
- }),
349
- },
350
- poolOutputValue,
351
- );
548
+ request: null,
549
+ lastRequestProcessingTime: currentTime,
550
+ },
551
+ });
352
552
 
353
- tx.pay.ToContract(
354
- stabilityPoolUtxo.address,
355
- {
356
- kind: 'inline',
357
- value: serialiseStabilityPoolDatum({
358
- Account: {
359
- ...accountDatum,
360
- accountSnapshot: newAccountSnapshot,
361
- request: null,
553
+ const accountOutputValWithoutAda = mkAssetsOf(
554
+ fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
555
+ 1n,
556
+ );
557
+
558
+ const accountOutMinUtxoLovelace = estimateUtxoMinLovelace(
559
+ lucid.config().protocolParameters!,
560
+ stabilityPoolUtxo.address,
561
+ accountOutputValWithoutAda,
562
+ { InlineDatum: { datum: accountOutputDat } },
563
+ );
564
+
565
+ // TODO: include Tx fee here.
566
+ const accountOutputAdaAmt =
567
+ lovelacesAmt(accountUtxo.assets) - extraOwnerOutputLovelacesAmt;
568
+
569
+ // This is to prevent spending ADA from the wallet submitting the request processing Tx.
570
+ if (accountOutputAdaAmt < accountOutMinUtxoLovelace) {
571
+ throw new Error("Account doesn't have enough ADA to be processed.");
572
+ }
573
+
574
+ tx.pay
575
+ .ToContract(
576
+ stabilityPoolUtxo.address,
577
+ {
578
+ kind: 'inline',
579
+ value: accountOutputDat,
362
580
  },
363
- }),
364
- },
365
- {
366
- lovelace:
367
- accountUtxo.assets.lovelace -
368
- BigInt(params.stabilityPoolParams.accountCreateFeeLovelaces),
369
- [params.stabilityPoolParams.accountToken[0].unCurrencySymbol +
370
- fromText(params.stabilityPoolParams.accountToken[1].unTokenName)]: 1n,
371
- },
372
- );
373
- } else if ('Adjust' in accountDatum.request) {
374
- const amount = accountDatum.request.Adjust.amount;
375
- const outputAddress = addressToBech32(
376
- accountDatum.request.Adjust.outputAddress,
377
- lucid.config().network!,
378
- );
379
- const myAddress = await lucid.wallet().address();
380
- const [updatedAccountSnapshot, reward, refInputs] = adjustmentHelper(
381
- stabilityPoolUtxo,
382
- newSnapshotUtxo,
383
- stabilityPoolDatum.poolSnapshot,
384
- stabilityPoolDatum.epochToScaleToSum,
385
- accountDatum.accountSnapshot,
386
- );
387
- const govDatum: GovDatum = parseGovDatumOrThrow(
388
- getInlineDatumOrThrow(govUtxo),
389
- );
390
- const iassetDatum: IAssetContent = parseIAssetDatumOrThrow(
391
- getInlineDatumOrThrow(iAssetUtxo),
392
- );
393
- const rewardLovelacesFee = calculateFeeFromPercentage(
394
- govDatum.protocolParams.collateralFeePercentage,
395
- reward,
396
- );
397
- const isDepositOrRewardWithdrawal: boolean = amount > 0n;
398
- const bigIntMax = (...args: bigint[]): bigint =>
399
- args.reduce((m, e) => (e > m ? e : m));
400
-
401
- const balanceChange: bigint = isDepositOrRewardWithdrawal
402
- ? amount
403
- : bigIntMax(amount, -fromSPInteger(updatedAccountSnapshot.depositVal));
404
- const newAccountSnapshot: StabilityPoolSnapshot = {
405
- ...updatedAccountSnapshot,
406
- depositVal: spAdd(
407
- updatedAccountSnapshot.depositVal,
408
- mkSPInteger(balanceChange),
409
- ),
410
- };
411
- const _newPoolDepositExcludingFee = spAdd(
412
- stabilityPoolDatum.poolSnapshot.depositVal,
413
- mkSPInteger(balanceChange),
414
- );
415
- const newPoolDepositExcludingFee =
416
- _newPoolDepositExcludingFee.value > 0n
417
- ? _newPoolDepositExcludingFee
418
- : mkSPInteger(0n);
419
- const withdrawalFee =
420
- isDepositOrRewardWithdrawal || newPoolDepositExcludingFee.value === 0n
421
- ? 0n
422
- : calculateFeeFromPercentage(
423
- iassetDatum.stabilityPoolWithdrawalFeePercentage,
424
- -balanceChange,
425
- );
426
- const newPoolDeposit = spAdd(
427
- newPoolDepositExcludingFee,
428
- mkSPInteger(withdrawalFee),
429
- );
430
- const newPoolProduct =
431
- withdrawalFee === 0n
432
- ? stabilityPoolDatum.poolSnapshot.productVal
433
- : spMul(
434
- stabilityPoolDatum.poolSnapshot.productVal,
435
- spAdd(
436
- mkSPInteger(1n),
437
- spDiv(mkSPInteger(withdrawalFee), newPoolDepositExcludingFee),
438
- ),
439
- );
440
- const newPoolSum = spAdd(
441
- stabilityPoolDatum.poolSnapshot.sumVal,
442
- spDiv(
443
- spMul(
444
- mkSPInteger(
445
- BigInt(params.stabilityPoolParams.accountAdjustmentFeeLovelaces),
581
+ addAssets(
582
+ accountOutputValWithoutAda,
583
+ mkLovelacesOf(accountOutputAdaAmt),
446
584
  ),
447
- newPoolProduct,
585
+ )
586
+ .pay.ToAddressWithData(
587
+ outputAddress,
588
+ {
589
+ kind: 'inline',
590
+ value: ownerOutputDat,
591
+ },
592
+ actualOwnerOutputVal,
593
+ );
594
+ })
595
+ .with({ Close: P.select() }, async (closeContent) => {
596
+ const accountTokenScriptRef = matchSingle(
597
+ await lucid.utxosByOutRef([
598
+ fromSystemParamsScriptRef(
599
+ sysParams.scriptReferences.authTokenPolicies.accountTokenRef,
600
+ ),
601
+ ]),
602
+ (_) =>
603
+ new Error('Expected a single cdp auth token policy Ref Script UTXO'),
604
+ );
605
+
606
+ const iassetDatum = parseIAssetDatumOrThrow(
607
+ getInlineDatumOrThrow(iAssetUtxo),
608
+ );
609
+
610
+ const outputAddress = addressToBech32(
611
+ closeContent.outputAddress,
612
+ lucid.config().network!,
613
+ );
614
+
615
+ const e2s2sIdxs = await findRelevantE2s2sIdxs(
616
+ lucid,
617
+ stabilityPoolDatum,
618
+ accountDatum.state,
619
+ allE2s2sSnapshotOrefs,
620
+ );
621
+
622
+ const { updatedAccountContent, reward } = updateAccount(
623
+ stabilityPoolDatum,
624
+ accountDatum,
625
+ e2s2sIdxs,
626
+ );
627
+
628
+ const newPoolDepositExcludingFee = spZeroNegatives(
629
+ spSub(
630
+ stabilityPoolDatum.state.depositVal,
631
+ updatedAccountContent.state.depositVal,
448
632
  ),
449
- newPoolDeposit,
450
- ),
451
- );
452
- const newPoolSnapshot: StabilityPoolSnapshot = {
453
- ...stabilityPoolDatum.poolSnapshot,
454
- depositVal: newPoolDeposit,
455
- sumVal: newPoolSum,
456
- productVal: newPoolProduct,
457
- };
458
- const newEpochToScaleToSum: EpochToScaleToSum = setSumInEpochToScaleToSum(
459
- stabilityPoolDatum.epochToScaleToSum,
460
- stabilityPoolDatum.poolSnapshot.epoch,
461
- stabilityPoolDatum.poolSnapshot.scale,
462
- newPoolSum,
463
- );
633
+ );
464
634
 
465
- if (rewardLovelacesFee > 0n) {
466
- await collectorFeeTx(rewardLovelacesFee, lucid, params, tx, collector);
467
- }
468
- tx.readFrom([govUtxo, iAssetUtxo, ...refInputs]);
469
- tx.pay.ToContract(
470
- stabilityPoolUtxo.address,
471
- {
472
- kind: 'inline',
473
- value: serialiseStabilityPoolDatum({
474
- StabilityPool: {
475
- ...stabilityPoolDatum,
476
- poolSnapshot: newPoolSnapshot,
477
- epochToScaleToSum: newEpochToScaleToSum,
635
+ const withdrawnAmt = zeroNegatives(
636
+ fromSPInteger(updatedAccountContent.state.depositVal),
637
+ );
638
+
639
+ const withdrawalFeeAmt =
640
+ newPoolDepositExcludingFee.value === 0n
641
+ ? 0n
642
+ : calculateFeeFromRatio(
643
+ iassetDatum.stabilityPoolWithdrawalFeeRatio,
644
+ withdrawnAmt,
645
+ );
646
+
647
+ const newPoolState = updatePoolStateWhenWithdrawalFee(withdrawalFeeAmt, {
648
+ ...stabilityPoolDatum.state,
649
+ depositVal: newPoolDepositExcludingFee,
650
+ });
651
+
652
+ const { e2s2sRefInputs, mkProcessRequestAccountRedeemerContent } =
653
+ createProcessRequestAccountRedeemer(
654
+ e2s2sIdxs,
655
+ [...baseRefInputs, accountTokenScriptRef],
656
+ currentTime,
657
+ );
658
+
659
+ if (e2s2sRefInputs.length > 0) {
660
+ tx.readFrom(e2s2sRefInputs);
661
+ }
662
+
663
+ tx.readFrom([accountTokenScriptRef])
664
+ .collectFrom([accountUtxo], {
665
+ kind: 'selected',
666
+ inputs: [stabilityPoolUtxo, accountUtxo],
667
+ makeRedeemer: (indices) => {
668
+ return serialiseStabilityPoolRedeemer({
669
+ ProcessRequestAccount: mkProcessRequestAccountRedeemerContent(
670
+ indices[0],
671
+ indices[1],
672
+ ),
673
+ });
478
674
  },
479
- }),
480
- },
481
- {
482
- lovelace:
483
- stabilityPoolUtxo.assets.lovelace +
484
- BigInt(params.stabilityPoolParams.accountAdjustmentFeeLovelaces) -
485
- reward,
486
- [params.stabilityPoolParams.stabilityPoolToken[0].unCurrencySymbol +
487
- fromText(params.stabilityPoolParams.stabilityPoolToken[1].unTokenName)]:
488
- 1n,
489
- [params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
490
- fromText(asset)]:
491
- stabilityPoolUtxo.assets[
492
- params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
493
- fromText(asset)
494
- ] ?? 0n + balanceChange + withdrawalFee,
495
- },
496
- );
497
- tx.pay.ToContract(
498
- stabilityPoolUtxo.address,
499
- {
500
- kind: 'inline',
501
- value: serialiseStabilityPoolDatum({
502
- Account: {
503
- ...accountDatum,
504
- accountSnapshot: newAccountSnapshot,
505
- request: null,
675
+ })
676
+ .mintAssets(
677
+ mkAssetsOf(
678
+ fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
679
+ -1n,
680
+ ),
681
+ Data.void(),
682
+ )
683
+ .pay.ToContract(
684
+ stabilityPoolUtxo.address,
685
+ {
686
+ kind: 'inline',
687
+ value: serialiseStabilityPoolDatum({
688
+ StabilityPool: {
689
+ ...stabilityPoolDatum,
690
+ state: newPoolState,
691
+ },
692
+ }),
506
693
  },
507
- }),
508
- },
509
- {
510
- lovelace:
511
- accountUtxo.assets.lovelace -
512
- BigInt(params.stabilityPoolParams.accountAdjustmentFeeLovelaces) -
513
- 2_000_000n,
514
- [params.stabilityPoolParams.accountToken[0].unCurrencySymbol +
515
- fromText(params.stabilityPoolParams.accountToken[1].unTokenName)]: 1n,
516
- },
517
- );
518
- if (myAddress !== outputAddress) {
519
- tx.pay.ToAddressWithData(
520
- outputAddress,
521
- {
522
- kind: 'inline',
523
- value: Data.to(
524
- {
525
- IndigoStabilityPoolAccountAdjustment: {
526
- spent_account: {
527
- txHash: { hash: accountUtxo.txHash },
528
- outputIndex: BigInt(accountUtxo.outputIndex),
529
- },
694
+ addAssets(
695
+ stabilityPoolUtxo.assets,
696
+ negateAssets(reward),
697
+ mkAssetsOf(iassetAssetClass, -withdrawnAmt + withdrawalFeeAmt),
698
+ ),
699
+ )
700
+ .pay.ToAddressWithData(
701
+ outputAddress,
702
+ {
703
+ kind: 'inline',
704
+ value: serialiseActionReturnDatum({
705
+ IndigoStabilityPoolAccountClosure: {
706
+ txHash: fromHex(accountUtxo.txHash),
707
+ outputIndex: BigInt(accountUtxo.outputIndex),
530
708
  },
531
- },
532
- ActionReturnDatum,
709
+ }),
710
+ },
711
+ addAssets(
712
+ mkLovelacesOf(lovelacesAmt(accountUtxo.assets)),
713
+ reward,
714
+ mkAssetsOf(iassetAssetClass, withdrawnAmt - withdrawalFeeAmt),
533
715
  ),
534
- },
535
- {
536
- lovelace: reward - rewardLovelacesFee + 2_000_000n,
537
- ...(!isDepositOrRewardWithdrawal
538
- ? {
539
- [params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
540
- fromText(asset)]: -balanceChange - withdrawalFee,
541
- }
542
- : {}),
543
- },
544
- );
545
- } else {
546
- // TODO: User is self-handling the process request, so we will need to handle the change datum
547
- }
548
- } else if ('Close' in accountDatum.request) {
549
- const outputAddress = addressToBech32(
550
- accountDatum.request.Close.outputAddress,
551
- lucid.config().network!,
552
- );
553
- const myAddress = await lucid.wallet().address();
554
- const [updatedAccountSnapshot, reward, refInputs] = adjustmentHelper(
555
- stabilityPoolUtxo,
556
- newSnapshotUtxo,
557
- stabilityPoolDatum.poolSnapshot,
558
- stabilityPoolDatum.epochToScaleToSum,
559
- accountDatum.accountSnapshot,
560
- );
561
- const govDatum: GovDatum = parseGovDatumOrThrow(
562
- getInlineDatumOrThrow(govUtxo),
563
- );
564
- const iassetDatum: IAssetContent = parseIAssetDatumOrThrow(
565
- getInlineDatumOrThrow(iAssetUtxo),
566
- );
567
- const rewardLovelacesFee = calculateFeeFromPercentage(
568
- govDatum.protocolParams.collateralFeePercentage,
569
- reward,
570
- );
571
- const fund = updatedAccountSnapshot.depositVal;
572
- const newPoolDepositExcludingFee = spSub(
573
- stabilityPoolDatum.poolSnapshot.depositVal,
574
- fund,
575
- );
576
- const withdrawnAmt = fund.value < 0n ? mkSPInteger(0n) : fund;
577
- const withdrawalFeeAmount =
578
- newPoolDepositExcludingFee.value === 0n
579
- ? 0n
580
- : calculateFeeFromPercentage(
581
- iassetDatum.stabilityPoolWithdrawalFeePercentage,
582
- withdrawnAmt.value,
583
- );
584
- const [newPoolDeposit, newPoolProduct] = updatePoolSnapshotWithdrawalFee(
585
- mkSPInteger(withdrawalFeeAmount),
586
- newPoolDepositExcludingFee,
587
- stabilityPoolDatum.poolSnapshot,
588
- );
589
- const newPoolSnapshot: StabilityPoolSnapshot = {
590
- ...stabilityPoolDatum.poolSnapshot,
591
- depositVal: newPoolDeposit,
592
- productVal: newPoolProduct,
593
- };
594
- const accountTokenRef = await scriptRef(
595
- params.scriptReferences.authTokenPolicies.accountTokenRef,
596
- lucid,
597
- );
598
- await collectorFeeTx(rewardLovelacesFee, lucid, params, tx, collector);
599
- tx.readFrom([govUtxo, iAssetUtxo, accountTokenRef, ...refInputs]);
600
- tx.mintAssets(
716
+ );
717
+ })
718
+ .exhaustive();
719
+
720
+ return tx;
721
+ }
722
+
723
+ export async function createE2s2sSnapshots(
724
+ stabilityPoolOref: OutRef,
725
+ sysParams: SystemParams,
726
+ lucid: LucidEvolution,
727
+ ): Promise<TxBuilder> {
728
+ const stabilityPoolRefScriptUtxo = matchSingle(
729
+ await lucid.utxosByOutRef([
730
+ fromSystemParamsScriptRef(
731
+ sysParams.scriptReferences.stabilityPoolValidatorRef,
732
+ ),
733
+ ]),
734
+ (_) => new Error('Expected a single stability pool Ref Script UTXO'),
735
+ );
736
+ const snapshotE2s2sPolicyRefScriptUtxo = matchSingle(
737
+ await lucid.utxosByOutRef([
738
+ fromSystemParamsScriptRef(
739
+ sysParams.scriptReferences.authTokenPolicies
740
+ .snapshotEpochToScaleToSumTokenRef,
741
+ ),
742
+ ]),
743
+ (_) => new Error('Expected a single snapshot e2s2s policy Ref Script UTXO'),
744
+ );
745
+
746
+ const spUtxo = matchSingle(
747
+ await lucid.utxosByOutRef([stabilityPoolOref]),
748
+ (_) => new Error('Expected a single stability pool UTXO'),
749
+ );
750
+ const spDatum = parseStabilityPoolDatumOrThrow(getInlineDatumOrThrow(spUtxo));
751
+
752
+ const [newSnapshotDatums, newAssetStates] =
753
+ partitionEpochToScaleToSums(spDatum);
754
+
755
+ if (newSnapshotDatums.length === 0) {
756
+ throw new Error('There has to be a snapshot being created.');
757
+ }
758
+
759
+ const snapshotAc = fromSystemParamsAsset(
760
+ sysParams.stabilityPoolParams.snapshotEpochToScaleToSumToken,
761
+ );
762
+
763
+ const tx = lucid
764
+ .newTx()
765
+ .readFrom([stabilityPoolRefScriptUtxo, snapshotE2s2sPolicyRefScriptUtxo])
766
+ .collectFrom(
767
+ [spUtxo],
768
+ serialiseStabilityPoolRedeemer('RecordEpochToScaleToSum'),
769
+ )
770
+ .mintAssets(
771
+ mkAssetsOf(snapshotAc, BigInt(newSnapshotDatums.length)),
772
+ Data.void(),
773
+ )
774
+ .pay.ToContract(
775
+ spUtxo.address,
601
776
  {
602
- [params.stabilityPoolParams.accountToken[0].unCurrencySymbol +
603
- fromText(params.stabilityPoolParams.accountToken[1].unTokenName)]: -1n,
777
+ kind: 'inline',
778
+ value: serialiseStabilityPoolDatum({
779
+ StabilityPool: { ...spDatum, assetStates: newAssetStates },
780
+ }),
604
781
  },
605
- Data.to(new Constr(0, [])),
782
+ spUtxo.assets,
606
783
  );
607
- const assetOutputAmountForSP =
608
- stabilityPoolUtxo.assets[
609
- params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
610
- fromText(asset)
611
- ] -
612
- fromSPInteger(withdrawnAmt) -
613
- withdrawalFeeAmount;
784
+
785
+ for (const newDatum of newSnapshotDatums) {
614
786
  tx.pay.ToContract(
615
- stabilityPoolUtxo.address,
787
+ spUtxo.address,
616
788
  {
617
789
  kind: 'inline',
618
790
  value: serialiseStabilityPoolDatum({
619
- StabilityPool: {
620
- ...stabilityPoolDatum,
621
- poolSnapshot: newPoolSnapshot,
622
- },
791
+ SnapshotEpochToScaleToSum: newDatum,
623
792
  }),
624
793
  },
625
- {
626
- lovelace: stabilityPoolUtxo.assets.lovelace - reward,
627
- [params.stabilityPoolParams.stabilityPoolToken[0].unCurrencySymbol +
628
- fromText(params.stabilityPoolParams.stabilityPoolToken[1].unTokenName)]:
629
- 1n,
630
- ...(assetOutputAmountForSP > 0n
631
- ? {
632
- [params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
633
- fromText(asset)]: assetOutputAmountForSP,
634
- }
635
- : {}),
636
- },
794
+ mkAssetsOf(snapshotAc, 1n),
637
795
  );
638
- if (myAddress !== outputAddress) {
639
- tx.pay.ToAddressWithData(
640
- outputAddress,
641
- {
642
- kind: 'inline',
643
- value: Data.to(
644
- {
645
- IndigoStabilityPoolAccountClosure: {
646
- closed_account: {
647
- txHash: { hash: accountUtxo.txHash },
648
- outputIndex: BigInt(accountUtxo.outputIndex),
649
- },
650
- },
651
- },
652
- ActionReturnDatum,
653
- ),
654
- },
655
- {
656
- lovelace: accountUtxo.assets.lovelace + reward - rewardLovelacesFee,
657
- [params.stabilityPoolParams.assetSymbol.unCurrencySymbol +
658
- fromText(asset)]: fromSPInteger(withdrawnAmt) - withdrawalFeeAmount,
659
- },
660
- );
661
- }
662
796
  }
663
797
 
664
798
  return tx;
@@ -669,29 +803,27 @@ export async function annulRequest(
669
803
  params: SystemParams,
670
804
  lucid: LucidEvolution,
671
805
  ): Promise<TxBuilder> {
672
- const stabilityPoolScriptRef = await scriptRef(
673
- params.scriptReferences.stabilityPoolValidatorRef,
674
- lucid,
806
+ const stabilityPoolRefScriptUtxo = matchSingle(
807
+ await lucid.utxosByOutRef([
808
+ fromSystemParamsScriptRef(
809
+ params.scriptReferences.stabilityPoolValidatorRef,
810
+ ),
811
+ ]),
812
+ (_) => new Error('Expected a single stability pool Ref Script UTXO'),
675
813
  );
676
-
677
- const oldAccountDatum: AccountContent = parseAccountDatum(
814
+ const oldAccountDatum: AccountContent = parseAccountDatumOrThrow(
678
815
  getInlineDatumOrThrow(accountUtxo),
679
816
  );
680
817
 
681
818
  const tx = lucid
682
819
  .newTx()
683
- .readFrom([stabilityPoolScriptRef])
820
+ .readFrom([stabilityPoolRefScriptUtxo])
684
821
  .collectFrom([accountUtxo], serialiseStabilityPoolRedeemer('AnnulRequest'))
685
822
  .addSignerKey(toHex(oldAccountDatum.owner));
686
823
 
687
824
  if (oldAccountDatum.request !== 'Create') {
688
825
  tx.pay.ToContract(
689
- credentialToAddress(lucid.config().network!, {
690
- hash: validatorToScriptHash(
691
- mkStabilityPoolValidatorFromSP(params.stabilityPoolParams),
692
- ),
693
- type: 'Script',
694
- }),
826
+ accountUtxo.address,
695
827
  {
696
828
  kind: 'inline',
697
829
  value: serialiseStabilityPoolDatum({