@indigo-labs/indigo-sdk 0.2.42 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/.github/workflows/ci.yml +4 -2
  2. package/README.md +88 -15
  3. package/dist/index.d.mts +3012 -2194
  4. package/dist/index.d.ts +3012 -2194
  5. package/dist/index.js +9849 -6198
  6. package/dist/index.mjs +8733 -4933
  7. package/package.json +14 -3
  8. package/src/contracts/cdp/helpers.ts +68 -72
  9. package/src/contracts/cdp/scripts.ts +50 -13
  10. package/src/contracts/cdp/transactions.ts +841 -546
  11. package/src/contracts/cdp/types-new.ts +256 -0
  12. package/src/contracts/cdp/types.ts +26 -144
  13. package/src/contracts/cdp-creator/scripts.ts +15 -9
  14. package/src/contracts/cdp-creator/types-new.ts +50 -0
  15. package/src/contracts/cdp-creator/types.ts +5 -31
  16. package/src/contracts/collector/scripts.ts +1 -1
  17. package/src/contracts/collector/transactions.ts +23 -13
  18. package/src/contracts/collector/types-new.ts +17 -0
  19. package/src/contracts/execute/scripts.ts +19 -10
  20. package/src/contracts/execute/types-new.ts +44 -0
  21. package/src/contracts/execute/types.ts +5 -38
  22. package/src/contracts/gov/helpers.ts +187 -51
  23. package/src/contracts/gov/scripts.ts +17 -10
  24. package/src/contracts/gov/transactions.ts +599 -271
  25. package/src/contracts/gov/types-new.ts +253 -100
  26. package/src/contracts/gov/types.ts +4 -71
  27. package/src/contracts/iasset/helpers.ts +172 -0
  28. package/src/contracts/iasset/scripts.ts +38 -0
  29. package/src/contracts/iasset/types.ts +154 -0
  30. package/src/contracts/initialize/actions.ts +768 -0
  31. package/src/contracts/initialize/helpers.ts +611 -36
  32. package/src/contracts/initialize/types.ts +102 -28
  33. package/src/contracts/interest-collection/helpers.ts +19 -0
  34. package/src/contracts/interest-collection/scripts.ts +44 -0
  35. package/src/contracts/interest-collection/transactions.ts +436 -0
  36. package/src/contracts/interest-collection/types-new.ts +50 -0
  37. package/src/contracts/interest-collection/types.ts +26 -0
  38. package/src/contracts/interest-oracle/helpers.ts +2 -30
  39. package/src/contracts/interest-oracle/scripts.ts +1 -1
  40. package/src/contracts/interest-oracle/transactions.ts +21 -16
  41. package/src/contracts/interest-oracle/types-new.ts +32 -0
  42. package/src/contracts/interest-oracle/types.ts +1 -40
  43. package/src/contracts/one-shot/transactions.ts +1 -2
  44. package/src/contracts/poll/helpers.ts +5 -23
  45. package/src/contracts/poll/scripts.ts +12 -13
  46. package/src/contracts/poll/types-poll-manager.ts +1 -19
  47. package/src/contracts/poll/types-poll-new.ts +170 -0
  48. package/src/contracts/poll/types-poll-shard.ts +2 -24
  49. package/src/contracts/price-oracle/helpers.ts +1 -4
  50. package/src/contracts/price-oracle/scripts.ts +3 -8
  51. package/src/contracts/price-oracle/transactions.ts +32 -25
  52. package/src/contracts/price-oracle/types-new.ts +50 -0
  53. package/src/contracts/price-oracle/types.ts +2 -36
  54. package/src/contracts/pyth-feed/helpers.ts +58 -0
  55. package/src/contracts/pyth-feed/scripts.ts +15 -0
  56. package/src/contracts/pyth-feed/types.ts +181 -0
  57. package/src/contracts/rob/helpers.ts +405 -0
  58. package/src/contracts/rob/scripts.ts +35 -0
  59. package/src/contracts/rob/transactions.ts +410 -0
  60. package/src/contracts/rob/types-new.ts +128 -0
  61. package/src/contracts/rob/types.ts +16 -0
  62. package/src/contracts/rob-leverage/helpers.ts +424 -0
  63. package/src/contracts/{leverage → rob-leverage}/transactions.ts +68 -48
  64. package/src/contracts/stability-pool/helpers.ts +714 -230
  65. package/src/contracts/stability-pool/scripts.ts +20 -15
  66. package/src/contracts/stability-pool/transactions.ts +628 -496
  67. package/src/contracts/stability-pool/types-new.ts +247 -100
  68. package/src/contracts/stability-pool/types.ts +5 -22
  69. package/src/contracts/stableswap/helpers.ts +22 -0
  70. package/src/contracts/stableswap/scripts.ts +37 -0
  71. package/src/contracts/stableswap/transactions.ts +647 -0
  72. package/src/contracts/stableswap/types-new.ts +131 -0
  73. package/src/contracts/stableswap/types.ts +17 -0
  74. package/src/contracts/staking/helpers.ts +49 -34
  75. package/src/contracts/staking/scripts.ts +1 -1
  76. package/src/contracts/staking/transactions.ts +85 -130
  77. package/src/contracts/staking/types-new.ts +60 -28
  78. package/src/contracts/staking/types.ts +1 -28
  79. package/src/contracts/treasury/helpers.ts +21 -0
  80. package/src/contracts/treasury/scripts.ts +16 -26
  81. package/src/contracts/treasury/transactions.ts +256 -27
  82. package/src/contracts/treasury/types-new.ts +69 -0
  83. package/src/contracts/treasury/types.ts +2 -43
  84. package/src/contracts/version-registry/scripts.ts +2 -2
  85. package/src/contracts/version-registry/types-new.ts +6 -7
  86. package/src/index.ts +37 -20
  87. package/src/scripts/auth-token-policy.ts +3 -2
  88. package/src/scripts/iasset-policy.ts +3 -2
  89. package/src/types/evolution-schema-options.ts +3 -3
  90. package/src/types/generic.ts +17 -89
  91. package/src/types/multisig.ts +48 -0
  92. package/src/types/on-chain-decimal.ts +14 -7
  93. package/src/types/rational.ts +61 -0
  94. package/src/types/system-params.ts +237 -41
  95. package/src/utils/array-utils.ts +70 -1
  96. package/src/utils/bigint-utils.ts +12 -0
  97. package/src/utils/indigo-helpers.ts +8 -10
  98. package/src/utils/lucid-utils.ts +47 -40
  99. package/src/utils/oracle-helpers.ts +62 -0
  100. package/src/utils/pyth/decode.ts +223 -0
  101. package/src/utils/pyth/encode.ts +262 -0
  102. package/src/utils/pyth/index.ts +14 -0
  103. package/src/utils/pyth/types.ts +87 -0
  104. package/src/validators/always-succeed-validator.ts +6 -0
  105. package/src/validators/cdp-creator-validator.ts +2 -2
  106. package/src/validators/cdp-redeem-validator.ts +7 -0
  107. package/src/validators/cdp-validator.ts +2 -2
  108. package/src/validators/collector-validator.ts +2 -2
  109. package/src/validators/execute-validator.ts +2 -2
  110. package/src/validators/governance-validator.ts +2 -2
  111. package/src/validators/iasset-validator.ts +7 -0
  112. package/src/validators/interest-collection-validator.ts +7 -0
  113. package/src/validators/interest-oracle-validator.ts +2 -2
  114. package/src/validators/poll-manager-validator.ts +2 -2
  115. package/src/validators/poll-shard-validator.ts +2 -2
  116. package/src/validators/price-oracle-validator.ts +7 -0
  117. package/src/validators/pyth-feed-validator.ts +7 -0
  118. package/src/validators/rob-validator.ts +7 -0
  119. package/src/validators/stability-pool-validator.ts +2 -2
  120. package/src/validators/stableswap-validator.ts +7 -0
  121. package/src/validators/staking-validator.ts +2 -2
  122. package/src/validators/treasury-validator.ts +2 -2
  123. package/src/validators/version-record-policy.ts +2 -2
  124. package/src/validators/version-registry-validator.ts +2 -2
  125. package/tests/always-succeed/script.ts +7 -0
  126. package/tests/bigint-utils.test.ts +41 -0
  127. package/tests/cdp/actions.ts +610 -0
  128. package/tests/cdp/cdp-helpers.ts +55 -0
  129. package/tests/cdp/cdp-queries.ts +440 -0
  130. package/tests/cdp/cdp.test.ts +6087 -0
  131. package/tests/cdp/transactions-mutated.ts +1729 -0
  132. package/tests/data/system-params.json +177 -34
  133. package/tests/datums.test.ts +209 -210
  134. package/tests/endpoints/initialize.ts +68 -0
  135. package/tests/endpoints/interest-collector.ts +37 -0
  136. package/tests/endpoints/treasury.ts +70 -0
  137. package/tests/gov/actions.ts +406 -0
  138. package/tests/gov/gov.test.ts +4450 -0
  139. package/tests/{queries → gov}/governance-queries.ts +6 -3
  140. package/tests/hash-checks.test.ts +38 -11
  141. package/tests/indigo-test-helpers.ts +100 -0
  142. package/tests/initialize.test.ts +61 -9
  143. package/tests/interest-collection/interest-collection.test.ts +892 -0
  144. package/tests/interest-collection/interest-collector-queries.ts +49 -0
  145. package/tests/interest-collection/transactions-mutated.ts +260 -0
  146. package/tests/interest-oracle.test.ts +43 -35
  147. package/tests/mock/assets-mock.ts +234 -23
  148. package/tests/mock/protocol-params-mock.ts +21 -0
  149. package/tests/price-oracle/actions.ts +163 -0
  150. package/tests/price-oracle/price-oracle-queries.ts +12 -0
  151. package/tests/price-oracle/price-oracle.test.ts +240 -0
  152. package/tests/price-oracle/transactions-mutated.ts +62 -0
  153. package/tests/pyth/endpoints.ts +96 -0
  154. package/tests/pyth/helpers.ts +37 -0
  155. package/tests/pyth/pyth-encoding.test.ts +376 -0
  156. package/tests/pyth/pyth-indigo.test.ts +509 -0
  157. package/tests/pyth/pyth.test.ts +300 -0
  158. package/tests/queries/execute-queries.ts +6 -5
  159. package/tests/queries/iasset-queries.ts +175 -5
  160. package/tests/queries/interest-oracle-queries.ts +4 -2
  161. package/tests/queries/poll-queries.ts +8 -9
  162. package/tests/queries/stability-pool-queries.ts +95 -48
  163. package/tests/queries/staking-queries.ts +4 -2
  164. package/tests/queries/treasury-queries.ts +80 -5
  165. package/tests/rob/actions.ts +58 -0
  166. package/tests/{lrp-leverage.test.ts → rob/rob-leverage.test.ts} +393 -296
  167. package/tests/rob/rob-queries.ts +95 -0
  168. package/tests/rob/rob.test.ts +3762 -0
  169. package/tests/rob/transactions-mutated.ts +853 -0
  170. package/tests/script-size.test.ts +240 -0
  171. package/tests/setup.ts +135 -0
  172. package/tests/stability-pool/actions.ts +220 -0
  173. package/tests/stability-pool.test.ts +6121 -667
  174. package/tests/stableswap/stableswap-actions.ts +84 -0
  175. package/tests/stableswap/stableswap-queries.ts +89 -0
  176. package/tests/stableswap/stableswap.test.ts +3891 -0
  177. package/tests/stableswap/transactions-mutated.ts +348 -0
  178. package/tests/staking.test.ts +82 -99
  179. package/tests/test-helpers.ts +58 -11
  180. package/tests/treasury.test.ts +242 -0
  181. package/tests/utils/asserts.ts +74 -0
  182. package/tests/utils/benchmark-utils.ts +81 -0
  183. package/tests/utils/index.ts +122 -4
  184. package/tsconfig.json +9 -1
  185. package/vitest.config.ts +3 -1
  186. package/src/contracts/collector/types.ts +0 -16
  187. package/src/contracts/initialize/transactions.ts +0 -891
  188. package/src/contracts/leverage/helpers.ts +0 -424
  189. package/src/contracts/lrp/helpers.ts +0 -294
  190. package/src/contracts/lrp/scripts.ts +0 -27
  191. package/src/contracts/lrp/transactions.ts +0 -250
  192. package/src/contracts/lrp/types.ts +0 -131
  193. package/src/contracts/poll/types-poll.ts +0 -88
  194. package/src/contracts/vesting/helpers.ts +0 -218
  195. package/src/utils/value-helpers.ts +0 -37
  196. package/src/validators/lrp-validator.ts +0 -7
  197. package/tests/cdp.test.ts +0 -1528
  198. package/tests/gov.test.ts +0 -2011
  199. package/tests/lrp.test.ts +0 -673
  200. package/tests/queries/cdp-queries.ts +0 -220
  201. package/tests/queries/lrp-queries.ts +0 -76
  202. package/tests/queries/price-oracle-queries.ts +0 -10
@@ -0,0 +1,4450 @@
1
+ import {
2
+ addAssets,
3
+ Emulator,
4
+ EmulatorAccount,
5
+ generateEmulatorAccount,
6
+ Lucid,
7
+ toText,
8
+ fromHex,
9
+ fromText,
10
+ paymentCredentialOf,
11
+ toHex,
12
+ unixTimeToSlot,
13
+ } from '@lucid-evolution/lucid';
14
+ import { describe, beforeEach, test, expect, assert } from 'vitest';
15
+ import {
16
+ AssetClass,
17
+ assetClassToUnit,
18
+ assetClassValueOf,
19
+ isSameAssetClass,
20
+ mkAssetsOf,
21
+ mkLovelacesOf,
22
+ } from '@3rd-eye-labs/cardano-offchain-common';
23
+ import { init } from '../endpoints/initialize';
24
+ import { findGov } from '../gov/governance-queries';
25
+ import {
26
+ addrDetails,
27
+ adjustStakingPosition,
28
+ createProposal,
29
+ createScriptAddress,
30
+ createShardsChunks,
31
+ endProposal,
32
+ executeProposal,
33
+ fromSystemParamsAsset,
34
+ matchSingle,
35
+ mergeShards,
36
+ ONE_DAY,
37
+ openStakingPosition,
38
+ startInterestOracle,
39
+ treasuryPrepareWithdrawal,
40
+ vote,
41
+ } from '../../src';
42
+
43
+ import {
44
+ findAllPollShards,
45
+ findPollManager,
46
+ findRandomPollShard,
47
+ } from '../queries/poll-queries';
48
+ import { findStakingPosition } from '../queries/staking-queries';
49
+ import {
50
+ option as O,
51
+ readonlyArray as RA,
52
+ task as T,
53
+ array as A,
54
+ function as F,
55
+ number as N,
56
+ } from 'fp-ts';
57
+ import { findExecute } from '../queries/execute-queries';
58
+ import {
59
+ getNewUtxosAtAddressAfterAction,
60
+ getValueChangeAtAddressAfterAction,
61
+ } from '../utils';
62
+ import { iusdInitialAssetCfg } from '../mock/assets-mock';
63
+ import { addressFromBech32 } from '@3rd-eye-labs/cardano-offchain-common';
64
+ import {
65
+ EXAMPLE_TOKEN_1,
66
+ EXAMPLE_TOKEN_2,
67
+ EXAMPLE_TOKEN_3,
68
+ MAINNET_PROTOCOL_PARAMETERS,
69
+ } from '../indigo-test-helpers';
70
+ import { benchmarkAndAwaitTx } from '../utils/benchmark-utils';
71
+ import {
72
+ findAllTreasuryUtxos,
73
+ findAllTreasuryUtxosWithNonAdaAsset,
74
+ } from '../queries/treasury-queries';
75
+ import {
76
+ createIndyUtxoAtTreasury,
77
+ createUtxoAtTreasury,
78
+ } from '../endpoints/treasury';
79
+ import { findRandomCdpCreator, findStableswapPool } from '../cdp/cdp-queries';
80
+ import {
81
+ runCreateAllShards,
82
+ runEndProposal,
83
+ runMergeAllShards,
84
+ runVote,
85
+ waitForVotingEnd,
86
+ } from './actions';
87
+ import {
88
+ LucidContext,
89
+ runAndAwaitTx,
90
+ runAndAwaitTxBuilder,
91
+ } from '../test-helpers';
92
+ import {
93
+ findAllCollateralAssetsOfIAsset,
94
+ findAllIAssets,
95
+ findCollateralAssetNew,
96
+ findIAsset,
97
+ } from '../queries/iasset-queries';
98
+ import { startPriceOracleTx } from '../../src/contracts/price-oracle/transactions';
99
+ import { rationalFromInt, rationalZero } from '../../src/types/rational';
100
+
101
+ type MyContext = LucidContext<{
102
+ admin: EmulatorAccount;
103
+ user: EmulatorAccount;
104
+ withdrawalAccount: EmulatorAccount;
105
+ }>;
106
+
107
+ describe('Gov', () => {
108
+ beforeEach<MyContext>(async (context: MyContext) => {
109
+ context.users = {
110
+ admin: generateEmulatorAccount({
111
+ lovelace: BigInt(100_000_000_000_000),
112
+ }),
113
+ user: generateEmulatorAccount(
114
+ addAssets(
115
+ mkLovelacesOf(150_000_000n),
116
+ mkAssetsOf(EXAMPLE_TOKEN_1, 1_000_000_000_000_000n),
117
+ mkAssetsOf(EXAMPLE_TOKEN_2, 1_000_000_000_000_000n),
118
+ mkAssetsOf(EXAMPLE_TOKEN_3, 1_000_000_000_000_000n),
119
+ ),
120
+ ),
121
+ withdrawalAccount: generateEmulatorAccount({}),
122
+ };
123
+
124
+ context.emulator = new Emulator(
125
+ [context.users.admin, context.users.user],
126
+ MAINNET_PROTOCOL_PARAMETERS,
127
+ );
128
+ context.lucid = await Lucid(context.emulator, 'Custom');
129
+ });
130
+
131
+ test<MyContext>('Create text proposal', async (context: MyContext) => {
132
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
133
+
134
+ const [sysParams, __] = await init(
135
+ context.lucid,
136
+ [iusdInitialAssetCfg()],
137
+ context.emulator.slot,
138
+ );
139
+
140
+ const govUtxo = await findGov(
141
+ context.lucid,
142
+ sysParams.validatorHashes.govHash,
143
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
144
+ );
145
+
146
+ const [tx, _] = await createProposal(
147
+ { TextProposal: fromHex(fromText('smth')) },
148
+ null,
149
+ sysParams,
150
+ context.lucid,
151
+ context.emulator.slot,
152
+ govUtxo.utxo,
153
+ [],
154
+ );
155
+
156
+ await benchmarkAndAwaitTx(
157
+ 'Gov - Create text proposal',
158
+ tx,
159
+ context.lucid,
160
+ context.emulator,
161
+ );
162
+ });
163
+
164
+ test<MyContext>('Create text proposal with shards', async (context: MyContext) => {
165
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
166
+
167
+ const [sysParams, _] = await init(
168
+ context.lucid,
169
+ [iusdInitialAssetCfg()],
170
+ context.emulator.slot,
171
+ );
172
+
173
+ const govUtxo = await findGov(
174
+ context.lucid,
175
+ sysParams.validatorHashes.govHash,
176
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
177
+ );
178
+
179
+ const [tx, pollId] = await createProposal(
180
+ { TextProposal: fromHex(fromText('smth')) },
181
+ null,
182
+ sysParams,
183
+ context.lucid,
184
+ context.emulator.slot,
185
+ govUtxo.utxo,
186
+ [],
187
+ );
188
+
189
+ await runAndAwaitTxBuilder(context.lucid, tx);
190
+
191
+ // Create all shards in one transaction.
192
+ {
193
+ const govUtxo = await findGov(
194
+ context.lucid,
195
+ sysParams.validatorHashes.govHash,
196
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
197
+ );
198
+
199
+ const pollUtxo = await findPollManager(
200
+ context.lucid,
201
+ sysParams.validatorHashes.pollManagerHash,
202
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
203
+ pollId,
204
+ );
205
+
206
+ await benchmarkAndAwaitTx(
207
+ `Gov - Create ${govUtxo.datum.protocolParams.totalShards} shards`,
208
+ await createShardsChunks(
209
+ govUtxo.datum.protocolParams.totalShards,
210
+ pollUtxo.utxo,
211
+ sysParams,
212
+ context.emulator.slot,
213
+ context.lucid,
214
+ ),
215
+ context.lucid,
216
+ context.emulator,
217
+ );
218
+ }
219
+
220
+ const pollUtxo = await findPollManager(
221
+ context.lucid,
222
+ sysParams.validatorHashes.pollManagerHash,
223
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
224
+ pollId,
225
+ );
226
+
227
+ expect(
228
+ pollUtxo.datum.createdShardsCount === pollUtxo.datum.totalShardsCount,
229
+ 'Expected total shards count being created',
230
+ ).toBeTruthy();
231
+ });
232
+
233
+ test<MyContext>('Merge proposal shards', async (context: MyContext) => {
234
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
235
+
236
+ const [sysParams, _] = await init(
237
+ context.lucid,
238
+ [iusdInitialAssetCfg()],
239
+ context.emulator.slot,
240
+ );
241
+
242
+ const govUtxo = await findGov(
243
+ context.lucid,
244
+ sysParams.validatorHashes.govHash,
245
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
246
+ );
247
+
248
+ const [tx, pollId] = await createProposal(
249
+ { TextProposal: fromHex(fromText('smth')) },
250
+ null,
251
+ sysParams,
252
+ context.lucid,
253
+ context.emulator.slot,
254
+ govUtxo.utxo,
255
+ [],
256
+ );
257
+
258
+ await runAndAwaitTxBuilder(context.lucid, tx);
259
+
260
+ {
261
+ const pollUtxo = await findPollManager(
262
+ context.lucid,
263
+ sysParams.validatorHashes.pollManagerHash,
264
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
265
+ pollId,
266
+ );
267
+
268
+ await runAndAwaitTx(
269
+ context.lucid,
270
+ createShardsChunks(
271
+ 2n,
272
+ pollUtxo.utxo,
273
+ sysParams,
274
+ context.emulator.slot,
275
+ context.lucid,
276
+ ),
277
+ );
278
+
279
+ const targetSlot = unixTimeToSlot(
280
+ context.lucid.config().network!,
281
+ Number(pollUtxo.datum.votingEndTime),
282
+ );
283
+ expect(targetSlot).toBeGreaterThan(context.emulator.slot);
284
+
285
+ context.emulator.awaitSlot(targetSlot - context.emulator.slot + 1);
286
+ }
287
+
288
+ {
289
+ const pollUtxo = await findPollManager(
290
+ context.lucid,
291
+ sysParams.validatorHashes.pollManagerHash,
292
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
293
+ pollId,
294
+ );
295
+
296
+ const allPollShards = await findAllPollShards(
297
+ context.lucid,
298
+ sysParams.validatorHashes.pollShardHash,
299
+ fromSystemParamsAsset(sysParams.pollShardParams.pollToken),
300
+ pollUtxo.datum.pollId,
301
+ );
302
+
303
+ assert(allPollShards.length === 2);
304
+
305
+ await benchmarkAndAwaitTx(
306
+ `Gov - Merge ${allPollShards.length} shards`,
307
+ await mergeShards(
308
+ pollUtxo.utxo,
309
+ allPollShards.map((u) => u.utxo),
310
+ sysParams,
311
+ context.lucid,
312
+ context.emulator.slot,
313
+ ),
314
+ context.lucid,
315
+ context.emulator,
316
+ );
317
+ }
318
+
319
+ const pollUtxo = await findPollManager(
320
+ context.lucid,
321
+ sysParams.validatorHashes.pollManagerHash,
322
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
323
+ pollId,
324
+ );
325
+
326
+ assert(pollUtxo.datum.talliedShardsCount === 2n);
327
+ });
328
+
329
+ test<MyContext>('Create propose iasset proposal', async (context: MyContext) => {
330
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
331
+
332
+ const [sysParams, ___] = await init(
333
+ context.lucid,
334
+ [iusdInitialAssetCfg()],
335
+ context.emulator.slot,
336
+ );
337
+
338
+ const govUtxo = await findGov(
339
+ context.lucid,
340
+ sysParams.validatorHashes.govHash,
341
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
342
+ );
343
+
344
+ const allIassetOrefs = (
345
+ await findAllIAssets(
346
+ context.lucid,
347
+ sysParams.validatorHashes.iassetHash,
348
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
349
+ )
350
+ ).map((iasset) => iasset.utxo);
351
+
352
+ const [tx, __] = await createProposal(
353
+ {
354
+ ProposeIAsset: {
355
+ asset: fromHex(fromText('iBTC')),
356
+ debtMintingFeeRatio: { numerator: 5n, denominator: 1_000n },
357
+ liquidationProcessingFeeRatio: { numerator: 2n, denominator: 100n },
358
+ stabilityPoolWithdrawalFeeRatio: {
359
+ numerator: 5n,
360
+ denominator: 1_000n,
361
+ },
362
+ redemptionReimbursementRatio: { numerator: 1n, denominator: 100n },
363
+ redemptionProcessingFeeRatio: { numerator: 1n, denominator: 100n },
364
+ },
365
+ },
366
+ null,
367
+ sysParams,
368
+ context.lucid,
369
+ context.emulator.slot,
370
+ govUtxo.utxo,
371
+ allIassetOrefs,
372
+ );
373
+
374
+ await benchmarkAndAwaitTx(
375
+ 'Gov - Create iasset proposal',
376
+ tx,
377
+ context.lucid,
378
+ context.emulator,
379
+ );
380
+ });
381
+
382
+ test<MyContext>('Create modify iasset proposal', async (context: MyContext) => {
383
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
384
+
385
+ const [sysParams, ___] = await init(
386
+ context.lucid,
387
+ [iusdInitialAssetCfg()],
388
+ context.emulator.slot,
389
+ );
390
+
391
+ const govUtxo = await findGov(
392
+ context.lucid,
393
+ sysParams.validatorHashes.govHash,
394
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
395
+ );
396
+
397
+ const allIassetOrefs = (
398
+ await findAllIAssets(
399
+ context.lucid,
400
+ sysParams.validatorHashes.iassetHash,
401
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
402
+ )
403
+ ).map((iasset) => iasset.utxo);
404
+
405
+ const [tx, __] = await createProposal(
406
+ {
407
+ ModifyIAsset: {
408
+ asset: fromHex(fromText('iBTC')),
409
+ newDebtMintingFeeRatio: rationalZero,
410
+ newLiquidationProcessingFeeRatio: {
411
+ numerator: 2n,
412
+ denominator: 100n,
413
+ },
414
+ newStabilityPoolWithdrawalFeeRatio: {
415
+ numerator: 5n,
416
+ denominator: 1_000n,
417
+ },
418
+ newRedemptionReimbursementRatio: { numerator: 1n, denominator: 100n },
419
+ newRedemptionProcessingFeeRatio: { numerator: 1n, denominator: 100n },
420
+ },
421
+ },
422
+ null,
423
+ sysParams,
424
+ context.lucid,
425
+ context.emulator.slot,
426
+ govUtxo.utxo,
427
+ allIassetOrefs,
428
+ );
429
+
430
+ await benchmarkAndAwaitTx(
431
+ 'Gov - Create modify iasset proposal',
432
+ tx,
433
+ context.lucid,
434
+ context.emulator,
435
+ );
436
+ });
437
+
438
+ test<MyContext>('Create add collateral asset proposal', async (context: MyContext) => {
439
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
440
+
441
+ const [sysParams, [iusdAssetInfo]] = await init(
442
+ context.lucid,
443
+ [iusdInitialAssetCfg()],
444
+ context.emulator.slot,
445
+ );
446
+
447
+ const [pkh, _] = await addrDetails(context.lucid);
448
+
449
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
450
+ 0n,
451
+ 0n,
452
+ 0n,
453
+ {
454
+ biasTime: 120_000n,
455
+ owner: pkh.hash,
456
+ },
457
+ context.lucid,
458
+ );
459
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
460
+
461
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
462
+ context.lucid,
463
+ 'IUSD_INDY_ORACLE',
464
+ rationalFromInt(1n),
465
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
466
+ context.emulator.slot,
467
+ );
468
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
469
+
470
+ const govUtxo = await findGov(
471
+ context.lucid,
472
+ sysParams.validatorHashes.govHash,
473
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
474
+ );
475
+
476
+ const allIassetOrefs = (
477
+ await findAllIAssets(
478
+ context.lucid,
479
+ sysParams.validatorHashes.iassetHash,
480
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
481
+ )
482
+ ).map((iasset) => iasset.utxo);
483
+
484
+ const [tx, __] = await createProposal(
485
+ {
486
+ AddCollateralAsset: {
487
+ correspondingIAsset: fromHex(
488
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
489
+ ),
490
+ collateralAsset: fromSystemParamsAsset(sysParams.govParams.indyAsset),
491
+ assetExtraDecimals: 0n,
492
+ assetPriceInfo: { OracleNft: priceOranceNft },
493
+ interestOracleNft: interestOracleNft,
494
+ redemptionRatio: rationalFromInt(2n),
495
+ maintenanceRatio: { numerator: 150n, denominator: 100n },
496
+ liquidationRatio: { numerator: 120n, denominator: 100n },
497
+ minCollateralAmt: 1_000_000n,
498
+ },
499
+ },
500
+ null,
501
+ sysParams,
502
+ context.lucid,
503
+ context.emulator.slot,
504
+ govUtxo.utxo,
505
+ allIassetOrefs,
506
+ );
507
+
508
+ await benchmarkAndAwaitTx(
509
+ 'Gov - Create collateral asset proposal',
510
+ tx,
511
+ context.lucid,
512
+ context.emulator,
513
+ );
514
+ });
515
+
516
+ test<MyContext>('Create update collateral asset proposal', async (context: MyContext) => {
517
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
518
+
519
+ const [sysParams, [iusdAssetInfo]] = await init(
520
+ context.lucid,
521
+ [iusdInitialAssetCfg()],
522
+ context.emulator.slot,
523
+ );
524
+
525
+ const [pkh, _] = await addrDetails(context.lucid);
526
+
527
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
528
+ 0n,
529
+ 0n,
530
+ 0n,
531
+ {
532
+ biasTime: 120_000n,
533
+ owner: pkh.hash,
534
+ },
535
+ context.lucid,
536
+ );
537
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
538
+
539
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
540
+ context.lucid,
541
+ 'NEW_IUSD_ADA_ORACLE',
542
+ rationalFromInt(1n),
543
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
544
+ context.emulator.slot,
545
+ );
546
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
547
+
548
+ const govUtxo = await findGov(
549
+ context.lucid,
550
+ sysParams.validatorHashes.govHash,
551
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
552
+ );
553
+
554
+ const allIassetOrefs = (
555
+ await findAllIAssets(
556
+ context.lucid,
557
+ sysParams.validatorHashes.iassetHash,
558
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
559
+ )
560
+ ).map((iasset) => iasset.utxo);
561
+
562
+ const [tx, __] = await createProposal(
563
+ {
564
+ UpdateCollateralAsset: {
565
+ correspondingIAsset: fromHex(
566
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
567
+ ),
568
+ collateralAsset: iusdAssetInfo.collateralAssets[0].collateralAsset,
569
+ newAssetExtraDecimals: 0n,
570
+ newAssetPriceInfo: { OracleNft: priceOranceNft },
571
+ newInterestOracleNft: interestOracleNft,
572
+ newLiquidationRatio: { numerator: 120n, denominator: 100n },
573
+ newMaintenanceRatio: { numerator: 150n, denominator: 100n },
574
+ newRedemptionRatio: { numerator: 150n, denominator: 100n },
575
+ newMinCollateralAmt: 10_000_000n,
576
+ },
577
+ },
578
+ null,
579
+ sysParams,
580
+ context.lucid,
581
+ context.emulator.slot,
582
+ govUtxo.utxo,
583
+ allIassetOrefs,
584
+ );
585
+
586
+ await benchmarkAndAwaitTx(
587
+ 'Gov - Create update collateral asset proposal',
588
+ tx,
589
+ context.lucid,
590
+ context.emulator,
591
+ );
592
+ });
593
+
594
+ test<MyContext>('Vote on proposal', async (context: MyContext) => {
595
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
596
+
597
+ const [sysParams, __] = await init(
598
+ context.lucid,
599
+ [iusdInitialAssetCfg()],
600
+ context.emulator.slot,
601
+ );
602
+
603
+ const govUtxo = await findGov(
604
+ context.lucid,
605
+ sysParams.validatorHashes.govHash,
606
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
607
+ );
608
+
609
+ const [tx, pollId] = await createProposal(
610
+ { TextProposal: fromHex(fromText('smth')) },
611
+ null,
612
+ sysParams,
613
+ context.lucid,
614
+ context.emulator.slot,
615
+ govUtxo.utxo,
616
+ [],
617
+ );
618
+
619
+ await runAndAwaitTxBuilder(context.lucid, tx);
620
+
621
+ await runCreateAllShards(pollId, sysParams, context);
622
+
623
+ await runAndAwaitTx(
624
+ context.lucid,
625
+ openStakingPosition(1_000_000n, sysParams, context.lucid),
626
+ );
627
+
628
+ const [pkh, _] = await addrDetails(context.lucid);
629
+
630
+ const stakingPosOref = await findStakingPosition(
631
+ context.lucid,
632
+ sysParams.validatorHashes.stakingHash,
633
+ fromSystemParamsAsset(sysParams.stakingParams.stakingToken),
634
+ pkh.hash,
635
+ );
636
+
637
+ const pollShard = await findRandomPollShard(
638
+ context.lucid,
639
+ sysParams.validatorHashes.pollShardHash,
640
+ fromSystemParamsAsset(sysParams.pollShardParams.pollToken),
641
+ pollId,
642
+ );
643
+
644
+ await benchmarkAndAwaitTx(
645
+ 'Gov - Vote on proposal',
646
+ await vote(
647
+ 'Yes',
648
+ pollShard.utxo,
649
+ stakingPosOref.utxo,
650
+ sysParams,
651
+ context.lucid,
652
+ context.emulator.slot,
653
+ ),
654
+ context.lucid,
655
+ context.emulator,
656
+ );
657
+ });
658
+
659
+ test<MyContext>('Vote on proposal, then deposit more INDY', async (context: MyContext) => {
660
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
661
+
662
+ const [sysParams, __] = await init(
663
+ context.lucid,
664
+ [iusdInitialAssetCfg()],
665
+ context.emulator.slot,
666
+ );
667
+
668
+ const govUtxo = await findGov(
669
+ context.lucid,
670
+ sysParams.validatorHashes.govHash,
671
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
672
+ );
673
+
674
+ const [tx, pollId] = await createProposal(
675
+ { TextProposal: fromHex(fromText('smth')) },
676
+ null,
677
+ sysParams,
678
+ context.lucid,
679
+ context.emulator.slot,
680
+ govUtxo.utxo,
681
+ [],
682
+ );
683
+
684
+ await runAndAwaitTxBuilder(context.lucid, tx);
685
+
686
+ await runCreateAllShards(pollId, sysParams, context);
687
+
688
+ await runAndAwaitTx(
689
+ context.lucid,
690
+ openStakingPosition(1_000_000n, sysParams, context.lucid),
691
+ );
692
+
693
+ await runVote(pollId, 'Yes', sysParams, context);
694
+
695
+ const [pkh, _skh] = await addrDetails(context.lucid);
696
+ const stakingPosUtxo = await findStakingPosition(
697
+ context.lucid,
698
+ sysParams.validatorHashes.stakingHash,
699
+ fromSystemParamsAsset(sysParams.stakingParams.stakingToken),
700
+ pkh.hash,
701
+ );
702
+
703
+ context.emulator.awaitSlot(60);
704
+
705
+ await runAndAwaitTx(
706
+ context.lucid,
707
+ adjustStakingPosition(
708
+ stakingPosUtxo.utxo,
709
+ 500_000_000n,
710
+ sysParams,
711
+ context.lucid,
712
+ context.emulator.slot,
713
+ ),
714
+ );
715
+ });
716
+
717
+ test<MyContext>('Vote on 2 proposals sequentially (lower pollID first)', async (context: MyContext) => {
718
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
719
+
720
+ const [sysParams, __] = await init(
721
+ context.lucid,
722
+ [iusdInitialAssetCfg()],
723
+ context.emulator.slot,
724
+ );
725
+
726
+ await runAndAwaitTx(
727
+ context.lucid,
728
+ openStakingPosition(1_000_000n, sysParams, context.lucid),
729
+ );
730
+ const [pkh, _] = await addrDetails(context.lucid);
731
+
732
+ // Create proposals
733
+ const createProposalsTask = F.pipe(
734
+ [fromHex(fromText('proposal 1')), fromHex(fromText('proposal 2'))].map(
735
+ (txtContent): T.Task<bigint> => {
736
+ return async () => {
737
+ const govUtxo = await findGov(
738
+ context.lucid,
739
+ sysParams.validatorHashes.govHash,
740
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
741
+ );
742
+
743
+ const [tx, pollId] = await createProposal(
744
+ { TextProposal: txtContent },
745
+ null,
746
+ sysParams,
747
+ context.lucid,
748
+ context.emulator.slot,
749
+ govUtxo.utxo,
750
+ [],
751
+ );
752
+
753
+ await runAndAwaitTxBuilder(context.lucid, tx);
754
+
755
+ await runCreateAllShards(pollId, sysParams, context);
756
+
757
+ return pollId;
758
+ };
759
+ },
760
+ ),
761
+ T.sequenceSeqArray,
762
+ );
763
+
764
+ const pollIds = await createProposalsTask();
765
+
766
+ // vote on each proposal
767
+ const voteEachProposalTask = F.pipe(
768
+ pollIds.map(
769
+ (pollId): T.Task<void> =>
770
+ async () => {
771
+ await runVote(
772
+ pollId,
773
+ Number(pollId) % 2 == 0 ? 'Yes' : 'No',
774
+ sysParams,
775
+ context,
776
+ );
777
+ },
778
+ ),
779
+ T.sequenceSeqArray,
780
+ );
781
+
782
+ await voteEachProposalTask();
783
+
784
+ const stakingPosUtxo = await findStakingPosition(
785
+ context.lucid,
786
+ sysParams.validatorHashes.stakingHash,
787
+ fromSystemParamsAsset(sysParams.stakingParams.stakingToken),
788
+ pkh.hash,
789
+ );
790
+
791
+ expect([...stakingPosUtxo.datum.lockedAmount.map((x) => x[0])]).toEqual([
792
+ 1n,
793
+ 2n,
794
+ ]);
795
+ });
796
+
797
+ test<MyContext>('Vote on 2 proposals in reverse (higher pollID first), both yes and no votes', async (context: MyContext) => {
798
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
799
+
800
+ const [sysParams, __] = await init(
801
+ context.lucid,
802
+ [iusdInitialAssetCfg()],
803
+ context.emulator.slot,
804
+ );
805
+
806
+ await runAndAwaitTx(
807
+ context.lucid,
808
+ openStakingPosition(1_000_000n, sysParams, context.lucid),
809
+ );
810
+ const [pkh, _] = await addrDetails(context.lucid);
811
+
812
+ // Create proposals
813
+ const createProposalsTask = F.pipe(
814
+ [fromHex(fromText('proposal 1')), fromHex(fromText('proposal 2'))].map(
815
+ (txtContent): T.Task<bigint> => {
816
+ return async () => {
817
+ const govUtxo = await findGov(
818
+ context.lucid,
819
+ sysParams.validatorHashes.govHash,
820
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
821
+ );
822
+
823
+ const [tx, pollId] = await createProposal(
824
+ { TextProposal: txtContent },
825
+ null,
826
+ sysParams,
827
+ context.lucid,
828
+ context.emulator.slot,
829
+ govUtxo.utxo,
830
+ [],
831
+ );
832
+
833
+ await runAndAwaitTxBuilder(context.lucid, tx);
834
+
835
+ await runCreateAllShards(pollId, sysParams, context);
836
+
837
+ return pollId;
838
+ };
839
+ },
840
+ ),
841
+ T.sequenceSeqArray,
842
+ );
843
+
844
+ const pollIdsDescending = F.pipe(
845
+ await createProposalsTask(),
846
+ RA.toArray, // Sort it from high to low
847
+ A.map(Number),
848
+ A.sort(N.Ord),
849
+ A.map(BigInt),
850
+ A.reverse,
851
+ );
852
+
853
+ // vote on each proposal
854
+ const voteEachProposalTask = F.pipe(
855
+ pollIdsDescending.map(
856
+ (pollId): T.Task<void> =>
857
+ async () => {
858
+ await runVote(
859
+ pollId,
860
+ Number(pollId) % 2 == 0 ? 'Yes' : 'No',
861
+ sysParams,
862
+ context,
863
+ );
864
+ },
865
+ ),
866
+ T.sequenceSeqArray,
867
+ );
868
+
869
+ await voteEachProposalTask();
870
+
871
+ const stakingPosUtxo = await findStakingPosition(
872
+ context.lucid,
873
+ sysParams.validatorHashes.stakingHash,
874
+ fromSystemParamsAsset(sysParams.stakingParams.stakingToken),
875
+ pkh.hash,
876
+ );
877
+
878
+ expect([...stakingPosUtxo.datum.lockedAmount.map((x) => x[0])]).toEqual([
879
+ 2n,
880
+ 1n,
881
+ ]);
882
+ });
883
+
884
+ test<MyContext>('End passed proposal', async (context: MyContext) => {
885
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
886
+
887
+ const [sysParams, _] = await init(
888
+ context.lucid,
889
+ [iusdInitialAssetCfg()],
890
+ context.emulator.slot,
891
+ );
892
+
893
+ const [tx, pollId] = await createProposal(
894
+ { TextProposal: fromHex(fromText('smth')) },
895
+ null,
896
+ sysParams,
897
+ context.lucid,
898
+ context.emulator.slot,
899
+ (
900
+ await findGov(
901
+ context.lucid,
902
+ sysParams.validatorHashes.govHash,
903
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
904
+ )
905
+ ).utxo,
906
+ [],
907
+ );
908
+
909
+ await runAndAwaitTxBuilder(context.lucid, tx);
910
+
911
+ await runCreateAllShards(pollId, sysParams, context);
912
+
913
+ await runAndAwaitTx(
914
+ context.lucid,
915
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
916
+ );
917
+
918
+ await runVote(pollId, 'Yes', sysParams, context);
919
+
920
+ await waitForVotingEnd(pollId, sysParams, context);
921
+
922
+ await runMergeAllShards(pollId, sysParams, context);
923
+
924
+ {
925
+ const pollUtxo = await findPollManager(
926
+ context.lucid,
927
+ sysParams.validatorHashes.pollManagerHash,
928
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
929
+ pollId,
930
+ );
931
+
932
+ const govUtxo = await findGov(
933
+ context.lucid,
934
+ sysParams.validatorHashes.govHash,
935
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
936
+ );
937
+
938
+ await benchmarkAndAwaitTx(
939
+ 'Gov - End proposal',
940
+ await endProposal(
941
+ pollUtxo.utxo,
942
+ govUtxo.utxo,
943
+ sysParams,
944
+ context.lucid,
945
+ context.emulator.slot,
946
+ ),
947
+ context.lucid,
948
+ context.emulator,
949
+ );
950
+ }
951
+
952
+ await expect(
953
+ findExecute(
954
+ context.lucid,
955
+ sysParams.validatorHashes.executeHash,
956
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
957
+ pollId,
958
+ ),
959
+ ).resolves.toBeDefined();
960
+ });
961
+
962
+ test<MyContext>('End failed proposal', async (context: MyContext) => {
963
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
964
+
965
+ const [sysParams, __] = await init(
966
+ context.lucid,
967
+ [iusdInitialAssetCfg()],
968
+ context.emulator.slot,
969
+ );
970
+
971
+ const [tx, pollId] = await createProposal(
972
+ { TextProposal: fromHex(fromText('smth')) },
973
+ null,
974
+ sysParams,
975
+ context.lucid,
976
+ context.emulator.slot,
977
+ (
978
+ await findGov(
979
+ context.lucid,
980
+ sysParams.validatorHashes.govHash,
981
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
982
+ )
983
+ ).utxo,
984
+ [],
985
+ );
986
+
987
+ await runAndAwaitTxBuilder(context.lucid, tx);
988
+
989
+ await runCreateAllShards(pollId, sysParams, context);
990
+
991
+ await runAndAwaitTx(
992
+ context.lucid,
993
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
994
+ );
995
+
996
+ await runVote(pollId, 'No', sysParams, context);
997
+
998
+ {
999
+ const pollUtxo = await findPollManager(
1000
+ context.lucid,
1001
+ sysParams.validatorHashes.pollManagerHash,
1002
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
1003
+ pollId,
1004
+ );
1005
+
1006
+ const targetSlot = unixTimeToSlot(
1007
+ context.lucid.config().network!,
1008
+ Number(pollUtxo.datum.votingEndTime),
1009
+ );
1010
+ expect(targetSlot).toBeGreaterThan(context.emulator.slot);
1011
+
1012
+ context.emulator.awaitSlot(targetSlot - context.emulator.slot + 1);
1013
+ }
1014
+
1015
+ await runMergeAllShards(pollId, sysParams, context);
1016
+
1017
+ const pollUtxo = await findPollManager(
1018
+ context.lucid,
1019
+ sysParams.validatorHashes.pollManagerHash,
1020
+ fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
1021
+ pollId,
1022
+ );
1023
+
1024
+ const govUtxo = await findGov(
1025
+ context.lucid,
1026
+ sysParams.validatorHashes.govHash,
1027
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1028
+ );
1029
+
1030
+ const [_, newUtxos] = await getNewUtxosAtAddressAfterAction(
1031
+ context.lucid,
1032
+ createScriptAddress(
1033
+ context.lucid.config().network!,
1034
+ sysParams.validatorHashes.treasuryHash,
1035
+ ),
1036
+ async () =>
1037
+ benchmarkAndAwaitTx(
1038
+ 'Gov - End failed proposal',
1039
+ await endProposal(
1040
+ pollUtxo.utxo,
1041
+ govUtxo.utxo,
1042
+ sysParams,
1043
+ context.lucid,
1044
+ context.emulator.slot,
1045
+ ),
1046
+ context.lucid,
1047
+ context.emulator,
1048
+ ),
1049
+ );
1050
+
1051
+ const treasuryOutput = matchSingle(
1052
+ newUtxos,
1053
+ () => new Error('Expected single treasury output'),
1054
+ );
1055
+
1056
+ assert(
1057
+ assetClassValueOf(
1058
+ treasuryOutput.assets,
1059
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
1060
+ ) === govUtxo.datum.protocolParams.proposalDeposit,
1061
+ 'Treasury should get proposal deposit back on failed proposal end',
1062
+ );
1063
+
1064
+ await expect(
1065
+ findExecute(
1066
+ context.lucid,
1067
+ sysParams.validatorHashes.executeHash,
1068
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1069
+ pollId,
1070
+ ),
1071
+ ).rejects.toThrow();
1072
+ });
1073
+
1074
+ test<MyContext>('Execute text proposal', async (context: MyContext) => {
1075
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1076
+
1077
+ const [sysParams, _] = await init(
1078
+ context.lucid,
1079
+ [iusdInitialAssetCfg()],
1080
+ context.emulator.slot,
1081
+ );
1082
+
1083
+ const [tx, pollId] = await createProposal(
1084
+ { TextProposal: fromHex(fromText('smth')) },
1085
+ null,
1086
+ sysParams,
1087
+ context.lucid,
1088
+ context.emulator.slot,
1089
+ (
1090
+ await findGov(
1091
+ context.lucid,
1092
+ sysParams.validatorHashes.govHash,
1093
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1094
+ )
1095
+ ).utxo,
1096
+ [],
1097
+ );
1098
+
1099
+ await runAndAwaitTxBuilder(context.lucid, tx);
1100
+
1101
+ await runCreateAllShards(pollId, sysParams, context);
1102
+
1103
+ await runAndAwaitTx(
1104
+ context.lucid,
1105
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1106
+ );
1107
+
1108
+ await runVote(pollId, 'Yes', sysParams, context);
1109
+
1110
+ await waitForVotingEnd(pollId, sysParams, context);
1111
+
1112
+ await runMergeAllShards(pollId, sysParams, context);
1113
+
1114
+ await runEndProposal(pollId, sysParams, context);
1115
+
1116
+ const govUtxo = await findGov(
1117
+ context.lucid,
1118
+ sysParams.validatorHashes.govHash,
1119
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1120
+ );
1121
+ const executeUtxo = await findExecute(
1122
+ context.lucid,
1123
+ sysParams.validatorHashes.executeHash,
1124
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1125
+ pollId,
1126
+ );
1127
+
1128
+ await benchmarkAndAwaitTx(
1129
+ 'Execute text proposal',
1130
+ await executeProposal(
1131
+ executeUtxo.utxo,
1132
+ govUtxo.utxo,
1133
+ null,
1134
+ null,
1135
+ null,
1136
+ null,
1137
+ null,
1138
+ null,
1139
+ sysParams,
1140
+ context.lucid,
1141
+ context.emulator.slot,
1142
+ ),
1143
+ context.lucid,
1144
+ context.emulator,
1145
+ );
1146
+ });
1147
+
1148
+ test<MyContext>('Execute text proposal with treasury withdrawal', async (context: MyContext) => {
1149
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1150
+
1151
+ const [sysParams, __] = await init(
1152
+ context.lucid,
1153
+ [iusdInitialAssetCfg()],
1154
+ context.emulator.slot,
1155
+ );
1156
+
1157
+ const withdrawalIndyAmt = 1_000n;
1158
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
1159
+ withdrawalIndyAmt,
1160
+ sysParams,
1161
+ context,
1162
+ );
1163
+
1164
+ const [tx, pollId] = await createProposal(
1165
+ { TextProposal: fromHex(fromText('smth')) },
1166
+ {
1167
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
1168
+ value: [
1169
+ {
1170
+ currencySymbol: fromHex(
1171
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
1172
+ ),
1173
+ tokenName: fromHex(
1174
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
1175
+ ),
1176
+ amount: withdrawalIndyAmt,
1177
+ },
1178
+ ],
1179
+ },
1180
+ sysParams,
1181
+ context.lucid,
1182
+ context.emulator.slot,
1183
+ (
1184
+ await findGov(
1185
+ context.lucid,
1186
+ sysParams.validatorHashes.govHash,
1187
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1188
+ )
1189
+ ).utxo,
1190
+ [],
1191
+ );
1192
+
1193
+ await runAndAwaitTxBuilder(context.lucid, tx);
1194
+
1195
+ await runCreateAllShards(pollId, sysParams, context);
1196
+
1197
+ await runAndAwaitTx(
1198
+ context.lucid,
1199
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1200
+ );
1201
+
1202
+ await runVote(pollId, 'Yes', sysParams, context);
1203
+
1204
+ await waitForVotingEnd(pollId, sysParams, context);
1205
+
1206
+ await runMergeAllShards(pollId, sysParams, context);
1207
+
1208
+ await runEndProposal(pollId, sysParams, context);
1209
+
1210
+ const govUtxo = await findGov(
1211
+ context.lucid,
1212
+ sysParams.validatorHashes.govHash,
1213
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1214
+ );
1215
+ const executeUtxo = await findExecute(
1216
+ context.lucid,
1217
+ sysParams.validatorHashes.executeHash,
1218
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1219
+ pollId,
1220
+ );
1221
+
1222
+ const [_, newVal] = await getValueChangeAtAddressAfterAction(
1223
+ context.lucid,
1224
+ context.users.withdrawalAccount.address,
1225
+ async () =>
1226
+ await benchmarkAndAwaitTx(
1227
+ 'Execute text proposal with treasury withdrawal',
1228
+ await executeProposal(
1229
+ executeUtxo.utxo,
1230
+ govUtxo.utxo,
1231
+ treasuryWithdrawalUtxo,
1232
+ null,
1233
+ null,
1234
+ null,
1235
+ null,
1236
+ null,
1237
+ sysParams,
1238
+ context.lucid,
1239
+ context.emulator.slot,
1240
+ ),
1241
+ context.lucid,
1242
+ context.emulator,
1243
+ ),
1244
+ );
1245
+
1246
+ expect(
1247
+ assetClassValueOf(
1248
+ newVal,
1249
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
1250
+ ) === withdrawalIndyAmt,
1251
+ 'Unexpected withdrawn indy amt',
1252
+ ).toBeTruthy();
1253
+ });
1254
+
1255
+ test<MyContext>('Execute text proposal with treasury withdrawal with Treasury PrepareWithdrawal', async (context: MyContext) => {
1256
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1257
+
1258
+ const [sysParams, __] = await init(
1259
+ context.lucid,
1260
+ [iusdInitialAssetCfg()],
1261
+ context.emulator.slot,
1262
+ );
1263
+
1264
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1265
+ const withdrawalAmt = 2n;
1266
+
1267
+ await createUtxoAtTreasury(
1268
+ mkAssetsOf(EXAMPLE_TOKEN_1, 5n),
1269
+ sysParams,
1270
+ context,
1271
+ );
1272
+ await createUtxoAtTreasury(
1273
+ mkAssetsOf(EXAMPLE_TOKEN_2, 5n),
1274
+ sysParams,
1275
+ context,
1276
+ );
1277
+
1278
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1279
+
1280
+ const [tx, pollId] = await createProposal(
1281
+ { TextProposal: fromHex(fromText('smth')) },
1282
+ {
1283
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
1284
+ value: [
1285
+ {
1286
+ ...EXAMPLE_TOKEN_1,
1287
+ amount: withdrawalAmt,
1288
+ },
1289
+ { ...EXAMPLE_TOKEN_2, amount: withdrawalAmt },
1290
+ ],
1291
+ },
1292
+ sysParams,
1293
+ context.lucid,
1294
+ context.emulator.slot,
1295
+ (
1296
+ await findGov(
1297
+ context.lucid,
1298
+ sysParams.validatorHashes.govHash,
1299
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1300
+ )
1301
+ ).utxo,
1302
+ [],
1303
+ );
1304
+
1305
+ await runAndAwaitTxBuilder(context.lucid, tx);
1306
+
1307
+ await runCreateAllShards(pollId, sysParams, context);
1308
+
1309
+ await runAndAwaitTx(
1310
+ context.lucid,
1311
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1312
+ );
1313
+
1314
+ await runVote(pollId, 'Yes', sysParams, context);
1315
+
1316
+ await waitForVotingEnd(pollId, sysParams, context);
1317
+
1318
+ await runMergeAllShards(pollId, sysParams, context);
1319
+
1320
+ await runEndProposal(pollId, sysParams, context);
1321
+
1322
+ const govUtxo = await findGov(
1323
+ context.lucid,
1324
+ sysParams.validatorHashes.govHash,
1325
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1326
+ );
1327
+ const executeUtxo = await findExecute(
1328
+ context.lucid,
1329
+ sysParams.validatorHashes.executeHash,
1330
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1331
+ pollId,
1332
+ );
1333
+
1334
+ // One UTxO with the DAO token, five ADA only UTxOs and
1335
+ // one UTxO with EXAMPLE_TOKEN_1 and one with EXAMPLE_TOKEN_2.
1336
+ assert(
1337
+ (await findAllTreasuryUtxos(context.lucid, sysParams)).length === 8,
1338
+ 'Expected 8 treasury withdrawal UTXOs prior to prepare withdrawal',
1339
+ );
1340
+
1341
+ // Prepare withdrawal
1342
+ await runAndAwaitTx(
1343
+ context.lucid,
1344
+ treasuryPrepareWithdrawal(
1345
+ await findAllTreasuryUtxosWithNonAdaAsset(context.lucid, sysParams),
1346
+ executeUtxo.utxo,
1347
+ context.lucid,
1348
+ sysParams,
1349
+ ),
1350
+ );
1351
+
1352
+ const treasuryWithdrawalUtxos = await findAllTreasuryUtxos(
1353
+ context.lucid,
1354
+ sysParams,
1355
+ );
1356
+
1357
+ // One with the value to withdraw and one UTxO with the change, plus five ADA only UTxOs.
1358
+ assert(
1359
+ treasuryWithdrawalUtxos.length === 7,
1360
+ 'Expected 7 treasury withdrawal UTXOs',
1361
+ );
1362
+
1363
+ const treasuryWithdrawalUtxo = matchSingle(
1364
+ treasuryWithdrawalUtxos.filter(
1365
+ (utxo) =>
1366
+ utxo.assets[assetClassToUnit(EXAMPLE_TOKEN_1)] === withdrawalAmt,
1367
+ ),
1368
+ () => new Error('Expected a single treasury withdrawal UTXO'),
1369
+ );
1370
+
1371
+ const [_, newVal] = await getValueChangeAtAddressAfterAction(
1372
+ context.lucid,
1373
+ context.users.withdrawalAccount.address,
1374
+ async () =>
1375
+ await runAndAwaitTx(
1376
+ context.lucid,
1377
+ executeProposal(
1378
+ executeUtxo.utxo,
1379
+ govUtxo.utxo,
1380
+ treasuryWithdrawalUtxo,
1381
+ null,
1382
+ null,
1383
+ null,
1384
+ null,
1385
+ null,
1386
+ sysParams,
1387
+ context.lucid,
1388
+ context.emulator.slot,
1389
+ ),
1390
+ ),
1391
+ );
1392
+
1393
+ expect(
1394
+ assetClassValueOf(newVal, EXAMPLE_TOKEN_1) === withdrawalAmt,
1395
+ 'Unexpected withdrawn indy amt',
1396
+ ).toBeTruthy();
1397
+ });
1398
+
1399
+ test<MyContext>('Execute create IAsset proposal', async (context: MyContext) => {
1400
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1401
+
1402
+ const [sysParams, _] = await init(
1403
+ context.lucid,
1404
+ [iusdInitialAssetCfg()],
1405
+ context.emulator.slot,
1406
+ );
1407
+
1408
+ const govUtxo = await findGov(
1409
+ context.lucid,
1410
+ sysParams.validatorHashes.govHash,
1411
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1412
+ );
1413
+
1414
+ const [tx, pollId] = await createProposal(
1415
+ {
1416
+ ProposeIAsset: {
1417
+ asset: fromHex(fromText('iBTC')),
1418
+ debtMintingFeeRatio: { numerator: 5n, denominator: 1_000n },
1419
+ liquidationProcessingFeeRatio: { numerator: 2n, denominator: 100n },
1420
+ stabilityPoolWithdrawalFeeRatio: {
1421
+ numerator: 5n,
1422
+ denominator: 1_000n,
1423
+ },
1424
+ redemptionReimbursementRatio: { numerator: 1n, denominator: 100n },
1425
+ redemptionProcessingFeeRatio: { numerator: 1n, denominator: 100n },
1426
+ },
1427
+ },
1428
+ null,
1429
+ sysParams,
1430
+ context.lucid,
1431
+ context.emulator.slot,
1432
+ govUtxo.utxo,
1433
+ (
1434
+ await findAllIAssets(
1435
+ context.lucid,
1436
+ sysParams.validatorHashes.iassetHash,
1437
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
1438
+ )
1439
+ ).map((iasset) => iasset.utxo),
1440
+ );
1441
+
1442
+ await runAndAwaitTxBuilder(context.lucid, tx);
1443
+
1444
+ await runCreateAllShards(pollId, sysParams, context);
1445
+
1446
+ await runAndAwaitTx(
1447
+ context.lucid,
1448
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1449
+ );
1450
+
1451
+ await runVote(pollId, 'Yes', sysParams, context);
1452
+
1453
+ await waitForVotingEnd(pollId, sysParams, context);
1454
+
1455
+ await runMergeAllShards(pollId, sysParams, context);
1456
+
1457
+ await runEndProposal(pollId, sysParams, context);
1458
+
1459
+ const executeUtxo = await findExecute(
1460
+ context.lucid,
1461
+ sysParams.validatorHashes.executeHash,
1462
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1463
+ pollId,
1464
+ );
1465
+
1466
+ await benchmarkAndAwaitTx(
1467
+ 'Execute create IAsset proposal',
1468
+ await executeProposal(
1469
+ executeUtxo.utxo,
1470
+ (
1471
+ await findGov(
1472
+ context.lucid,
1473
+ sysParams.validatorHashes.govHash,
1474
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1475
+ )
1476
+ ).utxo,
1477
+ null,
1478
+ (
1479
+ await findAllIAssets(
1480
+ context.lucid,
1481
+ sysParams.validatorHashes.iassetHash,
1482
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
1483
+ )
1484
+ ).map((iasset) => iasset.utxo),
1485
+ null,
1486
+ null,
1487
+ null,
1488
+ null,
1489
+ sysParams,
1490
+ context.lucid,
1491
+ context.emulator.slot,
1492
+ ),
1493
+ context.lucid,
1494
+ context.emulator,
1495
+ );
1496
+ });
1497
+
1498
+ test<MyContext>('Execute create asset proposal with treasury withdrawal', async (context: MyContext) => {
1499
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1500
+
1501
+ const [sysParams, _] = await init(
1502
+ context.lucid,
1503
+ [iusdInitialAssetCfg()],
1504
+ context.emulator.slot,
1505
+ );
1506
+
1507
+ const withdrawalIndyAmt = 1_000n;
1508
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
1509
+ withdrawalIndyAmt,
1510
+ sysParams,
1511
+ context,
1512
+ );
1513
+
1514
+ const govUtxo = await findGov(
1515
+ context.lucid,
1516
+ sysParams.validatorHashes.govHash,
1517
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1518
+ );
1519
+
1520
+ const [tx, pollId] = await createProposal(
1521
+ {
1522
+ ProposeIAsset: {
1523
+ asset: fromHex(fromText('iBTC')),
1524
+ debtMintingFeeRatio: { numerator: 5n, denominator: 1_000n },
1525
+ liquidationProcessingFeeRatio: { numerator: 2n, denominator: 100n },
1526
+ stabilityPoolWithdrawalFeeRatio: {
1527
+ numerator: 5n,
1528
+ denominator: 1_000n,
1529
+ },
1530
+ redemptionReimbursementRatio: { numerator: 1n, denominator: 100n },
1531
+ redemptionProcessingFeeRatio: { numerator: 1n, denominator: 100n },
1532
+ },
1533
+ },
1534
+ {
1535
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
1536
+ value: [
1537
+ {
1538
+ currencySymbol: fromHex(
1539
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
1540
+ ),
1541
+ tokenName: fromHex(
1542
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
1543
+ ),
1544
+ amount: withdrawalIndyAmt,
1545
+ },
1546
+ ],
1547
+ },
1548
+ sysParams,
1549
+ context.lucid,
1550
+ context.emulator.slot,
1551
+ govUtxo.utxo,
1552
+ (
1553
+ await findAllIAssets(
1554
+ context.lucid,
1555
+ sysParams.validatorHashes.iassetHash,
1556
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
1557
+ )
1558
+ ).map((iasset) => iasset.utxo),
1559
+ );
1560
+
1561
+ await runAndAwaitTxBuilder(context.lucid, tx);
1562
+
1563
+ await runCreateAllShards(pollId, sysParams, context);
1564
+
1565
+ await runAndAwaitTx(
1566
+ context.lucid,
1567
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1568
+ );
1569
+
1570
+ await runVote(pollId, 'Yes', sysParams, context);
1571
+
1572
+ await waitForVotingEnd(pollId, sysParams, context);
1573
+
1574
+ await runMergeAllShards(pollId, sysParams, context);
1575
+
1576
+ await runEndProposal(pollId, sysParams, context);
1577
+
1578
+ const executeUtxo = await findExecute(
1579
+ context.lucid,
1580
+ sysParams.validatorHashes.executeHash,
1581
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1582
+ pollId,
1583
+ );
1584
+
1585
+ const [__, newVal] = await getValueChangeAtAddressAfterAction(
1586
+ context.lucid,
1587
+ context.users.withdrawalAccount.address,
1588
+ async () =>
1589
+ benchmarkAndAwaitTx(
1590
+ 'Execute create asset proposal with treasury withdrawal',
1591
+ await executeProposal(
1592
+ executeUtxo.utxo,
1593
+ (
1594
+ await findGov(
1595
+ context.lucid,
1596
+ sysParams.validatorHashes.govHash,
1597
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1598
+ )
1599
+ ).utxo,
1600
+ treasuryWithdrawalUtxo,
1601
+ (
1602
+ await findAllIAssets(
1603
+ context.lucid,
1604
+ sysParams.validatorHashes.iassetHash,
1605
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
1606
+ )
1607
+ ).map((iasset) => iasset.utxo),
1608
+ null,
1609
+ null,
1610
+ null,
1611
+ null,
1612
+ sysParams,
1613
+ context.lucid,
1614
+ context.emulator.slot,
1615
+ ),
1616
+ context.lucid,
1617
+ context.emulator,
1618
+ ),
1619
+ );
1620
+
1621
+ expect(
1622
+ assetClassValueOf(
1623
+ newVal,
1624
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
1625
+ ) === withdrawalIndyAmt,
1626
+ 'Unexpected withdrawn indy amt',
1627
+ ).toBeTruthy();
1628
+ });
1629
+
1630
+ test<MyContext>('Execute modify asset proposal', async (context: MyContext) => {
1631
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1632
+
1633
+ const [sysParams, _] = await init(
1634
+ context.lucid,
1635
+ [iusdInitialAssetCfg()],
1636
+ context.emulator.slot,
1637
+ );
1638
+
1639
+ const govUtxo = await findGov(
1640
+ context.lucid,
1641
+ sysParams.validatorHashes.govHash,
1642
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1643
+ );
1644
+
1645
+ const iassetToModify = await findIAsset(
1646
+ context.lucid,
1647
+ sysParams.validatorHashes.iassetHash,
1648
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
1649
+ 'iUSD',
1650
+ );
1651
+
1652
+ const [tx, pollId] = await createProposal(
1653
+ {
1654
+ ModifyIAsset: {
1655
+ asset: fromHex(fromText('iUSD')),
1656
+ newDebtMintingFeeRatio: iassetToModify.datum.debtMintingFeeRatio,
1657
+ newLiquidationProcessingFeeRatio:
1658
+ iassetToModify.datum.liquidationProcessingFeeRatio,
1659
+ newStabilityPoolWithdrawalFeeRatio:
1660
+ iassetToModify.datum.stabilityPoolWithdrawalFeeRatio,
1661
+ newRedemptionReimbursementRatio:
1662
+ iassetToModify.datum.redemptionReimbursementRatio,
1663
+ newRedemptionProcessingFeeRatio:
1664
+ iassetToModify.datum.redemptionProcessingFeeRatio,
1665
+ },
1666
+ },
1667
+ null,
1668
+ sysParams,
1669
+ context.lucid,
1670
+ context.emulator.slot,
1671
+ govUtxo.utxo,
1672
+ [],
1673
+ );
1674
+
1675
+ await runAndAwaitTxBuilder(context.lucid, tx);
1676
+
1677
+ await runCreateAllShards(pollId, sysParams, context);
1678
+
1679
+ await runAndAwaitTx(
1680
+ context.lucid,
1681
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1682
+ );
1683
+
1684
+ await runVote(pollId, 'Yes', sysParams, context);
1685
+
1686
+ await waitForVotingEnd(pollId, sysParams, context);
1687
+
1688
+ await runMergeAllShards(pollId, sysParams, context);
1689
+
1690
+ await runEndProposal(pollId, sysParams, context);
1691
+
1692
+ const executeUtxo = await findExecute(
1693
+ context.lucid,
1694
+ sysParams.validatorHashes.executeHash,
1695
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1696
+ pollId,
1697
+ );
1698
+
1699
+ await benchmarkAndAwaitTx(
1700
+ 'Gov - Execute modify asset proposal',
1701
+ await executeProposal(
1702
+ executeUtxo.utxo,
1703
+ (
1704
+ await findGov(
1705
+ context.lucid,
1706
+ sysParams.validatorHashes.govHash,
1707
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1708
+ )
1709
+ ).utxo,
1710
+ null,
1711
+ null,
1712
+ iassetToModify.utxo,
1713
+ null,
1714
+ null,
1715
+ null,
1716
+ sysParams,
1717
+ context.lucid,
1718
+ context.emulator.slot,
1719
+ ),
1720
+ context.lucid,
1721
+ context.emulator,
1722
+ );
1723
+ });
1724
+
1725
+ test<MyContext>('Execute modify asset proposal with treasury withdrawal', async (context: MyContext) => {
1726
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1727
+
1728
+ const [sysParams, _] = await init(
1729
+ context.lucid,
1730
+ [iusdInitialAssetCfg()],
1731
+ context.emulator.slot,
1732
+ );
1733
+
1734
+ const withdrawalIndyAmt = 1_000n;
1735
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
1736
+ withdrawalIndyAmt,
1737
+ sysParams,
1738
+ context,
1739
+ );
1740
+
1741
+ const govUtxo = await findGov(
1742
+ context.lucid,
1743
+ sysParams.validatorHashes.govHash,
1744
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1745
+ );
1746
+
1747
+ const iassetToModify = await findIAsset(
1748
+ context.lucid,
1749
+ sysParams.validatorHashes.iassetHash,
1750
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
1751
+ 'iUSD',
1752
+ );
1753
+
1754
+ const [tx, pollId] = await createProposal(
1755
+ {
1756
+ ModifyIAsset: {
1757
+ asset: fromHex(fromText('iUSD')),
1758
+ newDebtMintingFeeRatio: iassetToModify.datum.debtMintingFeeRatio,
1759
+ newLiquidationProcessingFeeRatio:
1760
+ iassetToModify.datum.liquidationProcessingFeeRatio,
1761
+ newStabilityPoolWithdrawalFeeRatio:
1762
+ iassetToModify.datum.stabilityPoolWithdrawalFeeRatio,
1763
+ newRedemptionReimbursementRatio:
1764
+ iassetToModify.datum.redemptionReimbursementRatio,
1765
+ newRedemptionProcessingFeeRatio:
1766
+ iassetToModify.datum.redemptionProcessingFeeRatio,
1767
+ },
1768
+ },
1769
+ {
1770
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
1771
+ value: [
1772
+ {
1773
+ currencySymbol: fromHex(
1774
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
1775
+ ),
1776
+ tokenName: fromHex(
1777
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
1778
+ ),
1779
+ amount: withdrawalIndyAmt,
1780
+ },
1781
+ ],
1782
+ },
1783
+ sysParams,
1784
+ context.lucid,
1785
+ context.emulator.slot,
1786
+ govUtxo.utxo,
1787
+ [],
1788
+ );
1789
+
1790
+ await runAndAwaitTxBuilder(context.lucid, tx);
1791
+
1792
+ await runCreateAllShards(pollId, sysParams, context);
1793
+
1794
+ await runAndAwaitTx(
1795
+ context.lucid,
1796
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1797
+ );
1798
+
1799
+ await runVote(pollId, 'Yes', sysParams, context);
1800
+
1801
+ await waitForVotingEnd(pollId, sysParams, context);
1802
+
1803
+ await runMergeAllShards(pollId, sysParams, context);
1804
+
1805
+ await runEndProposal(pollId, sysParams, context);
1806
+
1807
+ const executeUtxo = await findExecute(
1808
+ context.lucid,
1809
+ sysParams.validatorHashes.executeHash,
1810
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1811
+ pollId,
1812
+ );
1813
+
1814
+ const [__, newVal] = await getValueChangeAtAddressAfterAction(
1815
+ context.lucid,
1816
+ context.users.withdrawalAccount.address,
1817
+ async () =>
1818
+ benchmarkAndAwaitTx(
1819
+ 'Gov - Execute modify asset proposal with treasury withdrawal',
1820
+ await executeProposal(
1821
+ executeUtxo.utxo,
1822
+ (
1823
+ await findGov(
1824
+ context.lucid,
1825
+ sysParams.validatorHashes.govHash,
1826
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1827
+ )
1828
+ ).utxo,
1829
+ treasuryWithdrawalUtxo,
1830
+ null,
1831
+ iassetToModify.utxo,
1832
+ null,
1833
+ null,
1834
+ null,
1835
+ sysParams,
1836
+ context.lucid,
1837
+ context.emulator.slot,
1838
+ ),
1839
+ context.lucid,
1840
+ context.emulator,
1841
+ ),
1842
+ );
1843
+
1844
+ expect(
1845
+ assetClassValueOf(
1846
+ newVal,
1847
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
1848
+ ) === withdrawalIndyAmt,
1849
+ 'Unexpected withdrawn indy amt',
1850
+ ).toBeTruthy();
1851
+ });
1852
+
1853
+ describe('Add collateral asset proposal', () => {
1854
+ test<MyContext>('Execute add collateral asset proposal (no collateral assets on the iassets)', async (context: MyContext) => {
1855
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1856
+
1857
+ const collateralAsset1: AssetClass = {
1858
+ currencySymbol: fromHex(
1859
+ '00000000000000000000000000000000000000000000000000000000',
1860
+ ),
1861
+ tokenName: fromHex(fromText('ABC')),
1862
+ };
1863
+
1864
+ const [sysParams, [iusdAssetInfo]] = await init(
1865
+ context.lucid,
1866
+ [
1867
+ {
1868
+ ...iusdInitialAssetCfg(),
1869
+ collateralAssets: [],
1870
+ },
1871
+ ],
1872
+ context.emulator.slot,
1873
+ );
1874
+
1875
+ const [pkh, _] = await addrDetails(context.lucid);
1876
+
1877
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
1878
+ 0n,
1879
+ 0n,
1880
+ 0n,
1881
+ {
1882
+ biasTime: 120_000n,
1883
+ owner: pkh.hash,
1884
+ },
1885
+ context.lucid,
1886
+ );
1887
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
1888
+
1889
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
1890
+ context.lucid,
1891
+ 'IUSD_INDY_ORACLE',
1892
+ rationalFromInt(1n),
1893
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
1894
+ context.emulator.slot,
1895
+ );
1896
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
1897
+
1898
+ const govUtxo = await findGov(
1899
+ context.lucid,
1900
+ sysParams.validatorHashes.govHash,
1901
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1902
+ );
1903
+
1904
+ const allIassetOrefs = (
1905
+ await findAllIAssets(
1906
+ context.lucid,
1907
+ sysParams.validatorHashes.iassetHash,
1908
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
1909
+ )
1910
+ ).map((iasset) => iasset.utxo);
1911
+
1912
+ const [tx, pollId] = await createProposal(
1913
+ {
1914
+ AddCollateralAsset: {
1915
+ correspondingIAsset: fromHex(
1916
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
1917
+ ),
1918
+ collateralAsset: collateralAsset1,
1919
+ assetExtraDecimals: 0n,
1920
+ assetPriceInfo: { OracleNft: priceOranceNft },
1921
+ interestOracleNft: interestOracleNft,
1922
+ redemptionRatio: rationalFromInt(2n),
1923
+ maintenanceRatio: { numerator: 150n, denominator: 100n },
1924
+ liquidationRatio: { numerator: 120n, denominator: 100n },
1925
+ minCollateralAmt: 1_000_000n,
1926
+ },
1927
+ },
1928
+ null,
1929
+ sysParams,
1930
+ context.lucid,
1931
+ context.emulator.slot,
1932
+ govUtxo.utxo,
1933
+ allIassetOrefs,
1934
+ );
1935
+
1936
+ await runAndAwaitTxBuilder(context.lucid, tx);
1937
+
1938
+ await runCreateAllShards(pollId, sysParams, context);
1939
+
1940
+ await runAndAwaitTx(
1941
+ context.lucid,
1942
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
1943
+ );
1944
+
1945
+ await runVote(pollId, 'Yes', sysParams, context);
1946
+
1947
+ await waitForVotingEnd(pollId, sysParams, context);
1948
+
1949
+ await runMergeAllShards(pollId, sysParams, context);
1950
+
1951
+ await runEndProposal(pollId, sysParams, context);
1952
+
1953
+ const executeUtxo = await findExecute(
1954
+ context.lucid,
1955
+ sysParams.validatorHashes.executeHash,
1956
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
1957
+ pollId,
1958
+ );
1959
+
1960
+ const iassetOutput = await findIAsset(
1961
+ context.lucid,
1962
+ sysParams.validatorHashes.iassetHash,
1963
+ fromSystemParamsAsset(sysParams.executeParams.iAssetToken),
1964
+ iusdAssetInfo.iassetTokenNameAscii,
1965
+ );
1966
+
1967
+ await benchmarkAndAwaitTx(
1968
+ 'Gov - Execute add collateral asset proposal (no collateral assets on the iasset)',
1969
+ await executeProposal(
1970
+ executeUtxo.utxo,
1971
+ (
1972
+ await findGov(
1973
+ context.lucid,
1974
+ sysParams.validatorHashes.govHash,
1975
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
1976
+ )
1977
+ ).utxo,
1978
+ null,
1979
+ null,
1980
+ iassetOutput.utxo,
1981
+ (
1982
+ await findAllCollateralAssetsOfIAsset(
1983
+ context.lucid,
1984
+ sysParams.validatorHashes.iassetHash,
1985
+ fromSystemParamsAsset(
1986
+ sysParams.executeParams.collateralAssetToken,
1987
+ ),
1988
+ fromHex(fromText(iusdAssetInfo.iassetTokenNameAscii)),
1989
+ )
1990
+ ).map((o) => o.utxo),
1991
+ null,
1992
+ null,
1993
+ sysParams,
1994
+ context.lucid,
1995
+ context.emulator.slot,
1996
+ ),
1997
+ context.lucid,
1998
+ context.emulator,
1999
+ );
2000
+
2001
+ const res = await findCollateralAssetNew(
2002
+ context,
2003
+ sysParams,
2004
+ iusdAssetInfo.iassetTokenNameAscii,
2005
+ collateralAsset1,
2006
+ );
2007
+
2008
+ expect(
2009
+ res.datum.firstCollateralAsset,
2010
+ 'Expected this collateral asset to become first',
2011
+ ).toBeTruthy();
2012
+
2013
+ expect(
2014
+ F.pipe(
2015
+ res.datum.nextCollateralAsset,
2016
+ O.fromNullable,
2017
+ O.match(
2018
+ () => true,
2019
+ // There shouldn't be any next collateral asset.
2020
+ (_) => false,
2021
+ ),
2022
+ ),
2023
+ 'Expected no next collateral asset',
2024
+ ).toBeTruthy();
2025
+ });
2026
+
2027
+ test<MyContext>('Execute add collateral asset proposal (start of the collateral asset chain)', async (context: MyContext) => {
2028
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2029
+
2030
+ const collateralAsset1: AssetClass = {
2031
+ currencySymbol: fromHex(
2032
+ '00000000000000000000000000000000000000000000000000000000',
2033
+ ),
2034
+ tokenName: fromHex(fromText('B')),
2035
+ };
2036
+ const collateralAsset2: AssetClass = {
2037
+ currencySymbol: fromHex(
2038
+ '00000000000000000000000000000000000000000000000000000000',
2039
+ ),
2040
+ tokenName: fromHex(fromText('A')),
2041
+ };
2042
+
2043
+ const [sysParams, [iusdAssetInfo]] = await init(
2044
+ context.lucid,
2045
+ [
2046
+ {
2047
+ ...iusdInitialAssetCfg(),
2048
+ collateralAssets: [
2049
+ {
2050
+ ...iusdInitialAssetCfg().collateralAssets[0],
2051
+ collateralAsset: collateralAsset1,
2052
+ },
2053
+ ],
2054
+ },
2055
+ ],
2056
+ context.emulator.slot,
2057
+ );
2058
+
2059
+ const [pkh, _] = await addrDetails(context.lucid);
2060
+
2061
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
2062
+ 0n,
2063
+ 0n,
2064
+ 0n,
2065
+ {
2066
+ biasTime: 120_000n,
2067
+ owner: pkh.hash,
2068
+ },
2069
+ context.lucid,
2070
+ );
2071
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
2072
+
2073
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
2074
+ context.lucid,
2075
+ 'IUSD_INDY_ORACLE',
2076
+ rationalFromInt(1n),
2077
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
2078
+ context.emulator.slot,
2079
+ );
2080
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
2081
+
2082
+ const govUtxo = await findGov(
2083
+ context.lucid,
2084
+ sysParams.validatorHashes.govHash,
2085
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2086
+ );
2087
+
2088
+ const allIassetOrefs = (
2089
+ await findAllIAssets(
2090
+ context.lucid,
2091
+ sysParams.validatorHashes.iassetHash,
2092
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
2093
+ )
2094
+ ).map((iasset) => iasset.utxo);
2095
+
2096
+ const [tx, pollId] = await createProposal(
2097
+ {
2098
+ AddCollateralAsset: {
2099
+ correspondingIAsset: fromHex(
2100
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
2101
+ ),
2102
+ collateralAsset: collateralAsset2,
2103
+ assetExtraDecimals: 0n,
2104
+ assetPriceInfo: { OracleNft: priceOranceNft },
2105
+ interestOracleNft: interestOracleNft,
2106
+ redemptionRatio: rationalFromInt(2n),
2107
+ maintenanceRatio: { numerator: 150n, denominator: 100n },
2108
+ liquidationRatio: { numerator: 120n, denominator: 100n },
2109
+ minCollateralAmt: 1_000_000n,
2110
+ },
2111
+ },
2112
+ null,
2113
+ sysParams,
2114
+ context.lucid,
2115
+ context.emulator.slot,
2116
+ govUtxo.utxo,
2117
+ allIassetOrefs,
2118
+ );
2119
+
2120
+ await runAndAwaitTxBuilder(context.lucid, tx);
2121
+
2122
+ await runCreateAllShards(pollId, sysParams, context);
2123
+
2124
+ await runAndAwaitTx(
2125
+ context.lucid,
2126
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
2127
+ );
2128
+
2129
+ await runVote(pollId, 'Yes', sysParams, context);
2130
+
2131
+ await waitForVotingEnd(pollId, sysParams, context);
2132
+
2133
+ await runMergeAllShards(pollId, sysParams, context);
2134
+
2135
+ await runEndProposal(pollId, sysParams, context);
2136
+
2137
+ const executeUtxo = await findExecute(
2138
+ context.lucid,
2139
+ sysParams.validatorHashes.executeHash,
2140
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
2141
+ pollId,
2142
+ );
2143
+
2144
+ const iassetOutput = await findIAsset(
2145
+ context.lucid,
2146
+ sysParams.validatorHashes.iassetHash,
2147
+ fromSystemParamsAsset(sysParams.executeParams.iAssetToken),
2148
+ iusdAssetInfo.iassetTokenNameAscii,
2149
+ );
2150
+
2151
+ await benchmarkAndAwaitTx(
2152
+ 'Gov - Execute add collateral asset proposal (start of the collateral asset chain)',
2153
+ await executeProposal(
2154
+ executeUtxo.utxo,
2155
+ (
2156
+ await findGov(
2157
+ context.lucid,
2158
+ sysParams.validatorHashes.govHash,
2159
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2160
+ )
2161
+ ).utxo,
2162
+ null,
2163
+ null,
2164
+ iassetOutput.utxo,
2165
+ (
2166
+ await findAllCollateralAssetsOfIAsset(
2167
+ context.lucid,
2168
+ sysParams.validatorHashes.iassetHash,
2169
+ fromSystemParamsAsset(
2170
+ sysParams.executeParams.collateralAssetToken,
2171
+ ),
2172
+ fromHex(fromText(iusdAssetInfo.iassetTokenNameAscii)),
2173
+ )
2174
+ ).map((o) => o.utxo),
2175
+ null,
2176
+ null,
2177
+ sysParams,
2178
+ context.lucid,
2179
+ context.emulator.slot,
2180
+ ),
2181
+ context.lucid,
2182
+ context.emulator,
2183
+ );
2184
+
2185
+ const res = await findCollateralAssetNew(
2186
+ context,
2187
+ sysParams,
2188
+ iusdAssetInfo.iassetTokenNameAscii,
2189
+ collateralAsset2,
2190
+ );
2191
+
2192
+ expect(
2193
+ res.datum.firstCollateralAsset,
2194
+ 'Expected this collateral asset to become first',
2195
+ ).toBeTruthy();
2196
+
2197
+ expect(
2198
+ F.pipe(
2199
+ res.datum.nextCollateralAsset,
2200
+ O.fromNullable,
2201
+ O.match(
2202
+ // There should be some next collateral asset
2203
+ () => false,
2204
+ (next) => isSameAssetClass(next, collateralAsset1),
2205
+ ),
2206
+ ),
2207
+ 'Expected correct next collateral asset',
2208
+ ).toBeTruthy();
2209
+ });
2210
+
2211
+ test<MyContext>('Execute add collateral asset proposal (middle of the collateral asset chain)', async (context: MyContext) => {
2212
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2213
+
2214
+ const collateralAsset1: AssetClass = {
2215
+ currencySymbol: fromHex(
2216
+ '00000000000000000000000000000000000000000000000000000000',
2217
+ ),
2218
+ tokenName: fromHex(fromText('A')),
2219
+ };
2220
+ const collateralAsset2: AssetClass = {
2221
+ currencySymbol: fromHex(
2222
+ '00000000000000000000000000000000000000000000000000000000',
2223
+ ),
2224
+ tokenName: fromHex(fromText('B')),
2225
+ };
2226
+ const collateralAsset3: AssetClass = {
2227
+ currencySymbol: fromHex(
2228
+ '00000000000000000000000000000000000000000000000000000000',
2229
+ ),
2230
+ tokenName: fromHex(fromText('C')),
2231
+ };
2232
+
2233
+ const [sysParams, [iusdAssetInfo]] = await init(
2234
+ context.lucid,
2235
+ [
2236
+ {
2237
+ ...iusdInitialAssetCfg(),
2238
+ collateralAssets: [
2239
+ {
2240
+ ...iusdInitialAssetCfg().collateralAssets[0],
2241
+ collateralAsset: collateralAsset1,
2242
+ nextCollateralAsset: collateralAsset3,
2243
+ },
2244
+ {
2245
+ ...iusdInitialAssetCfg().collateralAssets[0],
2246
+ collateralAsset: collateralAsset3,
2247
+ },
2248
+ ],
2249
+ },
2250
+ ],
2251
+ context.emulator.slot,
2252
+ );
2253
+
2254
+ const [pkh, _] = await addrDetails(context.lucid);
2255
+
2256
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
2257
+ 0n,
2258
+ 0n,
2259
+ 0n,
2260
+ {
2261
+ biasTime: 120_000n,
2262
+ owner: pkh.hash,
2263
+ },
2264
+ context.lucid,
2265
+ );
2266
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
2267
+
2268
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
2269
+ context.lucid,
2270
+ 'IUSD_INDY_ORACLE',
2271
+ rationalFromInt(1n),
2272
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
2273
+ context.emulator.slot,
2274
+ );
2275
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
2276
+
2277
+ const govUtxo = await findGov(
2278
+ context.lucid,
2279
+ sysParams.validatorHashes.govHash,
2280
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2281
+ );
2282
+
2283
+ const allIassetOrefs = (
2284
+ await findAllIAssets(
2285
+ context.lucid,
2286
+ sysParams.validatorHashes.iassetHash,
2287
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
2288
+ )
2289
+ ).map((iasset) => iasset.utxo);
2290
+
2291
+ const [tx, pollId] = await createProposal(
2292
+ {
2293
+ AddCollateralAsset: {
2294
+ correspondingIAsset: fromHex(
2295
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
2296
+ ),
2297
+ collateralAsset: collateralAsset2,
2298
+ assetExtraDecimals: 0n,
2299
+ assetPriceInfo: { OracleNft: priceOranceNft },
2300
+ interestOracleNft: interestOracleNft,
2301
+ redemptionRatio: rationalFromInt(2n),
2302
+ maintenanceRatio: { numerator: 150n, denominator: 100n },
2303
+ liquidationRatio: { numerator: 120n, denominator: 100n },
2304
+ minCollateralAmt: 1_000_000n,
2305
+ },
2306
+ },
2307
+ null,
2308
+ sysParams,
2309
+ context.lucid,
2310
+ context.emulator.slot,
2311
+ govUtxo.utxo,
2312
+ allIassetOrefs,
2313
+ );
2314
+
2315
+ await runAndAwaitTxBuilder(context.lucid, tx);
2316
+
2317
+ await runCreateAllShards(pollId, sysParams, context);
2318
+
2319
+ await runAndAwaitTx(
2320
+ context.lucid,
2321
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
2322
+ );
2323
+
2324
+ await runVote(pollId, 'Yes', sysParams, context);
2325
+
2326
+ await waitForVotingEnd(pollId, sysParams, context);
2327
+
2328
+ await runMergeAllShards(pollId, sysParams, context);
2329
+
2330
+ await runEndProposal(pollId, sysParams, context);
2331
+
2332
+ const executeUtxo = await findExecute(
2333
+ context.lucid,
2334
+ sysParams.validatorHashes.executeHash,
2335
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
2336
+ pollId,
2337
+ );
2338
+
2339
+ const iassetOutput = await findIAsset(
2340
+ context.lucid,
2341
+ sysParams.validatorHashes.iassetHash,
2342
+ fromSystemParamsAsset(sysParams.executeParams.iAssetToken),
2343
+ iusdAssetInfo.iassetTokenNameAscii,
2344
+ );
2345
+
2346
+ await benchmarkAndAwaitTx(
2347
+ 'Gov - Execute add collateral asset proposal (middle of the collateral asset chain)',
2348
+ await executeProposal(
2349
+ executeUtxo.utxo,
2350
+ (
2351
+ await findGov(
2352
+ context.lucid,
2353
+ sysParams.validatorHashes.govHash,
2354
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2355
+ )
2356
+ ).utxo,
2357
+ null,
2358
+ null,
2359
+ iassetOutput.utxo,
2360
+ (
2361
+ await findAllCollateralAssetsOfIAsset(
2362
+ context.lucid,
2363
+ sysParams.validatorHashes.iassetHash,
2364
+ fromSystemParamsAsset(
2365
+ sysParams.executeParams.collateralAssetToken,
2366
+ ),
2367
+ fromHex(fromText(iusdAssetInfo.iassetTokenNameAscii)),
2368
+ )
2369
+ ).map((o) => o.utxo),
2370
+ null,
2371
+ null,
2372
+ sysParams,
2373
+ context.lucid,
2374
+ context.emulator.slot,
2375
+ ),
2376
+ context.lucid,
2377
+ context.emulator,
2378
+ );
2379
+
2380
+ const newCollateralAsset = await findCollateralAssetNew(
2381
+ context,
2382
+ sysParams,
2383
+ iusdAssetInfo.iassetTokenNameAscii,
2384
+ collateralAsset2,
2385
+ );
2386
+ const collateralAssetFirst = await findCollateralAssetNew(
2387
+ context,
2388
+ sysParams,
2389
+ iusdAssetInfo.iassetTokenNameAscii,
2390
+ collateralAsset1,
2391
+ );
2392
+
2393
+ expect(
2394
+ collateralAssetFirst.datum.firstCollateralAsset,
2395
+ 'Expected this collateral asset to BE first',
2396
+ ).toBeTruthy();
2397
+
2398
+ expect(
2399
+ F.pipe(
2400
+ collateralAssetFirst.datum.nextCollateralAsset,
2401
+ O.fromNullable,
2402
+ O.match(
2403
+ // There should be some next collateral asset
2404
+ () => false,
2405
+ (next) => isSameAssetClass(next, collateralAsset2),
2406
+ ),
2407
+ ),
2408
+ 'Expected correct next collateral asset on the first collateral asset',
2409
+ ).toBeTruthy();
2410
+
2411
+ expect(
2412
+ newCollateralAsset.datum.firstCollateralAsset,
2413
+ 'Expected this collateral asset to NOT BE first',
2414
+ ).toBeFalsy();
2415
+
2416
+ expect(
2417
+ F.pipe(
2418
+ newCollateralAsset.datum.nextCollateralAsset,
2419
+ O.fromNullable,
2420
+ O.match(
2421
+ // There should be some next collateral asset
2422
+ () => false,
2423
+ (next) => isSameAssetClass(next, collateralAsset3),
2424
+ ),
2425
+ ),
2426
+ 'Expected correct next collateral asset on the new collateral asset',
2427
+ ).toBeTruthy();
2428
+ });
2429
+
2430
+ test<MyContext>('Execute add collateral asset proposal (end of the collateral asset chain)', async (context: MyContext) => {
2431
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2432
+
2433
+ const collateralAsset1: AssetClass = {
2434
+ currencySymbol: fromHex(
2435
+ '00000000000000000000000000000000000000000000000000000000',
2436
+ ),
2437
+ tokenName: fromHex(fromText('A')),
2438
+ };
2439
+ const collateralAsset2: AssetClass = {
2440
+ currencySymbol: fromHex(
2441
+ '00000000000000000000000000000000000000000000000000000000',
2442
+ ),
2443
+ tokenName: fromHex(fromText('B')),
2444
+ };
2445
+
2446
+ const [sysParams, [iusdAssetInfo]] = await init(
2447
+ context.lucid,
2448
+ [
2449
+ {
2450
+ ...iusdInitialAssetCfg(),
2451
+ collateralAssets: [
2452
+ {
2453
+ ...iusdInitialAssetCfg().collateralAssets[0],
2454
+ collateralAsset: collateralAsset1,
2455
+ },
2456
+ ],
2457
+ },
2458
+ ],
2459
+ context.emulator.slot,
2460
+ );
2461
+
2462
+ const [pkh, _] = await addrDetails(context.lucid);
2463
+
2464
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
2465
+ 0n,
2466
+ 0n,
2467
+ 0n,
2468
+ {
2469
+ biasTime: 120_000n,
2470
+ owner: pkh.hash,
2471
+ },
2472
+ context.lucid,
2473
+ );
2474
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
2475
+
2476
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
2477
+ context.lucid,
2478
+ 'IUSD_INDY_ORACLE',
2479
+ rationalFromInt(1n),
2480
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
2481
+ context.emulator.slot,
2482
+ );
2483
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
2484
+
2485
+ const govUtxo = await findGov(
2486
+ context.lucid,
2487
+ sysParams.validatorHashes.govHash,
2488
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2489
+ );
2490
+
2491
+ const allIassetOrefs = (
2492
+ await findAllIAssets(
2493
+ context.lucid,
2494
+ sysParams.validatorHashes.iassetHash,
2495
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
2496
+ )
2497
+ ).map((iasset) => iasset.utxo);
2498
+
2499
+ const [tx, pollId] = await createProposal(
2500
+ {
2501
+ AddCollateralAsset: {
2502
+ correspondingIAsset: fromHex(
2503
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
2504
+ ),
2505
+ collateralAsset: collateralAsset2,
2506
+ assetExtraDecimals: 0n,
2507
+ assetPriceInfo: { OracleNft: priceOranceNft },
2508
+ interestOracleNft: interestOracleNft,
2509
+ redemptionRatio: rationalFromInt(2n),
2510
+ maintenanceRatio: { numerator: 150n, denominator: 100n },
2511
+ liquidationRatio: { numerator: 120n, denominator: 100n },
2512
+ minCollateralAmt: 1_000_000n,
2513
+ },
2514
+ },
2515
+ null,
2516
+ sysParams,
2517
+ context.lucid,
2518
+ context.emulator.slot,
2519
+ govUtxo.utxo,
2520
+ allIassetOrefs,
2521
+ );
2522
+
2523
+ await runAndAwaitTxBuilder(context.lucid, tx);
2524
+
2525
+ await runCreateAllShards(pollId, sysParams, context);
2526
+
2527
+ await runAndAwaitTx(
2528
+ context.lucid,
2529
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
2530
+ );
2531
+
2532
+ await runVote(pollId, 'Yes', sysParams, context);
2533
+
2534
+ await waitForVotingEnd(pollId, sysParams, context);
2535
+
2536
+ await runMergeAllShards(pollId, sysParams, context);
2537
+
2538
+ await runEndProposal(pollId, sysParams, context);
2539
+
2540
+ const executeUtxo = await findExecute(
2541
+ context.lucid,
2542
+ sysParams.validatorHashes.executeHash,
2543
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
2544
+ pollId,
2545
+ );
2546
+
2547
+ const iassetOutput = await findIAsset(
2548
+ context.lucid,
2549
+ sysParams.validatorHashes.iassetHash,
2550
+ fromSystemParamsAsset(sysParams.executeParams.iAssetToken),
2551
+ iusdAssetInfo.iassetTokenNameAscii,
2552
+ );
2553
+
2554
+ await benchmarkAndAwaitTx(
2555
+ 'Gov - Execute add collateral asset proposal (end of the collateral asset chain)',
2556
+ await executeProposal(
2557
+ executeUtxo.utxo,
2558
+ (
2559
+ await findGov(
2560
+ context.lucid,
2561
+ sysParams.validatorHashes.govHash,
2562
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2563
+ )
2564
+ ).utxo,
2565
+ null,
2566
+ null,
2567
+ iassetOutput.utxo,
2568
+ (
2569
+ await findAllCollateralAssetsOfIAsset(
2570
+ context.lucid,
2571
+ sysParams.validatorHashes.iassetHash,
2572
+ fromSystemParamsAsset(
2573
+ sysParams.executeParams.collateralAssetToken,
2574
+ ),
2575
+ fromHex(fromText(iusdAssetInfo.iassetTokenNameAscii)),
2576
+ )
2577
+ ).map((o) => o.utxo),
2578
+ null,
2579
+ null,
2580
+ sysParams,
2581
+ context.lucid,
2582
+ context.emulator.slot,
2583
+ ),
2584
+ context.lucid,
2585
+ context.emulator,
2586
+ );
2587
+
2588
+ const newCollateralAsset = await findCollateralAssetNew(
2589
+ context,
2590
+ sysParams,
2591
+ iusdAssetInfo.iassetTokenNameAscii,
2592
+ collateralAsset2,
2593
+ );
2594
+ const collateralAssetFirst = await findCollateralAssetNew(
2595
+ context,
2596
+ sysParams,
2597
+ iusdAssetInfo.iassetTokenNameAscii,
2598
+ collateralAsset1,
2599
+ );
2600
+
2601
+ expect(
2602
+ collateralAssetFirst.datum.firstCollateralAsset,
2603
+ 'Expected this collateral asset to BE first',
2604
+ ).toBeTruthy();
2605
+
2606
+ expect(
2607
+ F.pipe(
2608
+ collateralAssetFirst.datum.nextCollateralAsset,
2609
+ O.fromNullable,
2610
+ O.match(
2611
+ // There should be some next collateral asset
2612
+ () => false,
2613
+ (next) => isSameAssetClass(next, collateralAsset2),
2614
+ ),
2615
+ ),
2616
+ 'Expected correct next collateral asset on the first collateral asset',
2617
+ ).toBeTruthy();
2618
+
2619
+ expect(
2620
+ newCollateralAsset.datum.firstCollateralAsset,
2621
+ 'Expected this collateral asset to NOT BE first',
2622
+ ).toBeFalsy();
2623
+
2624
+ expect(
2625
+ F.pipe(
2626
+ newCollateralAsset.datum.nextCollateralAsset,
2627
+ O.fromNullable,
2628
+ O.match(
2629
+ () => true,
2630
+ // There should be no next collateral asset
2631
+ (_) => false,
2632
+ ),
2633
+ ),
2634
+ 'Expected no next collateral asset on the new collateral asset',
2635
+ ).toBeTruthy();
2636
+ });
2637
+
2638
+ test<MyContext>('Execute add iasset and add collateral asset proposals in parallel (execute iasset first, then collateral asset)', async (context: MyContext) => {
2639
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2640
+
2641
+ const [sysParams, _] = await init(
2642
+ context.lucid,
2643
+ [iusdInitialAssetCfg()],
2644
+ context.emulator.slot,
2645
+ );
2646
+
2647
+ const [pkh, __] = await addrDetails(context.lucid);
2648
+
2649
+ const createIAssetProposal = async (
2650
+ iassetName: Uint8Array<ArrayBufferLike>,
2651
+ ): Promise<bigint> => {
2652
+ const govUtxo = await findGov(
2653
+ context.lucid,
2654
+ sysParams.validatorHashes.govHash,
2655
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2656
+ );
2657
+
2658
+ const [tx, pollId] = await createProposal(
2659
+ {
2660
+ ProposeIAsset: {
2661
+ asset: iassetName,
2662
+ debtMintingFeeRatio: { numerator: 5n, denominator: 1_000n },
2663
+ liquidationProcessingFeeRatio: {
2664
+ numerator: 2n,
2665
+ denominator: 100n,
2666
+ },
2667
+ stabilityPoolWithdrawalFeeRatio: {
2668
+ numerator: 5n,
2669
+ denominator: 1_000n,
2670
+ },
2671
+ redemptionReimbursementRatio: {
2672
+ numerator: 1n,
2673
+ denominator: 100n,
2674
+ },
2675
+ redemptionProcessingFeeRatio: {
2676
+ numerator: 1n,
2677
+ denominator: 100n,
2678
+ },
2679
+ },
2680
+ },
2681
+ null,
2682
+ sysParams,
2683
+ context.lucid,
2684
+ context.emulator.slot,
2685
+ govUtxo.utxo,
2686
+ (
2687
+ await findAllIAssets(
2688
+ context.lucid,
2689
+ sysParams.validatorHashes.iassetHash,
2690
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
2691
+ )
2692
+ ).map((iasset) => iasset.utxo),
2693
+ );
2694
+
2695
+ await runAndAwaitTxBuilder(context.lucid, tx);
2696
+
2697
+ return pollId;
2698
+ };
2699
+
2700
+ const createCollateralAssetProposal = async (
2701
+ iassetName: Uint8Array<ArrayBufferLike>,
2702
+ collateralAset: AssetClass,
2703
+ ): Promise<bigint> => {
2704
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
2705
+ 0n,
2706
+ 0n,
2707
+ 0n,
2708
+ {
2709
+ biasTime: 120_000n,
2710
+ owner: pkh.hash,
2711
+ },
2712
+ context.lucid,
2713
+ );
2714
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
2715
+
2716
+ const [priceOracleTx, priceOracleNft] = await startPriceOracleTx(
2717
+ context.lucid,
2718
+ 'SOME_ORACLE',
2719
+ rationalFromInt(1n),
2720
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
2721
+ context.emulator.slot,
2722
+ );
2723
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
2724
+
2725
+ const govUtxo = await findGov(
2726
+ context.lucid,
2727
+ sysParams.validatorHashes.govHash,
2728
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2729
+ );
2730
+
2731
+ const [tx, pollId] = await createProposal(
2732
+ {
2733
+ AddCollateralAsset: {
2734
+ correspondingIAsset: iassetName,
2735
+ collateralAsset: collateralAset,
2736
+ assetExtraDecimals: 0n,
2737
+ assetPriceInfo: { OracleNft: priceOracleNft },
2738
+ interestOracleNft: interestOracleNft,
2739
+ redemptionRatio: rationalFromInt(2n),
2740
+ maintenanceRatio: { numerator: 150n, denominator: 100n },
2741
+ liquidationRatio: { numerator: 120n, denominator: 100n },
2742
+ minCollateralAmt: 1_000_000n,
2743
+ },
2744
+ },
2745
+ null,
2746
+ sysParams,
2747
+ context.lucid,
2748
+ context.emulator.slot,
2749
+ govUtxo.utxo,
2750
+ [],
2751
+ );
2752
+
2753
+ await runAndAwaitTxBuilder(context.lucid, tx);
2754
+
2755
+ return pollId;
2756
+ };
2757
+
2758
+ const newIAsset = fromHex(fromText('iBTC'));
2759
+ const newCollateralAsset = fromSystemParamsAsset(
2760
+ sysParams.govParams.indyAsset,
2761
+ );
2762
+
2763
+ const createIAssetPollId = await createIAssetProposal(newIAsset);
2764
+ await runCreateAllShards(createIAssetPollId, sysParams, context);
2765
+
2766
+ const addCollateralAssetPollId = await createCollateralAssetProposal(
2767
+ newIAsset,
2768
+ newCollateralAsset,
2769
+ );
2770
+ await runCreateAllShards(addCollateralAssetPollId, sysParams, context);
2771
+
2772
+ await runAndAwaitTx(
2773
+ context.lucid,
2774
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
2775
+ );
2776
+
2777
+ await runVote(createIAssetPollId, 'Yes', sysParams, context);
2778
+ await runVote(addCollateralAssetPollId, 'Yes', sysParams, context);
2779
+
2780
+ await waitForVotingEnd(createIAssetPollId, sysParams, context);
2781
+ await waitForVotingEnd(addCollateralAssetPollId, sysParams, context);
2782
+
2783
+ await runMergeAllShards(createIAssetPollId, sysParams, context);
2784
+ await runMergeAllShards(addCollateralAssetPollId, sysParams, context);
2785
+
2786
+ await runEndProposal(createIAssetPollId, sysParams, context);
2787
+ await runEndProposal(addCollateralAssetPollId, sysParams, context);
2788
+
2789
+ // Execute the iasset proposal
2790
+ await runAndAwaitTx(
2791
+ context.lucid,
2792
+ executeProposal(
2793
+ (
2794
+ await findExecute(
2795
+ context.lucid,
2796
+ sysParams.validatorHashes.executeHash,
2797
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
2798
+ createIAssetPollId,
2799
+ )
2800
+ ).utxo,
2801
+ (
2802
+ await findGov(
2803
+ context.lucid,
2804
+ sysParams.validatorHashes.govHash,
2805
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2806
+ )
2807
+ ).utxo,
2808
+ null,
2809
+ (
2810
+ await findAllIAssets(
2811
+ context.lucid,
2812
+ sysParams.validatorHashes.iassetHash,
2813
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
2814
+ )
2815
+ ).map((iasset) => iasset.utxo),
2816
+ null,
2817
+ null,
2818
+ null,
2819
+ null,
2820
+ sysParams,
2821
+ context.lucid,
2822
+ context.emulator.slot,
2823
+ ),
2824
+ );
2825
+
2826
+ // Execute the add collateral asset proposal
2827
+ await runAndAwaitTx(
2828
+ context.lucid,
2829
+ executeProposal(
2830
+ (
2831
+ await findExecute(
2832
+ context.lucid,
2833
+ sysParams.validatorHashes.executeHash,
2834
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
2835
+ addCollateralAssetPollId,
2836
+ )
2837
+ ).utxo,
2838
+ (
2839
+ await findGov(
2840
+ context.lucid,
2841
+ sysParams.validatorHashes.govHash,
2842
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2843
+ )
2844
+ ).utxo,
2845
+ null,
2846
+ null,
2847
+ (
2848
+ await findIAsset(
2849
+ context.lucid,
2850
+ sysParams.validatorHashes.iassetHash,
2851
+ fromSystemParamsAsset(sysParams.executeParams.iAssetToken),
2852
+ toText(toHex(newIAsset)),
2853
+ )
2854
+ ).utxo,
2855
+ (
2856
+ await findAllCollateralAssetsOfIAsset(
2857
+ context.lucid,
2858
+ sysParams.validatorHashes.iassetHash,
2859
+ fromSystemParamsAsset(
2860
+ sysParams.executeParams.collateralAssetToken,
2861
+ ),
2862
+ newIAsset,
2863
+ )
2864
+ ).map((o) => o.utxo),
2865
+ null,
2866
+ null,
2867
+ sysParams,
2868
+ context.lucid,
2869
+ context.emulator.slot,
2870
+ ),
2871
+ );
2872
+ });
2873
+
2874
+ test<MyContext>('Execute add collateral asset proposal with treasury withdrawal', async (context: MyContext) => {
2875
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
2876
+
2877
+ const [sysParams, [iusdAssetInfo]] = await init(
2878
+ context.lucid,
2879
+ [iusdInitialAssetCfg()],
2880
+ context.emulator.slot,
2881
+ );
2882
+
2883
+ const withdrawalIndyAmt = 1_000n;
2884
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
2885
+ withdrawalIndyAmt,
2886
+ sysParams,
2887
+ context,
2888
+ );
2889
+
2890
+ const [pkh, _] = await addrDetails(context.lucid);
2891
+
2892
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
2893
+ 0n,
2894
+ 0n,
2895
+ 0n,
2896
+ {
2897
+ biasTime: 120_000n,
2898
+ owner: pkh.hash,
2899
+ },
2900
+ context.lucid,
2901
+ );
2902
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
2903
+
2904
+ const [priceOracleTx, priceOracleNft] = await startPriceOracleTx(
2905
+ context.lucid,
2906
+ 'IUSD_INDY_ORACLE',
2907
+ rationalFromInt(1n),
2908
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
2909
+ context.emulator.slot,
2910
+ );
2911
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
2912
+
2913
+ const govUtxo = await findGov(
2914
+ context.lucid,
2915
+ sysParams.validatorHashes.govHash,
2916
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
2917
+ );
2918
+
2919
+ const allIassetOrefs = (
2920
+ await findAllIAssets(
2921
+ context.lucid,
2922
+ sysParams.validatorHashes.iassetHash,
2923
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
2924
+ )
2925
+ ).map((iasset) => iasset.utxo);
2926
+
2927
+ const [tx, pollId] = await createProposal(
2928
+ {
2929
+ AddCollateralAsset: {
2930
+ correspondingIAsset: fromHex(
2931
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
2932
+ ),
2933
+ collateralAsset: fromSystemParamsAsset(
2934
+ sysParams.govParams.indyAsset,
2935
+ ),
2936
+ assetExtraDecimals: 0n,
2937
+ assetPriceInfo: { OracleNft: priceOracleNft },
2938
+ interestOracleNft: interestOracleNft,
2939
+ redemptionRatio: rationalFromInt(2n),
2940
+ maintenanceRatio: { numerator: 150n, denominator: 100n },
2941
+ liquidationRatio: { numerator: 120n, denominator: 100n },
2942
+ minCollateralAmt: 1_000_000n,
2943
+ },
2944
+ },
2945
+ {
2946
+ destination: addressFromBech32(
2947
+ context.users.withdrawalAccount.address,
2948
+ ),
2949
+ value: [
2950
+ {
2951
+ currencySymbol: fromHex(
2952
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
2953
+ ),
2954
+ tokenName: fromHex(
2955
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
2956
+ ),
2957
+ amount: withdrawalIndyAmt,
2958
+ },
2959
+ ],
2960
+ },
2961
+ sysParams,
2962
+ context.lucid,
2963
+ context.emulator.slot,
2964
+ govUtxo.utxo,
2965
+ allIassetOrefs,
2966
+ );
2967
+
2968
+ await runAndAwaitTxBuilder(context.lucid, tx);
2969
+
2970
+ await runCreateAllShards(pollId, sysParams, context);
2971
+
2972
+ await runAndAwaitTx(
2973
+ context.lucid,
2974
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
2975
+ );
2976
+
2977
+ await runVote(pollId, 'Yes', sysParams, context);
2978
+
2979
+ await waitForVotingEnd(pollId, sysParams, context);
2980
+
2981
+ await runMergeAllShards(pollId, sysParams, context);
2982
+
2983
+ await runEndProposal(pollId, sysParams, context);
2984
+
2985
+ const executeUtxo = await findExecute(
2986
+ context.lucid,
2987
+ sysParams.validatorHashes.executeHash,
2988
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
2989
+ pollId,
2990
+ );
2991
+
2992
+ const iassetOutput = await findIAsset(
2993
+ context.lucid,
2994
+ sysParams.validatorHashes.iassetHash,
2995
+ fromSystemParamsAsset(sysParams.executeParams.iAssetToken),
2996
+ iusdAssetInfo.iassetTokenNameAscii,
2997
+ );
2998
+
2999
+ const [__, newVal] = await getValueChangeAtAddressAfterAction(
3000
+ context.lucid,
3001
+ context.users.withdrawalAccount.address,
3002
+ async () =>
3003
+ await benchmarkAndAwaitTx(
3004
+ 'Gov - Execute add collateral asset proposal with treasury withdrawal',
3005
+ await executeProposal(
3006
+ executeUtxo.utxo,
3007
+ (
3008
+ await findGov(
3009
+ context.lucid,
3010
+ sysParams.validatorHashes.govHash,
3011
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3012
+ )
3013
+ ).utxo,
3014
+ treasuryWithdrawalUtxo,
3015
+ null,
3016
+ iassetOutput.utxo,
3017
+ (
3018
+ await findAllCollateralAssetsOfIAsset(
3019
+ context.lucid,
3020
+ sysParams.validatorHashes.iassetHash,
3021
+ fromSystemParamsAsset(
3022
+ sysParams.executeParams.collateralAssetToken,
3023
+ ),
3024
+ fromHex(fromText(iusdAssetInfo.iassetTokenNameAscii)),
3025
+ )
3026
+ ).map((o) => o.utxo),
3027
+ null,
3028
+ null,
3029
+ sysParams,
3030
+ context.lucid,
3031
+ context.emulator.slot,
3032
+ ),
3033
+ context.lucid,
3034
+ context.emulator,
3035
+ ),
3036
+ );
3037
+
3038
+ expect(
3039
+ assetClassValueOf(
3040
+ newVal,
3041
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
3042
+ ) === withdrawalIndyAmt,
3043
+ 'Unexpected withdrawn indy amt',
3044
+ ).toBeTruthy();
3045
+ });
3046
+ });
3047
+
3048
+ test<MyContext>('Execute update collateral asset proposal', async (context: MyContext) => {
3049
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3050
+
3051
+ const [sysParams, [iusdAssetInfo]] = await init(
3052
+ context.lucid,
3053
+ [iusdInitialAssetCfg()],
3054
+ context.emulator.slot,
3055
+ );
3056
+
3057
+ const [pkh, _] = await addrDetails(context.lucid);
3058
+
3059
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
3060
+ 0n,
3061
+ 0n,
3062
+ 0n,
3063
+ {
3064
+ biasTime: 120_000n,
3065
+ owner: pkh.hash,
3066
+ },
3067
+ context.lucid,
3068
+ );
3069
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
3070
+
3071
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
3072
+ context.lucid,
3073
+ 'NEW_IUSD_ADA_ORACLE',
3074
+ rationalFromInt(1n),
3075
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
3076
+ context.emulator.slot,
3077
+ );
3078
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
3079
+
3080
+ const govUtxo = await findGov(
3081
+ context.lucid,
3082
+ sysParams.validatorHashes.govHash,
3083
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3084
+ );
3085
+
3086
+ const allIassetOrefs = (
3087
+ await findAllIAssets(
3088
+ context.lucid,
3089
+ sysParams.validatorHashes.iassetHash,
3090
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3091
+ )
3092
+ ).map((iasset) => iasset.utxo);
3093
+
3094
+ const [tx, pollId] = await createProposal(
3095
+ {
3096
+ UpdateCollateralAsset: {
3097
+ correspondingIAsset: fromHex(
3098
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
3099
+ ),
3100
+ collateralAsset: iusdAssetInfo.collateralAssets[0].collateralAsset,
3101
+ newAssetExtraDecimals: 0n,
3102
+ newAssetPriceInfo: { OracleNft: priceOranceNft },
3103
+ newInterestOracleNft: interestOracleNft,
3104
+ newLiquidationRatio: { numerator: 120n, denominator: 100n },
3105
+ newMaintenanceRatio: { numerator: 150n, denominator: 100n },
3106
+ newRedemptionRatio: { numerator: 150n, denominator: 100n },
3107
+ newMinCollateralAmt: 10_000_000n,
3108
+ },
3109
+ },
3110
+ null,
3111
+ sysParams,
3112
+ context.lucid,
3113
+ context.emulator.slot,
3114
+ govUtxo.utxo,
3115
+ allIassetOrefs,
3116
+ );
3117
+
3118
+ await runAndAwaitTxBuilder(context.lucid, tx);
3119
+
3120
+ await runCreateAllShards(pollId, sysParams, context);
3121
+
3122
+ await runAndAwaitTx(
3123
+ context.lucid,
3124
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
3125
+ );
3126
+
3127
+ await runVote(pollId, 'Yes', sysParams, context);
3128
+
3129
+ await waitForVotingEnd(pollId, sysParams, context);
3130
+
3131
+ await runMergeAllShards(pollId, sysParams, context);
3132
+
3133
+ await runEndProposal(pollId, sysParams, context);
3134
+
3135
+ const executeUtxo = await findExecute(
3136
+ context.lucid,
3137
+ sysParams.validatorHashes.executeHash,
3138
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3139
+ pollId,
3140
+ );
3141
+
3142
+ await benchmarkAndAwaitTx(
3143
+ 'Gov - Execute update collateral asset proposal',
3144
+ await executeProposal(
3145
+ executeUtxo.utxo,
3146
+ (
3147
+ await findGov(
3148
+ context.lucid,
3149
+ sysParams.validatorHashes.govHash,
3150
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3151
+ )
3152
+ ).utxo,
3153
+ null,
3154
+ null,
3155
+ null,
3156
+ null,
3157
+ (
3158
+ await findCollateralAssetNew(
3159
+ context,
3160
+ sysParams,
3161
+ iusdAssetInfo.iassetTokenNameAscii,
3162
+ iusdAssetInfo.collateralAssets[0].collateralAsset,
3163
+ )
3164
+ ).utxo,
3165
+ null,
3166
+ sysParams,
3167
+ context.lucid,
3168
+ context.emulator.slot,
3169
+ ),
3170
+ context.lucid,
3171
+ context.emulator,
3172
+ );
3173
+ });
3174
+
3175
+ test<MyContext>('Execute update collateral asset proposal with treasury withdrawal', async (context: MyContext) => {
3176
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3177
+
3178
+ const [sysParams, [iusdAssetInfo]] = await init(
3179
+ context.lucid,
3180
+ [iusdInitialAssetCfg()],
3181
+ context.emulator.slot,
3182
+ );
3183
+
3184
+ const [pkh, _] = await addrDetails(context.lucid);
3185
+
3186
+ const withdrawalIndyAmt = 1_000n;
3187
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
3188
+ withdrawalIndyAmt,
3189
+ sysParams,
3190
+ context,
3191
+ );
3192
+
3193
+ const [startInterestTx, interestOracleNft] = await startInterestOracle(
3194
+ 0n,
3195
+ 0n,
3196
+ 0n,
3197
+ {
3198
+ biasTime: 120_000n,
3199
+ owner: pkh.hash,
3200
+ },
3201
+ context.lucid,
3202
+ );
3203
+ await runAndAwaitTxBuilder(context.lucid, startInterestTx);
3204
+
3205
+ const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
3206
+ context.lucid,
3207
+ 'NEW_IUSD_ADA_ORACLE',
3208
+ rationalFromInt(1n),
3209
+ { biasTime: 120_000n, expirationPeriod: 1_800_000n, owner: pkh.hash },
3210
+ context.emulator.slot,
3211
+ );
3212
+ await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
3213
+
3214
+ const govUtxo = await findGov(
3215
+ context.lucid,
3216
+ sysParams.validatorHashes.govHash,
3217
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3218
+ );
3219
+
3220
+ const allIassetOrefs = (
3221
+ await findAllIAssets(
3222
+ context.lucid,
3223
+ sysParams.validatorHashes.iassetHash,
3224
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3225
+ )
3226
+ ).map((iasset) => iasset.utxo);
3227
+
3228
+ const [tx, pollId] = await createProposal(
3229
+ {
3230
+ UpdateCollateralAsset: {
3231
+ correspondingIAsset: fromHex(
3232
+ fromText(iusdAssetInfo.iassetTokenNameAscii),
3233
+ ),
3234
+ collateralAsset: iusdAssetInfo.collateralAssets[0].collateralAsset,
3235
+ newAssetExtraDecimals: 0n,
3236
+ newAssetPriceInfo: { OracleNft: priceOranceNft },
3237
+ newInterestOracleNft: interestOracleNft,
3238
+ newLiquidationRatio: { numerator: 120n, denominator: 100n },
3239
+ newMaintenanceRatio: { numerator: 150n, denominator: 100n },
3240
+ newRedemptionRatio: { numerator: 150n, denominator: 100n },
3241
+ newMinCollateralAmt: 10_000_000n,
3242
+ },
3243
+ },
3244
+ {
3245
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
3246
+ value: [
3247
+ {
3248
+ currencySymbol: fromHex(
3249
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
3250
+ ),
3251
+ tokenName: fromHex(
3252
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
3253
+ ),
3254
+ amount: withdrawalIndyAmt,
3255
+ },
3256
+ ],
3257
+ },
3258
+ sysParams,
3259
+ context.lucid,
3260
+ context.emulator.slot,
3261
+ govUtxo.utxo,
3262
+ allIassetOrefs,
3263
+ );
3264
+
3265
+ await runAndAwaitTxBuilder(context.lucid, tx);
3266
+
3267
+ await runCreateAllShards(pollId, sysParams, context);
3268
+
3269
+ await runAndAwaitTx(
3270
+ context.lucid,
3271
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
3272
+ );
3273
+
3274
+ await runVote(pollId, 'Yes', sysParams, context);
3275
+
3276
+ await waitForVotingEnd(pollId, sysParams, context);
3277
+
3278
+ await runMergeAllShards(pollId, sysParams, context);
3279
+
3280
+ await runEndProposal(pollId, sysParams, context);
3281
+
3282
+ const executeUtxo = await findExecute(
3283
+ context.lucid,
3284
+ sysParams.validatorHashes.executeHash,
3285
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3286
+ pollId,
3287
+ );
3288
+
3289
+ const [__, newVal] = await getValueChangeAtAddressAfterAction(
3290
+ context.lucid,
3291
+ context.users.withdrawalAccount.address,
3292
+ async () =>
3293
+ await benchmarkAndAwaitTx(
3294
+ 'Gov - Execute update collateral asset proposal with treasury withdrawal',
3295
+ await executeProposal(
3296
+ executeUtxo.utxo,
3297
+ (
3298
+ await findGov(
3299
+ context.lucid,
3300
+ sysParams.validatorHashes.govHash,
3301
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3302
+ )
3303
+ ).utxo,
3304
+ treasuryWithdrawalUtxo,
3305
+ null,
3306
+ null,
3307
+ null,
3308
+ (
3309
+ await findCollateralAssetNew(
3310
+ context,
3311
+ sysParams,
3312
+ iusdAssetInfo.iassetTokenNameAscii,
3313
+ iusdAssetInfo.collateralAssets[0].collateralAsset,
3314
+ )
3315
+ ).utxo,
3316
+ null,
3317
+ sysParams,
3318
+ context.lucid,
3319
+ context.emulator.slot,
3320
+ ),
3321
+ context.lucid,
3322
+ context.emulator,
3323
+ ),
3324
+ );
3325
+
3326
+ expect(
3327
+ assetClassValueOf(
3328
+ newVal,
3329
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
3330
+ ) === withdrawalIndyAmt,
3331
+ 'Unexpected withdrawn indy amt',
3332
+ ).toBeTruthy();
3333
+ });
3334
+
3335
+ test<MyContext>('Execute create stableswap pool proposal', async (context: MyContext) => {
3336
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3337
+
3338
+ const [sysParams, _] = await init(
3339
+ context.lucid,
3340
+ [iusdInitialAssetCfg()],
3341
+ context.emulator.slot,
3342
+ );
3343
+
3344
+ const feeManager = fromHex(
3345
+ paymentCredentialOf(context.users.admin.address).hash,
3346
+ );
3347
+
3348
+ const govUtxo = await findGov(
3349
+ context.lucid,
3350
+ sysParams.validatorHashes.govHash,
3351
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3352
+ );
3353
+
3354
+ const [tx, pollId] = await createProposal(
3355
+ {
3356
+ ProposeStableswapPool: {
3357
+ iasset: fromHex(fromText('iUSD')),
3358
+ collateralAsset: EXAMPLE_TOKEN_1,
3359
+ collateralToIassetRatio: rationalFromInt(1n),
3360
+ mintingFeeRatio: { numerator: 5n, denominator: 1_000n },
3361
+ redemptionFeeRatio: { numerator: 5n, denominator: 1_000n },
3362
+ feeManager: feeManager,
3363
+ minMintingAmount: 0n,
3364
+ minRedemptionAmount: 0n,
3365
+ stableswapValHash: fromHex(sysParams.validatorHashes.stableswapHash),
3366
+ },
3367
+ },
3368
+ null,
3369
+ sysParams,
3370
+ context.lucid,
3371
+ context.emulator.slot,
3372
+ govUtxo.utxo,
3373
+ (
3374
+ await findAllIAssets(
3375
+ context.lucid,
3376
+ sysParams.validatorHashes.iassetHash,
3377
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3378
+ )
3379
+ ).map((iasset) => iasset.utxo),
3380
+ );
3381
+
3382
+ await runAndAwaitTxBuilder(context.lucid, tx);
3383
+
3384
+ await runCreateAllShards(pollId, sysParams, context);
3385
+
3386
+ await runAndAwaitTx(
3387
+ context.lucid,
3388
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
3389
+ );
3390
+
3391
+ await runVote(pollId, 'Yes', sysParams, context);
3392
+
3393
+ await waitForVotingEnd(pollId, sysParams, context);
3394
+
3395
+ await runMergeAllShards(pollId, sysParams, context);
3396
+
3397
+ await runEndProposal(pollId, sysParams, context);
3398
+
3399
+ const executeUtxo = await findExecute(
3400
+ context.lucid,
3401
+ sysParams.validatorHashes.executeHash,
3402
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3403
+ pollId,
3404
+ );
3405
+
3406
+ const iassetReference = await findIAsset(
3407
+ context.lucid,
3408
+ sysParams.validatorHashes.iassetHash,
3409
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3410
+ 'iUSD',
3411
+ );
3412
+
3413
+ const cdpCreatorUtxo = await findRandomCdpCreator(
3414
+ context.lucid,
3415
+ sysParams.validatorHashes.cdpCreatorHash,
3416
+ fromSystemParamsAsset(sysParams.cdpCreatorParams.cdpCreatorNft),
3417
+ );
3418
+
3419
+ await benchmarkAndAwaitTx(
3420
+ 'Execute create Stableswap proposal',
3421
+ await executeProposal(
3422
+ executeUtxo.utxo,
3423
+ (
3424
+ await findGov(
3425
+ context.lucid,
3426
+ sysParams.validatorHashes.govHash,
3427
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3428
+ )
3429
+ ).utxo,
3430
+ null,
3431
+ null,
3432
+ iassetReference.utxo,
3433
+ null,
3434
+ null,
3435
+ cdpCreatorUtxo,
3436
+ sysParams,
3437
+ context.lucid,
3438
+ context.emulator.slot,
3439
+ ),
3440
+ context.lucid,
3441
+ context.emulator,
3442
+ );
3443
+ });
3444
+
3445
+ test<MyContext>('Execute create stableswap pool proposal with treasury withdrawal', async (context: MyContext) => {
3446
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3447
+
3448
+ const [sysParams, _] = await init(
3449
+ context.lucid,
3450
+ [iusdInitialAssetCfg()],
3451
+ context.emulator.slot,
3452
+ );
3453
+
3454
+ const feeManager = fromHex(
3455
+ paymentCredentialOf(context.users.admin.address).hash,
3456
+ );
3457
+
3458
+ const withdrawalIndyAmt = 1_000n;
3459
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
3460
+ withdrawalIndyAmt,
3461
+ sysParams,
3462
+ context,
3463
+ );
3464
+
3465
+ const [tx, pollId] = await createProposal(
3466
+ {
3467
+ ProposeStableswapPool: {
3468
+ iasset: fromHex(fromText('iUSD')),
3469
+ collateralAsset: EXAMPLE_TOKEN_1,
3470
+ collateralToIassetRatio: rationalFromInt(1n),
3471
+ mintingFeeRatio: { numerator: 5n, denominator: 1_000n },
3472
+ redemptionFeeRatio: { numerator: 5n, denominator: 1_000n },
3473
+ feeManager: feeManager,
3474
+ minMintingAmount: 0n,
3475
+ minRedemptionAmount: 0n,
3476
+ stableswapValHash: fromHex(sysParams.validatorHashes.stableswapHash),
3477
+ },
3478
+ },
3479
+ {
3480
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
3481
+ value: [
3482
+ {
3483
+ currencySymbol: fromHex(
3484
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
3485
+ ),
3486
+ tokenName: fromHex(
3487
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
3488
+ ),
3489
+ amount: withdrawalIndyAmt,
3490
+ },
3491
+ ],
3492
+ },
3493
+ sysParams,
3494
+ context.lucid,
3495
+ context.emulator.slot,
3496
+ (
3497
+ await findGov(
3498
+ context.lucid,
3499
+ sysParams.validatorHashes.govHash,
3500
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3501
+ )
3502
+ ).utxo,
3503
+ (
3504
+ await findAllIAssets(
3505
+ context.lucid,
3506
+ sysParams.validatorHashes.iassetHash,
3507
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3508
+ )
3509
+ ).map((iasset) => iasset.utxo),
3510
+ );
3511
+
3512
+ await runAndAwaitTxBuilder(context.lucid, tx);
3513
+
3514
+ await runCreateAllShards(pollId, sysParams, context);
3515
+
3516
+ await runAndAwaitTx(
3517
+ context.lucid,
3518
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
3519
+ );
3520
+
3521
+ await runVote(pollId, 'Yes', sysParams, context);
3522
+
3523
+ await waitForVotingEnd(pollId, sysParams, context);
3524
+
3525
+ await runMergeAllShards(pollId, sysParams, context);
3526
+
3527
+ await runEndProposal(pollId, sysParams, context);
3528
+
3529
+ const executeUtxo = await findExecute(
3530
+ context.lucid,
3531
+ sysParams.validatorHashes.executeHash,
3532
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3533
+ pollId,
3534
+ );
3535
+
3536
+ const iassetReference = await findIAsset(
3537
+ context.lucid,
3538
+ sysParams.validatorHashes.iassetHash,
3539
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3540
+ 'iUSD',
3541
+ );
3542
+
3543
+ const cdpCreatorUtxo = await findRandomCdpCreator(
3544
+ context.lucid,
3545
+ sysParams.validatorHashes.cdpCreatorHash,
3546
+ fromSystemParamsAsset(sysParams.cdpCreatorParams.cdpCreatorNft),
3547
+ );
3548
+
3549
+ await benchmarkAndAwaitTx(
3550
+ 'Execute create Stableswap proposal with treasury withdrawal',
3551
+ await executeProposal(
3552
+ executeUtxo.utxo,
3553
+ (
3554
+ await findGov(
3555
+ context.lucid,
3556
+ sysParams.validatorHashes.govHash,
3557
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3558
+ )
3559
+ ).utxo,
3560
+ treasuryWithdrawalUtxo,
3561
+ null,
3562
+ iassetReference.utxo,
3563
+ null,
3564
+ null,
3565
+ cdpCreatorUtxo,
3566
+ sysParams,
3567
+ context.lucid,
3568
+ context.emulator.slot,
3569
+ ),
3570
+ context.lucid,
3571
+ context.emulator,
3572
+ );
3573
+ });
3574
+
3575
+ test<MyContext>('Execute modify stableswap pool proposal', async (context: MyContext) => {
3576
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3577
+
3578
+ const [sysParams, _] = await init(
3579
+ context.lucid,
3580
+ [iusdInitialAssetCfg()],
3581
+ context.emulator.slot,
3582
+ );
3583
+
3584
+ const feeManager = fromHex(
3585
+ paymentCredentialOf(context.users.admin.address).hash,
3586
+ );
3587
+ const newFeeManager = fromHex(
3588
+ paymentCredentialOf(context.users.user.address).hash,
3589
+ );
3590
+
3591
+ const iassetStableswapPool = fromHex(fromText('iUSD'));
3592
+ const collateralAssetStableswapPool = EXAMPLE_TOKEN_1;
3593
+
3594
+ const [tx1, pollId1] = await createProposal(
3595
+ {
3596
+ ProposeStableswapPool: {
3597
+ iasset: iassetStableswapPool,
3598
+ collateralAsset: collateralAssetStableswapPool,
3599
+ collateralToIassetRatio: rationalFromInt(1n),
3600
+ mintingFeeRatio: { numerator: 5n, denominator: 1_000n },
3601
+ redemptionFeeRatio: { numerator: 5n, denominator: 1_000n },
3602
+ feeManager: feeManager,
3603
+ minMintingAmount: 0n,
3604
+ minRedemptionAmount: 0n,
3605
+ stableswapValHash: fromHex(sysParams.validatorHashes.stableswapHash),
3606
+ },
3607
+ },
3608
+ null,
3609
+ sysParams,
3610
+ context.lucid,
3611
+ context.emulator.slot,
3612
+ (
3613
+ await findGov(
3614
+ context.lucid,
3615
+ sysParams.validatorHashes.govHash,
3616
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3617
+ )
3618
+ ).utxo,
3619
+ (
3620
+ await findAllIAssets(
3621
+ context.lucid,
3622
+ sysParams.validatorHashes.iassetHash,
3623
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3624
+ )
3625
+ ).map((iasset) => iasset.utxo),
3626
+ );
3627
+
3628
+ await runAndAwaitTxBuilder(context.lucid, tx1);
3629
+
3630
+ await runCreateAllShards(pollId1, sysParams, context);
3631
+
3632
+ await runAndAwaitTx(
3633
+ context.lucid,
3634
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
3635
+ );
3636
+
3637
+ await runVote(pollId1, 'Yes', sysParams, context);
3638
+
3639
+ await waitForVotingEnd(pollId1, sysParams, context);
3640
+
3641
+ await runMergeAllShards(pollId1, sysParams, context);
3642
+
3643
+ await runEndProposal(pollId1, sysParams, context);
3644
+
3645
+ const iassetReference = await findIAsset(
3646
+ context.lucid,
3647
+ sysParams.validatorHashes.iassetHash,
3648
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3649
+ 'iUSD',
3650
+ );
3651
+
3652
+ const cdpCreatorUtxo = await findRandomCdpCreator(
3653
+ context.lucid,
3654
+ sysParams.validatorHashes.cdpCreatorHash,
3655
+ fromSystemParamsAsset(sysParams.cdpCreatorParams.cdpCreatorNft),
3656
+ );
3657
+
3658
+ await runAndAwaitTx(
3659
+ context.lucid,
3660
+ executeProposal(
3661
+ (
3662
+ await findExecute(
3663
+ context.lucid,
3664
+ sysParams.validatorHashes.executeHash,
3665
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3666
+ pollId1,
3667
+ )
3668
+ ).utxo,
3669
+ (
3670
+ await findGov(
3671
+ context.lucid,
3672
+ sysParams.validatorHashes.govHash,
3673
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3674
+ )
3675
+ ).utxo,
3676
+ null,
3677
+ null,
3678
+ iassetReference.utxo,
3679
+ null,
3680
+ null,
3681
+ cdpCreatorUtxo,
3682
+ sysParams,
3683
+ context.lucid,
3684
+ context.emulator.slot,
3685
+ ),
3686
+ );
3687
+
3688
+ const [tx2, pollId2] = await createProposal(
3689
+ {
3690
+ ModifyStableswapPool: {
3691
+ iasset: iassetStableswapPool,
3692
+ collateralAsset: collateralAssetStableswapPool,
3693
+ newCollateralToIassetRatio: rationalFromInt(1n),
3694
+ newMintingFeeRatio: { numerator: 5n, denominator: 1_000n },
3695
+ newRedemptionFeeRatio: { numerator: 5n, denominator: 1_000n },
3696
+ newMintingEnabled: false,
3697
+ newRedemptionEnabled: true,
3698
+ newFeeManager: newFeeManager,
3699
+ newMinMintingAmount: 1n,
3700
+ newMinRedemptionAmount: 1n,
3701
+ newStableswapValHash: fromHex(
3702
+ fromText(sysParams.validatorHashes.stableswapHash),
3703
+ ),
3704
+ },
3705
+ },
3706
+ null,
3707
+ sysParams,
3708
+ context.lucid,
3709
+ context.emulator.slot,
3710
+ (
3711
+ await findGov(
3712
+ context.lucid,
3713
+ sysParams.validatorHashes.govHash,
3714
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3715
+ )
3716
+ ).utxo,
3717
+ (
3718
+ await findAllIAssets(
3719
+ context.lucid,
3720
+ sysParams.validatorHashes.iassetHash,
3721
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3722
+ )
3723
+ ).map((iasset) => iasset.utxo),
3724
+ );
3725
+
3726
+ await runAndAwaitTxBuilder(context.lucid, tx2);
3727
+
3728
+ await runCreateAllShards(pollId2, sysParams, context);
3729
+
3730
+ await runVote(pollId2, 'Yes', sysParams, context);
3731
+
3732
+ await waitForVotingEnd(pollId2, sysParams, context);
3733
+
3734
+ await runMergeAllShards(pollId2, sysParams, context);
3735
+
3736
+ await runEndProposal(pollId2, sysParams, context);
3737
+
3738
+ const stableswapPoolUtxo = await findStableswapPool(
3739
+ context.lucid,
3740
+ sysParams.validatorHashes.cdpHash,
3741
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
3742
+ toHex(iassetStableswapPool),
3743
+ collateralAssetStableswapPool,
3744
+ );
3745
+
3746
+ await benchmarkAndAwaitTx(
3747
+ 'Execute modify Stableswap proposal',
3748
+ await executeProposal(
3749
+ (
3750
+ await findExecute(
3751
+ context.lucid,
3752
+ sysParams.validatorHashes.executeHash,
3753
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3754
+ pollId2,
3755
+ )
3756
+ ).utxo,
3757
+ (
3758
+ await findGov(
3759
+ context.lucid,
3760
+ sysParams.validatorHashes.govHash,
3761
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3762
+ )
3763
+ ).utxo,
3764
+ null,
3765
+ null,
3766
+ null,
3767
+ null,
3768
+ null,
3769
+ stableswapPoolUtxo.utxo,
3770
+ sysParams,
3771
+ context.lucid,
3772
+ context.emulator.slot,
3773
+ ),
3774
+ context.lucid,
3775
+ context.emulator,
3776
+ );
3777
+ });
3778
+
3779
+ test<MyContext>('Execute modify stableswap pool proposal with treasury withdrawal', async (context: MyContext) => {
3780
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
3781
+
3782
+ const [sysParams, _] = await init(
3783
+ context.lucid,
3784
+ [iusdInitialAssetCfg()],
3785
+ context.emulator.slot,
3786
+ );
3787
+
3788
+ const feeManager = fromHex(
3789
+ paymentCredentialOf(context.users.admin.address).hash,
3790
+ );
3791
+ const newFeeManager = fromHex(
3792
+ paymentCredentialOf(context.users.user.address).hash,
3793
+ );
3794
+
3795
+ const iassetStableswapPool = fromHex(fromText('iUSD'));
3796
+ const collateralAssetStableswapPool = EXAMPLE_TOKEN_1;
3797
+
3798
+ const [tx1, pollId1] = await createProposal(
3799
+ {
3800
+ ProposeStableswapPool: {
3801
+ iasset: iassetStableswapPool,
3802
+ collateralAsset: collateralAssetStableswapPool,
3803
+ collateralToIassetRatio: rationalFromInt(1n),
3804
+ mintingFeeRatio: { numerator: 5n, denominator: 1_000n },
3805
+ redemptionFeeRatio: { numerator: 5n, denominator: 1_000n },
3806
+ feeManager: feeManager,
3807
+ minMintingAmount: 0n,
3808
+ minRedemptionAmount: 0n,
3809
+ stableswapValHash: fromHex(sysParams.validatorHashes.stableswapHash),
3810
+ },
3811
+ },
3812
+ null,
3813
+ sysParams,
3814
+ context.lucid,
3815
+ context.emulator.slot,
3816
+ (
3817
+ await findGov(
3818
+ context.lucid,
3819
+ sysParams.validatorHashes.govHash,
3820
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3821
+ )
3822
+ ).utxo,
3823
+ (
3824
+ await findAllIAssets(
3825
+ context.lucid,
3826
+ sysParams.validatorHashes.iassetHash,
3827
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3828
+ )
3829
+ ).map((iasset) => iasset.utxo),
3830
+ );
3831
+
3832
+ await runAndAwaitTxBuilder(context.lucid, tx1);
3833
+
3834
+ await runCreateAllShards(pollId1, sysParams, context);
3835
+
3836
+ await runAndAwaitTx(
3837
+ context.lucid,
3838
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
3839
+ );
3840
+
3841
+ await runVote(pollId1, 'Yes', sysParams, context);
3842
+
3843
+ await waitForVotingEnd(pollId1, sysParams, context);
3844
+
3845
+ await runMergeAllShards(pollId1, sysParams, context);
3846
+
3847
+ await runEndProposal(pollId1, sysParams, context);
3848
+
3849
+ let executeUtxo = await findExecute(
3850
+ context.lucid,
3851
+ sysParams.validatorHashes.executeHash,
3852
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3853
+ pollId1,
3854
+ );
3855
+
3856
+ const iassetReference = await findIAsset(
3857
+ context.lucid,
3858
+ sysParams.validatorHashes.iassetHash,
3859
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3860
+ 'iUSD',
3861
+ );
3862
+
3863
+ const cdpCreatorUtxo = await findRandomCdpCreator(
3864
+ context.lucid,
3865
+ sysParams.validatorHashes.cdpCreatorHash,
3866
+ fromSystemParamsAsset(sysParams.cdpCreatorParams.cdpCreatorNft),
3867
+ );
3868
+
3869
+ await runAndAwaitTx(
3870
+ context.lucid,
3871
+ executeProposal(
3872
+ executeUtxo.utxo,
3873
+ (
3874
+ await findGov(
3875
+ context.lucid,
3876
+ sysParams.validatorHashes.govHash,
3877
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3878
+ )
3879
+ ).utxo,
3880
+ null,
3881
+ null,
3882
+ iassetReference.utxo,
3883
+ null,
3884
+ null,
3885
+ cdpCreatorUtxo,
3886
+ sysParams,
3887
+ context.lucid,
3888
+ context.emulator.slot,
3889
+ ),
3890
+ );
3891
+
3892
+ const withdrawalIndyAmt = 1_000n;
3893
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
3894
+ withdrawalIndyAmt,
3895
+ sysParams,
3896
+ context,
3897
+ );
3898
+
3899
+ const [tx2, pollId2] = await createProposal(
3900
+ {
3901
+ ModifyStableswapPool: {
3902
+ iasset: iassetStableswapPool,
3903
+ collateralAsset: collateralAssetStableswapPool,
3904
+ newCollateralToIassetRatio: rationalFromInt(1n),
3905
+ newMintingFeeRatio: { numerator: 5n, denominator: 1_000n },
3906
+ newRedemptionFeeRatio: { numerator: 5n, denominator: 1_000n },
3907
+ newMintingEnabled: false,
3908
+ newRedemptionEnabled: true,
3909
+ newFeeManager: newFeeManager,
3910
+ newMinMintingAmount: 1n,
3911
+ newMinRedemptionAmount: 1n,
3912
+ newStableswapValHash: fromHex(
3913
+ fromText(sysParams.validatorHashes.stableswapHash),
3914
+ ),
3915
+ },
3916
+ },
3917
+ {
3918
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
3919
+ value: [
3920
+ {
3921
+ currencySymbol: fromHex(
3922
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
3923
+ ),
3924
+ tokenName: fromHex(
3925
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
3926
+ ),
3927
+ amount: withdrawalIndyAmt,
3928
+ },
3929
+ ],
3930
+ },
3931
+ sysParams,
3932
+ context.lucid,
3933
+ context.emulator.slot,
3934
+ (
3935
+ await findGov(
3936
+ context.lucid,
3937
+ sysParams.validatorHashes.govHash,
3938
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3939
+ )
3940
+ ).utxo,
3941
+ (
3942
+ await findAllIAssets(
3943
+ context.lucid,
3944
+ sysParams.validatorHashes.iassetHash,
3945
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
3946
+ )
3947
+ ).map((iasset) => iasset.utxo),
3948
+ );
3949
+
3950
+ await runAndAwaitTxBuilder(context.lucid, tx2);
3951
+
3952
+ await runCreateAllShards(pollId2, sysParams, context);
3953
+
3954
+ await runVote(pollId2, 'Yes', sysParams, context);
3955
+
3956
+ await waitForVotingEnd(pollId2, sysParams, context);
3957
+
3958
+ await runMergeAllShards(pollId2, sysParams, context);
3959
+
3960
+ await runEndProposal(pollId2, sysParams, context);
3961
+
3962
+ const stableswapPoolUtxo = await findStableswapPool(
3963
+ context.lucid,
3964
+ sysParams.validatorHashes.cdpHash,
3965
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
3966
+ toHex(iassetStableswapPool),
3967
+ collateralAssetStableswapPool,
3968
+ );
3969
+
3970
+ executeUtxo = await findExecute(
3971
+ context.lucid,
3972
+ sysParams.validatorHashes.executeHash,
3973
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
3974
+ pollId2,
3975
+ );
3976
+
3977
+ await benchmarkAndAwaitTx(
3978
+ 'Execute modify Stableswap proposal with treasury withdrawal',
3979
+ await executeProposal(
3980
+ executeUtxo.utxo,
3981
+ (
3982
+ await findGov(
3983
+ context.lucid,
3984
+ sysParams.validatorHashes.govHash,
3985
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
3986
+ )
3987
+ ).utxo,
3988
+ treasuryWithdrawalUtxo,
3989
+ null,
3990
+ null,
3991
+ null,
3992
+ null,
3993
+ stableswapPoolUtxo.utxo,
3994
+ sysParams,
3995
+ context.lucid,
3996
+ context.emulator.slot,
3997
+ ),
3998
+ context.lucid,
3999
+ context.emulator,
4000
+ );
4001
+ });
4002
+
4003
+ test<MyContext>('Execute modify protocol params proposal', async (context: MyContext) => {
4004
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
4005
+
4006
+ const [sysParams, _] = await init(
4007
+ context.lucid,
4008
+ [iusdInitialAssetCfg()],
4009
+ context.emulator.slot,
4010
+ );
4011
+
4012
+ const govUtxo = await findGov(
4013
+ context.lucid,
4014
+ sysParams.validatorHashes.govHash,
4015
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4016
+ );
4017
+
4018
+ const [tx, pollId] = await createProposal(
4019
+ {
4020
+ ModifyProtocolParams: {
4021
+ newParams: {
4022
+ proposalDeposit: govUtxo.datum.protocolParams.proposalDeposit * 2n,
4023
+ votingPeriod: ONE_DAY * 2n,
4024
+ effectiveDelay: govUtxo.datum.protocolParams.effectiveDelay,
4025
+ expirationPeriod: ONE_DAY * 2n,
4026
+ proposingPeriod: ONE_DAY,
4027
+ /// Total numer of shards used for voting.
4028
+ totalShards: govUtxo.datum.protocolParams.totalShards,
4029
+ /// The minimum number of votes (yes + no votes) for a proposal to be possible to pass.
4030
+ minimumQuorum: govUtxo.datum.protocolParams.minimumQuorum,
4031
+ /// Maximum amount of lovelaces that can be spent at once from the treasury.
4032
+ maxTreasuryLovelaceSpend:
4033
+ govUtxo.datum.protocolParams.maxTreasuryLovelaceSpend,
4034
+ /// Maximum amount of INDY that can be spent at once from the treasury.
4035
+ maxTreasuryIndySpend:
4036
+ govUtxo.datum.protocolParams.maxTreasuryIndySpend,
4037
+ cdpRedemptionRequiredSignature:
4038
+ govUtxo.datum.protocolParams.cdpRedemptionRequiredSignature,
4039
+ electorate: govUtxo.datum.protocolParams.electorate,
4040
+ foundationMultisig: govUtxo.datum.protocolParams.foundationMultisig,
4041
+ },
4042
+ },
4043
+ },
4044
+ null,
4045
+ sysParams,
4046
+ context.lucid,
4047
+ context.emulator.slot,
4048
+ govUtxo.utxo,
4049
+ [],
4050
+ );
4051
+
4052
+ await runAndAwaitTxBuilder(context.lucid, tx);
4053
+
4054
+ await runCreateAllShards(pollId, sysParams, context);
4055
+
4056
+ await runAndAwaitTx(
4057
+ context.lucid,
4058
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
4059
+ );
4060
+
4061
+ await runVote(pollId, 'Yes', sysParams, context);
4062
+
4063
+ await waitForVotingEnd(pollId, sysParams, context);
4064
+
4065
+ await runMergeAllShards(pollId, sysParams, context);
4066
+
4067
+ await runEndProposal(pollId, sysParams, context);
4068
+
4069
+ const executeUtxo = await findExecute(
4070
+ context.lucid,
4071
+ sysParams.validatorHashes.executeHash,
4072
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
4073
+ pollId,
4074
+ );
4075
+
4076
+ await benchmarkAndAwaitTx(
4077
+ 'Gov - Execute modify protocol params proposal',
4078
+ await executeProposal(
4079
+ executeUtxo.utxo,
4080
+ (
4081
+ await findGov(
4082
+ context.lucid,
4083
+ sysParams.validatorHashes.govHash,
4084
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4085
+ )
4086
+ ).utxo,
4087
+ null,
4088
+ null,
4089
+ null,
4090
+ null,
4091
+ null,
4092
+ null,
4093
+ sysParams,
4094
+ context.lucid,
4095
+ context.emulator.slot,
4096
+ ),
4097
+ context.lucid,
4098
+ context.emulator,
4099
+ );
4100
+ });
4101
+
4102
+ test<MyContext>('Execute modify protocol params proposal with treasury withdrawal', async (context: MyContext) => {
4103
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
4104
+
4105
+ const [sysParams, _] = await init(
4106
+ context.lucid,
4107
+ [iusdInitialAssetCfg()],
4108
+ context.emulator.slot,
4109
+ );
4110
+
4111
+ const withdrawalIndyAmt = 1_000n;
4112
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
4113
+ withdrawalIndyAmt,
4114
+ sysParams,
4115
+ context,
4116
+ );
4117
+
4118
+ const govUtxo = await findGov(
4119
+ context.lucid,
4120
+ sysParams.validatorHashes.govHash,
4121
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4122
+ );
4123
+
4124
+ const [tx, pollId] = await createProposal(
4125
+ {
4126
+ ModifyProtocolParams: {
4127
+ newParams: {
4128
+ proposalDeposit: govUtxo.datum.protocolParams.proposalDeposit * 2n,
4129
+ votingPeriod: ONE_DAY * 2n,
4130
+ effectiveDelay: govUtxo.datum.protocolParams.effectiveDelay,
4131
+ expirationPeriod: ONE_DAY * 2n,
4132
+ proposingPeriod: ONE_DAY,
4133
+ /// Total numer of shards used for voting.
4134
+ totalShards: govUtxo.datum.protocolParams.totalShards,
4135
+ /// The minimum number of votes (yes + no votes) for a proposal to be possible to pass.
4136
+ minimumQuorum: govUtxo.datum.protocolParams.minimumQuorum,
4137
+ /// Maximum amount of lovelaces that can be spent at once from the treasury.
4138
+ maxTreasuryLovelaceSpend:
4139
+ govUtxo.datum.protocolParams.maxTreasuryLovelaceSpend,
4140
+ /// Maximum amount of INDY that can be spent at once from the treasury.
4141
+ maxTreasuryIndySpend:
4142
+ govUtxo.datum.protocolParams.maxTreasuryIndySpend,
4143
+ cdpRedemptionRequiredSignature:
4144
+ govUtxo.datum.protocolParams.cdpRedemptionRequiredSignature,
4145
+ electorate: govUtxo.datum.protocolParams.electorate,
4146
+ foundationMultisig: govUtxo.datum.protocolParams.foundationMultisig,
4147
+ },
4148
+ },
4149
+ },
4150
+ {
4151
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
4152
+ value: [
4153
+ {
4154
+ currencySymbol: fromHex(
4155
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
4156
+ ),
4157
+ tokenName: fromHex(
4158
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
4159
+ ),
4160
+ amount: withdrawalIndyAmt,
4161
+ },
4162
+ ],
4163
+ },
4164
+ sysParams,
4165
+ context.lucid,
4166
+ context.emulator.slot,
4167
+ govUtxo.utxo,
4168
+ [],
4169
+ );
4170
+
4171
+ await runAndAwaitTxBuilder(context.lucid, tx);
4172
+
4173
+ await runCreateAllShards(pollId, sysParams, context);
4174
+
4175
+ await runAndAwaitTx(
4176
+ context.lucid,
4177
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
4178
+ );
4179
+
4180
+ await runVote(pollId, 'Yes', sysParams, context);
4181
+
4182
+ await waitForVotingEnd(pollId, sysParams, context);
4183
+
4184
+ await runMergeAllShards(pollId, sysParams, context);
4185
+
4186
+ await runEndProposal(pollId, sysParams, context);
4187
+
4188
+ const executeUtxo = await findExecute(
4189
+ context.lucid,
4190
+ sysParams.validatorHashes.executeHash,
4191
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
4192
+ pollId,
4193
+ );
4194
+
4195
+ const [__, newVal] = await getValueChangeAtAddressAfterAction(
4196
+ context.lucid,
4197
+ context.users.withdrawalAccount.address,
4198
+ async () =>
4199
+ benchmarkAndAwaitTx(
4200
+ 'Execute modify protocol params proposal with treasury withdrawal',
4201
+ await executeProposal(
4202
+ executeUtxo.utxo,
4203
+ (
4204
+ await findGov(
4205
+ context.lucid,
4206
+ sysParams.validatorHashes.govHash,
4207
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4208
+ )
4209
+ ).utxo,
4210
+ treasuryWithdrawalUtxo,
4211
+ null,
4212
+ null,
4213
+ null,
4214
+ null,
4215
+ null,
4216
+ sysParams,
4217
+ context.lucid,
4218
+ context.emulator.slot,
4219
+ ),
4220
+ context.lucid,
4221
+ context.emulator,
4222
+ ),
4223
+ );
4224
+
4225
+ expect(
4226
+ assetClassValueOf(
4227
+ newVal,
4228
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
4229
+ ) === withdrawalIndyAmt,
4230
+ 'Unexpected withdrawn indy amt',
4231
+ ).toBeTruthy();
4232
+ });
4233
+
4234
+ test<MyContext>('Execute upgrade protocol proposal', async (context: MyContext) => {
4235
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
4236
+
4237
+ const [sysParams, _] = await init(
4238
+ context.lucid,
4239
+ [iusdInitialAssetCfg()],
4240
+ context.emulator.slot,
4241
+ );
4242
+
4243
+ const govUtxo = await findGov(
4244
+ context.lucid,
4245
+ sysParams.validatorHashes.govHash,
4246
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4247
+ );
4248
+
4249
+ const [tx, pollId] = await createProposal(
4250
+ {
4251
+ UpgradeProtocol: {
4252
+ content: {
4253
+ upgradeId: govUtxo.datum.currentVersion + 1n,
4254
+ upgradePaths: [
4255
+ [
4256
+ fromHex(sysParams.validatorHashes.cdpHash),
4257
+ // NOTICE: this is just a placeholder, in real scenario it needs upgrade minting policy hash
4258
+ {
4259
+ upgradeSymbol: fromHex(
4260
+ sysParams.validatorHashes.cdpCreatorHash,
4261
+ ),
4262
+ },
4263
+ ],
4264
+ ],
4265
+ },
4266
+ },
4267
+ },
4268
+ null,
4269
+ sysParams,
4270
+ context.lucid,
4271
+ context.emulator.slot,
4272
+ govUtxo.utxo,
4273
+ [],
4274
+ );
4275
+
4276
+ await runAndAwaitTxBuilder(context.lucid, tx);
4277
+
4278
+ await runCreateAllShards(pollId, sysParams, context);
4279
+
4280
+ await runAndAwaitTx(
4281
+ context.lucid,
4282
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
4283
+ );
4284
+
4285
+ await runVote(pollId, 'Yes', sysParams, context);
4286
+
4287
+ await waitForVotingEnd(pollId, sysParams, context);
4288
+
4289
+ await runMergeAllShards(pollId, sysParams, context);
4290
+
4291
+ await runEndProposal(pollId, sysParams, context);
4292
+
4293
+ const executeUtxo = await findExecute(
4294
+ context.lucid,
4295
+ sysParams.validatorHashes.executeHash,
4296
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
4297
+ pollId,
4298
+ );
4299
+
4300
+ await benchmarkAndAwaitTx(
4301
+ 'Gov - Execute upgrade protocol proposal',
4302
+ await executeProposal(
4303
+ executeUtxo.utxo,
4304
+ (
4305
+ await findGov(
4306
+ context.lucid,
4307
+ sysParams.validatorHashes.govHash,
4308
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4309
+ )
4310
+ ).utxo,
4311
+ null,
4312
+ null,
4313
+ null,
4314
+ null,
4315
+ null,
4316
+ null,
4317
+ sysParams,
4318
+ context.lucid,
4319
+ context.emulator.slot,
4320
+ ),
4321
+ context.lucid,
4322
+ context.emulator,
4323
+ );
4324
+ });
4325
+
4326
+ test<MyContext>('Execute upgrade protocol proposal with withdrawal', async (context: MyContext) => {
4327
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
4328
+
4329
+ const [sysParams, _] = await init(
4330
+ context.lucid,
4331
+ [iusdInitialAssetCfg()],
4332
+ context.emulator.slot,
4333
+ );
4334
+
4335
+ const withdrawalIndyAmt = 1_000n;
4336
+ const treasuryWithdrawalUtxo = await createIndyUtxoAtTreasury(
4337
+ withdrawalIndyAmt,
4338
+ sysParams,
4339
+ context,
4340
+ );
4341
+
4342
+ const govUtxo = await findGov(
4343
+ context.lucid,
4344
+ sysParams.validatorHashes.govHash,
4345
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4346
+ );
4347
+
4348
+ const [tx, pollId] = await createProposal(
4349
+ {
4350
+ UpgradeProtocol: {
4351
+ content: {
4352
+ upgradeId: govUtxo.datum.currentVersion + 1n,
4353
+ upgradePaths: [
4354
+ [
4355
+ fromHex(sysParams.validatorHashes.cdpHash),
4356
+ // NOTICE: this is just a placeholder, in real scenario it needs upgrade minting policy hash
4357
+ {
4358
+ upgradeSymbol: fromHex(
4359
+ sysParams.validatorHashes.cdpCreatorHash,
4360
+ ),
4361
+ },
4362
+ ],
4363
+ ],
4364
+ },
4365
+ },
4366
+ },
4367
+ {
4368
+ destination: addressFromBech32(context.users.withdrawalAccount.address),
4369
+ value: [
4370
+ {
4371
+ currencySymbol: fromHex(
4372
+ sysParams.govParams.indyAsset[0].unCurrencySymbol,
4373
+ ),
4374
+ tokenName: fromHex(
4375
+ fromText(sysParams.govParams.indyAsset[1].unTokenName),
4376
+ ),
4377
+ amount: withdrawalIndyAmt,
4378
+ },
4379
+ ],
4380
+ },
4381
+ sysParams,
4382
+ context.lucid,
4383
+ context.emulator.slot,
4384
+ govUtxo.utxo,
4385
+ [],
4386
+ );
4387
+
4388
+ await runAndAwaitTxBuilder(context.lucid, tx);
4389
+
4390
+ await runCreateAllShards(pollId, sysParams, context);
4391
+
4392
+ await runAndAwaitTx(
4393
+ context.lucid,
4394
+ openStakingPosition(100_000_000_000n, sysParams, context.lucid),
4395
+ );
4396
+
4397
+ await runVote(pollId, 'Yes', sysParams, context);
4398
+
4399
+ await waitForVotingEnd(pollId, sysParams, context);
4400
+
4401
+ await runMergeAllShards(pollId, sysParams, context);
4402
+
4403
+ await runEndProposal(pollId, sysParams, context);
4404
+
4405
+ const executeUtxo = await findExecute(
4406
+ context.lucid,
4407
+ sysParams.validatorHashes.executeHash,
4408
+ fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
4409
+ pollId,
4410
+ );
4411
+
4412
+ const [__, newVal] = await getValueChangeAtAddressAfterAction(
4413
+ context.lucid,
4414
+ context.users.withdrawalAccount.address,
4415
+ async () =>
4416
+ benchmarkAndAwaitTx(
4417
+ 'Gov - Execute upgrade protocol proposal with withdrawal',
4418
+ await executeProposal(
4419
+ executeUtxo.utxo,
4420
+ (
4421
+ await findGov(
4422
+ context.lucid,
4423
+ sysParams.validatorHashes.govHash,
4424
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
4425
+ )
4426
+ ).utxo,
4427
+ treasuryWithdrawalUtxo,
4428
+ null,
4429
+ null,
4430
+ null,
4431
+ null,
4432
+ null,
4433
+ sysParams,
4434
+ context.lucid,
4435
+ context.emulator.slot,
4436
+ ),
4437
+ context.lucid,
4438
+ context.emulator,
4439
+ ),
4440
+ );
4441
+
4442
+ expect(
4443
+ assetClassValueOf(
4444
+ newVal,
4445
+ fromSystemParamsAsset(sysParams.govParams.indyAsset),
4446
+ ) === withdrawalIndyAmt,
4447
+ 'Unexpected withdrawn indy amt',
4448
+ ).toBeTruthy();
4449
+ });
4450
+ });