@ixo/editor 6.1.0 → 6.1.2

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.
@@ -1014,13 +1014,11 @@ registerAction({
1014
1014
  }
1015
1015
  const quorumPercent = clampPercent(inputs.quorumPercent, "quorumPercent", { allowZero: true });
1016
1016
  const thresholdPercent = clampPercent(inputs.thresholdPercent, "thresholdPercent");
1017
- const vetoThresholdPercent = clampPercent(inputs.vetoThresholdPercent, "vetoThresholdPercent", { allowZero: true });
1018
- if (thresholdPercent + vetoThresholdPercent > 100) {
1019
- throw new Error("thresholdPercent + vetoThresholdPercent cannot exceed 100");
1020
- }
1021
1017
  const allowRevoting = Boolean(inputs.allowRevoting);
1022
1018
  const data = {
1023
- onlyMembersExecute: false,
1019
+ // Group creation instantiates the proposal module with
1020
+ // only_members_execute: true — preserve that policy on updates.
1021
+ onlyMembersExecute: true,
1024
1022
  thresholdType: "%",
1025
1023
  thresholdPercentage: thresholdPercent,
1026
1024
  quorumEnabled: quorumPercent > 0,
@@ -1028,11 +1026,7 @@ registerAction({
1028
1026
  quorumPercentage: quorumPercent,
1029
1027
  proposalDuration: Math.trunc(votingPeriodHours),
1030
1028
  proposalDurationUnits: "hours",
1031
- allowRevoting,
1032
- // TODO(governance): the editor's UpdateProposalConfigData / the consumer's
1033
- // message builder don't yet carry a veto threshold for single-choice
1034
- // voting. Passed through so the consumer can apply it once supported.
1035
- vetoThresholdPercentage: vetoThresholdPercent
1029
+ allowRevoting
1036
1030
  };
1037
1031
  const updateVotingConfigAction = { type: "UpdateVotingConfig", data };
1038
1032
  const title = String(inputs.title || "").trim() || "Update governance settings";
@@ -1095,8 +1089,16 @@ registerAction({
1095
1089
  if (!denom) throw new Error("denom is required");
1096
1090
  const amount = Number(inputs.amount);
1097
1091
  if (!Number.isFinite(amount) || amount <= 0) throw new Error("amount must be greater than 0");
1098
- const spendAction = { type: "Spend", data: { to: recipient, denom, amount: String(amount) } };
1099
- const title = String(inputs.title || "").trim() || `Send ${amount} ${denom} to ${recipient}`;
1092
+ const KNOWN_DENOMS = {
1093
+ uixo: { symbol: "IXO", exponent: 6 }
1094
+ };
1095
+ const tokenInfo = KNOWN_DENOMS[denom];
1096
+ if (!tokenInfo) {
1097
+ throw new Error(`Sending ${denom} is not supported yet \u2014 only IXO transfers are currently available`);
1098
+ }
1099
+ const baseAmount = BigInt(Math.round(amount * 10 ** tokenInfo.exponent)).toString();
1100
+ const spendAction = { type: "Spend", data: { to: recipient, denom, amount: baseAmount } };
1101
+ const title = String(inputs.title || "").trim() || `Send ${amount} ${tokenInfo.symbol} to ${recipient}`;
1100
1102
  const description = String(inputs.description || "").trim() || "Sends funds from the group treasury once the proposal passes.";
1101
1103
  const { preProposalContractAddress } = await handlers.getPreProposalContractAddress({ coreAddress });
1102
1104
  const { groupContractAddress } = await handlers.getGroupContractAddress({ coreAddress });
@@ -1196,7 +1198,7 @@ registerAction({
1196
1198
  requiredCapability: "email/send",
1197
1199
  // Email send is autonomous-enough to be triggered by another block's event.
1198
1200
  // When wired as a listener, the assignee on the email block is DM'd to
1199
- // invoke it for each pending event. See docs/events-and-triggers-plan.md §3.6.
1201
+ // invoke it for each pending event. See docs/flow-engine/events-and-triggers-plan.md §3.6.
1200
1202
  eligibleForEventTrigger: true,
1201
1203
  inputSchema: {
1202
1204
  type: "object",
@@ -2797,13 +2799,13 @@ registerAction({
2797
2799
  required: ["proposalId", "vote", "proposalContractAddress"],
2798
2800
  properties: {
2799
2801
  proposalId: { type: "number", description: "The proposal number to vote on." },
2800
- vote: { type: "string", description: "The vote to cast: yes, no, no_with_veto, or abstain." },
2802
+ vote: { type: "string", description: "The vote to cast: yes, no, or abstain." },
2801
2803
  proposalContractAddress: { type: "string", description: "The proposal module contract address." },
2802
2804
  rationale: { type: "string", description: "Optional rationale provided with the vote." }
2803
2805
  }
2804
2806
  },
2805
2807
  outputSchema: [
2806
- { path: "vote", displayName: "Vote", type: "string", description: "The vote cast (yes, no, no_with_veto, abstain)" },
2808
+ { path: "vote", displayName: "Vote", type: "string", description: "The vote cast (yes, no, abstain)" },
2807
2809
  { path: "rationale", displayName: "Rationale", type: "string", description: "Optional rationale provided with the vote" },
2808
2810
  { path: "proposalId", displayName: "Proposal ID", type: "string", description: "The proposal that was voted on" },
2809
2811
  { path: "votedAt", displayName: "Voted At", type: "string", description: "ISO timestamp of when the vote was cast" }
@@ -2823,7 +2825,7 @@ registerAction({
2823
2825
  if (!proposalId || isNaN(proposalId)) throw new Error("proposalId is required");
2824
2826
  if (!vote) throw new Error("vote is required");
2825
2827
  if (!proposalContractAddress) throw new Error("proposalContractAddress is required");
2826
- const validVotes = ["yes", "no", "no_with_veto", "abstain"];
2828
+ const validVotes = ["yes", "no", "abstain"];
2827
2829
  if (!validVotes.includes(vote)) {
2828
2830
  throw new Error(`vote must be one of: ${validVotes.join(", ")}`);
2829
2831
  }
@@ -4071,15 +4073,23 @@ function parseDuration(raw) {
4071
4073
  function buildGroupConfig(groupType, governance, memberConfig) {
4072
4074
  const duration = parseDuration(governance.votingPeriod || "604800s");
4073
4075
  const thresholdNum = parseFloat(governance.threshold || "0.51");
4076
+ const quorumNum = parseFloat(governance.quorum);
4077
+ const unstakingDuration = governance.unstakingDuration ? parseDuration(governance.unstakingDuration) : null;
4074
4078
  const baseConfig = {
4075
4079
  proposalDurationAmount: duration.amount,
4076
4080
  proposalDurationUnit: duration.unit,
4077
4081
  proposalSubmissionPolicy: "members",
4078
4082
  voteSwitching: false
4079
4083
  };
4084
+ const decisionPolicy = {
4085
+ passingThreshold: "percentage",
4086
+ passingThresholdPercentage: Math.round(thresholdNum * 100),
4087
+ ...Number.isFinite(quorumNum) && quorumNum > 0 ? { quorum: "percentage", quorumPercentage: Math.round(quorumNum * 100) } : {}
4088
+ };
4080
4089
  if (groupType === "multisig") {
4081
4090
  const members2 = memberConfig?.members || [];
4082
4091
  return {
4092
+ ...baseConfig,
4083
4093
  threshold: memberConfig?.multisigThreshold || 1,
4084
4094
  membershipCategory: [{ members: members2.map((m) => m.did) }]
4085
4095
  };
@@ -4087,21 +4097,23 @@ function buildGroupConfig(groupType, governance, memberConfig) {
4087
4097
  if (groupType === "nftStaking") {
4088
4098
  return {
4089
4099
  ...baseConfig,
4100
+ ...decisionPolicy,
4090
4101
  nftContractAddress: memberConfig?.nftContractAddress || "",
4091
- unstakingDuration: governance.unstakingDuration ? parseDuration(governance.unstakingDuration) : void 0
4102
+ ...unstakingDuration ? { unstakingDurationAmount: unstakingDuration.amount, unstakingDurationUnit: unstakingDuration.unit } : {}
4092
4103
  };
4093
4104
  }
4094
4105
  if (groupType === "tokenStaking") {
4095
4106
  const tokenConfig = memberConfig?.tokenConfig || {};
4096
4107
  return {
4097
4108
  ...baseConfig,
4098
- passingThreshold: thresholdNum === 0.5 ? "majority" : "percentage",
4099
- passingThresholdPercentage: Math.round(thresholdNum * 100),
4109
+ ...decisionPolicy,
4110
+ isExistingToken: Boolean(tokenConfig.isExistingToken),
4111
+ tokenAddress: tokenConfig.tokenAddress || "",
4100
4112
  tokenName: tokenConfig.tokenName || "",
4101
4113
  tokenSymbol: tokenConfig.tokenSymbol || "",
4102
4114
  tokenSupply: tokenConfig.tokenSupply || 0,
4103
4115
  distributionCategory: tokenConfig.distributionCategory || [],
4104
- unstakingDuration: governance.unstakingDuration ? parseDuration(governance.unstakingDuration) : void 0
4116
+ ...unstakingDuration ? { unstakingDurationAmount: unstakingDuration.amount, unstakingDurationUnit: unstakingDuration.unit } : {}
4105
4117
  };
4106
4118
  }
4107
4119
  const members = memberConfig?.members || [];
@@ -4117,9 +4129,9 @@ function buildGroupConfig(groupType, governance, memberConfig) {
4117
4129
  }
4118
4130
  return {
4119
4131
  ...baseConfig,
4120
- passingThreshold: thresholdNum === 0.5 ? "majority" : "percentage",
4121
- passingThresholdPercentage: Math.round(thresholdNum * 100),
4122
- membershipCategory: Array.from(byRole.values()).map(({ dids, weight }) => ({
4132
+ ...decisionPolicy,
4133
+ membershipCategory: Array.from(byRole.entries()).map(([role, { dids, weight }]) => ({
4134
+ categoryName: role,
4123
4135
  members: dids.map((did) => ({ memberAddress: did })),
4124
4136
  weightPerMember: weight
4125
4137
  }))
@@ -13894,4 +13906,4 @@ export {
13894
13906
  executeQueuedFlowAgentCoreCommands,
13895
13907
  FlowAgentService
13896
13908
  };
13897
- //# sourceMappingURL=chunk-RJOVPEAW.js.map
13909
+ //# sourceMappingURL=chunk-5Y2WABQE.js.map