Skip to content

Commit ec7acf1

Browse files
committed
Implement amulet form to action encoder [ci]
Fixes #2413 Signed-off-by: fayi-da <[email protected]>
1 parent dbd35e3 commit ec7acf1

File tree

4 files changed

+565
-7
lines changed

4 files changed

+565
-7
lines changed
Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { describe, expect, test } from 'vitest';
5+
import { ConfigChange } from '../../utils/types';
6+
import { buildAmuletRulesConfigFromChanges } from '../../utils/buildAmuletRulesConfigFromChanges';
7+
8+
describe('buildAmuletRulesConfigFromChanges', () => {
9+
test('should build AmuletConfig with provided changes', () => {
10+
const changes: ConfigChange[] = [
11+
{
12+
fieldName: 'tickDuration',
13+
label: 'Tick Duration',
14+
currentValue: '1000',
15+
newValue: '2000',
16+
},
17+
{
18+
fieldName: 'transferPreapprovalFee',
19+
label: 'Transfer Preapproval Fee',
20+
currentValue: '0.1',
21+
newValue: '0.2',
22+
},
23+
{
24+
fieldName: 'featuredAppActivityMarkerAmount',
25+
label: 'Featured App Activity Marker Amount',
26+
currentValue: '100',
27+
newValue: '200',
28+
},
29+
{
30+
fieldName: 'transferConfigCreateFee',
31+
label: 'Transfer Config Create Fee',
32+
currentValue: '0.5',
33+
newValue: '1.0',
34+
},
35+
{
36+
fieldName: 'transferConfigHoldingFeeRate',
37+
label: 'Transfer Config Holding Fee Rate',
38+
currentValue: '0.01',
39+
newValue: '0.02',
40+
},
41+
{
42+
fieldName: 'transferConfigTransferFeeInitialRate',
43+
label: 'Transfer Fee Initial Rate',
44+
currentValue: '0.001',
45+
newValue: '0.002',
46+
},
47+
{
48+
fieldName: 'transferFeeSteps1_1',
49+
label: 'Transfer Fee Step 1 Amount',
50+
currentValue: '100',
51+
newValue: '200',
52+
},
53+
{
54+
fieldName: 'transferFeeSteps1_2',
55+
label: 'Transfer Fee Step 1 Rate',
56+
currentValue: '0.001',
57+
newValue: '0.002',
58+
},
59+
{
60+
fieldName: 'transferConfigLockHolderFee',
61+
label: 'Lock Holder Fee',
62+
currentValue: '0.1',
63+
newValue: '0.2',
64+
},
65+
{
66+
fieldName: 'transferConfigExtraFeaturedAppRewardAmount',
67+
label: 'Extra Featured App Reward Amount',
68+
currentValue: '50',
69+
newValue: '100',
70+
},
71+
{
72+
fieldName: 'transferConfigMaxNumInputs',
73+
label: 'Max Num Inputs',
74+
currentValue: '10',
75+
newValue: '20',
76+
},
77+
{
78+
fieldName: 'transferConfigMaxNumOutputs',
79+
label: 'Max Num Outputs',
80+
currentValue: '10',
81+
newValue: '20',
82+
},
83+
{
84+
fieldName: 'transferConfigMaxNumLockHolders',
85+
label: 'Max Num Lock Holders',
86+
currentValue: '5',
87+
newValue: '10',
88+
},
89+
{
90+
fieldName: 'issuanceCurveInitialValueAmuletToIssuePerYear',
91+
label: 'Amulet To Issue Per Year',
92+
currentValue: '1000000',
93+
newValue: '2000000',
94+
},
95+
{
96+
fieldName: 'issuanceCurveInitialValueValidatorRewardPercentage',
97+
label: 'Validator Reward Percentage',
98+
currentValue: '0.4',
99+
newValue: '0.5',
100+
},
101+
{
102+
fieldName: 'issuanceCurveInitialValueAppRewardPercentage',
103+
label: 'App Reward Percentage',
104+
currentValue: '0.3',
105+
newValue: '0.35',
106+
},
107+
{
108+
fieldName: 'issuanceCurveInitialValueValidatorRewardCap',
109+
label: 'Validator Reward Cap',
110+
currentValue: '1000',
111+
newValue: '2000',
112+
},
113+
{
114+
fieldName: 'issuanceCurveInitialValueFeaturedAppRewardCap',
115+
label: 'Featured App Reward Cap',
116+
currentValue: '500',
117+
newValue: '1000',
118+
},
119+
{
120+
fieldName: 'issuanceCurveInitialValueUnfeaturedAppRewardCap',
121+
label: 'Unfeatured App Reward Cap',
122+
currentValue: '100',
123+
newValue: '200',
124+
},
125+
{
126+
fieldName: 'issuanceCurveInitialValueOptValidatorFaucetCap',
127+
label: 'Opt Validator Faucet Cap',
128+
currentValue: '50',
129+
newValue: '100',
130+
},
131+
{
132+
fieldName: 'decentralizedSynchronizerActiveSynchronizer',
133+
label: 'Active Synchronizer',
134+
currentValue: 'sync1',
135+
newValue: 'sync2',
136+
},
137+
{
138+
fieldName: 'decentralizedSynchronizerRequiredSynchronizers0',
139+
label: 'Required Synchronizer 1',
140+
currentValue: 'sync1',
141+
newValue: 'sync1',
142+
},
143+
{
144+
fieldName: 'decentralizedSynchronizerRequiredSynchronizers1',
145+
label: 'Required Synchronizer 2',
146+
currentValue: 'sync2',
147+
newValue: 'sync2',
148+
},
149+
{
150+
fieldName: 'decentralizedSynchronizerFeesBaseRateTrafficLimitsBurstAmount',
151+
label: 'Burst Amount',
152+
currentValue: '1000',
153+
newValue: '2000',
154+
},
155+
{
156+
fieldName: 'decentralizedSynchronizerFeesBaseRateTrafficLimitsBurstWindow',
157+
label: 'Burst Window',
158+
currentValue: '60000000',
159+
newValue: '120000000',
160+
},
161+
{
162+
fieldName: 'decentralizedSynchronizerFeesExtraTrafficPrice',
163+
label: 'Extra Traffic Price',
164+
currentValue: '0.1',
165+
newValue: '0.2',
166+
},
167+
{
168+
fieldName: 'decentralizedSynchronizerFeesReadVsWriteScalingFactor',
169+
label: 'Read Vs Write Scaling Factor',
170+
currentValue: '1.5',
171+
newValue: '2.0',
172+
},
173+
{
174+
fieldName: 'decentralizedSynchronizerFeesMinTopupAmount',
175+
label: 'Min Topup Amount',
176+
currentValue: '10',
177+
newValue: '20',
178+
},
179+
{
180+
fieldName: 'packageConfigAmulet',
181+
label: 'Amulet Package',
182+
currentValue: '0.1.1',
183+
newValue: '0.2.0',
184+
},
185+
{
186+
fieldName: 'packageConfigAmuletNameService',
187+
label: 'Amulet Name Service Package',
188+
currentValue: '0.1.1',
189+
newValue: '0.2.0',
190+
},
191+
{
192+
fieldName: 'packageConfigDsoGovernance',
193+
label: 'DSO Governance Package',
194+
currentValue: '0.1.1',
195+
newValue: '0.2.0',
196+
},
197+
{
198+
fieldName: 'packageConfigValidatorLifecycle',
199+
label: 'Validator Lifecycle Package',
200+
currentValue: '0.1.1',
201+
newValue: '0.2.0',
202+
},
203+
{
204+
fieldName: 'packageConfigWallet',
205+
label: 'Wallet Package',
206+
currentValue: '0.1.1',
207+
newValue: '0.2.0',
208+
},
209+
{
210+
fieldName: 'packageConfigWalletPayments',
211+
label: 'Wallet Payments Package',
212+
currentValue: '0.1.1',
213+
newValue: '0.2.0',
214+
},
215+
];
216+
217+
const result = buildAmuletRulesConfigFromChanges(changes);
218+
219+
expect(result.tickDuration.microseconds).toBe('2000');
220+
expect(result.transferPreapprovalFee).toBe('0.2');
221+
expect(result.featuredAppActivityMarkerAmount).toBe('200');
222+
223+
expect(result.transferConfig.createFee.fee).toBe('1.0');
224+
expect(result.transferConfig.holdingFee).toEqual({ rate: '0.02' });
225+
expect(result.transferConfig.transferFee.initialRate).toBe('0.002');
226+
expect(result.transferConfig.transferFee.steps).toEqual([{ _1: '200', _2: '0.002' }]);
227+
expect(result.transferConfig.lockHolderFee.fee).toBe('0.2');
228+
expect(result.transferConfig.extraFeaturedAppRewardAmount).toBe('100');
229+
expect(result.transferConfig.maxNumInputs).toBe('20');
230+
expect(result.transferConfig.maxNumOutputs).toBe('20');
231+
expect(result.transferConfig.maxNumLockHolders).toBe('10');
232+
233+
expect(result.issuanceCurve.initialValue.amuletToIssuePerYear).toBe('2000000');
234+
expect(result.issuanceCurve.initialValue.validatorRewardPercentage).toBe('0.5');
235+
expect(result.issuanceCurve.initialValue.appRewardPercentage).toBe('0.35');
236+
expect(result.issuanceCurve.initialValue.validatorRewardCap).toBe('2000');
237+
expect(result.issuanceCurve.initialValue.featuredAppRewardCap).toBe('1000');
238+
expect(result.issuanceCurve.initialValue.unfeaturedAppRewardCap).toBe('200');
239+
expect(result.issuanceCurve.initialValue.optValidatorFaucetCap).toBe('100');
240+
241+
expect(result.decentralizedSynchronizer.activeSynchronizer).toBe('sync2');
242+
const expectedRequiredSynchronizers = Array.from(
243+
result.decentralizedSynchronizer.requiredSynchronizers.map.entriesArray().map(e => e[0])
244+
).sort();
245+
expect(expectedRequiredSynchronizers).toEqual(['sync1', 'sync2']);
246+
expect(result.decentralizedSynchronizer.fees.baseRateTrafficLimits.burstAmount).toBe('2000');
247+
expect(
248+
result.decentralizedSynchronizer.fees.baseRateTrafficLimits.burstWindow.microseconds
249+
).toBe('120000000');
250+
expect(result.decentralizedSynchronizer.fees.extraTrafficPrice).toBe('0.2');
251+
expect(result.decentralizedSynchronizer.fees.readVsWriteScalingFactor).toBe('2.0');
252+
expect(result.decentralizedSynchronizer.fees.minTopupAmount).toBe('20');
253+
254+
expect(result.packageConfig.amulet).toBe('0.2.0');
255+
expect(result.packageConfig.amuletNameService).toBe('0.2.0');
256+
expect(result.packageConfig.dsoGovernance).toBe('0.2.0');
257+
expect(result.packageConfig.validatorLifecycle).toBe('0.2.0');
258+
expect(result.packageConfig.wallet).toBe('0.2.0');
259+
expect(result.packageConfig.walletPayments).toBe('0.2.0');
260+
});
261+
262+
test('should handle multiple transfer fee steps', () => {
263+
const changes: ConfigChange[] = [
264+
{
265+
fieldName: 'transferConfigTransferFeeInitialRate',
266+
label: 'Transfer Fee Initial Rate',
267+
currentValue: '0.001',
268+
newValue: '0.002',
269+
},
270+
{
271+
fieldName: 'transferFeeSteps1_1',
272+
label: 'Transfer Fee Step 1 Amount',
273+
currentValue: '100',
274+
newValue: '200',
275+
},
276+
{
277+
fieldName: 'transferFeeSteps1_2',
278+
label: 'Transfer Fee Step 1 Rate',
279+
currentValue: '0.001',
280+
newValue: '0.002',
281+
},
282+
{
283+
fieldName: 'transferFeeSteps2_1',
284+
label: 'Transfer Fee Step 2 Amount',
285+
currentValue: '500',
286+
newValue: '1000',
287+
},
288+
{
289+
fieldName: 'transferFeeSteps2_2',
290+
label: 'Transfer Fee Step 2 Rate',
291+
currentValue: '0.0005',
292+
newValue: '0.001',
293+
},
294+
];
295+
296+
const result = buildAmuletRulesConfigFromChanges(changes);
297+
298+
expect(result.transferConfig.transferFee.steps).toEqual([
299+
{ _1: '200', _2: '0.002' },
300+
{ _1: '1000', _2: '0.001' },
301+
]);
302+
});
303+
304+
test('should handle issuance curve future values', () => {
305+
const changes: ConfigChange[] = [
306+
{
307+
fieldName: 'issuanceCurveFutureValues0',
308+
label: 'Future Value 0 Time',
309+
currentValue: '1000000',
310+
newValue: '2000000',
311+
},
312+
{
313+
fieldName: 'issuanceCurveFutureValues0AmuletToIssuePerYear',
314+
label: 'Future Value 0 Amulet To Issue Per Year',
315+
currentValue: '1000000',
316+
newValue: '2000000',
317+
},
318+
{
319+
fieldName: 'issuanceCurveFutureValues0ValidatorRewardPercentage',
320+
label: 'Future Value 0 Validator Reward Percentage',
321+
currentValue: '0.4',
322+
newValue: '0.5',
323+
},
324+
{
325+
fieldName: 'issuanceCurveFutureValues0AppRewardPercentage',
326+
label: 'Future Value 0 App Reward Percentage',
327+
currentValue: '0.3',
328+
newValue: '0.35',
329+
},
330+
{
331+
fieldName: 'issuanceCurveFutureValues0ValidatorRewardCap',
332+
label: 'Future Value 0 Validator Reward Cap',
333+
currentValue: '1000',
334+
newValue: '2000',
335+
},
336+
{
337+
fieldName: 'issuanceCurveFutureValues0FeaturedAppRewardCap',
338+
label: 'Future Value 0 Featured App Reward Cap',
339+
currentValue: '500',
340+
newValue: '1000',
341+
},
342+
{
343+
fieldName: 'issuanceCurveFutureValues0UnfeaturedAppRewardCap',
344+
label: 'Future Value 0 Unfeatured App Reward Cap',
345+
currentValue: '100',
346+
newValue: '200',
347+
},
348+
{
349+
fieldName: 'issuanceCurveFutureValues0OptValidatorFaucetCap',
350+
label: 'Future Value 0 Opt Validator Faucet Cap',
351+
currentValue: '50',
352+
newValue: '100',
353+
},
354+
];
355+
356+
const result = buildAmuletRulesConfigFromChanges(changes);
357+
358+
expect(result.issuanceCurve.futureValues.length).toBe(1);
359+
expect(result.issuanceCurve.futureValues[0]).toEqual({
360+
_1: { microseconds: '2000000' },
361+
_2: {
362+
amuletToIssuePerYear: '2000000',
363+
validatorRewardPercentage: '0.5',
364+
appRewardPercentage: '0.35',
365+
validatorRewardCap: '2000',
366+
featuredAppRewardCap: '1000',
367+
unfeaturedAppRewardCap: '200',
368+
optValidatorFaucetCap: '100',
369+
},
370+
});
371+
});
372+
});

0 commit comments

Comments
 (0)