@ixo/oracle-runtime-workers 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/package.json +2 -2
  2. package/src/plugins/hub-actions/hub-actions.plugin.ts +73 -24
  3. package/src/plugins/ixo-chain/balances.ts +141 -0
  4. package/src/plugins/ixo-chain/blocksync.ts +11 -6
  5. package/src/plugins/ixo-chain/denoms.ts +84 -36
  6. package/src/plugins/ixo-chain/http.ts +300 -63
  7. package/src/plugins/ixo-chain/ixo-chain.plugin.ts +182 -301
  8. package/src/plugins/ixo-chain/kinds/chain/account.ts +516 -0
  9. package/src/plugins/ixo-chain/kinds/chain/claims.ts +287 -0
  10. package/src/plugins/ixo-chain/kinds/chain/economics.ts +237 -0
  11. package/src/plugins/ixo-chain/kinds/chain/governance.ts +455 -0
  12. package/src/plugins/ixo-chain/kinds/chain/grants.ts +682 -0
  13. package/src/plugins/ixo-chain/kinds/chain/index.ts +23 -0
  14. package/src/plugins/ixo-chain/kinds/chain/liquid-staking.ts +279 -0
  15. package/src/plugins/ixo-chain/kinds/chain/shared.ts +286 -0
  16. package/src/plugins/ixo-chain/kinds/chain/staking.ts +220 -0
  17. package/src/plugins/ixo-chain/kinds/coins.ts +112 -0
  18. package/src/plugins/ixo-chain/kinds/core.ts +246 -0
  19. package/src/plugins/ixo-chain/kinds/indexed/agent-deposits.ts +124 -0
  20. package/src/plugins/ixo-chain/kinds/indexed/dao-proposals.ts +379 -0
  21. package/src/plugins/ixo-chain/kinds/indexed/daos.ts +319 -0
  22. package/src/plugins/ixo-chain/kinds/indexed/disputes.ts +159 -0
  23. package/src/plugins/ixo-chain/kinds/indexed/evaluations.ts +172 -0
  24. package/src/plugins/ixo-chain/kinds/indexed/index.ts +21 -0
  25. package/src/plugins/ixo-chain/kinds/indexed/liquid-stake-history.ts +160 -0
  26. package/src/plugins/ixo-chain/kinds/indexed/member-budgets.ts +175 -0
  27. package/src/plugins/ixo-chain/kinds/indexed/shared.ts +211 -0
  28. package/src/plugins/ixo-chain/kinds/indexed/token-history.ts +205 -0
  29. package/src/plugins/ixo-chain/kinds/registry.ts +43 -0
  30. package/src/plugins/ixo-chain/kinds/types.ts +156 -0
  31. package/src/plugins/ixo-chain/lookup.ts +470 -0
  32. package/src/plugins/ixo-chain/overview.ts +1060 -0
  33. package/src/plugins/ixo-chain/queries.ts +170 -138
  34. package/src/plugins/ixo-chain/rest.ts +129 -54
  35. package/src/plugins/ixo-chain/summaries.ts +3 -2
@@ -0,0 +1,287 @@
1
+ /**
2
+ * `claim_intents` and `collection_membership`: x/claims state the index
3
+ * does not answer, read from the chain.
4
+ */
5
+ import { z } from 'zod';
6
+ import { defineKind, type KindResult } from '../types';
7
+ import { displayCoins } from '../coins';
8
+ import { clip } from '../../summaries';
9
+ import {
10
+ COLLECTION_ID,
11
+ accountFor,
12
+ addressArg,
13
+ coinsOr,
14
+ coinsSchema,
15
+ durationText,
16
+ failed,
17
+ firstArg,
18
+ isPast,
19
+ } from './shared';
20
+
21
+ const pagination = z.object({ next_key: z.string().nullish() }).nullish();
22
+ const cw20Schema = z.object({ address: z.string(), amount: z.string() });
23
+
24
+ /** cw20 amounts as shown: the token contract and its base units. */
25
+ const cw20Of = (payments: z.infer<typeof cw20Schema>[]) =>
26
+ payments.slice(0, 5).map((payment) => ({
27
+ contract: clip(payment.address, 80),
28
+ amountBaseUnits: clip(payment.amount, 40),
29
+ }));
30
+
31
+ /** A store key for `pagination.key`: its bytes base64, escaped for a query string. */
32
+ const keyParam = (key: string) => encodeURIComponent(btoa(key));
33
+
34
+ /** cw20 amounts as shown, or `empty`. */
35
+ const cw20Or = <Empty extends string>(
36
+ payments: z.infer<typeof cw20Schema>[],
37
+ empty: Empty,
38
+ ) => (payments.length ? cw20Of(payments) : empty);
39
+
40
+ const collectionIdArg = z
41
+ .string()
42
+ .describe('Claim collection id, e.g. "8250".');
43
+
44
+ /* ── claim intents ────────────────────────────────────────────────────── */
45
+
46
+ /**
47
+ * Intents read per request. x/claims keys an intent
48
+ * `<agentAddress>/<collectionId>/<intentId>` (`IntentKeyCreate`) and lists
49
+ * the whole store in key order, so a page that starts at the key
50
+ * `<agent>/` (or `<agent>/<collection>/`) holds that agent's intents
51
+ * first; the first intent of another agent (or collection) ends them.
52
+ */
53
+ const INTENT_SCAN = 200;
54
+
55
+ const intentsResponse = z.object({
56
+ intents: z.array(
57
+ z.object({
58
+ id: z.string(),
59
+ agent_address: z.string(),
60
+ collection_id: z.string(),
61
+ claim_id: z.string().optional(),
62
+ created_at: z.string().nullish(),
63
+ expire_at: z.string().nullish(),
64
+ status: z.string(),
65
+ amount: coinsSchema.default([]),
66
+ cw20_payment: z.array(cw20Schema).default([]),
67
+ cw1155_payment: z.array(z.unknown()).default([]),
68
+ member_address: z.string().optional(),
69
+ }),
70
+ ),
71
+ pagination,
72
+ });
73
+
74
+ export const claimIntentsKind = defineKind({
75
+ name: 'claim_intents',
76
+ summary:
77
+ "An agent's claim intents: payments reserved in escrow before a claim is submitted.",
78
+ explain: [
79
+ 'A claim intent (x/claims) is an agent\'s declared plan to submit a claim in a collection: the payment it asks for (`coins`, bank coins or "none"; `cw20` tokens) is moved into the collection\'s escrow when the intent is created. `status`: active (waiting for the claim; `expiresAt` is the deadline), fulfilled (the claim was submitted, `claimId`; the escrow is paid out on approval or returned on rejection), expired (no claim in time; the escrow went back).',
80
+ '`pastExpiry: true` = still active on chain but past its deadline: the chain expires it on its next pass. `forMember` = the team member the intent is on behalf of.',
81
+ "The kind reads up to 200 intents starting at this account's (and collection's) first one; `matched` counts them, `complete: false` = there were more than 200, so the list may be missing some.",
82
+ ].join('\n'),
83
+ source: 'chain',
84
+ list: true,
85
+ args: z.strictObject({
86
+ address: addressArg,
87
+ collectionId: collectionIdArg.optional(),
88
+ first: firstArg,
89
+ }),
90
+ example: {},
91
+ plan(input, ctx) {
92
+ const account = accountFor(ctx, input.address);
93
+ if ('invalid' in account) return account;
94
+ const { collectionId } = input;
95
+ if (collectionId !== undefined && !COLLECTION_ID.test(collectionId))
96
+ return { invalid: 'collectionId must be a number such as "8250".' };
97
+ return {
98
+ source: 'chain',
99
+ async run(): Promise<KindResult> {
100
+ const start = `${account.address}/${collectionId === undefined ? '' : `${collectionId}/`}`;
101
+ const read = await ctx.rest(
102
+ `/ixo/claims/intents?pagination.key=${keyParam(start)}&pagination.limit=${INTENT_SCAN}`,
103
+ intentsResponse,
104
+ { label: 'claim intents' },
105
+ );
106
+ if (!read.ok) return failed(read.failure);
107
+ const { intents: page, pagination: paging } = read.value;
108
+ const theirs = (intent: (typeof page)[number]) =>
109
+ intent.agent_address === account.address &&
110
+ (collectionId === undefined || intent.collection_id === collectionId);
111
+ const end = page.findIndex((intent) => !theirs(intent));
112
+ const mine = end < 0 ? page : page.slice(0, end);
113
+ const intents = await Promise.all(
114
+ mine.slice(0, ctx.first).map(async (intent) => {
115
+ const status = intent.status.toLowerCase();
116
+ return {
117
+ id: clip(intent.id, 40),
118
+ collectionId: clip(intent.collection_id, 20),
119
+ status: clip(status, 20),
120
+ coins: await coinsOr(ctx, intent.amount, 'none'),
121
+ ...(intent.cw20_payment.length
122
+ ? { cw20: cw20Of(intent.cw20_payment) }
123
+ : {}),
124
+ ...(intent.cw1155_payment.length
125
+ ? { cw1155Payments: intent.cw1155_payment.length }
126
+ : {}),
127
+ createdAt: intent.created_at ?? null,
128
+ expiresAt: intent.expire_at ?? null,
129
+ ...(status === 'active' &&
130
+ intent.expire_at &&
131
+ isPast(intent.expire_at)
132
+ ? { pastExpiry: true }
133
+ : {}),
134
+ ...(intent.claim_id
135
+ ? { claimId: clip(intent.claim_id, 120) }
136
+ : {}),
137
+ ...(intent.member_address
138
+ ? { forMember: clip(intent.member_address, 80) }
139
+ : {}),
140
+ };
141
+ }),
142
+ );
143
+ return {
144
+ ok: true,
145
+ subject: account.subject,
146
+ first: ctx.first,
147
+ data: {
148
+ address: account.address,
149
+ ...(collectionId !== undefined ? { collectionId } : {}),
150
+ intents,
151
+ matched: mine.length,
152
+ // Another agent's intent ended the account's, or the store did.
153
+ complete: end >= 0 || !paging?.next_key,
154
+ },
155
+ };
156
+ },
157
+ };
158
+ },
159
+ });
160
+
161
+ /* ── collection membership ────────────────────────────────────────────── */
162
+
163
+ const memberBudget = z.object({
164
+ member_address: z.string(),
165
+ period: z.string(),
166
+ period_spend_limit: coinsSchema.default([]),
167
+ period_spent: coinsSchema.default([]),
168
+ period_cw20_spend_limit: z.array(cw20Schema).default([]),
169
+ period_cw20_spent: z.array(cw20Schema).default([]),
170
+ period_reset_at: z.string().nullish(),
171
+ });
172
+ const depositBalance = z.object({
173
+ agent_address: z.string(),
174
+ amount: coinsSchema.default([]),
175
+ withdrawable_at: z.string().nullish(),
176
+ });
177
+ const membersResponse = z.object({
178
+ member_budgets: z.array(memberBudget),
179
+ pagination,
180
+ });
181
+ const depositsResponse = z.object({
182
+ balances: z.array(depositBalance),
183
+ pagination,
184
+ });
185
+
186
+ /**
187
+ * The list page that starts at `address`. x/claims keys member budgets
188
+ * and deposits by `<collection>/<address>` and lists one collection's
189
+ * under the `<collection>/` prefix, so a page keyed at the address holds
190
+ * that account's record first if it exists. The point routes answer HTTP
191
+ * 500 for an absent record, which `ctx.rest` cannot tell from a fault.
192
+ */
193
+ const fromAddress = (address: string) =>
194
+ `pagination.key=${encodeURIComponent(btoa(address))}&pagination.limit=1`;
195
+
196
+ export const collectionMembershipKind = defineKind({
197
+ name: 'collection_membership',
198
+ summary:
199
+ "An account's team-member budget and performance deposit in one claim collection.",
200
+ explain: [
201
+ '`member: true` = the account is a team member of the collection with a spending budget (x/claims member budget): it may reserve up to `budget.spendLimit` per `budget.period` for claim intents (`budget.spent` so far this period, "none" = nothing yet; reset at `budget.resetAt`; `resetDue` = that time has passed and the budget refills on the next use). "none allowed" = the budget allows no spending of that kind (bank coins, or cw20 tokens: `cw20SpendLimit`, `cw20Spent`). `member: false` = no member budget here (an agent may still submit claims through an authz grant: see `authz_grants`).',
202
+ "`deposit` = the agent's performance deposit held in the collection's escrow (null = none), as `coin` (or `coins` when it holds several denoms): it can be slashed when a dispute against the agent is lost. `lockEnded: true` = its lock (`withdrawableAt`, null = none) is over, so it can be withdrawn unless a dispute against the agent is still open.",
203
+ 'Amounts are display units (`amount` + `symbol`) with `amountBaseUnits`; cw20 amounts are base units of the token contract.',
204
+ ].join('\n'),
205
+ source: 'chain',
206
+ list: false,
207
+ args: z.strictObject({ collectionId: collectionIdArg, address: addressArg }),
208
+ example: { collectionId: '8250' },
209
+ plan(input, ctx) {
210
+ const account = accountFor(ctx, input.address);
211
+ if ('invalid' in account) return account;
212
+ const { collectionId } = input;
213
+ if (!COLLECTION_ID.test(collectionId))
214
+ return { invalid: 'collectionId must be a number such as "8250".' };
215
+ const base = `/ixo/claims/collection/${collectionId}`;
216
+ return {
217
+ source: 'chain',
218
+ async run(): Promise<KindResult> {
219
+ const [members, deposits] = await Promise.all([
220
+ ctx.rest(
221
+ `${base}/members?${fromAddress(account.address)}`,
222
+ membersResponse,
223
+ { label: 'collection member budget' },
224
+ ),
225
+ ctx.rest(
226
+ `${base}/deposits?${fromAddress(account.address)}`,
227
+ depositsResponse,
228
+ { label: 'collection deposit' },
229
+ ),
230
+ ]);
231
+ if (!members.ok) return failed(members.failure);
232
+ if (!deposits.ok) return failed(deposits.failure);
233
+ const budget = members.value.member_budgets.find(
234
+ (entry) => entry.member_address === account.address,
235
+ );
236
+ const deposit = deposits.value.balances.find(
237
+ (entry) => entry.agent_address === account.address,
238
+ );
239
+ const withdrawableAt = deposit?.withdrawable_at ?? null;
240
+ // A drained deposit is removed from the store: an empty one is none.
241
+ const held = deposit ? await displayCoins(ctx, deposit.amount) : [];
242
+ return {
243
+ ok: true,
244
+ subject: account.subject,
245
+ data: {
246
+ address: account.address,
247
+ collectionId,
248
+ member: !!budget,
249
+ ...(budget
250
+ ? {
251
+ budget: {
252
+ period: durationText(budget.period),
253
+ // The intent handler lets a member spend only what the
254
+ // limit lists: an empty limit allows nothing.
255
+ spendLimit: await coinsOr(
256
+ ctx,
257
+ budget.period_spend_limit,
258
+ 'none allowed',
259
+ ),
260
+ spent: await coinsOr(ctx, budget.period_spent, 'none'),
261
+ cw20SpendLimit: cw20Or(
262
+ budget.period_cw20_spend_limit,
263
+ 'none allowed',
264
+ ),
265
+ cw20Spent: cw20Or(budget.period_cw20_spent, 'none'),
266
+ resetAt: budget.period_reset_at ?? null,
267
+ ...(budget.period_reset_at && isPast(budget.period_reset_at)
268
+ ? { resetDue: true }
269
+ : {}),
270
+ },
271
+ }
272
+ : {}),
273
+ deposit: held.length
274
+ ? {
275
+ ...(held.length === 1 && held[0]
276
+ ? { coin: held[0] }
277
+ : { coins: held }),
278
+ withdrawableAt,
279
+ lockEnded: withdrawableAt === null || isPast(withdrawableAt),
280
+ }
281
+ : null,
282
+ },
283
+ };
284
+ },
285
+ };
286
+ },
287
+ });
@@ -0,0 +1,237 @@
1
+ /**
2
+ * `network_economics`: how new IXO is minted. The x/mint parameters, the
3
+ * provisions the chain mints this epoch and the epoch clock, each from a
4
+ * 10 min per-isolate cache.
5
+ */
6
+ import { z } from 'zod';
7
+ import { defineKind, type KindContext, type KindResult } from '../types';
8
+ import { displayCoin } from '../coins';
9
+ import { clip } from '../../summaries';
10
+ import {
11
+ DEC_ONE,
12
+ ReadCache,
13
+ decMul,
14
+ decPercent,
15
+ durationText,
16
+ failed,
17
+ parseDec,
18
+ sharePercent,
19
+ } from './shared';
20
+
21
+ /** Mint parameters, provisions and epochs are reused for 10 min. */
22
+ export const ECONOMICS_TTL_MS = 600_000;
23
+ /** Reductions replayed at most when checking the schedule (one per period; mainnet has had one). */
24
+ const MAX_REDUCTIONS = 1_000n;
25
+
26
+ const paramsResponse = z.object({
27
+ params: z.object({
28
+ mint_denom: z.string(),
29
+ genesis_epoch_provisions: z.string(),
30
+ epoch_identifier: z.string(),
31
+ reduction_period_in_epochs: z.string(),
32
+ reduction_factor: z.string(),
33
+ distribution_proportions: z.object({
34
+ staking: z.string(),
35
+ impact_rewards: z.string(),
36
+ community_pool: z.string(),
37
+ }),
38
+ minting_rewards_distribution_start_epoch: z.string(),
39
+ }),
40
+ });
41
+ const provisionsResponse = z.object({ epoch_provisions: z.string() });
42
+ const epochsResponse = z.object({
43
+ epochs: z.array(
44
+ z.object({
45
+ identifier: z.string(),
46
+ duration: z.string(),
47
+ current_epoch: z.string(),
48
+ current_epoch_start_time: z.string(),
49
+ epoch_counting_started: z.boolean(),
50
+ }),
51
+ ),
52
+ });
53
+
54
+ type Params = z.infer<typeof paramsResponse>['params'];
55
+ type Epoch = z.infer<typeof epochsResponse>['epochs'][number];
56
+
57
+ const params = new ReadCache<z.infer<typeof paramsResponse>>(
58
+ ECONOMICS_TTL_MS,
59
+ 8,
60
+ );
61
+ const provisions = new ReadCache<z.infer<typeof provisionsResponse>>(
62
+ ECONOMICS_TTL_MS,
63
+ 8,
64
+ );
65
+ const epochs = new ReadCache<z.infer<typeof epochsResponse>>(
66
+ ECONOMICS_TTL_MS,
67
+ 8,
68
+ );
69
+
70
+ const cached = <S extends z.ZodType>(
71
+ cache: ReadCache<z.infer<S>>,
72
+ ctx: KindContext,
73
+ path: string,
74
+ schema: S,
75
+ label: string,
76
+ ) => cache.get(ctx, path, () => ctx.rest(path, schema, { label }));
77
+
78
+ const COUNT = /^\d{1,12}$/;
79
+
80
+ /**
81
+ * The next provisions reduction. x/mint cuts the provisions by
82
+ * `reduction_factor` at the end of the epoch `start + n × period`
83
+ * (`start` = the distribution start epoch); the chain does not expose
84
+ * the epoch of the last cut, so the schedule is replayed from the
85
+ * genesis provisions with the chain's own decimal rounding and used only
86
+ * when it reproduces exactly the provisions the chain reports now (a
87
+ * parameter changed by governance on the way would not). Null otherwise,
88
+ * or before minting started.
89
+ */
90
+ function nextReduction(
91
+ values: Params,
92
+ current: bigint,
93
+ epoch: Epoch,
94
+ ): { epoch: string; around: string | null; provisionsAfter: bigint } | null {
95
+ const genesis = parseDec(values.genesis_epoch_provisions);
96
+ const factor = parseDec(values.reduction_factor);
97
+ const count = (value: string) => (COUNT.test(value) ? BigInt(value) : null);
98
+ const start = count(values.minting_rewards_distribution_start_epoch);
99
+ const period = count(values.reduction_period_in_epochs);
100
+ const now = count(epoch.current_epoch);
101
+ if (
102
+ genesis === null ||
103
+ factor === null ||
104
+ start === null ||
105
+ period === null ||
106
+ now === null
107
+ )
108
+ return null;
109
+ // The epoch in progress has not ended: the last one ended is now − 1.
110
+ const lastEnded = now - 1n;
111
+ if (period <= 0n || !epoch.epoch_counting_started || lastEnded < start)
112
+ return null;
113
+ const cuts = (lastEnded - start) / period;
114
+ if (cuts > MAX_REDUCTIONS) return null;
115
+ let expected = genesis;
116
+ for (let n = 0n; n < cuts; n += 1n) expected = decMul(expected, factor);
117
+ if (expected !== current) return null;
118
+ const target = start + (cuts + 1n) * period;
119
+ const seconds = /^(\d{1,12})s$/.exec(epoch.duration)?.[1];
120
+ const startedAt = Date.parse(epoch.current_epoch_start_time);
121
+ // The reduction runs when the target epoch ends.
122
+ const around =
123
+ seconds && Number.isFinite(startedAt)
124
+ ? new Date(
125
+ startedAt + Number((target - now + 1n) * BigInt(seconds)) * 1000,
126
+ ).toISOString()
127
+ : null;
128
+ return {
129
+ epoch: target.toString(),
130
+ around,
131
+ provisionsAfter: decMul(current, factor),
132
+ };
133
+ }
134
+
135
+ export const networkEconomicsKind = defineKind({
136
+ name: 'network_economics',
137
+ summary:
138
+ 'How new IXO is minted: provisions per epoch, the next reduction, where it goes.',
139
+ explain: [
140
+ 'IXO inflation (x/mint): at the end of every epoch (`epoch.identifier`, e.g. "day", each `epoch.length`) the chain mints `provisionsPerEpoch` new IXO and splits it by `distribution` (staking rewards to delegators, impact rewards, the community pool).',
141
+ 'Every `reduction.everyEpochs` epochs the provisions are multiplied by `reduction.factor` (a cut of `reduction.cutPercent`). `reduction.next` gives the epoch of the next cut, roughly when (`around`, the end of that epoch) and the provisions after it; it is left out when the current parameters do not reproduce the provisions the chain reports (e.g. after a governance change), so it is never a guess.',
142
+ 'Amounts are display units (`amount` + `symbol`) with `amountBaseUnits` (fractions of a base unit dropped).',
143
+ ].join('\n'),
144
+ source: 'chain',
145
+ list: false,
146
+ args: z.strictObject({}),
147
+ example: {},
148
+ plan(_input, ctx) {
149
+ return {
150
+ source: 'chain',
151
+ async run(): Promise<KindResult> {
152
+ const [paramsRead, provisionsRead, epochsRead] = await Promise.all([
153
+ cached(
154
+ params,
155
+ ctx,
156
+ '/ixo/mint/v1beta1/params',
157
+ paramsResponse,
158
+ 'mint params',
159
+ ),
160
+ cached(
161
+ provisions,
162
+ ctx,
163
+ '/ixo/mint/v1beta1/epoch_provisions',
164
+ provisionsResponse,
165
+ 'epoch provisions',
166
+ ),
167
+ cached(
168
+ epochs,
169
+ ctx,
170
+ '/ixo/epochs/v1beta1/epochs',
171
+ epochsResponse,
172
+ 'epochs',
173
+ ),
174
+ ]);
175
+ if (!paramsRead.ok) return failed(paramsRead.failure);
176
+ if (!provisionsRead.ok) return failed(provisionsRead.failure);
177
+ if (!epochsRead.ok) return failed(epochsRead.failure);
178
+ const values = paramsRead.value.params;
179
+ const denom = values.mint_denom;
180
+ const current = parseDec(provisionsRead.value.epoch_provisions);
181
+ const epoch = epochsRead.value.epochs.find(
182
+ (entry) => entry.identifier === values.epoch_identifier,
183
+ );
184
+ const coin = (scaled: bigint) =>
185
+ displayCoin(ctx, { denom, amount: (scaled / DEC_ONE).toString() });
186
+ const next =
187
+ current !== null && epoch
188
+ ? nextReduction(values, current, epoch)
189
+ : null;
190
+ const factor = parseDec(values.reduction_factor);
191
+ const split = values.distribution_proportions;
192
+ return {
193
+ ok: true,
194
+ data: {
195
+ mintDenom: clip(denom, 60),
196
+ ...(epoch
197
+ ? {
198
+ epoch: {
199
+ identifier: clip(epoch.identifier, 40),
200
+ length: durationText(epoch.duration),
201
+ current: epoch.current_epoch,
202
+ startedAt: epoch.current_epoch_start_time,
203
+ },
204
+ }
205
+ : {}),
206
+ ...(current !== null
207
+ ? { provisionsPerEpoch: await coin(current) }
208
+ : {}),
209
+ reduction: {
210
+ factor: clip(values.reduction_factor, 30),
211
+ ...(factor !== null && factor <= DEC_ONE
212
+ ? { cutPercent: sharePercent(DEC_ONE - factor, DEC_ONE) }
213
+ : {}),
214
+ everyEpochs: values.reduction_period_in_epochs,
215
+ ...(next
216
+ ? {
217
+ next: {
218
+ epoch: next.epoch,
219
+ around: next.around,
220
+ provisionsAfter: await coin(next.provisionsAfter),
221
+ },
222
+ }
223
+ : {}),
224
+ },
225
+ distribution: {
226
+ staking: decPercent(split.staking),
227
+ impactRewards: decPercent(split.impact_rewards),
228
+ communityPool: decPercent(split.community_pool),
229
+ },
230
+ distributionStartEpoch:
231
+ values.minting_rewards_distribution_start_epoch,
232
+ },
233
+ };
234
+ },
235
+ };
236
+ },
237
+ });