@indigo-labs/indigo-sdk 0.2.41 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/.github/workflows/ci.yml +4 -2
  2. package/dist/index.d.mts +3008 -2194
  3. package/dist/index.d.ts +3008 -2194
  4. package/dist/index.js +9827 -6194
  5. package/dist/index.mjs +8591 -4809
  6. package/package.json +14 -3
  7. package/src/contracts/cdp/helpers.ts +68 -72
  8. package/src/contracts/cdp/scripts.ts +50 -13
  9. package/src/contracts/cdp/transactions.ts +831 -545
  10. package/src/contracts/cdp/types-new.ts +256 -0
  11. package/src/contracts/cdp/types.ts +26 -144
  12. package/src/contracts/cdp-creator/scripts.ts +15 -9
  13. package/src/contracts/cdp-creator/types-new.ts +50 -0
  14. package/src/contracts/cdp-creator/types.ts +5 -31
  15. package/src/contracts/collector/scripts.ts +1 -1
  16. package/src/contracts/collector/transactions.ts +23 -13
  17. package/src/contracts/collector/types-new.ts +17 -0
  18. package/src/contracts/execute/scripts.ts +19 -10
  19. package/src/contracts/execute/types-new.ts +44 -0
  20. package/src/contracts/execute/types.ts +5 -38
  21. package/src/contracts/gov/helpers.ts +187 -51
  22. package/src/contracts/gov/scripts.ts +17 -10
  23. package/src/contracts/gov/transactions.ts +599 -271
  24. package/src/contracts/gov/types-new.ts +253 -100
  25. package/src/contracts/gov/types.ts +4 -71
  26. package/src/contracts/iasset/helpers.ts +172 -0
  27. package/src/contracts/iasset/scripts.ts +38 -0
  28. package/src/contracts/iasset/types.ts +154 -0
  29. package/src/contracts/initialize/actions.ts +768 -0
  30. package/src/contracts/initialize/helpers.ts +611 -36
  31. package/src/contracts/initialize/types.ts +102 -28
  32. package/src/contracts/interest-collection/helpers.ts +19 -0
  33. package/src/contracts/interest-collection/scripts.ts +44 -0
  34. package/src/contracts/interest-collection/transactions.ts +436 -0
  35. package/src/contracts/interest-collection/types-new.ts +50 -0
  36. package/src/contracts/interest-collection/types.ts +26 -0
  37. package/src/contracts/interest-oracle/helpers.ts +2 -30
  38. package/src/contracts/interest-oracle/scripts.ts +1 -1
  39. package/src/contracts/interest-oracle/transactions.ts +21 -16
  40. package/src/contracts/interest-oracle/types-new.ts +32 -0
  41. package/src/contracts/interest-oracle/types.ts +1 -40
  42. package/src/contracts/one-shot/transactions.ts +1 -2
  43. package/src/contracts/poll/helpers.ts +5 -23
  44. package/src/contracts/poll/scripts.ts +12 -13
  45. package/src/contracts/poll/types-poll-manager.ts +1 -19
  46. package/src/contracts/poll/types-poll-new.ts +170 -0
  47. package/src/contracts/poll/types-poll-shard.ts +2 -24
  48. package/src/contracts/price-oracle/helpers.ts +1 -4
  49. package/src/contracts/price-oracle/scripts.ts +3 -8
  50. package/src/contracts/price-oracle/transactions.ts +32 -25
  51. package/src/contracts/price-oracle/types-new.ts +50 -0
  52. package/src/contracts/price-oracle/types.ts +2 -36
  53. package/src/contracts/pyth-feed/helpers.ts +58 -0
  54. package/src/contracts/pyth-feed/scripts.ts +15 -0
  55. package/src/contracts/pyth-feed/types.ts +181 -0
  56. package/src/contracts/rob/helpers.ts +405 -0
  57. package/src/contracts/rob/scripts.ts +35 -0
  58. package/src/contracts/rob/transactions.ts +410 -0
  59. package/src/contracts/rob/types-new.ts +128 -0
  60. package/src/contracts/rob/types.ts +16 -0
  61. package/src/contracts/rob-leverage/helpers.ts +424 -0
  62. package/src/contracts/{leverage → rob-leverage}/transactions.ts +68 -48
  63. package/src/contracts/stability-pool/helpers.ts +714 -230
  64. package/src/contracts/stability-pool/scripts.ts +20 -15
  65. package/src/contracts/stability-pool/transactions.ts +625 -495
  66. package/src/contracts/stability-pool/types-new.ts +237 -100
  67. package/src/contracts/stability-pool/types.ts +5 -22
  68. package/src/contracts/stableswap/helpers.ts +22 -0
  69. package/src/contracts/stableswap/scripts.ts +37 -0
  70. package/src/contracts/stableswap/transactions.ts +647 -0
  71. package/src/contracts/stableswap/types-new.ts +131 -0
  72. package/src/contracts/stableswap/types.ts +17 -0
  73. package/src/contracts/staking/helpers.ts +49 -34
  74. package/src/contracts/staking/scripts.ts +1 -1
  75. package/src/contracts/staking/transactions.ts +85 -130
  76. package/src/contracts/staking/types-new.ts +60 -28
  77. package/src/contracts/staking/types.ts +1 -28
  78. package/src/contracts/treasury/helpers.ts +21 -0
  79. package/src/contracts/treasury/scripts.ts +16 -26
  80. package/src/contracts/treasury/transactions.ts +256 -27
  81. package/src/contracts/treasury/types-new.ts +69 -0
  82. package/src/contracts/treasury/types.ts +2 -43
  83. package/src/contracts/version-registry/scripts.ts +2 -2
  84. package/src/contracts/version-registry/types-new.ts +6 -7
  85. package/src/index.ts +37 -20
  86. package/src/scripts/auth-token-policy.ts +3 -2
  87. package/src/scripts/iasset-policy.ts +3 -2
  88. package/src/types/evolution-schema-options.ts +3 -3
  89. package/src/types/generic.ts +17 -89
  90. package/src/types/multisig.ts +48 -0
  91. package/src/types/on-chain-decimal.ts +14 -7
  92. package/src/types/rational.ts +61 -0
  93. package/src/types/system-params.ts +237 -41
  94. package/src/utils/array-utils.ts +70 -1
  95. package/src/utils/bigint-utils.ts +12 -0
  96. package/src/utils/indigo-helpers.ts +8 -10
  97. package/src/utils/lucid-utils.ts +47 -40
  98. package/src/utils/oracle-helpers.ts +62 -0
  99. package/src/utils/pyth/decode.ts +223 -0
  100. package/src/utils/pyth/encode.ts +262 -0
  101. package/src/utils/pyth/index.ts +14 -0
  102. package/src/utils/pyth/types.ts +87 -0
  103. package/src/validators/always-succeed-validator.ts +6 -0
  104. package/src/validators/cdp-creator-validator.ts +2 -2
  105. package/src/validators/cdp-redeem-validator.ts +7 -0
  106. package/src/validators/cdp-validator.ts +2 -2
  107. package/src/validators/collector-validator.ts +2 -2
  108. package/src/validators/execute-validator.ts +2 -2
  109. package/src/validators/governance-validator.ts +2 -2
  110. package/src/validators/iasset-validator.ts +7 -0
  111. package/src/validators/interest-collection-validator.ts +7 -0
  112. package/src/validators/interest-oracle-validator.ts +2 -2
  113. package/src/validators/poll-manager-validator.ts +2 -2
  114. package/src/validators/poll-shard-validator.ts +2 -2
  115. package/src/validators/price-oracle-validator.ts +7 -0
  116. package/src/validators/pyth-feed-validator.ts +7 -0
  117. package/src/validators/rob-validator.ts +7 -0
  118. package/src/validators/stability-pool-validator.ts +2 -2
  119. package/src/validators/stableswap-validator.ts +7 -0
  120. package/src/validators/staking-validator.ts +2 -2
  121. package/src/validators/treasury-validator.ts +2 -2
  122. package/src/validators/version-record-policy.ts +2 -2
  123. package/src/validators/version-registry-validator.ts +2 -2
  124. package/tests/always-succeed/script.ts +7 -0
  125. package/tests/bigint-utils.test.ts +41 -0
  126. package/tests/cdp/actions.ts +611 -0
  127. package/tests/cdp/cdp-helpers.ts +55 -0
  128. package/tests/cdp/cdp-queries.ts +440 -0
  129. package/tests/cdp/cdp.test.ts +6087 -0
  130. package/tests/cdp/transactions-mutated.ts +1729 -0
  131. package/tests/data/system-params.json +177 -34
  132. package/tests/datums.test.ts +209 -210
  133. package/tests/endpoints/initialize.ts +68 -0
  134. package/tests/endpoints/interest-collector.ts +37 -0
  135. package/tests/endpoints/treasury.ts +70 -0
  136. package/tests/gov/actions.ts +406 -0
  137. package/tests/gov/gov.test.ts +4450 -0
  138. package/tests/{queries → gov}/governance-queries.ts +6 -3
  139. package/tests/hash-checks.test.ts +38 -11
  140. package/tests/indigo-test-helpers.ts +100 -0
  141. package/tests/initialize.test.ts +61 -9
  142. package/tests/interest-collection/interest-collection.test.ts +892 -0
  143. package/tests/interest-collection/interest-collector-queries.ts +49 -0
  144. package/tests/interest-collection/transactions-mutated.ts +260 -0
  145. package/tests/interest-oracle.test.ts +43 -35
  146. package/tests/mock/assets-mock.ts +234 -23
  147. package/tests/mock/protocol-params-mock.ts +21 -0
  148. package/tests/price-oracle/actions.ts +163 -0
  149. package/tests/price-oracle/price-oracle-queries.ts +12 -0
  150. package/tests/price-oracle/price-oracle.test.ts +240 -0
  151. package/tests/price-oracle/transactions-mutated.ts +62 -0
  152. package/tests/pyth/endpoints.ts +96 -0
  153. package/tests/pyth/helpers.ts +37 -0
  154. package/tests/pyth/pyth-encoding.test.ts +376 -0
  155. package/tests/pyth/pyth-indigo.test.ts +509 -0
  156. package/tests/pyth/pyth.test.ts +300 -0
  157. package/tests/queries/execute-queries.ts +6 -5
  158. package/tests/queries/iasset-queries.ts +175 -5
  159. package/tests/queries/interest-oracle-queries.ts +4 -2
  160. package/tests/queries/poll-queries.ts +8 -9
  161. package/tests/queries/stability-pool-queries.ts +95 -48
  162. package/tests/queries/staking-queries.ts +4 -2
  163. package/tests/queries/treasury-queries.ts +80 -5
  164. package/tests/rob/actions.ts +58 -0
  165. package/tests/{lrp-leverage.test.ts → rob/rob-leverage.test.ts} +393 -296
  166. package/tests/rob/rob-queries.ts +95 -0
  167. package/tests/rob/rob.test.ts +3762 -0
  168. package/tests/rob/transactions-mutated.ts +853 -0
  169. package/tests/script-size.test.ts +240 -0
  170. package/tests/setup.ts +135 -0
  171. package/tests/stability-pool/actions.ts +210 -0
  172. package/tests/stability-pool.test.ts +5469 -666
  173. package/tests/stableswap/stableswap-actions.ts +84 -0
  174. package/tests/stableswap/stableswap-queries.ts +89 -0
  175. package/tests/stableswap/stableswap.test.ts +3891 -0
  176. package/tests/stableswap/transactions-mutated.ts +348 -0
  177. package/tests/staking.test.ts +82 -99
  178. package/tests/test-helpers.ts +58 -11
  179. package/tests/treasury.test.ts +242 -0
  180. package/tests/utils/asserts.ts +74 -0
  181. package/tests/utils/benchmark-utils.ts +81 -0
  182. package/tests/utils/index.ts +122 -4
  183. package/tsconfig.json +9 -1
  184. package/vitest.config.ts +3 -1
  185. package/src/contracts/collector/types.ts +0 -16
  186. package/src/contracts/initialize/transactions.ts +0 -891
  187. package/src/contracts/leverage/helpers.ts +0 -424
  188. package/src/contracts/lrp/helpers.ts +0 -294
  189. package/src/contracts/lrp/scripts.ts +0 -27
  190. package/src/contracts/lrp/transactions.ts +0 -250
  191. package/src/contracts/lrp/types.ts +0 -131
  192. package/src/contracts/poll/types-poll.ts +0 -88
  193. package/src/contracts/vesting/helpers.ts +0 -218
  194. package/src/utils/value-helpers.ts +0 -37
  195. package/src/validators/lrp-validator.ts +0 -7
  196. package/tests/cdp.test.ts +0 -1528
  197. package/tests/gov.test.ts +0 -2011
  198. package/tests/lrp.test.ts +0 -673
  199. package/tests/queries/cdp-queries.ts +0 -220
  200. package/tests/queries/lrp-queries.ts +0 -76
  201. package/tests/queries/price-oracle-queries.ts +0 -10
@@ -0,0 +1,3891 @@
1
+ import { assert, beforeEach, test } from 'vitest';
2
+ import {
3
+ IndigoTestContext,
4
+ repeat,
5
+ runAndAwaitTx,
6
+ runAndAwaitTxBuilder,
7
+ } from '../test-helpers';
8
+ import {
9
+ createIndigoTestContext,
10
+ EXAMPLE_TOKEN_1,
11
+ } from '../indigo-test-helpers';
12
+ import { benchmarkAndAwaitTx } from '../utils/benchmark-utils';
13
+ import {
14
+ batchProcessStableswapOrders,
15
+ cancelStableswapOrder,
16
+ createStableswapOrder,
17
+ updateStableswapPoolFees,
18
+ } from '../../src/contracts/stableswap/transactions';
19
+ import {
20
+ createScriptAddress,
21
+ fromSystemParamsAsset,
22
+ mkTreasuryAddr,
23
+ } from '../../src';
24
+ import {
25
+ addAssets,
26
+ Assets,
27
+ credentialToAddress,
28
+ fromHex,
29
+ fromText,
30
+ paymentCredentialOf,
31
+ UTxO,
32
+ } from '@lucid-evolution/lucid';
33
+ import {
34
+ findAllNecessaryOrefs,
35
+ findPriceOracleFromCollateralAsset,
36
+ findStableswapPool,
37
+ } from '../cdp/cdp-queries';
38
+ import {
39
+ findSingleStableswapOrder,
40
+ findStableswapOrders,
41
+ } from './stableswap-queries';
42
+ import { feedPriceOracleTx } from '../../src/contracts/price-oracle/transactions';
43
+ import {
44
+ addressFromBech32,
45
+ assetClassValueOf,
46
+ lovelacesAmt,
47
+ mkLovelacesOf,
48
+ negateAssets,
49
+ } from '@3rd-eye-labs/cardano-offchain-common';
50
+ import { runCreateStableswapPool } from './stableswap-actions';
51
+ import { getValueChangeAtAddressAfterAction } from '../utils';
52
+ import { array as A } from 'fp-ts';
53
+ import { runOpenCdp } from '../cdp/actions';
54
+ import { Data } from '@evolution-sdk/evolution';
55
+ import { serialiseStableswapOrderDatum } from '../../src/contracts/stableswap/types-new';
56
+ import { BASE_MAX_EXECUTION_FEE } from '../../src/contracts/stableswap/helpers';
57
+ import { StableswapPoolContent } from '../../src/contracts/cdp/types-new';
58
+ import { mutatedBatchProcessStableswapOrders } from './transactions-mutated';
59
+ import { expectScriptFailure } from '../utils/asserts';
60
+ import {
61
+ findRandomTreasuryUtxoWithOnlyAda,
62
+ findRandomTreasuryUtxoWithAsset,
63
+ } from '../queries/treasury-queries';
64
+ import { createUtxoAtTreasury } from '../endpoints/treasury';
65
+ import { rationalFromInt, rationalZero } from '../../src/types/rational';
66
+
67
+ beforeEach<IndigoTestContext>(async (context: IndigoTestContext) => {
68
+ await createIndigoTestContext(context);
69
+ });
70
+
71
+ test<IndigoTestContext>('Stableswap - Create Order', async (context: IndigoTestContext) => {
72
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
73
+
74
+ await runCreateStableswapPool(
75
+ context.assetConfigs[0].iassetTokenNameAscii,
76
+ EXAMPLE_TOKEN_1,
77
+ context,
78
+ );
79
+
80
+ const stableswapPool = await findStableswapPool(
81
+ context.lucid,
82
+ context.systemParams.validatorHashes.cdpHash,
83
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
84
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
85
+ EXAMPLE_TOKEN_1,
86
+ );
87
+
88
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
89
+
90
+ await benchmarkAndAwaitTx(
91
+ 'Stableswap - Create Order',
92
+ await createStableswapOrder(
93
+ context.assetConfigs[0].iassetTokenNameAscii,
94
+ EXAMPLE_TOKEN_1,
95
+ 10_000_000n,
96
+ true,
97
+ stableswapPool.datum,
98
+ context.systemParams,
99
+ context.lucid,
100
+ ),
101
+ context.lucid,
102
+ context.emulator,
103
+ );
104
+ });
105
+
106
+ test<IndigoTestContext>('Stableswap - Cancel Order', async (context: IndigoTestContext) => {
107
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
108
+
109
+ await runCreateStableswapPool(
110
+ context.assetConfigs[0].iassetTokenNameAscii,
111
+ EXAMPLE_TOKEN_1,
112
+ context,
113
+ );
114
+
115
+ const stableswapPool = await findStableswapPool(
116
+ context.lucid,
117
+ context.systemParams.validatorHashes.cdpHash,
118
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
119
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
120
+ EXAMPLE_TOKEN_1,
121
+ );
122
+
123
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
124
+
125
+ await runAndAwaitTx(
126
+ context.lucid,
127
+ createStableswapOrder(
128
+ context.assetConfigs[0].iassetTokenNameAscii,
129
+ EXAMPLE_TOKEN_1,
130
+ 10_000_000n,
131
+ true,
132
+ stableswapPool.datum,
133
+ context.systemParams,
134
+ context.lucid,
135
+ ),
136
+ );
137
+
138
+ const stableswapOrder = await findSingleStableswapOrder(
139
+ context.lucid,
140
+ context.systemParams.validatorHashes.stableswapHash,
141
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
142
+ EXAMPLE_TOKEN_1,
143
+ );
144
+
145
+ await benchmarkAndAwaitTx(
146
+ 'Stableswap - Cancel Order',
147
+ await cancelStableswapOrder(
148
+ stableswapOrder.utxo,
149
+ context.systemParams,
150
+ context.lucid,
151
+ ),
152
+ context.lucid,
153
+ context.emulator,
154
+ );
155
+ });
156
+
157
+ test<IndigoTestContext>('Stableswap - Batch a single order to mint', async (context: IndigoTestContext) => {
158
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
159
+
160
+ await runCreateStableswapPool(
161
+ context.assetConfigs[0].iassetTokenNameAscii,
162
+ EXAMPLE_TOKEN_1,
163
+ context,
164
+ );
165
+
166
+ let stableswapPool = await findStableswapPool(
167
+ context.lucid,
168
+ context.systemParams.validatorHashes.cdpHash,
169
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
170
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
171
+ EXAMPLE_TOKEN_1,
172
+ );
173
+
174
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
175
+
176
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
177
+ addAssets(acc, utxo.assets),
178
+ )(await context.lucid.utxosAt(context.users.user.address));
179
+
180
+ await runAndAwaitTx(
181
+ context.lucid,
182
+ createStableswapOrder(
183
+ context.assetConfigs[0].iassetTokenNameAscii,
184
+ EXAMPLE_TOKEN_1,
185
+ 10_000_000n,
186
+ true,
187
+ stableswapPool.datum,
188
+ context.systemParams,
189
+ context.lucid,
190
+ ),
191
+ );
192
+
193
+ const stableswapOrder = await findSingleStableswapOrder(
194
+ context.lucid,
195
+ context.systemParams.validatorHashes.stableswapHash,
196
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
197
+ EXAMPLE_TOKEN_1,
198
+ );
199
+
200
+ await createUtxoAtTreasury(
201
+ mkLovelacesOf(2_000_000n),
202
+ context.systemParams,
203
+ context,
204
+ );
205
+
206
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
207
+ context.lucid,
208
+ context.systemParams,
209
+ );
210
+
211
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
212
+ context.lucid,
213
+ mkTreasuryAddr(context.lucid, context.systemParams),
214
+ async () =>
215
+ benchmarkAndAwaitTx(
216
+ 'Stableswap - Batch a single order to mint',
217
+ await batchProcessStableswapOrders(
218
+ [stableswapOrder.utxo],
219
+ stableswapPool.utxo,
220
+ treasuryUtxo,
221
+ context.systemParams,
222
+ context.lucid,
223
+ ),
224
+ context.lucid,
225
+ context.emulator,
226
+ ),
227
+ );
228
+
229
+ ///////////////////////////////////
230
+ // Checks after last transaction //
231
+ ///////////////////////////////////
232
+
233
+ stableswapPool = await findStableswapPool(
234
+ context.lucid,
235
+ context.systemParams.validatorHashes.cdpHash,
236
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
237
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
238
+ EXAMPLE_TOKEN_1,
239
+ );
240
+
241
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
242
+ addAssets(acc, utxo.assets),
243
+ )(await context.lucid.utxosAt(context.users.user.address));
244
+
245
+ const userValueDiff = addAssets(
246
+ finalUserValue,
247
+ negateAssets(initialUserValue),
248
+ );
249
+
250
+ const iassetAc = {
251
+ currencySymbol: fromHex(
252
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
253
+ ),
254
+ tokenName: stableswapOrder.datum.iasset,
255
+ };
256
+
257
+ assert(
258
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_000n,
259
+ 'Unexpected iAsset value received by the treasury',
260
+ );
261
+
262
+ assert(
263
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
264
+ 10_000_000n,
265
+ 'Unexpected value held by stableswap pool',
266
+ );
267
+
268
+ assert(
269
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 50_000n,
270
+ 'Unexpected value received by order owner',
271
+ );
272
+ });
273
+
274
+ test<IndigoTestContext>('Stableswap - Batch a single order to mint with no minting fee', async (context: IndigoTestContext) => {
275
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
276
+
277
+ await runCreateStableswapPool(
278
+ context.assetConfigs[0].iassetTokenNameAscii,
279
+ EXAMPLE_TOKEN_1,
280
+ context,
281
+ rationalFromInt(1n),
282
+ // 0% minting fee.
283
+ rationalZero,
284
+ );
285
+
286
+ let stableswapPool = await findStableswapPool(
287
+ context.lucid,
288
+ context.systemParams.validatorHashes.cdpHash,
289
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
290
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
291
+ EXAMPLE_TOKEN_1,
292
+ );
293
+
294
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
295
+
296
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
297
+ addAssets(acc, utxo.assets),
298
+ )(await context.lucid.utxosAt(context.users.user.address));
299
+
300
+ await runAndAwaitTx(
301
+ context.lucid,
302
+ createStableswapOrder(
303
+ context.assetConfigs[0].iassetTokenNameAscii,
304
+ EXAMPLE_TOKEN_1,
305
+ 10_000_000n,
306
+ true,
307
+ stableswapPool.datum,
308
+ context.systemParams,
309
+ context.lucid,
310
+ ),
311
+ );
312
+
313
+ const stableswapOrder = await findSingleStableswapOrder(
314
+ context.lucid,
315
+ context.systemParams.validatorHashes.stableswapHash,
316
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
317
+ EXAMPLE_TOKEN_1,
318
+ );
319
+
320
+ await createUtxoAtTreasury(
321
+ mkLovelacesOf(2_000_000n),
322
+ context.systemParams,
323
+ context,
324
+ );
325
+
326
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
327
+ context.lucid,
328
+ context.systemParams,
329
+ );
330
+
331
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
332
+ context.lucid,
333
+ mkTreasuryAddr(context.lucid, context.systemParams),
334
+ async () =>
335
+ await runAndAwaitTx(
336
+ context.lucid,
337
+ batchProcessStableswapOrders(
338
+ [stableswapOrder.utxo],
339
+ stableswapPool.utxo,
340
+ treasuryUtxo,
341
+ context.systemParams,
342
+ context.lucid,
343
+ ),
344
+ ),
345
+ );
346
+
347
+ ///////////////////////////////////
348
+ // Checks after last transaction //
349
+ ///////////////////////////////////
350
+
351
+ stableswapPool = await findStableswapPool(
352
+ context.lucid,
353
+ context.systemParams.validatorHashes.cdpHash,
354
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
355
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
356
+ EXAMPLE_TOKEN_1,
357
+ );
358
+
359
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
360
+ addAssets(acc, utxo.assets),
361
+ )(await context.lucid.utxosAt(context.users.user.address));
362
+
363
+ const userValueDiff = addAssets(
364
+ finalUserValue,
365
+ negateAssets(initialUserValue),
366
+ );
367
+
368
+ const iassetAc = {
369
+ currencySymbol: fromHex(
370
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
371
+ ),
372
+ tokenName: stableswapOrder.datum.iasset,
373
+ };
374
+
375
+ assert(
376
+ assetClassValueOf(treasuryValChange, iassetAc) == 0n,
377
+ 'Unexpected iAsset value received by the treasury',
378
+ );
379
+
380
+ assert(
381
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
382
+ 10_000_000n,
383
+ 'Unexpected value held by stableswap pool',
384
+ );
385
+
386
+ assert(
387
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n,
388
+ 'Unexpected value received by order owner',
389
+ );
390
+ });
391
+
392
+ test<IndigoTestContext>('Stableswap - Batch a single order to redeem', async (context: IndigoTestContext) => {
393
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
394
+
395
+ await runCreateStableswapPool(
396
+ context.assetConfigs[0].iassetTokenNameAscii,
397
+ EXAMPLE_TOKEN_1,
398
+ context,
399
+ );
400
+
401
+ let stableswapPool = await findStableswapPool(
402
+ context.lucid,
403
+ context.systemParams.validatorHashes.cdpHash,
404
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
405
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
406
+ EXAMPLE_TOKEN_1,
407
+ );
408
+
409
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
410
+
411
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
412
+ addAssets(acc, utxo.assets),
413
+ )(await context.lucid.utxosAt(context.users.user.address));
414
+
415
+ // Mint iAsset to supply the pool with collateral asset.
416
+ // It also provides the treasury with a UTxO with iAsset.
417
+ await runAndAwaitTx(
418
+ context.lucid,
419
+ createStableswapOrder(
420
+ context.assetConfigs[0].iassetTokenNameAscii,
421
+ EXAMPLE_TOKEN_1,
422
+ 10_000_000n,
423
+ true,
424
+ stableswapPool.datum,
425
+ context.systemParams,
426
+ context.lucid,
427
+ ),
428
+ );
429
+
430
+ let stableswapOrder = await findSingleStableswapOrder(
431
+ context.lucid,
432
+ context.systemParams.validatorHashes.stableswapHash,
433
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
434
+ EXAMPLE_TOKEN_1,
435
+ );
436
+
437
+ await createUtxoAtTreasury(
438
+ mkLovelacesOf(2_000_000n),
439
+ context.systemParams,
440
+ context,
441
+ );
442
+
443
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
444
+ context.lucid,
445
+ context.systemParams,
446
+ );
447
+
448
+ await runAndAwaitTx(
449
+ context.lucid,
450
+ batchProcessStableswapOrders(
451
+ [stableswapOrder.utxo],
452
+ stableswapPool.utxo,
453
+ treasuryUtxo,
454
+ context.systemParams,
455
+ context.lucid,
456
+ ),
457
+ );
458
+
459
+ // Redeem part of the collateral asset previously supplied to the pool.
460
+ await runAndAwaitTx(
461
+ context.lucid,
462
+ createStableswapOrder(
463
+ context.assetConfigs[0].iassetTokenNameAscii,
464
+ EXAMPLE_TOKEN_1,
465
+ 5_000_000n,
466
+ false,
467
+ stableswapPool.datum,
468
+ context.systemParams,
469
+ context.lucid,
470
+ ),
471
+ );
472
+
473
+ stableswapOrder = await findSingleStableswapOrder(
474
+ context.lucid,
475
+ context.systemParams.validatorHashes.stableswapHash,
476
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
477
+ EXAMPLE_TOKEN_1,
478
+ );
479
+
480
+ stableswapPool = await findStableswapPool(
481
+ context.lucid,
482
+ context.systemParams.validatorHashes.cdpHash,
483
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
484
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
485
+ EXAMPLE_TOKEN_1,
486
+ );
487
+
488
+ const iassetAc = {
489
+ currencySymbol: fromHex(
490
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
491
+ ),
492
+ tokenName: stableswapOrder.datum.iasset,
493
+ };
494
+
495
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
496
+ context.lucid,
497
+ context.systemParams,
498
+ iassetAc,
499
+ );
500
+
501
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
502
+ context.lucid,
503
+ mkTreasuryAddr(context.lucid, context.systemParams),
504
+ async () =>
505
+ benchmarkAndAwaitTx(
506
+ 'Stableswap - Batch a single order to redeem',
507
+ await batchProcessStableswapOrders(
508
+ [stableswapOrder.utxo],
509
+ stableswapPool.utxo,
510
+ treasuryUtxo,
511
+ context.systemParams,
512
+ context.lucid,
513
+ ),
514
+ context.lucid,
515
+ context.emulator,
516
+ ),
517
+ );
518
+
519
+ ///////////////////////////////////
520
+ // Checks after last transaction //
521
+ ///////////////////////////////////
522
+
523
+ stableswapPool = await findStableswapPool(
524
+ context.lucid,
525
+ context.systemParams.validatorHashes.cdpHash,
526
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
527
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
528
+ EXAMPLE_TOKEN_1,
529
+ );
530
+
531
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
532
+ addAssets(acc, utxo.assets),
533
+ )(await context.lucid.utxosAt(context.users.user.address));
534
+
535
+ const userValueDiff = addAssets(
536
+ finalUserValue,
537
+ negateAssets(initialUserValue),
538
+ );
539
+
540
+ assert(
541
+ assetClassValueOf(treasuryValChange, iassetAc) == 25_000n &&
542
+ 0n <= lovelacesAmt(treasuryValChange) &&
543
+ lovelacesAmt(treasuryValChange) <= 9_000n,
544
+ 'Unexpected value received by the treasury',
545
+ );
546
+
547
+ assert(
548
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
549
+ 10_000_000n - (5_000_000n - 25_000n),
550
+ 'Unexpected value held by stableswap pool',
551
+ );
552
+
553
+ assert(
554
+ assetClassValueOf(userValueDiff, iassetAc) ==
555
+ 10_000_000n - 50_000n - 5_000_000n &&
556
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
557
+ -10_000_000n + (5_000_000n - 25_000n),
558
+ 'Unexpected value received by order owner',
559
+ );
560
+ });
561
+
562
+ test<IndigoTestContext>('Stableswap - Batch a single order to redeem with no redemption fee', async (context: IndigoTestContext) => {
563
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
564
+
565
+ await runCreateStableswapPool(
566
+ context.assetConfigs[0].iassetTokenNameAscii,
567
+ EXAMPLE_TOKEN_1,
568
+ context,
569
+ rationalFromInt(1n),
570
+ // 0% minting fee.
571
+ rationalZero,
572
+ // 0% redemption fee.
573
+ rationalZero,
574
+ );
575
+
576
+ let stableswapPool = await findStableswapPool(
577
+ context.lucid,
578
+ context.systemParams.validatorHashes.cdpHash,
579
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
580
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
581
+ EXAMPLE_TOKEN_1,
582
+ );
583
+
584
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
585
+
586
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
587
+ addAssets(acc, utxo.assets),
588
+ )(await context.lucid.utxosAt(context.users.user.address));
589
+
590
+ // Mint iAsset to supply the pool with collateral asset.
591
+ await runAndAwaitTx(
592
+ context.lucid,
593
+ createStableswapOrder(
594
+ context.assetConfigs[0].iassetTokenNameAscii,
595
+ EXAMPLE_TOKEN_1,
596
+ 10_000_000n,
597
+ true,
598
+ stableswapPool.datum,
599
+ context.systemParams,
600
+ context.lucid,
601
+ ),
602
+ );
603
+
604
+ let stableswapOrder = await findSingleStableswapOrder(
605
+ context.lucid,
606
+ context.systemParams.validatorHashes.stableswapHash,
607
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
608
+ EXAMPLE_TOKEN_1,
609
+ );
610
+
611
+ await createUtxoAtTreasury(
612
+ mkLovelacesOf(2_000_000n),
613
+ context.systemParams,
614
+ context,
615
+ );
616
+
617
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
618
+ context.lucid,
619
+ context.systemParams,
620
+ );
621
+
622
+ await runAndAwaitTx(
623
+ context.lucid,
624
+ batchProcessStableswapOrders(
625
+ [stableswapOrder.utxo],
626
+ stableswapPool.utxo,
627
+ treasuryUtxo,
628
+ context.systemParams,
629
+ context.lucid,
630
+ ),
631
+ );
632
+
633
+ // Redeem part of the collateral asset previously supplied to the pool.
634
+ await runAndAwaitTx(
635
+ context.lucid,
636
+ createStableswapOrder(
637
+ context.assetConfigs[0].iassetTokenNameAscii,
638
+ EXAMPLE_TOKEN_1,
639
+ 5_000_000n,
640
+ false,
641
+ stableswapPool.datum,
642
+ context.systemParams,
643
+ context.lucid,
644
+ ),
645
+ );
646
+
647
+ stableswapOrder = await findSingleStableswapOrder(
648
+ context.lucid,
649
+ context.systemParams.validatorHashes.stableswapHash,
650
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
651
+ EXAMPLE_TOKEN_1,
652
+ );
653
+
654
+ stableswapPool = await findStableswapPool(
655
+ context.lucid,
656
+ context.systemParams.validatorHashes.cdpHash,
657
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
658
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
659
+ EXAMPLE_TOKEN_1,
660
+ );
661
+
662
+ const iassetAc = {
663
+ currencySymbol: fromHex(
664
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
665
+ ),
666
+ tokenName: stableswapOrder.datum.iasset,
667
+ };
668
+
669
+ // This will not be used in the transaction, but is passed only as a placeholder.
670
+ treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
671
+ context.lucid,
672
+ context.systemParams,
673
+ );
674
+
675
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
676
+ context.lucid,
677
+ mkTreasuryAddr(context.lucid, context.systemParams),
678
+ async () =>
679
+ runAndAwaitTx(
680
+ context.lucid,
681
+ batchProcessStableswapOrders(
682
+ [stableswapOrder.utxo],
683
+ stableswapPool.utxo,
684
+ treasuryUtxo,
685
+ context.systemParams,
686
+ context.lucid,
687
+ ),
688
+ ),
689
+ );
690
+
691
+ ///////////////////////////////////
692
+ // Checks after last transaction //
693
+ ///////////////////////////////////
694
+
695
+ stableswapPool = await findStableswapPool(
696
+ context.lucid,
697
+ context.systemParams.validatorHashes.cdpHash,
698
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
699
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
700
+ EXAMPLE_TOKEN_1,
701
+ );
702
+
703
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
704
+ addAssets(acc, utxo.assets),
705
+ )(await context.lucid.utxosAt(context.users.user.address));
706
+
707
+ const userValueDiff = addAssets(
708
+ finalUserValue,
709
+ negateAssets(initialUserValue),
710
+ );
711
+
712
+ assert(
713
+ assetClassValueOf(treasuryValChange, iassetAc) == 0n,
714
+ 'Unexpected value received by the treasury',
715
+ );
716
+
717
+ assert(
718
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
719
+ 10_000_000n - 5_000_000n,
720
+ 'Unexpected value held by stableswap pool',
721
+ );
722
+
723
+ assert(
724
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 5_000_000n &&
725
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
726
+ -10_000_000n + 5_000_000n,
727
+ 'Unexpected value received by order owner',
728
+ );
729
+ });
730
+
731
+ test<IndigoTestContext>('Stableswap - Batch a single order to redeem emptying the pool', async (context: IndigoTestContext) => {
732
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
733
+
734
+ await runCreateStableswapPool(
735
+ context.assetConfigs[0].iassetTokenNameAscii,
736
+ EXAMPLE_TOKEN_1,
737
+ context,
738
+ );
739
+
740
+ let stableswapPool = await findStableswapPool(
741
+ context.lucid,
742
+ context.systemParams.validatorHashes.cdpHash,
743
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
744
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
745
+ EXAMPLE_TOKEN_1,
746
+ );
747
+
748
+ const orefs = await findAllNecessaryOrefs(
749
+ context.lucid,
750
+ context.systemParams,
751
+ context.assetConfigs[0].iassetTokenNameAscii,
752
+ context.assetConfigs[0].collateralAssets[0].collateralAsset,
753
+ );
754
+ const priceOracleUtxo = await findPriceOracleFromCollateralAsset(
755
+ context.lucid,
756
+ orefs.collateralAsset,
757
+ );
758
+
759
+ await runAndAwaitTx(
760
+ context.lucid,
761
+ feedPriceOracleTx(
762
+ context.lucid,
763
+ priceOracleUtxo!,
764
+ rationalFromInt(1n),
765
+ context.assetConfigs[0].collateralAssets[0].oracleParams!,
766
+ context.emulator.slot,
767
+ ),
768
+ );
769
+
770
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
771
+
772
+ // Mint extra iAsset to have enough to empty the pool.
773
+ await runAndAwaitTx(
774
+ context.lucid,
775
+ runOpenCdp(
776
+ context,
777
+ context.systemParams,
778
+ context.assetConfigs[0].iassetTokenNameAscii,
779
+ context.assetConfigs[0].collateralAssets[0].collateralAsset,
780
+ 10_000_000n,
781
+ 5_000_000n,
782
+ ),
783
+ );
784
+
785
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
786
+ addAssets(acc, utxo.assets),
787
+ )(await context.lucid.utxosAt(context.users.user.address));
788
+
789
+ // Mint iAsset to supply the pool with collateral asset
790
+ // It also provides the treasury with a UTxO with iAsset.
791
+ await runAndAwaitTx(
792
+ context.lucid,
793
+ createStableswapOrder(
794
+ context.assetConfigs[0].iassetTokenNameAscii,
795
+ EXAMPLE_TOKEN_1,
796
+ 10_000_000n,
797
+ true,
798
+ stableswapPool.datum,
799
+ context.systemParams,
800
+ context.lucid,
801
+ ),
802
+ );
803
+
804
+ let stableswapOrder = await findSingleStableswapOrder(
805
+ context.lucid,
806
+ context.systemParams.validatorHashes.stableswapHash,
807
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
808
+ EXAMPLE_TOKEN_1,
809
+ );
810
+
811
+ await createUtxoAtTreasury(
812
+ mkLovelacesOf(2_000_000n),
813
+ context.systemParams,
814
+ context,
815
+ );
816
+
817
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
818
+ context.lucid,
819
+ context.systemParams,
820
+ );
821
+
822
+ await runAndAwaitTx(
823
+ context.lucid,
824
+ batchProcessStableswapOrders(
825
+ [stableswapOrder.utxo],
826
+ stableswapPool.utxo,
827
+ treasuryUtxo,
828
+ context.systemParams,
829
+ context.lucid,
830
+ ),
831
+ );
832
+
833
+ // Redeem all the assets left in the pool.
834
+ await runAndAwaitTx(
835
+ context.lucid,
836
+ createStableswapOrder(
837
+ context.assetConfigs[0].iassetTokenNameAscii,
838
+ EXAMPLE_TOKEN_1,
839
+ // After taking a 0.5% fee, the effective amount is 10_000_000.
840
+ 10_050_251n,
841
+ false,
842
+ stableswapPool.datum,
843
+ context.systemParams,
844
+ context.lucid,
845
+ ),
846
+ );
847
+
848
+ stableswapOrder = await findSingleStableswapOrder(
849
+ context.lucid,
850
+ context.systemParams.validatorHashes.stableswapHash,
851
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
852
+ EXAMPLE_TOKEN_1,
853
+ );
854
+
855
+ stableswapPool = await findStableswapPool(
856
+ context.lucid,
857
+ context.systemParams.validatorHashes.cdpHash,
858
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
859
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
860
+ EXAMPLE_TOKEN_1,
861
+ );
862
+
863
+ const iassetAc = {
864
+ currencySymbol: fromHex(
865
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
866
+ ),
867
+ tokenName: stableswapOrder.datum.iasset,
868
+ };
869
+
870
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
871
+ context.lucid,
872
+ context.systemParams,
873
+ iassetAc,
874
+ );
875
+
876
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
877
+ context.lucid,
878
+ mkTreasuryAddr(context.lucid, context.systemParams),
879
+ async () =>
880
+ runAndAwaitTx(
881
+ context.lucid,
882
+ batchProcessStableswapOrders(
883
+ [stableswapOrder.utxo],
884
+ stableswapPool.utxo,
885
+ treasuryUtxo,
886
+ context.systemParams,
887
+ context.lucid,
888
+ ),
889
+ ),
890
+ );
891
+
892
+ ///////////////////////////////////
893
+ // Checks after last transaction //
894
+ ///////////////////////////////////
895
+
896
+ stableswapPool = await findStableswapPool(
897
+ context.lucid,
898
+ context.systemParams.validatorHashes.cdpHash,
899
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
900
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
901
+ EXAMPLE_TOKEN_1,
902
+ );
903
+
904
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
905
+ addAssets(acc, utxo.assets),
906
+ )(await context.lucid.utxosAt(context.users.user.address));
907
+
908
+ const userValueDiff = addAssets(
909
+ finalUserValue,
910
+ negateAssets(initialUserValue),
911
+ );
912
+
913
+ assert(
914
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_251n &&
915
+ 0n <= lovelacesAmt(treasuryValChange) &&
916
+ lovelacesAmt(treasuryValChange) <= 9_000n,
917
+ 'Unexpected value received by the treasury',
918
+ );
919
+
920
+ assert(
921
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 0n,
922
+ 'Unexpected value held by stableswap pool',
923
+ );
924
+
925
+ assert(
926
+ assetClassValueOf(userValueDiff, iassetAc) ==
927
+ 10_000_000n - 50_000n - 10_050_251n &&
928
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
929
+ -10_000_000n + 10_000_000n,
930
+ 'Unexpected value received by order owner',
931
+ );
932
+ });
933
+
934
+ test<IndigoTestContext>('Stableswap - Batch a single order to mint assets with smaller scale', async (context: IndigoTestContext) => {
935
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
936
+
937
+ await runCreateStableswapPool(
938
+ context.assetConfigs[0].iassetTokenNameAscii,
939
+ EXAMPLE_TOKEN_1,
940
+ context,
941
+ rationalFromInt(1_000n),
942
+ );
943
+
944
+ let stableswapPool = await findStableswapPool(
945
+ context.lucid,
946
+ context.systemParams.validatorHashes.cdpHash,
947
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
948
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
949
+ EXAMPLE_TOKEN_1,
950
+ );
951
+
952
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
953
+
954
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
955
+ addAssets(acc, utxo.assets),
956
+ )(await context.lucid.utxosAt(context.users.user.address));
957
+
958
+ await runAndAwaitTx(
959
+ context.lucid,
960
+ createStableswapOrder(
961
+ context.assetConfigs[0].iassetTokenNameAscii,
962
+ EXAMPLE_TOKEN_1,
963
+ 10_000_000n,
964
+ true,
965
+ stableswapPool.datum,
966
+ context.systemParams,
967
+ context.lucid,
968
+ ),
969
+ );
970
+
971
+ const stableswapOrder = await findSingleStableswapOrder(
972
+ context.lucid,
973
+ context.systemParams.validatorHashes.stableswapHash,
974
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
975
+ EXAMPLE_TOKEN_1,
976
+ );
977
+
978
+ await createUtxoAtTreasury(
979
+ mkLovelacesOf(2_000_000n),
980
+ context.systemParams,
981
+ context,
982
+ );
983
+
984
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
985
+ context.lucid,
986
+ context.systemParams,
987
+ );
988
+
989
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
990
+ context.lucid,
991
+ mkTreasuryAddr(context.lucid, context.systemParams),
992
+ async () =>
993
+ runAndAwaitTx(
994
+ context.lucid,
995
+ batchProcessStableswapOrders(
996
+ [stableswapOrder.utxo],
997
+ stableswapPool.utxo,
998
+ treasuryUtxo,
999
+ context.systemParams,
1000
+ context.lucid,
1001
+ ),
1002
+ ),
1003
+ );
1004
+
1005
+ ///////////////////////////////////
1006
+ // Checks after last transaction //
1007
+ ///////////////////////////////////
1008
+
1009
+ stableswapPool = await findStableswapPool(
1010
+ context.lucid,
1011
+ context.systemParams.validatorHashes.cdpHash,
1012
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1013
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1014
+ EXAMPLE_TOKEN_1,
1015
+ );
1016
+
1017
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1018
+ addAssets(acc, utxo.assets),
1019
+ )(await context.lucid.utxosAt(context.users.user.address));
1020
+
1021
+ const userValueDiff = addAssets(
1022
+ finalUserValue,
1023
+ negateAssets(initialUserValue),
1024
+ );
1025
+
1026
+ const iassetAc = {
1027
+ currencySymbol: fromHex(
1028
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
1029
+ ),
1030
+ tokenName: stableswapOrder.datum.iasset,
1031
+ };
1032
+
1033
+ assert(
1034
+ assetClassValueOf(treasuryValChange, iassetAc) == 50n,
1035
+ 'Unexpected iAsset value received by the treasury',
1036
+ );
1037
+
1038
+ assert(
1039
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
1040
+ 10_000_000n,
1041
+ 'Unexpected value held by stableswap pool',
1042
+ );
1043
+
1044
+ assert(
1045
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000n - 50n,
1046
+ 'Unexpected value received by order owner',
1047
+ );
1048
+ });
1049
+
1050
+ test<IndigoTestContext>('Stableswap - Batch a single order to mint assets with bigger scale', async (context: IndigoTestContext) => {
1051
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1052
+
1053
+ await runCreateStableswapPool(
1054
+ context.assetConfigs[0].iassetTokenNameAscii,
1055
+ EXAMPLE_TOKEN_1,
1056
+ context,
1057
+ { numerator: 1n, denominator: 1_000n },
1058
+ );
1059
+
1060
+ let stableswapPool = await findStableswapPool(
1061
+ context.lucid,
1062
+ context.systemParams.validatorHashes.cdpHash,
1063
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1064
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1065
+ EXAMPLE_TOKEN_1,
1066
+ );
1067
+
1068
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1069
+
1070
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1071
+ addAssets(acc, utxo.assets),
1072
+ )(await context.lucid.utxosAt(context.users.user.address));
1073
+
1074
+ await runAndAwaitTx(
1075
+ context.lucid,
1076
+ createStableswapOrder(
1077
+ context.assetConfigs[0].iassetTokenNameAscii,
1078
+ EXAMPLE_TOKEN_1,
1079
+ 10_000_000n,
1080
+ true,
1081
+ stableswapPool.datum,
1082
+ context.systemParams,
1083
+ context.lucid,
1084
+ ),
1085
+ );
1086
+
1087
+ const stableswapOrder = await findSingleStableswapOrder(
1088
+ context.lucid,
1089
+ context.systemParams.validatorHashes.stableswapHash,
1090
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1091
+ EXAMPLE_TOKEN_1,
1092
+ );
1093
+
1094
+ await createUtxoAtTreasury(
1095
+ mkLovelacesOf(2_000_000n),
1096
+ context.systemParams,
1097
+ context,
1098
+ );
1099
+
1100
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
1101
+ context.lucid,
1102
+ context.systemParams,
1103
+ );
1104
+
1105
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
1106
+ context.lucid,
1107
+ mkTreasuryAddr(context.lucid, context.systemParams),
1108
+ async () =>
1109
+ runAndAwaitTx(
1110
+ context.lucid,
1111
+ batchProcessStableswapOrders(
1112
+ [stableswapOrder.utxo],
1113
+ stableswapPool.utxo,
1114
+ treasuryUtxo,
1115
+ context.systemParams,
1116
+ context.lucid,
1117
+ ),
1118
+ ),
1119
+ );
1120
+
1121
+ ///////////////////////////////////
1122
+ // Checks after last transaction //
1123
+ ///////////////////////////////////
1124
+
1125
+ stableswapPool = await findStableswapPool(
1126
+ context.lucid,
1127
+ context.systemParams.validatorHashes.cdpHash,
1128
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1129
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1130
+ EXAMPLE_TOKEN_1,
1131
+ );
1132
+
1133
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1134
+ addAssets(acc, utxo.assets),
1135
+ )(await context.lucid.utxosAt(context.users.user.address));
1136
+
1137
+ const userValueDiff = addAssets(
1138
+ finalUserValue,
1139
+ negateAssets(initialUserValue),
1140
+ );
1141
+
1142
+ const iassetAc = {
1143
+ currencySymbol: fromHex(
1144
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
1145
+ ),
1146
+ tokenName: stableswapOrder.datum.iasset,
1147
+ };
1148
+
1149
+ assert(
1150
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_000_000n,
1151
+ 'Unexpected iAsset value received by the treasury',
1152
+ );
1153
+
1154
+ assert(
1155
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
1156
+ 10_000_000n,
1157
+ 'Unexpected value held by stableswap pool',
1158
+ );
1159
+
1160
+ assert(
1161
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000_000_000n - 50_000_000n,
1162
+ 'Unexpected value received by order owner',
1163
+ );
1164
+ });
1165
+
1166
+ test<IndigoTestContext>('Stableswap - Batch a single order to redeem assets with smaller scale', async (context: IndigoTestContext) => {
1167
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1168
+
1169
+ await runCreateStableswapPool(
1170
+ context.assetConfigs[0].iassetTokenNameAscii,
1171
+ EXAMPLE_TOKEN_1,
1172
+ context,
1173
+ rationalFromInt(1_000n),
1174
+ );
1175
+
1176
+ let stableswapPool = await findStableswapPool(
1177
+ context.lucid,
1178
+ context.systemParams.validatorHashes.cdpHash,
1179
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1180
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1181
+ EXAMPLE_TOKEN_1,
1182
+ );
1183
+
1184
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1185
+
1186
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1187
+ addAssets(acc, utxo.assets),
1188
+ )(await context.lucid.utxosAt(context.users.user.address));
1189
+
1190
+ // Mint iAsset to supply the pool with collateral asset.
1191
+ // It also provides the treasury with a UTxO with iAsset.
1192
+ await runAndAwaitTx(
1193
+ context.lucid,
1194
+ createStableswapOrder(
1195
+ context.assetConfigs[0].iassetTokenNameAscii,
1196
+ EXAMPLE_TOKEN_1,
1197
+ 10_000_000n,
1198
+ true,
1199
+ stableswapPool.datum,
1200
+ context.systemParams,
1201
+ context.lucid,
1202
+ ),
1203
+ );
1204
+
1205
+ let stableswapOrder = await findSingleStableswapOrder(
1206
+ context.lucid,
1207
+ context.systemParams.validatorHashes.stableswapHash,
1208
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1209
+ EXAMPLE_TOKEN_1,
1210
+ );
1211
+
1212
+ await createUtxoAtTreasury(
1213
+ mkLovelacesOf(2_000_000n),
1214
+ context.systemParams,
1215
+ context,
1216
+ );
1217
+
1218
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
1219
+ context.lucid,
1220
+ context.systemParams,
1221
+ );
1222
+
1223
+ await runAndAwaitTx(
1224
+ context.lucid,
1225
+ batchProcessStableswapOrders(
1226
+ [stableswapOrder.utxo],
1227
+ stableswapPool.utxo,
1228
+ treasuryUtxo,
1229
+ context.systemParams,
1230
+ context.lucid,
1231
+ ),
1232
+ );
1233
+
1234
+ // Redeem part of the collateral asset previously supplied to the pool.
1235
+ await runAndAwaitTx(
1236
+ context.lucid,
1237
+ createStableswapOrder(
1238
+ context.assetConfigs[0].iassetTokenNameAscii,
1239
+ EXAMPLE_TOKEN_1,
1240
+ 5_000n,
1241
+ false,
1242
+ stableswapPool.datum,
1243
+ context.systemParams,
1244
+ context.lucid,
1245
+ ),
1246
+ );
1247
+
1248
+ stableswapOrder = await findSingleStableswapOrder(
1249
+ context.lucid,
1250
+ context.systemParams.validatorHashes.stableswapHash,
1251
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1252
+ EXAMPLE_TOKEN_1,
1253
+ );
1254
+
1255
+ stableswapPool = await findStableswapPool(
1256
+ context.lucid,
1257
+ context.systemParams.validatorHashes.cdpHash,
1258
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1259
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1260
+ EXAMPLE_TOKEN_1,
1261
+ );
1262
+
1263
+ const iassetAc = {
1264
+ currencySymbol: fromHex(
1265
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
1266
+ ),
1267
+ tokenName: stableswapOrder.datum.iasset,
1268
+ };
1269
+
1270
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
1271
+ context.lucid,
1272
+ context.systemParams,
1273
+ iassetAc,
1274
+ );
1275
+
1276
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
1277
+ context.lucid,
1278
+ mkTreasuryAddr(context.lucid, context.systemParams),
1279
+ async () =>
1280
+ runAndAwaitTx(
1281
+ context.lucid,
1282
+ batchProcessStableswapOrders(
1283
+ [stableswapOrder.utxo],
1284
+ stableswapPool.utxo,
1285
+ treasuryUtxo,
1286
+ context.systemParams,
1287
+ context.lucid,
1288
+ ),
1289
+ ),
1290
+ );
1291
+
1292
+ ///////////////////////////////////
1293
+ // Checks after last transaction //
1294
+ ///////////////////////////////////
1295
+
1296
+ stableswapPool = await findStableswapPool(
1297
+ context.lucid,
1298
+ context.systemParams.validatorHashes.cdpHash,
1299
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1300
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1301
+ EXAMPLE_TOKEN_1,
1302
+ );
1303
+
1304
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1305
+ addAssets(acc, utxo.assets),
1306
+ )(await context.lucid.utxosAt(context.users.user.address));
1307
+
1308
+ const userValueDiff = addAssets(
1309
+ finalUserValue,
1310
+ negateAssets(initialUserValue),
1311
+ );
1312
+
1313
+ assert(
1314
+ assetClassValueOf(treasuryValChange, iassetAc) == 25n &&
1315
+ 0n <= lovelacesAmt(treasuryValChange) &&
1316
+ lovelacesAmt(treasuryValChange) <= 9_000n,
1317
+ 'Unexpected value received by the treasury',
1318
+ );
1319
+
1320
+ assert(
1321
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
1322
+ 10_000_000n - (5_000_000n - 25_000n),
1323
+ 'Unexpected value held by stableswap pool',
1324
+ );
1325
+
1326
+ assert(
1327
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000n - 50n - 5_000n &&
1328
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
1329
+ -10_000_000n + (5_000_000n - 25_000n),
1330
+ 'Unexpected value received by order owner',
1331
+ );
1332
+ });
1333
+
1334
+ test<IndigoTestContext>('Stableswap - Batch a single order to redeem assets with bigger scale', async (context: IndigoTestContext) => {
1335
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1336
+
1337
+ await runCreateStableswapPool(
1338
+ context.assetConfigs[0].iassetTokenNameAscii,
1339
+ EXAMPLE_TOKEN_1,
1340
+ context,
1341
+ { numerator: 1n, denominator: 1_000n },
1342
+ );
1343
+
1344
+ let stableswapPool = await findStableswapPool(
1345
+ context.lucid,
1346
+ context.systemParams.validatorHashes.cdpHash,
1347
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1348
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1349
+ EXAMPLE_TOKEN_1,
1350
+ );
1351
+
1352
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1353
+
1354
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1355
+ addAssets(acc, utxo.assets),
1356
+ )(await context.lucid.utxosAt(context.users.user.address));
1357
+
1358
+ // Mint iAsset to supply the pool with collateral asset.
1359
+ // It also provides the treasury with a UTxO with iAsset.
1360
+ await runAndAwaitTx(
1361
+ context.lucid,
1362
+ createStableswapOrder(
1363
+ context.assetConfigs[0].iassetTokenNameAscii,
1364
+ EXAMPLE_TOKEN_1,
1365
+ 10_000_000n,
1366
+ true,
1367
+ stableswapPool.datum,
1368
+ context.systemParams,
1369
+ context.lucid,
1370
+ ),
1371
+ );
1372
+
1373
+ let stableswapOrder = await findSingleStableswapOrder(
1374
+ context.lucid,
1375
+ context.systemParams.validatorHashes.stableswapHash,
1376
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1377
+ EXAMPLE_TOKEN_1,
1378
+ );
1379
+
1380
+ await createUtxoAtTreasury(
1381
+ mkLovelacesOf(2_000_000n),
1382
+ context.systemParams,
1383
+ context,
1384
+ );
1385
+
1386
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
1387
+ context.lucid,
1388
+ context.systemParams,
1389
+ );
1390
+
1391
+ await runAndAwaitTx(
1392
+ context.lucid,
1393
+ batchProcessStableswapOrders(
1394
+ [stableswapOrder.utxo],
1395
+ stableswapPool.utxo,
1396
+ treasuryUtxo,
1397
+ context.systemParams,
1398
+ context.lucid,
1399
+ ),
1400
+ );
1401
+
1402
+ // Redeem part of the collateral asset previously supplied to the pool.
1403
+ await runAndAwaitTx(
1404
+ context.lucid,
1405
+ createStableswapOrder(
1406
+ context.assetConfigs[0].iassetTokenNameAscii,
1407
+ EXAMPLE_TOKEN_1,
1408
+ 5_000_000_000n,
1409
+ false,
1410
+ stableswapPool.datum,
1411
+ context.systemParams,
1412
+ context.lucid,
1413
+ ),
1414
+ );
1415
+
1416
+ stableswapOrder = await findSingleStableswapOrder(
1417
+ context.lucid,
1418
+ context.systemParams.validatorHashes.stableswapHash,
1419
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1420
+ EXAMPLE_TOKEN_1,
1421
+ );
1422
+
1423
+ stableswapPool = await findStableswapPool(
1424
+ context.lucid,
1425
+ context.systemParams.validatorHashes.cdpHash,
1426
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1427
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1428
+ EXAMPLE_TOKEN_1,
1429
+ );
1430
+
1431
+ const iassetAc = {
1432
+ currencySymbol: fromHex(
1433
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
1434
+ ),
1435
+ tokenName: stableswapOrder.datum.iasset,
1436
+ };
1437
+
1438
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
1439
+ context.lucid,
1440
+ context.systemParams,
1441
+ iassetAc,
1442
+ );
1443
+
1444
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
1445
+ context.lucid,
1446
+ mkTreasuryAddr(context.lucid, context.systemParams),
1447
+ async () =>
1448
+ runAndAwaitTx(
1449
+ context.lucid,
1450
+ batchProcessStableswapOrders(
1451
+ [stableswapOrder.utxo],
1452
+ stableswapPool.utxo,
1453
+ treasuryUtxo,
1454
+ context.systemParams,
1455
+ context.lucid,
1456
+ ),
1457
+ ),
1458
+ );
1459
+
1460
+ ///////////////////////////////////
1461
+ // Checks after last transaction //
1462
+ ///////////////////////////////////
1463
+
1464
+ stableswapPool = await findStableswapPool(
1465
+ context.lucid,
1466
+ context.systemParams.validatorHashes.cdpHash,
1467
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1468
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1469
+ EXAMPLE_TOKEN_1,
1470
+ );
1471
+
1472
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1473
+ addAssets(acc, utxo.assets),
1474
+ )(await context.lucid.utxosAt(context.users.user.address));
1475
+
1476
+ const userValueDiff = addAssets(
1477
+ finalUserValue,
1478
+ negateAssets(initialUserValue),
1479
+ );
1480
+
1481
+ assert(
1482
+ assetClassValueOf(treasuryValChange, iassetAc) == 25_000_000n &&
1483
+ 0n <= lovelacesAmt(treasuryValChange) &&
1484
+ lovelacesAmt(treasuryValChange) <= 9_000n,
1485
+ 'Unexpected value received by the treasury',
1486
+ );
1487
+
1488
+ assert(
1489
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
1490
+ 10_000_000n - (5_000_000n - 25_000n),
1491
+ 'Unexpected value held by stableswap pool',
1492
+ );
1493
+
1494
+ assert(
1495
+ assetClassValueOf(userValueDiff, iassetAc) ==
1496
+ 10_000_000_000n - 50_000_000n - 5_000_000_000n &&
1497
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
1498
+ -10_000_000n + (5_000_000n - 25_000n),
1499
+ 'Unexpected value received by order owner',
1500
+ );
1501
+ });
1502
+
1503
+ test<IndigoTestContext>('Stableswap - Batch multiple orders to mint from same owner, 11', async (context: IndigoTestContext) => {
1504
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1505
+
1506
+ await runCreateStableswapPool(
1507
+ context.assetConfigs[0].iassetTokenNameAscii,
1508
+ EXAMPLE_TOKEN_1,
1509
+ context,
1510
+ );
1511
+
1512
+ let stableswapPool = await findStableswapPool(
1513
+ context.lucid,
1514
+ context.systemParams.validatorHashes.cdpHash,
1515
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1516
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1517
+ EXAMPLE_TOKEN_1,
1518
+ );
1519
+
1520
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1521
+
1522
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1523
+ addAssets(acc, utxo.assets),
1524
+ )(await context.lucid.utxosAt(context.users.user.address));
1525
+
1526
+ const numberOfOrders = 11;
1527
+
1528
+ await repeat(numberOfOrders, async () => {
1529
+ await runAndAwaitTx(
1530
+ context.lucid,
1531
+ createStableswapOrder(
1532
+ context.assetConfigs[0].iassetTokenNameAscii,
1533
+ EXAMPLE_TOKEN_1,
1534
+ 10_000_000n,
1535
+ true,
1536
+ stableswapPool.datum,
1537
+ context.systemParams,
1538
+ context.lucid,
1539
+ ),
1540
+ );
1541
+ });
1542
+
1543
+ const stableswapOrders = await findStableswapOrders(
1544
+ context.lucid,
1545
+ context.systemParams.validatorHashes.stableswapHash,
1546
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1547
+ EXAMPLE_TOKEN_1,
1548
+ );
1549
+
1550
+ await createUtxoAtTreasury(
1551
+ mkLovelacesOf(2_000_000n),
1552
+ context.systemParams,
1553
+ context,
1554
+ );
1555
+
1556
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
1557
+ context.lucid,
1558
+ context.systemParams,
1559
+ );
1560
+
1561
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
1562
+ context.lucid,
1563
+ mkTreasuryAddr(context.lucid, context.systemParams),
1564
+ async () =>
1565
+ benchmarkAndAwaitTx(
1566
+ 'Stableswap - Batch multiple orders to mint from same owner, 11',
1567
+ await batchProcessStableswapOrders(
1568
+ stableswapOrders.map((order) => order.utxo),
1569
+ stableswapPool.utxo,
1570
+ treasuryUtxo,
1571
+ context.systemParams,
1572
+ context.lucid,
1573
+ ),
1574
+ context.lucid,
1575
+ context.emulator,
1576
+ ),
1577
+ );
1578
+
1579
+ ///////////////////////////////////
1580
+ // Checks after last transaction //
1581
+ ///////////////////////////////////
1582
+
1583
+ stableswapPool = await findStableswapPool(
1584
+ context.lucid,
1585
+ context.systemParams.validatorHashes.cdpHash,
1586
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1587
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1588
+ EXAMPLE_TOKEN_1,
1589
+ );
1590
+
1591
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1592
+ addAssets(acc, utxo.assets),
1593
+ )(await context.lucid.utxosAt(context.users.user.address));
1594
+
1595
+ const userValueDiff = addAssets(
1596
+ finalUserValue,
1597
+ negateAssets(initialUserValue),
1598
+ );
1599
+
1600
+ const iassetAc = {
1601
+ currencySymbol: fromHex(
1602
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
1603
+ ),
1604
+ tokenName: stableswapOrders[0].datum.iasset,
1605
+ };
1606
+
1607
+ assert(
1608
+ assetClassValueOf(treasuryValChange, iassetAc) ==
1609
+ BigInt(numberOfOrders) * 50_000n,
1610
+ 'Unexpected iAsset value received by the treasury',
1611
+ );
1612
+
1613
+ assert(
1614
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
1615
+ BigInt(numberOfOrders) * 10_000_000n,
1616
+ 'Unexpected value held by stableswap pool',
1617
+ );
1618
+
1619
+ assert(
1620
+ assetClassValueOf(userValueDiff, iassetAc) ==
1621
+ BigInt(numberOfOrders) * (10_000_000n - 50_000n),
1622
+ 'Unexpected value received by order owner',
1623
+ );
1624
+ });
1625
+
1626
+ test<IndigoTestContext>('Stableswap - Batch multiple orders to redeem from same owner, 9', async (context: IndigoTestContext) => {
1627
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1628
+
1629
+ await runCreateStableswapPool(
1630
+ context.assetConfigs[0].iassetTokenNameAscii,
1631
+ EXAMPLE_TOKEN_1,
1632
+ context,
1633
+ );
1634
+
1635
+ let stableswapPool = await findStableswapPool(
1636
+ context.lucid,
1637
+ context.systemParams.validatorHashes.cdpHash,
1638
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1639
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1640
+ EXAMPLE_TOKEN_1,
1641
+ );
1642
+
1643
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1644
+
1645
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1646
+ addAssets(acc, utxo.assets),
1647
+ )(await context.lucid.utxosAt(context.users.user.address));
1648
+
1649
+ const numberOfOrders = 9;
1650
+
1651
+ // Mint iAsset to supply the pool with collateral asset.
1652
+ // It also provides the treasury with a UTxO with iAsset.
1653
+ await runAndAwaitTx(
1654
+ context.lucid,
1655
+ createStableswapOrder(
1656
+ context.assetConfigs[0].iassetTokenNameAscii,
1657
+ EXAMPLE_TOKEN_1,
1658
+ BigInt(numberOfOrders) * 10_000_000n,
1659
+ true,
1660
+ stableswapPool.datum,
1661
+ context.systemParams,
1662
+ context.lucid,
1663
+ ),
1664
+ );
1665
+
1666
+ let stableswapOrders = await findStableswapOrders(
1667
+ context.lucid,
1668
+ context.systemParams.validatorHashes.stableswapHash,
1669
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1670
+ EXAMPLE_TOKEN_1,
1671
+ );
1672
+
1673
+ await createUtxoAtTreasury(
1674
+ mkLovelacesOf(2_000_000n),
1675
+ context.systemParams,
1676
+ context,
1677
+ );
1678
+
1679
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
1680
+ context.lucid,
1681
+ context.systemParams,
1682
+ );
1683
+
1684
+ await runAndAwaitTx(
1685
+ context.lucid,
1686
+ batchProcessStableswapOrders(
1687
+ stableswapOrders.map((order) => order.utxo),
1688
+ stableswapPool.utxo,
1689
+ treasuryUtxo,
1690
+ context.systemParams,
1691
+ context.lucid,
1692
+ ),
1693
+ );
1694
+
1695
+ // Redeem part of the collateral asset previously supplied to the pool.
1696
+ await repeat(numberOfOrders, async () => {
1697
+ await runAndAwaitTx(
1698
+ context.lucid,
1699
+ createStableswapOrder(
1700
+ context.assetConfigs[0].iassetTokenNameAscii,
1701
+ EXAMPLE_TOKEN_1,
1702
+ 5_000_000n,
1703
+ false,
1704
+ stableswapPool.datum,
1705
+ context.systemParams,
1706
+ context.lucid,
1707
+ ),
1708
+ );
1709
+ });
1710
+
1711
+ stableswapOrders = await findStableswapOrders(
1712
+ context.lucid,
1713
+ context.systemParams.validatorHashes.stableswapHash,
1714
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1715
+ EXAMPLE_TOKEN_1,
1716
+ );
1717
+
1718
+ stableswapPool = await findStableswapPool(
1719
+ context.lucid,
1720
+ context.systemParams.validatorHashes.cdpHash,
1721
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1722
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1723
+ EXAMPLE_TOKEN_1,
1724
+ );
1725
+
1726
+ const iassetAc = {
1727
+ currencySymbol: fromHex(
1728
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
1729
+ ),
1730
+ tokenName: stableswapOrders[0].datum.iasset,
1731
+ };
1732
+
1733
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
1734
+ context.lucid,
1735
+ context.systemParams,
1736
+ iassetAc,
1737
+ );
1738
+
1739
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
1740
+ context.lucid,
1741
+ mkTreasuryAddr(context.lucid, context.systemParams),
1742
+ async () =>
1743
+ benchmarkAndAwaitTx(
1744
+ 'Stableswap - Batch multiple orders to redeem from same owner, 9',
1745
+ await batchProcessStableswapOrders(
1746
+ stableswapOrders.map((order) => order.utxo),
1747
+ stableswapPool.utxo,
1748
+ treasuryUtxo,
1749
+ context.systemParams,
1750
+ context.lucid,
1751
+ ),
1752
+ context.lucid,
1753
+ context.emulator,
1754
+ ),
1755
+ );
1756
+
1757
+ ///////////////////////////////////
1758
+ // Checks after last transaction //
1759
+ ///////////////////////////////////
1760
+
1761
+ stableswapPool = await findStableswapPool(
1762
+ context.lucid,
1763
+ context.systemParams.validatorHashes.cdpHash,
1764
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1765
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1766
+ EXAMPLE_TOKEN_1,
1767
+ );
1768
+
1769
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1770
+ addAssets(acc, utxo.assets),
1771
+ )(await context.lucid.utxosAt(context.users.user.address));
1772
+
1773
+ const userValueDiff = addAssets(
1774
+ finalUserValue,
1775
+ negateAssets(initialUserValue),
1776
+ );
1777
+
1778
+ assert(
1779
+ assetClassValueOf(treasuryValChange, iassetAc) ==
1780
+ BigInt(numberOfOrders) * 25_000n &&
1781
+ 0n <= lovelacesAmt(treasuryValChange) &&
1782
+ lovelacesAmt(treasuryValChange) <= 9_000n,
1783
+ 'Unexpected value received by the treasury',
1784
+ );
1785
+
1786
+ assert(
1787
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
1788
+ BigInt(numberOfOrders) * (10_000_000n - (5_000_000n - 25_000n)),
1789
+ 'Unexpected value held by stableswap pool',
1790
+ );
1791
+
1792
+ assert(
1793
+ assetClassValueOf(userValueDiff, iassetAc) ==
1794
+ BigInt(numberOfOrders) * (10_000_000n - 50_000n - 5_000_000n) &&
1795
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
1796
+ BigInt(numberOfOrders) * (-10_000_000n + (5_000_000n - 25_000n)),
1797
+ 'Unexpected value received by order owner',
1798
+ );
1799
+ });
1800
+
1801
+ test<IndigoTestContext>('Stableswap - Batch multiple orders to mint from different owners', async (context: IndigoTestContext) => {
1802
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1803
+
1804
+ await runCreateStableswapPool(
1805
+ context.assetConfigs[0].iassetTokenNameAscii,
1806
+ EXAMPLE_TOKEN_1,
1807
+ context,
1808
+ );
1809
+
1810
+ let stableswapPool = await findStableswapPool(
1811
+ context.lucid,
1812
+ context.systemParams.validatorHashes.cdpHash,
1813
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1814
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1815
+ EXAMPLE_TOKEN_1,
1816
+ );
1817
+
1818
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1819
+ addAssets(acc, utxo.assets),
1820
+ )(await context.lucid.utxosAt(context.users.admin.address));
1821
+
1822
+ await runAndAwaitTx(
1823
+ context.lucid,
1824
+ createStableswapOrder(
1825
+ context.assetConfigs[0].iassetTokenNameAscii,
1826
+ EXAMPLE_TOKEN_1,
1827
+ 10_000_000n,
1828
+ true,
1829
+ stableswapPool.datum,
1830
+ context.systemParams,
1831
+ context.lucid,
1832
+ ),
1833
+ );
1834
+
1835
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1836
+
1837
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1838
+ addAssets(acc, utxo.assets),
1839
+ )(await context.lucid.utxosAt(context.users.user.address));
1840
+
1841
+ await runAndAwaitTx(
1842
+ context.lucid,
1843
+ createStableswapOrder(
1844
+ context.assetConfigs[0].iassetTokenNameAscii,
1845
+ EXAMPLE_TOKEN_1,
1846
+ 5_000_000n,
1847
+ true,
1848
+ stableswapPool.datum,
1849
+ context.systemParams,
1850
+ context.lucid,
1851
+ ),
1852
+ );
1853
+
1854
+ const stableswapOrders = await findStableswapOrders(
1855
+ context.lucid,
1856
+ context.systemParams.validatorHashes.stableswapHash,
1857
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1858
+ EXAMPLE_TOKEN_1,
1859
+ );
1860
+
1861
+ await createUtxoAtTreasury(
1862
+ mkLovelacesOf(2_000_000n),
1863
+ context.systemParams,
1864
+ context,
1865
+ );
1866
+
1867
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
1868
+ context.lucid,
1869
+ context.systemParams,
1870
+ );
1871
+
1872
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
1873
+ context.lucid,
1874
+ mkTreasuryAddr(context.lucid, context.systemParams),
1875
+ async () =>
1876
+ runAndAwaitTx(
1877
+ context.lucid,
1878
+ batchProcessStableswapOrders(
1879
+ stableswapOrders.map((order) => order.utxo),
1880
+ stableswapPool.utxo,
1881
+ treasuryUtxo,
1882
+ context.systemParams,
1883
+ context.lucid,
1884
+ ),
1885
+ ),
1886
+ );
1887
+
1888
+ ///////////////////////////////////
1889
+ // Checks after last transaction //
1890
+ ///////////////////////////////////
1891
+
1892
+ stableswapPool = await findStableswapPool(
1893
+ context.lucid,
1894
+ context.systemParams.validatorHashes.cdpHash,
1895
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1896
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1897
+ EXAMPLE_TOKEN_1,
1898
+ );
1899
+
1900
+ const iassetAc = {
1901
+ currencySymbol: fromHex(
1902
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
1903
+ ),
1904
+ tokenName: stableswapOrders[0].datum.iasset,
1905
+ };
1906
+
1907
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1908
+ addAssets(acc, utxo.assets),
1909
+ )(await context.lucid.utxosAt(context.users.admin.address));
1910
+
1911
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1912
+ addAssets(acc, utxo.assets),
1913
+ )(await context.lucid.utxosAt(context.users.user.address));
1914
+
1915
+ const adminValueDiff = addAssets(
1916
+ finalAdminValue,
1917
+ negateAssets(initialAdminValue),
1918
+ );
1919
+
1920
+ const userValueDiff = addAssets(
1921
+ finalUserValue,
1922
+ negateAssets(initialUserValue),
1923
+ );
1924
+
1925
+ assert(
1926
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_000n + 25_000n,
1927
+ 'Unexpected iAsset value received by the treasury',
1928
+ );
1929
+
1930
+ assert(
1931
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
1932
+ 10_000_000n + 5_000_000n,
1933
+ 'Unexpected value held by stableswap pool',
1934
+ );
1935
+
1936
+ assert(
1937
+ assetClassValueOf(adminValueDiff, iassetAc) == 10_000_000n - 50_000n &&
1938
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n,
1939
+ 'Unexpected value received by order #1 owner',
1940
+ );
1941
+
1942
+ assert(
1943
+ assetClassValueOf(userValueDiff, iassetAc) == 5_000_000n - 25_000n &&
1944
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -5_000_000n,
1945
+ 'Unexpected value received by order #2 owner',
1946
+ );
1947
+ });
1948
+
1949
+ test<IndigoTestContext>('Stableswap - Batch multiple orders to mint with rounded amounts', async (context: IndigoTestContext) => {
1950
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1951
+
1952
+ await runCreateStableswapPool(
1953
+ context.assetConfigs[0].iassetTokenNameAscii,
1954
+ EXAMPLE_TOKEN_1,
1955
+ context,
1956
+ // 0.999991 relative price
1957
+ { numerator: 1_000_000n, denominator: 1_000_009n },
1958
+ //15% fee
1959
+ { numerator: 15n, denominator: 100n },
1960
+ );
1961
+
1962
+ let stableswapPool = await findStableswapPool(
1963
+ context.lucid,
1964
+ context.systemParams.validatorHashes.cdpHash,
1965
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
1966
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1967
+ EXAMPLE_TOKEN_1,
1968
+ );
1969
+
1970
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1971
+
1972
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
1973
+ addAssets(acc, utxo.assets),
1974
+ )(await context.lucid.utxosAt(context.users.user.address));
1975
+
1976
+ const numberOfOrders = 10;
1977
+
1978
+ await repeat(numberOfOrders, async () => {
1979
+ await runAndAwaitTx(
1980
+ context.lucid,
1981
+ createStableswapOrder(
1982
+ context.assetConfigs[0].iassetTokenNameAscii,
1983
+ EXAMPLE_TOKEN_1,
1984
+ // The eq. iAsset amount is 100,000.9, rounded to 100,000.
1985
+ 100_000n,
1986
+ true,
1987
+ stableswapPool.datum,
1988
+ context.systemParams,
1989
+ context.lucid,
1990
+ ),
1991
+ );
1992
+ });
1993
+
1994
+ const stableswapOrders = await findStableswapOrders(
1995
+ context.lucid,
1996
+ context.systemParams.validatorHashes.stableswapHash,
1997
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
1998
+ EXAMPLE_TOKEN_1,
1999
+ );
2000
+
2001
+ await createUtxoAtTreasury(
2002
+ mkLovelacesOf(2_000_000n),
2003
+ context.systemParams,
2004
+ context,
2005
+ );
2006
+
2007
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
2008
+ context.lucid,
2009
+ context.systemParams,
2010
+ );
2011
+
2012
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2013
+
2014
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2015
+ addAssets(acc, utxo.assets),
2016
+ )(await context.lucid.utxosAt(context.users.admin.address));
2017
+
2018
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
2019
+ context.lucid,
2020
+ mkTreasuryAddr(context.lucid, context.systemParams),
2021
+ async () =>
2022
+ runAndAwaitTx(
2023
+ context.lucid,
2024
+ batchProcessStableswapOrders(
2025
+ stableswapOrders.map((order) => order.utxo),
2026
+ stableswapPool.utxo,
2027
+ treasuryUtxo,
2028
+ context.systemParams,
2029
+ context.lucid,
2030
+ ),
2031
+ ),
2032
+ );
2033
+
2034
+ ///////////////////////////////////
2035
+ // Checks after last transaction //
2036
+ ///////////////////////////////////
2037
+
2038
+ stableswapPool = await findStableswapPool(
2039
+ context.lucid,
2040
+ context.systemParams.validatorHashes.cdpHash,
2041
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2042
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2043
+ EXAMPLE_TOKEN_1,
2044
+ );
2045
+
2046
+ const iassetAc = {
2047
+ currencySymbol: fromHex(
2048
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
2049
+ ),
2050
+ tokenName: stableswapOrders[0].datum.iasset,
2051
+ };
2052
+
2053
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2054
+ addAssets(acc, utxo.assets),
2055
+ )(await context.lucid.utxosAt(context.users.admin.address));
2056
+
2057
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2058
+ addAssets(acc, utxo.assets),
2059
+ )(await context.lucid.utxosAt(context.users.user.address));
2060
+
2061
+ const adminValueDiff = addAssets(
2062
+ finalAdminValue,
2063
+ negateAssets(initialAdminValue),
2064
+ );
2065
+
2066
+ const userValueDiff = addAssets(
2067
+ finalUserValue,
2068
+ negateAssets(initialUserValue),
2069
+ );
2070
+
2071
+ assert(
2072
+ assetClassValueOf(treasuryValChange, iassetAc) ==
2073
+ BigInt(numberOfOrders) * 15_000n,
2074
+ 'Unexpected iAsset value received by the treasury',
2075
+ );
2076
+
2077
+ assert(
2078
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
2079
+ BigInt(numberOfOrders) * 100_000n,
2080
+ 'Unexpected value held by stableswap pool',
2081
+ );
2082
+
2083
+ assert(
2084
+ assetClassValueOf(userValueDiff, iassetAc) ==
2085
+ BigInt(numberOfOrders) * (100_000n - 15_000n) &&
2086
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
2087
+ BigInt(numberOfOrders) * -100_000n,
2088
+ 'Unexpected value received by orders owner',
2089
+ );
2090
+
2091
+ assert(
2092
+ assetClassValueOf(adminValueDiff, iassetAc) == 0n &&
2093
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) == 0n,
2094
+ 'Unexpected value received by the admin',
2095
+ );
2096
+ });
2097
+
2098
+ test<IndigoTestContext>('Stableswap - Batch orders to mint with insignificant value', async (context: IndigoTestContext) => {
2099
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2100
+
2101
+ await runCreateStableswapPool(
2102
+ context.assetConfigs[0].iassetTokenNameAscii,
2103
+ EXAMPLE_TOKEN_1,
2104
+ context,
2105
+ // The collateral asset has one more decimal place than the iAsset.
2106
+ rationalFromInt(10n),
2107
+ );
2108
+
2109
+ let stableswapPool = await findStableswapPool(
2110
+ context.lucid,
2111
+ context.systemParams.validatorHashes.cdpHash,
2112
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2113
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2114
+ EXAMPLE_TOKEN_1,
2115
+ );
2116
+
2117
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2118
+
2119
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2120
+ addAssets(acc, utxo.assets),
2121
+ )(await context.lucid.utxosAt(context.users.user.address));
2122
+
2123
+ await runAndAwaitTx(
2124
+ context.lucid,
2125
+ createStableswapOrder(
2126
+ context.assetConfigs[0].iassetTokenNameAscii,
2127
+ EXAMPLE_TOKEN_1,
2128
+ // 1.0000001 of collateral asset, equivalent to 1 iAsset.
2129
+ 10_000_001n,
2130
+ true,
2131
+ stableswapPool.datum,
2132
+ context.systemParams,
2133
+ context.lucid,
2134
+ ),
2135
+ );
2136
+
2137
+ const stableswapOrders = await findStableswapOrders(
2138
+ context.lucid,
2139
+ context.systemParams.validatorHashes.stableswapHash,
2140
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2141
+ EXAMPLE_TOKEN_1,
2142
+ );
2143
+
2144
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2145
+
2146
+ await createUtxoAtTreasury(
2147
+ mkLovelacesOf(2_000_000n),
2148
+ context.systemParams,
2149
+ context,
2150
+ );
2151
+
2152
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
2153
+ context.lucid,
2154
+ context.systemParams,
2155
+ );
2156
+
2157
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2158
+ addAssets(acc, utxo.assets),
2159
+ )(await context.lucid.utxosAt(context.users.admin.address));
2160
+
2161
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
2162
+ context.lucid,
2163
+ mkTreasuryAddr(context.lucid, context.systemParams),
2164
+ async () =>
2165
+ runAndAwaitTx(
2166
+ context.lucid,
2167
+ batchProcessStableswapOrders(
2168
+ stableswapOrders.map((order) => order.utxo),
2169
+ stableswapPool.utxo,
2170
+ treasuryUtxo,
2171
+ context.systemParams,
2172
+ context.lucid,
2173
+ ),
2174
+ ),
2175
+ );
2176
+
2177
+ ///////////////////////////////////
2178
+ // Checks after last transaction //
2179
+ ///////////////////////////////////
2180
+
2181
+ stableswapPool = await findStableswapPool(
2182
+ context.lucid,
2183
+ context.systemParams.validatorHashes.cdpHash,
2184
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2185
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2186
+ EXAMPLE_TOKEN_1,
2187
+ );
2188
+
2189
+ const iassetAc = {
2190
+ currencySymbol: fromHex(
2191
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
2192
+ ),
2193
+ tokenName: stableswapOrders[0].datum.iasset,
2194
+ };
2195
+
2196
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2197
+ addAssets(acc, utxo.assets),
2198
+ )(await context.lucid.utxosAt(context.users.admin.address));
2199
+
2200
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2201
+ addAssets(acc, utxo.assets),
2202
+ )(await context.lucid.utxosAt(context.users.user.address));
2203
+
2204
+ const adminValueDiff = addAssets(
2205
+ finalAdminValue,
2206
+ negateAssets(initialAdminValue),
2207
+ );
2208
+
2209
+ const userValueDiff = addAssets(
2210
+ finalUserValue,
2211
+ negateAssets(initialUserValue),
2212
+ );
2213
+
2214
+ assert(
2215
+ assetClassValueOf(treasuryValChange, iassetAc) == 5_000n,
2216
+ 'Unexpected iAsset value received by the treasury',
2217
+ );
2218
+
2219
+ assert(
2220
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
2221
+ 10_000_000n,
2222
+ 'Unexpected value held by stableswap pool',
2223
+ );
2224
+
2225
+ assert(
2226
+ assetClassValueOf(userValueDiff, iassetAc) == 1_000_000n - 5_000n &&
2227
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_001n,
2228
+ 'Unexpected value received by orders owner',
2229
+ );
2230
+
2231
+ assert(
2232
+ assetClassValueOf(adminValueDiff, iassetAc) == 0n &&
2233
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) == 1n,
2234
+ 'Unexpected value received by the admin',
2235
+ );
2236
+ });
2237
+
2238
+ test<IndigoTestContext>('Stableswap - Batch multiple orders to redeem from different owners', async (context: IndigoTestContext) => {
2239
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2240
+
2241
+ await runCreateStableswapPool(
2242
+ context.assetConfigs[0].iassetTokenNameAscii,
2243
+ EXAMPLE_TOKEN_1,
2244
+ context,
2245
+ );
2246
+
2247
+ let stableswapPool = await findStableswapPool(
2248
+ context.lucid,
2249
+ context.systemParams.validatorHashes.cdpHash,
2250
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2251
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2252
+ EXAMPLE_TOKEN_1,
2253
+ );
2254
+
2255
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2256
+ addAssets(acc, utxo.assets),
2257
+ )(await context.lucid.utxosAt(context.users.admin.address));
2258
+
2259
+ // Mint iAsset to supply the pool with collateral asset.
2260
+ // It also provides the treasury with a UTxO with iAsset.
2261
+ await runAndAwaitTx(
2262
+ context.lucid,
2263
+ createStableswapOrder(
2264
+ context.assetConfigs[0].iassetTokenNameAscii,
2265
+ EXAMPLE_TOKEN_1,
2266
+ 10_000_000n,
2267
+ true,
2268
+ stableswapPool.datum,
2269
+ context.systemParams,
2270
+ context.lucid,
2271
+ ),
2272
+ );
2273
+
2274
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2275
+
2276
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2277
+ addAssets(acc, utxo.assets),
2278
+ )(await context.lucid.utxosAt(context.users.user.address));
2279
+
2280
+ // Mint iAsset to supply the pool with collateral asset.
2281
+ await runAndAwaitTx(
2282
+ context.lucid,
2283
+ createStableswapOrder(
2284
+ context.assetConfigs[0].iassetTokenNameAscii,
2285
+ EXAMPLE_TOKEN_1,
2286
+ 10_000_000n,
2287
+ true,
2288
+ stableswapPool.datum,
2289
+ context.systemParams,
2290
+ context.lucid,
2291
+ ),
2292
+ );
2293
+
2294
+ let stableswapOrders = await findStableswapOrders(
2295
+ context.lucid,
2296
+ context.systemParams.validatorHashes.stableswapHash,
2297
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2298
+ EXAMPLE_TOKEN_1,
2299
+ );
2300
+
2301
+ await createUtxoAtTreasury(
2302
+ mkLovelacesOf(2_000_000n),
2303
+ context.systemParams,
2304
+ context,
2305
+ );
2306
+
2307
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
2308
+ context.lucid,
2309
+ context.systemParams,
2310
+ );
2311
+
2312
+ await runAndAwaitTx(
2313
+ context.lucid,
2314
+ batchProcessStableswapOrders(
2315
+ stableswapOrders.map((order) => order.utxo),
2316
+ stableswapPool.utxo,
2317
+ treasuryUtxo,
2318
+ context.systemParams,
2319
+ context.lucid,
2320
+ ),
2321
+ );
2322
+
2323
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2324
+
2325
+ // Redeem part of the collateral asset previously supplied to the pool.
2326
+ await runAndAwaitTx(
2327
+ context.lucid,
2328
+ createStableswapOrder(
2329
+ context.assetConfigs[0].iassetTokenNameAscii,
2330
+ EXAMPLE_TOKEN_1,
2331
+ 5_000_000n,
2332
+ false,
2333
+ stableswapPool.datum,
2334
+ context.systemParams,
2335
+ context.lucid,
2336
+ ),
2337
+ );
2338
+
2339
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2340
+
2341
+ // Redeem part of the collateral asset previously supplied to the pool.
2342
+ await runAndAwaitTx(
2343
+ context.lucid,
2344
+ createStableswapOrder(
2345
+ context.assetConfigs[0].iassetTokenNameAscii,
2346
+ EXAMPLE_TOKEN_1,
2347
+ 2_500_000n,
2348
+ false,
2349
+ stableswapPool.datum,
2350
+ context.systemParams,
2351
+ context.lucid,
2352
+ ),
2353
+ );
2354
+
2355
+ stableswapOrders = await findStableswapOrders(
2356
+ context.lucid,
2357
+ context.systemParams.validatorHashes.stableswapHash,
2358
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2359
+ EXAMPLE_TOKEN_1,
2360
+ );
2361
+
2362
+ stableswapPool = await findStableswapPool(
2363
+ context.lucid,
2364
+ context.systemParams.validatorHashes.cdpHash,
2365
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2366
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2367
+ EXAMPLE_TOKEN_1,
2368
+ );
2369
+
2370
+ const iassetAc = {
2371
+ currencySymbol: fromHex(
2372
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
2373
+ ),
2374
+ tokenName: stableswapOrders[0].datum.iasset,
2375
+ };
2376
+
2377
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
2378
+ context.lucid,
2379
+ context.systemParams,
2380
+ iassetAc,
2381
+ );
2382
+
2383
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
2384
+ context.lucid,
2385
+ mkTreasuryAddr(context.lucid, context.systemParams),
2386
+ async () =>
2387
+ runAndAwaitTx(
2388
+ context.lucid,
2389
+ batchProcessStableswapOrders(
2390
+ stableswapOrders.map((order) => order.utxo),
2391
+ stableswapPool.utxo,
2392
+ treasuryUtxo,
2393
+ context.systemParams,
2394
+ context.lucid,
2395
+ ),
2396
+ ),
2397
+ );
2398
+
2399
+ ///////////////////////////////////
2400
+ // Checks after last transaction //
2401
+ ///////////////////////////////////
2402
+
2403
+ stableswapPool = await findStableswapPool(
2404
+ context.lucid,
2405
+ context.systemParams.validatorHashes.cdpHash,
2406
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2407
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2408
+ EXAMPLE_TOKEN_1,
2409
+ );
2410
+
2411
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2412
+ addAssets(acc, utxo.assets),
2413
+ )(await context.lucid.utxosAt(context.users.admin.address));
2414
+
2415
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2416
+ addAssets(acc, utxo.assets),
2417
+ )(await context.lucid.utxosAt(context.users.user.address));
2418
+
2419
+ const adminValueDiff = addAssets(
2420
+ finalAdminValue,
2421
+ negateAssets(initialAdminValue),
2422
+ );
2423
+
2424
+ const userValueDiff = addAssets(
2425
+ finalUserValue,
2426
+ negateAssets(initialUserValue),
2427
+ );
2428
+
2429
+ const numberOfOrders = 2;
2430
+
2431
+ assert(
2432
+ assetClassValueOf(treasuryValChange, iassetAc) == 25_000n + 12_500n &&
2433
+ 0n <= lovelacesAmt(treasuryValChange) &&
2434
+ lovelacesAmt(treasuryValChange) <= 9_000n,
2435
+ 'Unexpected value received by the treasury',
2436
+ );
2437
+
2438
+ assert(
2439
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
2440
+ BigInt(numberOfOrders) * 10_000_000n -
2441
+ (5_000_000n - 25_000n) -
2442
+ (2_500_000n - 12_500n),
2443
+ 'Unexpected value held by stableswap pool',
2444
+ );
2445
+
2446
+ assert(
2447
+ assetClassValueOf(adminValueDiff, iassetAc) ==
2448
+ 10_000_000n - 50_000n - 5_000_000n &&
2449
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) ==
2450
+ -10_000_000n + (5_000_000n - 25_000n),
2451
+ 'Unexpected value received by order #1 owner',
2452
+ );
2453
+
2454
+ assert(
2455
+ assetClassValueOf(userValueDiff, iassetAc) ==
2456
+ 10_000_000n - 50_000n - 2_500_000n &&
2457
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
2458
+ -10_000_000n + (2_500_000n - 12_500n),
2459
+ 'Unexpected value received by order #2 owner',
2460
+ );
2461
+ });
2462
+
2463
+ test<IndigoTestContext>('Stableswap - Batch multiple orders to redeem with rounded amounts', async (context: IndigoTestContext) => {
2464
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2465
+
2466
+ await runCreateStableswapPool(
2467
+ context.assetConfigs[0].iassetTokenNameAscii,
2468
+ EXAMPLE_TOKEN_1,
2469
+ context,
2470
+ // 1.000019 relative price
2471
+ { numerator: 1_000_000n, denominator: 999_981n },
2472
+ // 1% fee
2473
+ { numerator: 1n, denominator: 100n },
2474
+ // 0.0015% fee
2475
+ { numerator: 15n, denominator: 1_000_000n },
2476
+ );
2477
+
2478
+ let stableswapPool = await findStableswapPool(
2479
+ context.lucid,
2480
+ context.systemParams.validatorHashes.cdpHash,
2481
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2482
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2483
+ EXAMPLE_TOKEN_1,
2484
+ );
2485
+
2486
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2487
+
2488
+ const numberOfOrders = 3;
2489
+
2490
+ // Mint iAsset to supply the pool with collateral asset.
2491
+ // It also provides the treasury with a UTxO with iAsset.
2492
+ await runAndAwaitTx(
2493
+ context.lucid,
2494
+ createStableswapOrder(
2495
+ context.assetConfigs[0].iassetTokenNameAscii,
2496
+ EXAMPLE_TOKEN_1,
2497
+ BigInt(numberOfOrders) * 200_000n,
2498
+ true,
2499
+ stableswapPool.datum,
2500
+ context.systemParams,
2501
+ context.lucid,
2502
+ ),
2503
+ );
2504
+
2505
+ let stableswapOrders = await findStableswapOrders(
2506
+ context.lucid,
2507
+ context.systemParams.validatorHashes.stableswapHash,
2508
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2509
+ EXAMPLE_TOKEN_1,
2510
+ );
2511
+
2512
+ await createUtxoAtTreasury(
2513
+ mkLovelacesOf(2_000_000n),
2514
+ context.systemParams,
2515
+ context,
2516
+ );
2517
+
2518
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
2519
+ context.lucid,
2520
+ context.systemParams,
2521
+ );
2522
+
2523
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2524
+
2525
+ await runAndAwaitTx(
2526
+ context.lucid,
2527
+ batchProcessStableswapOrders(
2528
+ stableswapOrders.map((order) => order.utxo),
2529
+ stableswapPool.utxo,
2530
+ treasuryUtxo,
2531
+ context.systemParams,
2532
+ context.lucid,
2533
+ ),
2534
+ );
2535
+
2536
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2537
+
2538
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2539
+ addAssets(acc, utxo.assets),
2540
+ )(await context.lucid.utxosAt(context.users.user.address));
2541
+
2542
+ // Redeem part of the collateral asset previously supplied to the pool.
2543
+ await repeat(numberOfOrders, async () => {
2544
+ await runAndAwaitTx(
2545
+ context.lucid,
2546
+ createStableswapOrder(
2547
+ context.assetConfigs[0].iassetTokenNameAscii,
2548
+ EXAMPLE_TOKEN_1,
2549
+ // The fee will be 1.5 iAssets, rounded to 1.
2550
+ // The equivalent collateral amt after fees is 100000.9000171, rounded to 100,000.
2551
+ 100_000n,
2552
+ false,
2553
+ stableswapPool.datum,
2554
+ context.systemParams,
2555
+ context.lucid,
2556
+ ),
2557
+ );
2558
+ });
2559
+
2560
+ stableswapOrders = await findStableswapOrders(
2561
+ context.lucid,
2562
+ context.systemParams.validatorHashes.stableswapHash,
2563
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2564
+ EXAMPLE_TOKEN_1,
2565
+ );
2566
+
2567
+ stableswapPool = await findStableswapPool(
2568
+ context.lucid,
2569
+ context.systemParams.validatorHashes.cdpHash,
2570
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2571
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2572
+ EXAMPLE_TOKEN_1,
2573
+ );
2574
+
2575
+ const iassetAc = {
2576
+ currencySymbol: fromHex(
2577
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
2578
+ ),
2579
+ tokenName: stableswapOrders[0].datum.iasset,
2580
+ };
2581
+
2582
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
2583
+ context.lucid,
2584
+ context.systemParams,
2585
+ iassetAc,
2586
+ );
2587
+
2588
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2589
+
2590
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2591
+ addAssets(acc, utxo.assets),
2592
+ )(await context.lucid.utxosAt(context.users.admin.address));
2593
+
2594
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
2595
+ context.lucid,
2596
+ mkTreasuryAddr(context.lucid, context.systemParams),
2597
+ async () =>
2598
+ await runAndAwaitTx(
2599
+ context.lucid,
2600
+ batchProcessStableswapOrders(
2601
+ stableswapOrders.map((order) => order.utxo),
2602
+ stableswapPool.utxo,
2603
+ treasuryUtxo,
2604
+ context.systemParams,
2605
+ context.lucid,
2606
+ ),
2607
+ ),
2608
+ );
2609
+
2610
+ ///////////////////////////////////
2611
+ // Checks after last transaction //
2612
+ ///////////////////////////////////
2613
+
2614
+ stableswapPool = await findStableswapPool(
2615
+ context.lucid,
2616
+ context.systemParams.validatorHashes.cdpHash,
2617
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2618
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2619
+ EXAMPLE_TOKEN_1,
2620
+ );
2621
+
2622
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2623
+ addAssets(acc, utxo.assets),
2624
+ )(await context.lucid.utxosAt(context.users.user.address));
2625
+
2626
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2627
+ addAssets(acc, utxo.assets),
2628
+ )(await context.lucid.utxosAt(context.users.admin.address));
2629
+
2630
+ const userValueDiff = addAssets(
2631
+ finalUserValue,
2632
+ negateAssets(initialUserValue),
2633
+ );
2634
+
2635
+ const adminValueDiff = addAssets(
2636
+ finalAdminValue,
2637
+ negateAssets(initialAdminValue),
2638
+ );
2639
+
2640
+ assert(
2641
+ assetClassValueOf(treasuryValChange, iassetAc) ==
2642
+ BigInt(numberOfOrders) * 1n &&
2643
+ 0n <= lovelacesAmt(treasuryValChange) &&
2644
+ lovelacesAmt(treasuryValChange) <= 9_000n,
2645
+ 'Unexpected value received by the treasury',
2646
+ );
2647
+
2648
+ assert(
2649
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
2650
+ BigInt(numberOfOrders) * (200_000n - 100_000n),
2651
+ 'Unexpected value held by stableswap pool',
2652
+ );
2653
+
2654
+ assert(
2655
+ assetClassValueOf(userValueDiff, iassetAc) ==
2656
+ BigInt(numberOfOrders) * -100_000n &&
2657
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) ==
2658
+ BigInt(numberOfOrders) * 100_000n,
2659
+ 'Unexpected value received by order owner',
2660
+ );
2661
+
2662
+ assert(
2663
+ assetClassValueOf(adminValueDiff, iassetAc) == 0n &&
2664
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) == 0n,
2665
+ 'Unexpected value received by the admin',
2666
+ );
2667
+ });
2668
+
2669
+ test<IndigoTestContext>('Stableswap - Batch an order to redeem with insignificant value', async (context: IndigoTestContext) => {
2670
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2671
+
2672
+ await runCreateStableswapPool(
2673
+ context.assetConfigs[0].iassetTokenNameAscii,
2674
+ EXAMPLE_TOKEN_1,
2675
+ context,
2676
+ // The iAsset has one more decimal place than the collateral asset.
2677
+ { numerator: 1n, denominator: 10n },
2678
+ );
2679
+
2680
+ let stableswapPool = await findStableswapPool(
2681
+ context.lucid,
2682
+ context.systemParams.validatorHashes.cdpHash,
2683
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2684
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2685
+ EXAMPLE_TOKEN_1,
2686
+ );
2687
+
2688
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2689
+
2690
+ // Mint iAsset to supply the pool with collateral asset.
2691
+ // It also provides the treasury with a UTxO with iAsset.
2692
+ await runAndAwaitTx(
2693
+ context.lucid,
2694
+ createStableswapOrder(
2695
+ context.assetConfigs[0].iassetTokenNameAscii,
2696
+ EXAMPLE_TOKEN_1,
2697
+ 2_000_000n,
2698
+ true,
2699
+ stableswapPool.datum,
2700
+ context.systemParams,
2701
+ context.lucid,
2702
+ ),
2703
+ );
2704
+
2705
+ let stableswapOrders = await findStableswapOrders(
2706
+ context.lucid,
2707
+ context.systemParams.validatorHashes.stableswapHash,
2708
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2709
+ EXAMPLE_TOKEN_1,
2710
+ );
2711
+
2712
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2713
+
2714
+ await createUtxoAtTreasury(
2715
+ mkLovelacesOf(2_000_000n),
2716
+ context.systemParams,
2717
+ context,
2718
+ );
2719
+
2720
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
2721
+ context.lucid,
2722
+ context.systemParams,
2723
+ );
2724
+
2725
+ await runAndAwaitTx(
2726
+ context.lucid,
2727
+ batchProcessStableswapOrders(
2728
+ stableswapOrders.map((order) => order.utxo),
2729
+ stableswapPool.utxo,
2730
+ treasuryUtxo,
2731
+ context.systemParams,
2732
+ context.lucid,
2733
+ ),
2734
+ );
2735
+
2736
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2737
+
2738
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2739
+ addAssets(acc, utxo.assets),
2740
+ )(await context.lucid.utxosAt(context.users.user.address));
2741
+
2742
+ // Redeem part of the collateral asset previously supplied to the pool.
2743
+ await runAndAwaitTx(
2744
+ context.lucid,
2745
+ createStableswapOrder(
2746
+ context.assetConfigs[0].iassetTokenNameAscii,
2747
+ EXAMPLE_TOKEN_1,
2748
+ // 1.000001 of iAsset, equivalent to 1 collateral asset.
2749
+ 10_000_001n,
2750
+ false,
2751
+ stableswapPool.datum,
2752
+ context.systemParams,
2753
+ context.lucid,
2754
+ ),
2755
+ );
2756
+
2757
+ stableswapOrders = await findStableswapOrders(
2758
+ context.lucid,
2759
+ context.systemParams.validatorHashes.stableswapHash,
2760
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2761
+ EXAMPLE_TOKEN_1,
2762
+ );
2763
+
2764
+ stableswapPool = await findStableswapPool(
2765
+ context.lucid,
2766
+ context.systemParams.validatorHashes.cdpHash,
2767
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2768
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2769
+ EXAMPLE_TOKEN_1,
2770
+ );
2771
+
2772
+ const iassetAc = {
2773
+ currencySymbol: fromHex(
2774
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
2775
+ ),
2776
+ tokenName: stableswapOrders[0].datum.iasset,
2777
+ };
2778
+
2779
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
2780
+ context.lucid,
2781
+ context.systemParams,
2782
+ iassetAc,
2783
+ );
2784
+
2785
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2786
+
2787
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2788
+ addAssets(acc, utxo.assets),
2789
+ )(await context.lucid.utxosAt(context.users.admin.address));
2790
+
2791
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
2792
+ context.lucid,
2793
+ mkTreasuryAddr(context.lucid, context.systemParams),
2794
+ async () =>
2795
+ await runAndAwaitTx(
2796
+ context.lucid,
2797
+ batchProcessStableswapOrders(
2798
+ stableswapOrders.map((order) => order.utxo),
2799
+ stableswapPool.utxo,
2800
+ treasuryUtxo,
2801
+ context.systemParams,
2802
+ context.lucid,
2803
+ ),
2804
+ ),
2805
+ );
2806
+
2807
+ ///////////////////////////////////
2808
+ // Checks after last transaction //
2809
+ ///////////////////////////////////
2810
+
2811
+ stableswapPool = await findStableswapPool(
2812
+ context.lucid,
2813
+ context.systemParams.validatorHashes.cdpHash,
2814
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2815
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2816
+ EXAMPLE_TOKEN_1,
2817
+ );
2818
+
2819
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2820
+ addAssets(acc, utxo.assets),
2821
+ )(await context.lucid.utxosAt(context.users.user.address));
2822
+
2823
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2824
+ addAssets(acc, utxo.assets),
2825
+ )(await context.lucid.utxosAt(context.users.admin.address));
2826
+
2827
+ const userValueDiff = addAssets(
2828
+ finalUserValue,
2829
+ negateAssets(initialUserValue),
2830
+ );
2831
+
2832
+ const adminValueDiff = addAssets(
2833
+ finalAdminValue,
2834
+ negateAssets(initialAdminValue),
2835
+ );
2836
+
2837
+ assert(
2838
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_000n &&
2839
+ 0n <= lovelacesAmt(treasuryValChange) &&
2840
+ lovelacesAmt(treasuryValChange) <= 9_000n,
2841
+ 'Unexpected value received by the treasury',
2842
+ );
2843
+
2844
+ assert(
2845
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
2846
+ 2_000_000n - 1_000_000n + 5_000n,
2847
+ 'Unexpected value held by stableswap pool',
2848
+ );
2849
+
2850
+ assert(
2851
+ assetClassValueOf(userValueDiff, iassetAc) == -10_000_001n &&
2852
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == 1_000_000n - 5_000n,
2853
+ 'Unexpected value received by order owner',
2854
+ );
2855
+
2856
+ assert(
2857
+ assetClassValueOf(adminValueDiff, iassetAc) == 1n &&
2858
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) == 0n,
2859
+ 'Unexpected value received by the admin',
2860
+ );
2861
+ });
2862
+
2863
+ test<IndigoTestContext>('Stableswap - Batch an order to mint with an order to redeem', async (context: IndigoTestContext) => {
2864
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2865
+
2866
+ await runCreateStableswapPool(
2867
+ context.assetConfigs[0].iassetTokenNameAscii,
2868
+ EXAMPLE_TOKEN_1,
2869
+ context,
2870
+ );
2871
+
2872
+ let stableswapPool = await findStableswapPool(
2873
+ context.lucid,
2874
+ context.systemParams.validatorHashes.cdpHash,
2875
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2876
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2877
+ EXAMPLE_TOKEN_1,
2878
+ );
2879
+
2880
+ // Mint iAsset to supply the pool with collateral asset.
2881
+ // It also provides the treasury with a UTxO with iAsset.
2882
+ await runAndAwaitTx(
2883
+ context.lucid,
2884
+ createStableswapOrder(
2885
+ context.assetConfigs[0].iassetTokenNameAscii,
2886
+ EXAMPLE_TOKEN_1,
2887
+ 20_000_000n,
2888
+ true,
2889
+ stableswapPool.datum,
2890
+ context.systemParams,
2891
+ context.lucid,
2892
+ ),
2893
+ );
2894
+
2895
+ let stableswapOrders = await findStableswapOrders(
2896
+ context.lucid,
2897
+ context.systemParams.validatorHashes.stableswapHash,
2898
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2899
+ EXAMPLE_TOKEN_1,
2900
+ );
2901
+
2902
+ await createUtxoAtTreasury(
2903
+ mkLovelacesOf(2_000_000n),
2904
+ context.systemParams,
2905
+ context,
2906
+ );
2907
+
2908
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
2909
+ context.lucid,
2910
+ context.systemParams,
2911
+ );
2912
+
2913
+ await runAndAwaitTx(
2914
+ context.lucid,
2915
+ batchProcessStableswapOrders(
2916
+ stableswapOrders.map((order) => order.utxo),
2917
+ stableswapPool.utxo,
2918
+ treasuryUtxo,
2919
+ context.systemParams,
2920
+ context.lucid,
2921
+ ),
2922
+ );
2923
+
2924
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2925
+ addAssets(acc, utxo.assets),
2926
+ )(await context.lucid.utxosAt(context.users.admin.address));
2927
+
2928
+ // Order to redeem.
2929
+ await runAndAwaitTx(
2930
+ context.lucid,
2931
+ createStableswapOrder(
2932
+ context.assetConfigs[0].iassetTokenNameAscii,
2933
+ EXAMPLE_TOKEN_1,
2934
+ 10_000_000n,
2935
+ false,
2936
+ stableswapPool.datum,
2937
+ context.systemParams,
2938
+ context.lucid,
2939
+ ),
2940
+ );
2941
+
2942
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
2943
+
2944
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
2945
+ addAssets(acc, utxo.assets),
2946
+ )(await context.lucid.utxosAt(context.users.user.address));
2947
+
2948
+ // Order to mint.
2949
+ await runAndAwaitTx(
2950
+ context.lucid,
2951
+ createStableswapOrder(
2952
+ context.assetConfigs[0].iassetTokenNameAscii,
2953
+ EXAMPLE_TOKEN_1,
2954
+ 10_000_000n,
2955
+ true,
2956
+ stableswapPool.datum,
2957
+ context.systemParams,
2958
+ context.lucid,
2959
+ ),
2960
+ );
2961
+
2962
+ stableswapOrders = await findStableswapOrders(
2963
+ context.lucid,
2964
+ context.systemParams.validatorHashes.stableswapHash,
2965
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2966
+ EXAMPLE_TOKEN_1,
2967
+ );
2968
+
2969
+ stableswapPool = await findStableswapPool(
2970
+ context.lucid,
2971
+ context.systemParams.validatorHashes.cdpHash,
2972
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
2973
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
2974
+ EXAMPLE_TOKEN_1,
2975
+ );
2976
+
2977
+ const iassetAc = {
2978
+ currencySymbol: fromHex(
2979
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
2980
+ ),
2981
+ tokenName: stableswapOrders[0].datum.iasset,
2982
+ };
2983
+
2984
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
2985
+ context.lucid,
2986
+ context.systemParams,
2987
+ iassetAc,
2988
+ );
2989
+
2990
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
2991
+ context.lucid,
2992
+ mkTreasuryAddr(context.lucid, context.systemParams),
2993
+ async () =>
2994
+ runAndAwaitTx(
2995
+ context.lucid,
2996
+ batchProcessStableswapOrders(
2997
+ stableswapOrders.map((order) => order.utxo),
2998
+ stableswapPool.utxo,
2999
+ treasuryUtxo,
3000
+ context.systemParams,
3001
+ context.lucid,
3002
+ ),
3003
+ ),
3004
+ );
3005
+
3006
+ ///////////////////////////////////
3007
+ // Checks after last transaction //
3008
+ ///////////////////////////////////
3009
+
3010
+ stableswapPool = await findStableswapPool(
3011
+ context.lucid,
3012
+ context.systemParams.validatorHashes.cdpHash,
3013
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3014
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3015
+ EXAMPLE_TOKEN_1,
3016
+ );
3017
+
3018
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3019
+ addAssets(acc, utxo.assets),
3020
+ )(await context.lucid.utxosAt(context.users.admin.address));
3021
+
3022
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3023
+ addAssets(acc, utxo.assets),
3024
+ )(await context.lucid.utxosAt(context.users.user.address));
3025
+
3026
+ const adminValueDiff = addAssets(
3027
+ finalAdminValue,
3028
+ negateAssets(initialAdminValue),
3029
+ );
3030
+
3031
+ const userValueDiff = addAssets(
3032
+ finalUserValue,
3033
+ negateAssets(initialUserValue),
3034
+ );
3035
+
3036
+ assert(
3037
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_000n + 50_000n &&
3038
+ 0n <= lovelacesAmt(treasuryValChange) &&
3039
+ lovelacesAmt(treasuryValChange) <= 9_000n,
3040
+ 'Unexpected value received by the treasury',
3041
+ );
3042
+
3043
+ // The first 20_000_000 come from the minting order processed before the batch.
3044
+ assert(
3045
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
3046
+ 20_000_000n + 50_000n,
3047
+ 'Unexpected collateral asset value held by stableswap pool',
3048
+ );
3049
+
3050
+ assert(
3051
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 50_000n &&
3052
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n,
3053
+ 'Unexpected value received by minting order owner',
3054
+ );
3055
+
3056
+ assert(
3057
+ assetClassValueOf(adminValueDiff, iassetAc) == -10_000_000n &&
3058
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) ==
3059
+ 10_000_000n - 50_000n,
3060
+ 'Unexpected value received by redeeming order owner',
3061
+ );
3062
+ });
3063
+
3064
+ test<IndigoTestContext>('Stableswap - Batch an order to mint with an order to redeem (with destination datum)', async (context: IndigoTestContext) => {
3065
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3066
+
3067
+ await runCreateStableswapPool(
3068
+ context.assetConfigs[0].iassetTokenNameAscii,
3069
+ EXAMPLE_TOKEN_1,
3070
+ context,
3071
+ );
3072
+
3073
+ let stableswapPool = await findStableswapPool(
3074
+ context.lucid,
3075
+ context.systemParams.validatorHashes.cdpHash,
3076
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3077
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3078
+ EXAMPLE_TOKEN_1,
3079
+ );
3080
+
3081
+ // Mint iAsset to supply the pool with collateral asset.
3082
+ // It also provides the treasury with a UTxO with iAsset.
3083
+ await runAndAwaitTx(
3084
+ context.lucid,
3085
+ createStableswapOrder(
3086
+ context.assetConfigs[0].iassetTokenNameAscii,
3087
+ EXAMPLE_TOKEN_1,
3088
+ 20_000_000n,
3089
+ true,
3090
+ stableswapPool.datum,
3091
+ context.systemParams,
3092
+ context.lucid,
3093
+ undefined,
3094
+ Data.fromCBORHex('d87980'),
3095
+ ),
3096
+ );
3097
+
3098
+ let stableswapOrders = await findStableswapOrders(
3099
+ context.lucid,
3100
+ context.systemParams.validatorHashes.stableswapHash,
3101
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3102
+ EXAMPLE_TOKEN_1,
3103
+ );
3104
+
3105
+ await createUtxoAtTreasury(
3106
+ mkLovelacesOf(2_000_000n),
3107
+ context.systemParams,
3108
+ context,
3109
+ );
3110
+
3111
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
3112
+ context.lucid,
3113
+ context.systemParams,
3114
+ );
3115
+
3116
+ await runAndAwaitTx(
3117
+ context.lucid,
3118
+ batchProcessStableswapOrders(
3119
+ stableswapOrders.map((order) => order.utxo),
3120
+ stableswapPool.utxo,
3121
+ treasuryUtxo,
3122
+ context.systemParams,
3123
+ context.lucid,
3124
+ ),
3125
+ );
3126
+
3127
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3128
+ addAssets(acc, utxo.assets),
3129
+ )(await context.lucid.utxosAt(context.users.admin.address));
3130
+
3131
+ // Order to redeem.
3132
+ await runAndAwaitTx(
3133
+ context.lucid,
3134
+ createStableswapOrder(
3135
+ context.assetConfigs[0].iassetTokenNameAscii,
3136
+ EXAMPLE_TOKEN_1,
3137
+ 10_000_000n,
3138
+ false,
3139
+ stableswapPool.datum,
3140
+ context.systemParams,
3141
+ context.lucid,
3142
+ undefined,
3143
+ Data.fromCBORHex('d87980'),
3144
+ ),
3145
+ );
3146
+
3147
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
3148
+
3149
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3150
+ addAssets(acc, utxo.assets),
3151
+ )(await context.lucid.utxosAt(context.users.user.address));
3152
+
3153
+ // Order to mint.
3154
+ await runAndAwaitTx(
3155
+ context.lucid,
3156
+ createStableswapOrder(
3157
+ context.assetConfigs[0].iassetTokenNameAscii,
3158
+ EXAMPLE_TOKEN_1,
3159
+ 10_000_000n,
3160
+ true,
3161
+ stableswapPool.datum,
3162
+ context.systemParams,
3163
+ context.lucid,
3164
+ undefined,
3165
+ Data.fromCBORHex('d87a80'),
3166
+ ),
3167
+ );
3168
+
3169
+ stableswapOrders = await findStableswapOrders(
3170
+ context.lucid,
3171
+ context.systemParams.validatorHashes.stableswapHash,
3172
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3173
+ EXAMPLE_TOKEN_1,
3174
+ );
3175
+
3176
+ stableswapPool = await findStableswapPool(
3177
+ context.lucid,
3178
+ context.systemParams.validatorHashes.cdpHash,
3179
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3180
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3181
+ EXAMPLE_TOKEN_1,
3182
+ );
3183
+
3184
+ const iassetAc = {
3185
+ currencySymbol: fromHex(
3186
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
3187
+ ),
3188
+ tokenName: stableswapOrders[0].datum.iasset,
3189
+ };
3190
+
3191
+ treasuryUtxo = await findRandomTreasuryUtxoWithAsset(
3192
+ context.lucid,
3193
+ context.systemParams,
3194
+ iassetAc,
3195
+ );
3196
+
3197
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
3198
+ context.lucid,
3199
+ mkTreasuryAddr(context.lucid, context.systemParams),
3200
+ async () =>
3201
+ runAndAwaitTx(
3202
+ context.lucid,
3203
+ batchProcessStableswapOrders(
3204
+ stableswapOrders.map((order) => order.utxo),
3205
+ stableswapPool.utxo,
3206
+ treasuryUtxo,
3207
+ context.systemParams,
3208
+ context.lucid,
3209
+ ),
3210
+ ),
3211
+ );
3212
+
3213
+ ///////////////////////////////////
3214
+ // Checks after last transaction //
3215
+ ///////////////////////////////////
3216
+
3217
+ stableswapPool = await findStableswapPool(
3218
+ context.lucid,
3219
+ context.systemParams.validatorHashes.cdpHash,
3220
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3221
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3222
+ EXAMPLE_TOKEN_1,
3223
+ );
3224
+
3225
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3226
+ addAssets(acc, utxo.assets),
3227
+ )(await context.lucid.utxosAt(context.users.admin.address));
3228
+
3229
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3230
+ addAssets(acc, utxo.assets),
3231
+ )(await context.lucid.utxosAt(context.users.user.address));
3232
+
3233
+ const adminValueDiff = addAssets(
3234
+ finalAdminValue,
3235
+ negateAssets(initialAdminValue),
3236
+ );
3237
+
3238
+ const userValueDiff = addAssets(
3239
+ finalUserValue,
3240
+ negateAssets(initialUserValue),
3241
+ );
3242
+
3243
+ assert(
3244
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_000n + 50_000n &&
3245
+ 0n <= lovelacesAmt(treasuryValChange) &&
3246
+ lovelacesAmt(treasuryValChange) <= 9_000n,
3247
+ 'Unexpected value received by the treasury',
3248
+ );
3249
+
3250
+ // This comes from the minting order processed before the batch.
3251
+ assert(
3252
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) ==
3253
+ 20_000_000n + 50_000n,
3254
+ 'Unexpected value held by stableswap pool',
3255
+ );
3256
+
3257
+ assert(
3258
+ assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 50_000n &&
3259
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n,
3260
+ 'Unexpected value received by minting order owner',
3261
+ );
3262
+
3263
+ assert(
3264
+ assetClassValueOf(adminValueDiff, iassetAc) == -10_000_000n &&
3265
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) ==
3266
+ 10_000_000n - 50_000n,
3267
+ 'Unexpected value received by redeeming order owner',
3268
+ );
3269
+ });
3270
+
3271
+ test<IndigoTestContext>('Stableswap - Batch an order to mint with an order to redeem with an empty pool', async (context: IndigoTestContext) => {
3272
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3273
+
3274
+ await runCreateStableswapPool(
3275
+ context.assetConfigs[0].iassetTokenNameAscii,
3276
+ EXAMPLE_TOKEN_1,
3277
+ context,
3278
+ );
3279
+
3280
+ let stableswapPool = await findStableswapPool(
3281
+ context.lucid,
3282
+ context.systemParams.validatorHashes.cdpHash,
3283
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3284
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3285
+ EXAMPLE_TOKEN_1,
3286
+ );
3287
+
3288
+ let orefs = await findAllNecessaryOrefs(
3289
+ context.lucid,
3290
+ context.systemParams,
3291
+ context.assetConfigs[0].iassetTokenNameAscii,
3292
+ context.assetConfigs[0].collateralAssets[0].collateralAsset,
3293
+ );
3294
+ const priceOracleUtxo = await findPriceOracleFromCollateralAsset(
3295
+ context.lucid,
3296
+ orefs.collateralAsset,
3297
+ );
3298
+
3299
+ await runAndAwaitTx(
3300
+ context.lucid,
3301
+ feedPriceOracleTx(
3302
+ context.lucid,
3303
+ priceOracleUtxo!,
3304
+ rationalFromInt(1n),
3305
+ context.assetConfigs[0].collateralAssets[0].oracleParams!,
3306
+ context.emulator.slot,
3307
+ ),
3308
+ );
3309
+
3310
+ const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3311
+ addAssets(acc, utxo.assets),
3312
+ )(await context.lucid.utxosAt(context.users.admin.address));
3313
+
3314
+ // Order to mint.
3315
+ await runAndAwaitTx(
3316
+ context.lucid,
3317
+ createStableswapOrder(
3318
+ context.assetConfigs[0].iassetTokenNameAscii,
3319
+ EXAMPLE_TOKEN_1,
3320
+ 10_000_000n,
3321
+ true,
3322
+ stableswapPool.datum,
3323
+ context.systemParams,
3324
+ context.lucid,
3325
+ ),
3326
+ );
3327
+
3328
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
3329
+
3330
+ orefs = await findAllNecessaryOrefs(
3331
+ context.lucid,
3332
+ context.systemParams,
3333
+ context.assetConfigs[0].iassetTokenNameAscii,
3334
+ context.assetConfigs[0].collateralAssets[0].collateralAsset,
3335
+ );
3336
+
3337
+ // Get some iAsset to be able to redeem from stableswap pool.
3338
+ await runAndAwaitTx(
3339
+ context.lucid,
3340
+ runOpenCdp(
3341
+ context,
3342
+ context.systemParams,
3343
+ context.assetConfigs[0].iassetTokenNameAscii,
3344
+ context.assetConfigs[0].collateralAssets[0].collateralAsset,
3345
+ 50_000_000n,
3346
+ 20_000_000n,
3347
+ ),
3348
+ );
3349
+
3350
+ const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3351
+ addAssets(acc, utxo.assets),
3352
+ )(await context.lucid.utxosAt(context.users.user.address));
3353
+
3354
+ // Order to redeem.
3355
+ await runAndAwaitTx(
3356
+ context.lucid,
3357
+ createStableswapOrder(
3358
+ context.assetConfigs[0].iassetTokenNameAscii,
3359
+ EXAMPLE_TOKEN_1,
3360
+ 10_050_251n,
3361
+ false,
3362
+ stableswapPool.datum,
3363
+ context.systemParams,
3364
+ context.lucid,
3365
+ ),
3366
+ );
3367
+
3368
+ const stableswapOrders = await findStableswapOrders(
3369
+ context.lucid,
3370
+ context.systemParams.validatorHashes.stableswapHash,
3371
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3372
+ EXAMPLE_TOKEN_1,
3373
+ );
3374
+
3375
+ await createUtxoAtTreasury(
3376
+ mkLovelacesOf(2_000_000n),
3377
+ context.systemParams,
3378
+ context,
3379
+ );
3380
+
3381
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
3382
+ context.lucid,
3383
+ context.systemParams,
3384
+ );
3385
+
3386
+ const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction(
3387
+ context.lucid,
3388
+ mkTreasuryAddr(context.lucid, context.systemParams),
3389
+ async () =>
3390
+ runAndAwaitTx(
3391
+ context.lucid,
3392
+ batchProcessStableswapOrders(
3393
+ stableswapOrders.map((order) => order.utxo),
3394
+ stableswapPool.utxo,
3395
+ treasuryUtxo,
3396
+ context.systemParams,
3397
+ context.lucid,
3398
+ ),
3399
+ ),
3400
+ );
3401
+
3402
+ ///////////////////////////////////
3403
+ // Checks after last transaction //
3404
+ ///////////////////////////////////
3405
+
3406
+ stableswapPool = await findStableswapPool(
3407
+ context.lucid,
3408
+ context.systemParams.validatorHashes.cdpHash,
3409
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3410
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3411
+ EXAMPLE_TOKEN_1,
3412
+ );
3413
+
3414
+ const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3415
+ addAssets(acc, utxo.assets),
3416
+ )(await context.lucid.utxosAt(context.users.admin.address));
3417
+
3418
+ const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
3419
+ addAssets(acc, utxo.assets),
3420
+ )(await context.lucid.utxosAt(context.users.user.address));
3421
+
3422
+ const adminValueDiff = addAssets(
3423
+ finalAdminValue,
3424
+ negateAssets(initialAdminValue),
3425
+ );
3426
+
3427
+ const userValueDiff = addAssets(
3428
+ finalUserValue,
3429
+ negateAssets(initialUserValue),
3430
+ );
3431
+
3432
+ const iassetAc = {
3433
+ currencySymbol: fromHex(
3434
+ context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol,
3435
+ ),
3436
+ tokenName: stableswapOrders[0].datum.iasset,
3437
+ };
3438
+
3439
+ assert(
3440
+ assetClassValueOf(treasuryValChange, iassetAc) == 50_000n + 50_251n,
3441
+ 'Unexpected iAsset value received by the treasury',
3442
+ );
3443
+
3444
+ assert(
3445
+ assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 0n,
3446
+ 'Unexpected value held by stableswap pool',
3447
+ );
3448
+
3449
+ assert(
3450
+ assetClassValueOf(adminValueDiff, iassetAc) == 10_000_000n - 50_000n &&
3451
+ assetClassValueOf(adminValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n,
3452
+ 'Unexpected value received by minting order owner',
3453
+ );
3454
+
3455
+ assert(
3456
+ assetClassValueOf(userValueDiff, iassetAc) == -10_050_251n &&
3457
+ assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == 10_000_000n,
3458
+ 'Unexpected value received by redeeming order owner',
3459
+ );
3460
+ });
3461
+
3462
+ test<IndigoTestContext>('Stableswap - Update fees from fee manager', async (context: IndigoTestContext) => {
3463
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3464
+
3465
+ await runCreateStableswapPool(
3466
+ context.assetConfigs[0].iassetTokenNameAscii,
3467
+ EXAMPLE_TOKEN_1,
3468
+ context,
3469
+ );
3470
+
3471
+ let stableswapPool: { utxo: UTxO; datum: StableswapPoolContent } =
3472
+ await findStableswapPool(
3473
+ context.lucid,
3474
+ context.systemParams.validatorHashes.cdpHash,
3475
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3476
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3477
+ EXAMPLE_TOKEN_1,
3478
+ );
3479
+
3480
+ const feeTxHash = await runAndAwaitTxBuilder(
3481
+ context.lucid,
3482
+ context.lucid.newTx().pay.ToAddress(
3483
+ credentialToAddress(context.lucid.config().network!, {
3484
+ hash: context.systemParams.validatorHashes.stableswapHash,
3485
+ type: 'Script',
3486
+ }),
3487
+ mkLovelacesOf(2_000_000n),
3488
+ ),
3489
+ );
3490
+
3491
+ assert(
3492
+ stableswapPool.datum.mintingFeeRatio.numerator === 5n &&
3493
+ stableswapPool.datum.mintingFeeRatio.denominator === 1_000n,
3494
+ 'Unexpected minting fee percentage prior to update',
3495
+ );
3496
+
3497
+ assert(
3498
+ stableswapPool.datum.redemptionFeeRatio.numerator === 5n &&
3499
+ stableswapPool.datum.redemptionFeeRatio.denominator === 1_000n,
3500
+ 'Unexpected redemption fee percentage prior to update',
3501
+ );
3502
+
3503
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3504
+
3505
+ await benchmarkAndAwaitTx(
3506
+ 'Stableswap - Update fees',
3507
+ await updateStableswapPoolFees(
3508
+ stableswapPool.utxo,
3509
+ { txHash: feeTxHash, outputIndex: 0 },
3510
+ { numerator: 1n, denominator: 100n },
3511
+ { numerator: 1n, denominator: 100n },
3512
+ context.systemParams,
3513
+ context.lucid,
3514
+ ),
3515
+ context.lucid,
3516
+ context.emulator,
3517
+ );
3518
+
3519
+ ///////////////////////////////////
3520
+ // Checks after last transaction //
3521
+ ///////////////////////////////////
3522
+
3523
+ stableswapPool = await findStableswapPool(
3524
+ context.lucid,
3525
+ context.systemParams.validatorHashes.cdpHash,
3526
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3527
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3528
+ EXAMPLE_TOKEN_1,
3529
+ );
3530
+
3531
+ assert(
3532
+ stableswapPool.datum.mintingFeeRatio.numerator === 1n &&
3533
+ stableswapPool.datum.mintingFeeRatio.denominator === 100n,
3534
+ 'Unexpected minting fee percentage',
3535
+ );
3536
+
3537
+ assert(
3538
+ stableswapPool.datum.mintingFeeRatio.numerator === 1n &&
3539
+ stableswapPool.datum.mintingFeeRatio.denominator === 100n,
3540
+ 'Unexpected redemption fee percentage',
3541
+ );
3542
+ });
3543
+
3544
+ test<IndigoTestContext>('Stableswap - Update fees from fee manager - fails with large minting fee', async (context: IndigoTestContext) => {
3545
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3546
+
3547
+ await runCreateStableswapPool(
3548
+ context.assetConfigs[0].iassetTokenNameAscii,
3549
+ EXAMPLE_TOKEN_1,
3550
+ context,
3551
+ );
3552
+
3553
+ const stableswapPool: { utxo: UTxO; datum: StableswapPoolContent } =
3554
+ await findStableswapPool(
3555
+ context.lucid,
3556
+ context.systemParams.validatorHashes.cdpHash,
3557
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3558
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3559
+ EXAMPLE_TOKEN_1,
3560
+ );
3561
+
3562
+ const feeTxHash = await runAndAwaitTxBuilder(
3563
+ context.lucid,
3564
+ context.lucid.newTx().pay.ToAddress(
3565
+ credentialToAddress(context.lucid.config().network!, {
3566
+ hash: context.systemParams.validatorHashes.stableswapHash,
3567
+ type: 'Script',
3568
+ }),
3569
+ mkLovelacesOf(2_000_000n),
3570
+ ),
3571
+ );
3572
+
3573
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3574
+
3575
+ await expectScriptFailure(
3576
+ 'Minting fee ratio is between [0%, 100%]',
3577
+ updateStableswapPoolFees(
3578
+ stableswapPool.utxo,
3579
+ { txHash: feeTxHash, outputIndex: 0 },
3580
+ { numerator: 1_005n, denominator: 10n },
3581
+ { numerator: 1n, denominator: 100n },
3582
+ context.systemParams,
3583
+ context.lucid,
3584
+ ),
3585
+ );
3586
+ });
3587
+
3588
+ test<IndigoTestContext>('Stableswap - Update fees from fee manager - fails with large redemption fee', async (context: IndigoTestContext) => {
3589
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3590
+
3591
+ await runCreateStableswapPool(
3592
+ context.assetConfigs[0].iassetTokenNameAscii,
3593
+ EXAMPLE_TOKEN_1,
3594
+ context,
3595
+ );
3596
+
3597
+ const stableswapPool: { utxo: UTxO; datum: StableswapPoolContent } =
3598
+ await findStableswapPool(
3599
+ context.lucid,
3600
+ context.systemParams.validatorHashes.cdpHash,
3601
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3602
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3603
+ EXAMPLE_TOKEN_1,
3604
+ );
3605
+
3606
+ const feeTxHash = await runAndAwaitTxBuilder(
3607
+ context.lucid,
3608
+ context.lucid.newTx().pay.ToAddress(
3609
+ credentialToAddress(context.lucid.config().network!, {
3610
+ hash: context.systemParams.validatorHashes.stableswapHash,
3611
+ type: 'Script',
3612
+ }),
3613
+ mkLovelacesOf(2_000_000n),
3614
+ ),
3615
+ );
3616
+
3617
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3618
+
3619
+ await expectScriptFailure(
3620
+ 'Redemption fee ratio is between [0%, 100%]',
3621
+ updateStableswapPoolFees(
3622
+ stableswapPool.utxo,
3623
+ { txHash: feeTxHash, outputIndex: 0 },
3624
+ { numerator: 1n, denominator: 100n },
3625
+ { numerator: 1_005n, denominator: 10n },
3626
+ context.systemParams,
3627
+ context.lucid,
3628
+ ),
3629
+ );
3630
+ });
3631
+
3632
+ test<IndigoTestContext>('Stableswap - Process a two-step order, ex. USDC -> iUSD -> USDC', async (context: IndigoTestContext) => {
3633
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3634
+
3635
+ await runCreateStableswapPool(
3636
+ context.assetConfigs[0].iassetTokenNameAscii,
3637
+ EXAMPLE_TOKEN_1,
3638
+ context,
3639
+ );
3640
+
3641
+ let stableswapPool = await findStableswapPool(
3642
+ context.lucid,
3643
+ context.systemParams.validatorHashes.cdpHash,
3644
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3645
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3646
+ EXAMPLE_TOKEN_1,
3647
+ );
3648
+
3649
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
3650
+ const userAddress = await context.lucid.wallet().address();
3651
+ const pkh = paymentCredentialOf(userAddress);
3652
+
3653
+ // Create order to mint iAsset, forwarding to a stableswap order to redeem the iAsset.
3654
+ await runAndAwaitTx(
3655
+ context.lucid,
3656
+ createStableswapOrder(
3657
+ context.assetConfigs[0].iassetTokenNameAscii,
3658
+ EXAMPLE_TOKEN_1,
3659
+ 10_000_000n,
3660
+ true,
3661
+ stableswapPool.datum,
3662
+ context.systemParams,
3663
+ context.lucid,
3664
+ createScriptAddress(
3665
+ context.lucid.config().network!,
3666
+ context.systemParams.validatorHashes.stableswapHash,
3667
+ ),
3668
+ Data.fromCBORHex(
3669
+ serialiseStableswapOrderDatum({
3670
+ iasset: fromHex(
3671
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3672
+ ),
3673
+ collateralAsset: EXAMPLE_TOKEN_1,
3674
+ owner: fromHex(pkh.hash),
3675
+ destination: addressFromBech32(userAddress),
3676
+ destinationInlineDatum: null,
3677
+ maxExecutionFee: BASE_MAX_EXECUTION_FEE,
3678
+ maxFeeRatio: stableswapPool.datum.mintingFeeRatio,
3679
+ }),
3680
+ ),
3681
+ BASE_MAX_EXECUTION_FEE,
3682
+ 1_000_000n,
3683
+ ),
3684
+ );
3685
+
3686
+ let stableswapOrder = await findSingleStableswapOrder(
3687
+ context.lucid,
3688
+ context.systemParams.validatorHashes.stableswapHash,
3689
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3690
+ EXAMPLE_TOKEN_1,
3691
+ );
3692
+
3693
+ await createUtxoAtTreasury(
3694
+ mkLovelacesOf(2_000_000n),
3695
+ context.systemParams,
3696
+ context,
3697
+ );
3698
+
3699
+ let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
3700
+ context.lucid,
3701
+ context.systemParams,
3702
+ );
3703
+
3704
+ await runAndAwaitTx(
3705
+ context.lucid,
3706
+ batchProcessStableswapOrders(
3707
+ [stableswapOrder.utxo],
3708
+ stableswapPool.utxo,
3709
+ treasuryUtxo,
3710
+ context.systemParams,
3711
+ context.lucid,
3712
+ ),
3713
+ );
3714
+
3715
+ // Redeem part of the collateral asset previously supplied to the pool.
3716
+ stableswapOrder = await findSingleStableswapOrder(
3717
+ context.lucid,
3718
+ context.systemParams.validatorHashes.stableswapHash,
3719
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3720
+ EXAMPLE_TOKEN_1,
3721
+ );
3722
+
3723
+ stableswapPool = await findStableswapPool(
3724
+ context.lucid,
3725
+ context.systemParams.validatorHashes.cdpHash,
3726
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3727
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3728
+ EXAMPLE_TOKEN_1,
3729
+ );
3730
+
3731
+ await createUtxoAtTreasury(
3732
+ mkLovelacesOf(2_000_000n),
3733
+ context.systemParams,
3734
+ context,
3735
+ );
3736
+
3737
+ treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
3738
+ context.lucid,
3739
+ context.systemParams,
3740
+ );
3741
+
3742
+ await runAndAwaitTx(
3743
+ context.lucid,
3744
+ batchProcessStableswapOrders(
3745
+ [stableswapOrder.utxo],
3746
+ stableswapPool.utxo,
3747
+ treasuryUtxo,
3748
+ context.systemParams,
3749
+ context.lucid,
3750
+ ),
3751
+ );
3752
+ });
3753
+
3754
+ test<IndigoTestContext>('Stableswap - Batcher tries to steal more than the max execution fee', async (context: IndigoTestContext) => {
3755
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3756
+
3757
+ await runCreateStableswapPool(
3758
+ context.assetConfigs[0].iassetTokenNameAscii,
3759
+ EXAMPLE_TOKEN_1,
3760
+ context,
3761
+ );
3762
+
3763
+ const stableswapPool = await findStableswapPool(
3764
+ context.lucid,
3765
+ context.systemParams.validatorHashes.cdpHash,
3766
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3767
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3768
+ EXAMPLE_TOKEN_1,
3769
+ );
3770
+
3771
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
3772
+
3773
+ // Create order to mint iAsset.
3774
+ await runAndAwaitTx(
3775
+ context.lucid,
3776
+ createStableswapOrder(
3777
+ context.assetConfigs[0].iassetTokenNameAscii,
3778
+ EXAMPLE_TOKEN_1,
3779
+ 10_000_000n,
3780
+ true,
3781
+ stableswapPool.datum,
3782
+ context.systemParams,
3783
+ context.lucid,
3784
+ undefined,
3785
+ undefined,
3786
+ BASE_MAX_EXECUTION_FEE,
3787
+ 10_000_000n,
3788
+ ),
3789
+ );
3790
+
3791
+ const stableswapOrder = await findSingleStableswapOrder(
3792
+ context.lucid,
3793
+ context.systemParams.validatorHashes.stableswapHash,
3794
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3795
+ EXAMPLE_TOKEN_1,
3796
+ );
3797
+
3798
+ await createUtxoAtTreasury(
3799
+ mkLovelacesOf(2_000_000n),
3800
+ context.systemParams,
3801
+ context,
3802
+ );
3803
+
3804
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
3805
+ context.lucid,
3806
+ context.systemParams,
3807
+ );
3808
+
3809
+ await expectScriptFailure(
3810
+ 'Minted amount wrongly sent to order destination',
3811
+ mutatedBatchProcessStableswapOrders(
3812
+ [stableswapOrder.utxo],
3813
+ stableswapPool.utxo,
3814
+ treasuryUtxo,
3815
+ context.systemParams,
3816
+ context.lucid,
3817
+ {
3818
+ type: 'exceed-max-execution-fee',
3819
+ maxExecutionFee: BASE_MAX_EXECUTION_FEE + 1_000_000n,
3820
+ },
3821
+ ),
3822
+ );
3823
+ });
3824
+
3825
+ test<IndigoTestContext>('Stableswap - Pool exceeds max fee percentage', async (context: IndigoTestContext) => {
3826
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3827
+
3828
+ await runCreateStableswapPool(
3829
+ context.assetConfigs[0].iassetTokenNameAscii,
3830
+ EXAMPLE_TOKEN_1,
3831
+ context,
3832
+ );
3833
+
3834
+ const stableswapPool = await findStableswapPool(
3835
+ context.lucid,
3836
+ context.systemParams.validatorHashes.cdpHash,
3837
+ fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken),
3838
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3839
+ EXAMPLE_TOKEN_1,
3840
+ );
3841
+
3842
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
3843
+
3844
+ // Create order to mint iAsset, though with a 0% max fee percentage.
3845
+ await runAndAwaitTx(
3846
+ context.lucid,
3847
+ createStableswapOrder(
3848
+ context.assetConfigs[0].iassetTokenNameAscii,
3849
+ EXAMPLE_TOKEN_1,
3850
+ 10_000_000n,
3851
+ true,
3852
+ stableswapPool.datum,
3853
+ context.systemParams,
3854
+ context.lucid,
3855
+ undefined,
3856
+ undefined,
3857
+ BASE_MAX_EXECUTION_FEE,
3858
+ 0n,
3859
+ rationalFromInt(0n),
3860
+ ),
3861
+ );
3862
+
3863
+ const stableswapOrder = await findSingleStableswapOrder(
3864
+ context.lucid,
3865
+ context.systemParams.validatorHashes.stableswapHash,
3866
+ fromText(context.assetConfigs[0].iassetTokenNameAscii),
3867
+ EXAMPLE_TOKEN_1,
3868
+ );
3869
+
3870
+ await createUtxoAtTreasury(
3871
+ mkLovelacesOf(2_000_000n),
3872
+ context.systemParams,
3873
+ context,
3874
+ );
3875
+
3876
+ const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda(
3877
+ context.lucid,
3878
+ context.systemParams,
3879
+ );
3880
+
3881
+ await expectScriptFailure(
3882
+ 'Pool minting fee exceeds order max fee ratio',
3883
+ batchProcessStableswapOrders(
3884
+ [stableswapOrder.utxo],
3885
+ stableswapPool.utxo,
3886
+ treasuryUtxo,
3887
+ context.systemParams,
3888
+ context.lucid,
3889
+ ),
3890
+ );
3891
+ });