@continuumdao/ctm-mpc-defi 0.2.54 → 0.2.56

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.
@@ -191,10 +191,10 @@ function docsBaseUrl() {
191
191
  return raw.replace(/\/+$/, "");
192
192
  }
193
193
  function parseCommitteeAddressesFromConstitution(markdown) {
194
- const text = String(markdown || "");
195
- const start = text.search(/^### Committee List\s*$/m);
194
+ const text2 = String(markdown || "");
195
+ const start = text2.search(/^### Committee List\s*$/m);
196
196
  if (start < 0) return [];
197
- const lines = text.slice(start).split("\n");
197
+ const lines = text2.slice(start).split("\n");
198
198
  const addresses = [];
199
199
  for (let i = 1; i < lines.length; i += 1) {
200
200
  const line = lines[i] ?? "";
@@ -260,9 +260,10 @@ function checksumOrEmpty(value) {
260
260
  if (!raw) return "";
261
261
  return viem.getAddress(raw);
262
262
  }
263
- function normalizeInput(inp) {
263
+ function normalizeInput(inp, index) {
264
+ const explicit = String(inp?.name || "").trim();
264
265
  return {
265
- name: String(inp?.name || ""),
266
+ name: explicit || `arg${index}`,
266
267
  type: String(inp?.type || ""),
267
268
  value: String(inp?.value ?? "")
268
269
  };
@@ -279,7 +280,7 @@ function normalizeAction(action) {
279
280
  target: checksumOrEmpty(action.target),
280
281
  value: String(action.value || "0"),
281
282
  signature: String(action.signature || ""),
282
- inputs: (action.inputs || []).map(normalizeInput)
283
+ inputs: (action.inputs || []).map((inp, index) => normalizeInput(inp, index))
283
284
  };
284
285
  }
285
286
  function assertProposalCatalogConstants() {
@@ -351,11 +352,11 @@ var init_defiEvmClient = __esm({
351
352
  // src/core/purpose.ts
352
353
  function mergePurposeText(purposeText, purposeSuffix) {
353
354
  const t = (purposeText ?? "").trim();
354
- const suffix = (purposeSuffix ?? "").trim();
355
- if (!suffix) return t;
355
+ const suffix2 = (purposeSuffix ?? "").trim();
356
+ if (!suffix2) return t;
356
357
  return t ? `${t}
357
358
 
358
- ${suffix}` : suffix;
359
+ ${suffix2}` : suffix2;
359
360
  }
360
361
  var init_purpose = __esm({
361
362
  "src/core/purpose.ts"() {
@@ -929,8 +930,8 @@ async function continuumDaoForumUnread(args) {
929
930
  if (args.filter?.trim()) qs2.set("filter", args.filter.trim());
930
931
  if (args.start != null) qs2.set("start", String(args.start));
931
932
  if (args.limit != null) qs2.set("limit", String(args.limit));
932
- const suffix = qs2.toString() ? `?${qs2}` : "";
933
- return forumFetch(`/api/continuum/forum/unread${suffix}`, {
933
+ const suffix2 = qs2.toString() ? `?${qs2}` : "";
934
+ return forumFetch(`/api/continuum/forum/unread${suffix2}`, {
934
935
  forumUrl: args.forumUrl,
935
936
  ticket: args.ticket
936
937
  });
@@ -1453,8 +1454,8 @@ function buildFoundryProposalSimulatePlan(args) {
1453
1454
  )
1454
1455
  });
1455
1456
  args.batches.forEach((batch, bi) => {
1456
- const suffix = batch.label != null ? solIdent(batch.label, `Option${(batch.optionIndex ?? bi) + 1}`) : "Bravo";
1457
- const contractName = `ContinuumDaoSimulateExecute${suffix}`;
1457
+ const suffix2 = batch.label != null ? solIdent(batch.label, `Option${(batch.optionIndex ?? bi) + 1}`) : "Bravo";
1458
+ const contractName = `ContinuumDaoSimulateExecute${suffix2}`;
1458
1459
  const path = `script/${contractName}.s.sol`;
1459
1460
  const body = [
1460
1461
  " function run() external {",
@@ -2684,13 +2685,25 @@ async function buildEvmMultisignBodyContinuumDaoCastVoteBravoFromMcp(args) {
2684
2685
  }
2685
2686
  async function continuumDaoRegisterProposal(payload) {
2686
2687
  assertContinuumDaoForumTopicKey(payload.forumKey);
2688
+ const body = JSON.stringify(payload);
2687
2689
  const res = await fetch(`${exports.CONTINUUM_DAO_GOVERNANCE_API}/proposals/create`, {
2688
2690
  method: "POST",
2689
2691
  headers: { "Content-Type": "application/json" },
2690
- body: JSON.stringify(payload)
2692
+ body
2691
2693
  });
2692
- if (!res.ok) throw new Error(`proposals/create: ${res.status} ${await res.text()}`);
2693
- return { ok: true, result: await res.json() };
2694
+ const text2 = await res.text();
2695
+ if (res.status === 409) {
2696
+ const repair = await fetch(`${exports.CONTINUUM_DAO_GOVERNANCE_API}/proposals/repair`, {
2697
+ method: "POST",
2698
+ headers: { "Content-Type": "application/json" },
2699
+ body
2700
+ });
2701
+ const repairText = await repair.text();
2702
+ if (!repair.ok) throw new Error(`proposals/repair: ${repair.status} ${repairText}`);
2703
+ return { ok: true, result: JSON.parse(repairText) };
2704
+ }
2705
+ if (!res.ok) throw new Error(`proposals/create: ${res.status} ${text2}`);
2706
+ return { ok: true, result: JSON.parse(text2) };
2694
2707
  }
2695
2708
  exports.CONTINUUM_DAO_PROPOSE_FALLBACK = void 0; exports.CONTINUUM_DAO_VOTE_FALLBACK = void 0; exports.CONTINUUM_DAO_EXECUTE_FALLBACK = void 0; exports.CONTINUUM_DAO_CANCEL_FALLBACK = void 0; exports.CONTINUUM_DAO_GOV_EVM_TYPES = void 0; exports.governorWriteAbi = void 0; var governorReadAbi, FORUM_SECTION_TO_PROPOSAL_TYPE; exports.GOVERNOR_STATE = void 0; exports.GOVERNOR_STATE_LABELS = void 0;
2696
2709
  var init_governance = __esm({
@@ -5286,10 +5299,20 @@ function foldMarketplaceEvents(events, initial) {
5286
5299
  for (const ev of events) applyMarketplaceEvent(book, ev);
5287
5300
  return book;
5288
5301
  }
5302
+ function auctionDeadlineUnix(auction) {
5303
+ const unix = Number(auction.deadlineUnix);
5304
+ if (Number.isFinite(unix) && unix > 0) return unix;
5305
+ if (auction.deadlineAt) {
5306
+ const ms = Date.parse(auction.deadlineAt);
5307
+ if (Number.isFinite(ms) && ms > 0) return Math.floor(ms / 1e3);
5308
+ }
5309
+ return unix;
5310
+ }
5289
5311
  function deriveAuctionStatus(auction, nowUnix) {
5290
- const deadline = Number(auction.deadlineUnix);
5312
+ const deadline = auctionDeadlineUnix(auction);
5291
5313
  if (auction.storedStatus === "Pending" && Number.isFinite(deadline) && nowUnix >= deadline) return "Expired";
5292
5314
  if (auction.storedStatus === "Active" && Number.isFinite(deadline) && nowUnix >= deadline) return "Complete";
5315
+ if (auction.storedStatus === "Pending") return "Active";
5293
5316
  return auction.derivedStatus || auction.storedStatus;
5294
5317
  }
5295
5318
  function applyDerivedStatuses(book, nowUnix) {
@@ -5399,7 +5422,11 @@ function keyGenOwnsVeCtm(snap, seller) {
5399
5422
  return false;
5400
5423
  }
5401
5424
  function assertNotOwn(snap, seller, tokenId) {
5402
- if (same2(snap.owner, snap.executor) || seller && same2(seller, snap.executor) || snap.executorLiveAuction) {
5425
+ const listedByKeyGen = seller != null && same2(seller, snap.executor) || snap.listing != null && snap.listing.status === 1 && same2(snap.listing.creator, snap.executor);
5426
+ if (listedByKeyGen && !snap.executorLiveAuction) {
5427
+ throw new Error(`This KeyGen listed veCTM #${tokenId.toString()}. Delist it instead of buying it.`);
5428
+ }
5429
+ if (same2(snap.owner, snap.executor) || snap.executorLiveAuction) {
5403
5430
  throw new Error(`This KeyGen already owns veCTM #${tokenId.toString()} and cannot buy or bid on it.`);
5404
5431
  }
5405
5432
  }
@@ -5471,6 +5498,7 @@ function planMarketplaceSteps(input, snap) {
5471
5498
  const m = snap.marketplace;
5472
5499
  switch (input.action) {
5473
5500
  case "createListing": {
5501
+ assertNotAttached(snap, input.tokenId);
5474
5502
  assertPayment(snap);
5475
5503
  assertDeadline(snap, input.deadline);
5476
5504
  if (!same2(snap.owner, snap.executor)) throw new Error("Only the veCTM owner can create a listing.");
@@ -5497,7 +5525,9 @@ function planMarketplaceSteps(input, snap) {
5497
5525
  ]);
5498
5526
  }
5499
5527
  case "delist": {
5500
- if (!snap.listing || snap.listing.status !== 1) throw new Error("No open listing for this KeyGen.");
5528
+ const listing = snap.listing;
5529
+ const openForKeyGen = listing != null && listing.status === 1 && same2(listing.creator, snap.executor);
5530
+ if (!openForKeyGen) throw new Error("No open listing for this KeyGen.");
5501
5531
  return [
5502
5532
  {
5503
5533
  to: m,
@@ -5542,6 +5572,7 @@ function planMarketplaceSteps(input, snap) {
5542
5572
  ]);
5543
5573
  }
5544
5574
  case "createOffering": {
5575
+ assertNotAttached(snap, input.tokenId);
5545
5576
  assertNotOwn(snap, void 0, input.tokenId);
5546
5577
  assertPayment(snap);
5547
5578
  assertDeadline(snap, input.deadline);
@@ -6232,8 +6263,8 @@ async function getJson(url) {
6232
6263
  try {
6233
6264
  const res = await fetch(url);
6234
6265
  if (!res.ok) {
6235
- const text = await res.text().catch(() => "");
6236
- return { ok: false, status: res.status, error: new Error(`${url}: ${res.status} ${text}`.trim()) };
6266
+ const text2 = await res.text().catch(() => "");
6267
+ return { ok: false, status: res.status, error: new Error(`${url}: ${res.status} ${text2}`.trim()) };
6237
6268
  }
6238
6269
  return { ok: true, body: await res.json() };
6239
6270
  } catch (err) {
@@ -6273,6 +6304,37 @@ function matchAuction(row, args, includeInactive) {
6273
6304
  if (args.seller && row.seller.toLowerCase() !== args.seller.toLowerCase()) return false;
6274
6305
  return true;
6275
6306
  }
6307
+ function presentAddress(value) {
6308
+ const text2 = (value ?? "").trim();
6309
+ if (!text2 || /^0x0+$/i.test(text2)) return "";
6310
+ return text2;
6311
+ }
6312
+ function sameAddress(a, b) {
6313
+ const left = (a ?? "").trim();
6314
+ const right = (b ?? "").trim();
6315
+ return Boolean(left && right && left.toLowerCase() === right.toLowerCase());
6316
+ }
6317
+ function annotateListingViewer(items, viewer) {
6318
+ const who = presentAddress(viewer);
6319
+ if (!who) return items;
6320
+ return items.map((row) => {
6321
+ const seller = presentAddress(row.seller) || presentAddress(row.creator) || presentAddress(row.currentOwner);
6322
+ const closed = row.storedStatus === "Fulfilled" || row.storedStatus === "Delisted" || row.storedStatus === "DelistedOrRescinded";
6323
+ const open = !closed && (row.storedStatus === "Open" || row.protocolStatus === "Open");
6324
+ const mine = sameAddress(seller, who);
6325
+ return { ...row, viewerAction: mine && open ? "delist" : mine ? "none" : open ? "buy" : "none" };
6326
+ });
6327
+ }
6328
+ function presentAuction(row, nowUnix = Math.floor(Date.now() / 1e3)) {
6329
+ const derivedStatus = deriveAuctionStatus({ ...row, bids: row.bids ?? [] }, nowUnix);
6330
+ const closed = derivedStatus === "Complete" || derivedStatus === "Expired";
6331
+ return {
6332
+ ...row,
6333
+ bids: row.bids ?? [],
6334
+ derivedStatus,
6335
+ needsSettle: closed ? true : row.needsSettle
6336
+ };
6337
+ }
6276
6338
  function listFrom(items, source) {
6277
6339
  return { items, nextCursor: null, source };
6278
6340
  }
@@ -6302,11 +6364,18 @@ async function fetchContinuumDaoMarketplaceListings(args = {}) {
6302
6364
  const res = await getJson(url);
6303
6365
  if (res.ok) {
6304
6366
  const body = res.body;
6305
- return { items: body.items ?? [], nextCursor: body.nextCursor ?? null, source: "api" };
6367
+ return {
6368
+ items: annotateListingViewer(body.items ?? [], args.viewer),
6369
+ nextCursor: body.nextCursor ?? null,
6370
+ source: "api"
6371
+ };
6306
6372
  }
6307
6373
  if (args.cursor || !isOffline(res.status)) throw res.error;
6308
6374
  const book = await logsBook(args);
6309
- return listFrom(book.listings.filter((row) => matchOrder(row, args, includeInactive)), "logs");
6375
+ return listFrom(
6376
+ annotateListingViewer(book.listings.filter((row) => matchOrder(row, args, includeInactive)), args.viewer),
6377
+ "logs"
6378
+ );
6310
6379
  }
6311
6380
  async function fetchContinuumDaoMarketplaceOfferings(args = {}) {
6312
6381
  const includeInactive = Boolean(args.includeInactive);
@@ -6343,20 +6412,30 @@ async function fetchContinuumDaoMarketplaceAuctions(args = {}) {
6343
6412
  if (res.ok) {
6344
6413
  const body = res.body;
6345
6414
  return {
6346
- items: (body.items ?? []).map((row) => ({ ...row, bids: row.bids ?? [] })),
6415
+ items: (body.items ?? []).map((row) => presentAuction(row)).filter((row) => includeInactive || isLiveAuctionStatus(row.derivedStatus)),
6347
6416
  nextCursor: body.nextCursor ?? null,
6348
6417
  source: "api"
6349
6418
  };
6350
6419
  }
6351
6420
  if (args.cursor || !isOffline(res.status)) throw res.error;
6352
6421
  const book = await logsBook(args);
6353
- return listFrom(book.auctions.filter((row) => matchAuction(row, args, includeInactive)), "logs");
6422
+ return listFrom(book.auctions.filter((row) => matchAuction(row, args, includeInactive)).map((row) => presentAuction(row)), "logs");
6354
6423
  }
6355
6424
  async function fetchContinuumDaoMarketplaceToken(args) {
6356
6425
  const url = `${apiBase(args)}/marketplace/tokens/${encodeURIComponent(args.tokenId)}${qs({ viewer: args.viewer })}`;
6357
6426
  const res = await getJson(url);
6358
6427
  if (res.ok && res.body && typeof res.body === "object") {
6359
- return { ...res.body, source: "api" };
6428
+ const body = res.body;
6429
+ return {
6430
+ ...body,
6431
+ auction: body.auction ? presentAuction(body.auction) : null,
6432
+ history: {
6433
+ listings: body.history?.listings ?? [],
6434
+ offerings: body.history?.offerings ?? [],
6435
+ auctions: (body.history?.auctions ?? []).map((row) => presentAuction(row))
6436
+ },
6437
+ source: "api"
6438
+ };
6360
6439
  }
6361
6440
  if (!res.ok && !isOffline(res.status)) throw res.error;
6362
6441
  const book = await logsBook(args);
@@ -6367,11 +6446,14 @@ async function fetchContinuumDaoMarketplaceToken(args) {
6367
6446
  token: { tokenId: args.tokenId },
6368
6447
  listing: listings.find((row) => isOpenOrder(row)) ?? null,
6369
6448
  offerings: offerings.filter((row) => isOpenOrder(row)),
6370
- auction: auctions.find((row) => isLiveAuctionStatus(row.derivedStatus)) ?? null,
6449
+ auction: (() => {
6450
+ const live = auctions.find((row) => isLiveAuctionStatus(row.derivedStatus));
6451
+ return live ? presentAuction(live) : null;
6452
+ })(),
6371
6453
  history: {
6372
6454
  listings: listings.filter((row) => !isOpenOrder(row)),
6373
6455
  offerings: offerings.filter((row) => !isOpenOrder(row)),
6374
- auctions: auctions.filter((row) => !isLiveAuctionStatus(row.derivedStatus))
6456
+ auctions: auctions.filter((row) => !isLiveAuctionStatus(row.derivedStatus)).map((row) => presentAuction(row))
6375
6457
  },
6376
6458
  source: "logs"
6377
6459
  };
@@ -6398,7 +6480,7 @@ async function fetchContinuumDaoMarketplaceActivity(args) {
6398
6480
  return {
6399
6481
  address: args.address,
6400
6482
  orders: body.orders ?? [],
6401
- auctions: (body.auctions ?? []).map((row) => ({ ...row, bids: row.bids ?? [] })),
6483
+ auctions: (body.auctions ?? []).map((row) => presentAuction(row)),
6402
6484
  source: "api"
6403
6485
  };
6404
6486
  }
@@ -6411,7 +6493,7 @@ async function fetchContinuumDaoMarketplaceActivity(args) {
6411
6493
  const auctions = book.auctions.filter((row) => {
6412
6494
  return row.seller.toLowerCase() === address || (row.buyer ?? "").toLowerCase() === address || (row.highestBidder ?? "").toLowerCase() === address || row.bids.some((bid) => bid.bidder.toLowerCase() === address);
6413
6495
  });
6414
- return { address: args.address, orders, auctions, source: "logs" };
6496
+ return { address: args.address, orders, auctions: auctions.map((row) => presentAuction(row)), source: "logs" };
6415
6497
  }
6416
6498
 
6417
6499
  // src/protocols/evm/continuum-dao/marketplaceSearch.ts
@@ -6483,6 +6565,13 @@ function positive(value) {
6483
6565
  const trimmed = (value ?? "").trim();
6484
6566
  return trimmed && trimmed !== "0" ? trimmed : "";
6485
6567
  }
6568
+ function party(...values) {
6569
+ for (const value of values) {
6570
+ const text2 = (value ?? "").trim();
6571
+ if (text2 && !/^0x0+$/i.test(text2)) return text2;
6572
+ }
6573
+ return "";
6574
+ }
6486
6575
  function unlockUnixFrom(row) {
6487
6576
  const iso2 = positive(row.unlockTimeAt);
6488
6577
  if (iso2) {
@@ -6502,7 +6591,7 @@ function listingCandidate(row) {
6502
6591
  kind: "listing",
6503
6592
  tokenId: row.tokenId,
6504
6593
  onchainIndex: row.onchainIndex,
6505
- seller: row.seller ?? row.creator,
6594
+ seller: party(row.seller, row.creator, row.currentOwner),
6506
6595
  paymentToken: row.paymentToken,
6507
6596
  price: asBig(row.price),
6508
6597
  priceBasis: "ask",
@@ -6560,7 +6649,7 @@ function rankMarketplaceSearchHits(rows, query, nowUnix = Math.floor(Date.now()
6560
6649
  const excludeOwned = query.excludeOwned !== false && Boolean(executor);
6561
6650
  let matched = rows.filter((row) => {
6562
6651
  if (query.paymentToken && !same3(row.paymentToken, query.paymentToken)) return false;
6563
- if (excludeOwned && same3(row.seller, executor)) return false;
6652
+ if (excludeOwned && row.kind !== "listing" && same3(row.seller, executor)) return false;
6564
6653
  if (minLocked != null && row.locked < minLocked) return false;
6565
6654
  if (maxLocked != null && row.locked > maxLocked) return false;
6566
6655
  if (unlockAfter != null && row.unlockUnix < unlockAfter) return false;
@@ -6568,6 +6657,10 @@ function rankMarketplaceSearchHits(rows, query, nowUnix = Math.floor(Date.now()
6568
6657
  if (monthCap != null && (row.unlockUnix <= nowUnix || row.unlockUnix > monthCap)) return false;
6569
6658
  return true;
6570
6659
  });
6660
+ matched = matched.map((row) => {
6661
+ const ownListing = Boolean(executor && row.kind === "listing" && same3(row.seller, executor));
6662
+ return ownListing ? { ...row, fillable: false } : row;
6663
+ });
6571
6664
  const priceSort = sort === "price" || sort === "pricePerLockedCtm";
6572
6665
  if (priceSort && !query.paymentToken) {
6573
6666
  const tokens = new Set(matched.map((row) => row.paymentToken.toLowerCase()));
@@ -6592,9 +6685,16 @@ function rankMarketplaceSearchHits(rows, query, nowUnix = Math.floor(Date.now()
6592
6685
  return a.tokenId.localeCompare(b.tokenId);
6593
6686
  });
6594
6687
  const limit = Math.min(MAX_LIMIT, Math.max(1, query.limit ?? DEFAULT_LIMIT));
6595
- return matched.slice(0, limit).map((row) => toHit(row, nowUnix));
6688
+ return matched.slice(0, limit).map((row) => {
6689
+ const ownListing = Boolean(executor && row.kind === "listing" && same3(row.seller, executor));
6690
+ return toHit(
6691
+ ownListing ? { ...row, fillable: false } : row,
6692
+ nowUnix,
6693
+ ownListing ? "delist" : row.kind === "auction" ? "bid" : "buy"
6694
+ );
6695
+ });
6596
6696
  }
6597
- function toHit(row, nowUnix) {
6697
+ function toHit(row, nowUnix, action) {
6598
6698
  const meta4 = paymentMeta(row.paymentToken);
6599
6699
  const perCtm = row.locked > 0n ? row.price * 10n ** 18n / row.locked : 0n;
6600
6700
  const months = row.unlockUnix > nowUnix ? ((row.unlockUnix - nowUnix) / MONTH_SECONDS).toFixed(1) : row.unlockUnix > 0 ? "0" : "";
@@ -6615,7 +6715,8 @@ function toHit(row, nowUnix) {
6615
6715
  pricePerLockedCtm: row.locked > 0n ? humanAmount(perCtm, meta4.decimals) : "",
6616
6716
  deadlineAt: row.deadlineUnix > 0 ? new Date(row.deadlineUnix * 1e3).toISOString() : "",
6617
6717
  attached: row.attached,
6618
- fillable: row.fillable
6718
+ fillable: row.fillable,
6719
+ action
6619
6720
  };
6620
6721
  }
6621
6722
  async function fillMissingLocks(rows, rpcUrl, chainId) {
@@ -7156,6 +7257,172 @@ function marketplaceVeCtmReceivedBy(detail, executor) {
7156
7257
  return null;
7157
7258
  }
7158
7259
 
7260
+ // src/protocols/evm/continuum-dao/purpose.ts
7261
+ init_constants();
7262
+ function chainParts(chainId) {
7263
+ const n = typeof chainId === "number" ? chainId : Number.parseInt(String(chainId ?? "").trim(), 10);
7264
+ const id = Number.isFinite(n) ? n : 0;
7265
+ if (id === exports.CONTINUUM_DAO_LINEA_CHAIN_ID) return { name: "Linea Mainnet", id };
7266
+ if (id === exports.CONTINUUM_DAO_LINEA_SEPOLIA_CHAIN_ID) return { name: "Linea Sepolia", id };
7267
+ if (id === exports.CONTINUUM_DAO_ETHEREUM_CHAIN_ID) return { name: "Ethereum Mainnet", id };
7268
+ return { name: "chain", id };
7269
+ }
7270
+ function suffix(chainId) {
7271
+ const { name, id } = chainParts(chainId);
7272
+ return `on ${name} (chainId ${id})`;
7273
+ }
7274
+ function text(value) {
7275
+ return String(value ?? "").trim();
7276
+ }
7277
+ function tokenLabel(value) {
7278
+ const id = text(value);
7279
+ return id ? `#${id}` : "#\u2026";
7280
+ }
7281
+ function shortAddr(value) {
7282
+ const trimmed = text(value);
7283
+ if (!trimmed) return "\u2026";
7284
+ try {
7285
+ if (!viem.isAddress(trimmed)) return trimmed;
7286
+ const addr2 = viem.getAddress(trimmed);
7287
+ return `${addr2.slice(0, 6)}\u2026${addr2.slice(-4)}`;
7288
+ } catch {
7289
+ return trimmed;
7290
+ }
7291
+ }
7292
+ function weeksLabel(seconds) {
7293
+ const n = Number(text(seconds));
7294
+ if (!Number.isFinite(n) || n <= 0) return "\u2026 weeks";
7295
+ const weeks = Math.max(1, Math.round(n / exports.WEEK_SECONDS));
7296
+ return `${weeks} week${weeks === 1 ? "" : "s"}`;
7297
+ }
7298
+ function paymentMeta3(address) {
7299
+ const lower = text(address).toLowerCase();
7300
+ if (lower === exports.MARKETPLACE_USDC_LINEA_ADDRESS.toLowerCase()) return { symbol: "USDC", decimals: 6 };
7301
+ if (lower === exports.MARKETPLACE_WETH_LINEA_ADDRESS.toLowerCase()) return { symbol: "WETH", decimals: 18 };
7302
+ if (lower === exports.CTM_TOKEN_ADDRESS.toLowerCase()) return { symbol: "CTM", decimals: 18 };
7303
+ return { symbol: "token", decimals: 18 };
7304
+ }
7305
+ function moneyFromWei(wei, paymentToken) {
7306
+ const raw = text(wei);
7307
+ if (!raw) return "\u2026 token";
7308
+ try {
7309
+ const meta4 = paymentMeta3(paymentToken);
7310
+ const human2 = viem.formatUnits(BigInt(raw), meta4.decimals).replace(/(\.\d*?[1-9])0+$/, "$1").replace(/\.0+$/, "");
7311
+ return `${human2} ${meta4.symbol}`;
7312
+ } catch {
7313
+ return raw;
7314
+ }
7315
+ }
7316
+ function deadlineLabel(value) {
7317
+ const n = Number(text(value));
7318
+ if (!Number.isFinite(n) || n <= 0) return "\u2026";
7319
+ const date = new Date(n * 1e3);
7320
+ if (Number.isNaN(date.getTime())) return "\u2026";
7321
+ return `${date.toISOString().slice(0, 16).replace("T", " ")} UTC`;
7322
+ }
7323
+ function bravoLabel(support) {
7324
+ const raw = text(support).toLowerCase();
7325
+ if (raw === "0" || raw === "against") return "Against";
7326
+ if (raw === "1" || raw === "for") return "For";
7327
+ if (raw === "2" || raw === "abstain") return "Abstain";
7328
+ return null;
7329
+ }
7330
+ function proposalLabel(input) {
7331
+ const title = text(input.title || input.proposalTitle);
7332
+ if (title) return title;
7333
+ const id = text(input.proposalId);
7334
+ return id ? `proposal ${id}` : "proposal";
7335
+ }
7336
+ function buildContinuumDaoMcpPurpose(action, input) {
7337
+ const end = suffix(input.chainId);
7338
+ const id = tokenLabel(input.tokenId);
7339
+ switch (action) {
7340
+ case "createLock":
7341
+ return `ContinuumDAO: create lock ${text(input.amountHuman) || "\u2026"} CTM for ${weeksLabel(input.lockDurationSeconds)} ${end}`;
7342
+ case "increaseAmount":
7343
+ return `ContinuumDAO: increase lock ${id} by ${text(input.amountHuman) || "\u2026"} CTM ${end}`;
7344
+ case "increaseUnlockTime":
7345
+ return `ContinuumDAO: extend lock ${id} by ${weeksLabel(input.lockDurationSeconds)} ${end}`;
7346
+ case "split":
7347
+ return `ContinuumDAO: split lock ${id}, extract ${text(input.extractedHuman) || "\u2026"} CTM ${end}`;
7348
+ case "merge": {
7349
+ const from = tokenLabel(input.fromTokenId);
7350
+ const into = text(input.toTokenId);
7351
+ return into ? `ContinuumDAO: merge lock ${from} into #${into} ${end}` : `ContinuumDAO: merge lock ${from} into \u2026 ${end}`;
7352
+ }
7353
+ case "withdraw":
7354
+ return `ContinuumDAO: withdraw expired lock ${id} ${end}`;
7355
+ case "liquidate":
7356
+ return `ContinuumDAO: liquidate lock ${id} ${end}`;
7357
+ case "delegate":
7358
+ return text(input.delegatee) ? `ContinuumDAO: delegate voting power to ${shortAddr(input.delegatee)} ${end}` : `ContinuumDAO: delegate voting power ${end}`;
7359
+ case "undelegate":
7360
+ return `ContinuumDAO: undelegate (return voting power to this KeyGen) ${end}`;
7361
+ case "transfer":
7362
+ return text(input.to) ? `ContinuumDAO: transfer veCTM ${id} to ${shortAddr(input.to)} ${end}` : `ContinuumDAO: transfer veCTM ${id} ${end}`;
7363
+ case "attach":
7364
+ return text(input.tokenId) ? `ContinuumDAO: attach veCTM ${id} to this node ${end}` : `ContinuumDAO: attach veCTM to this node ${end}`;
7365
+ case "requestDetach":
7366
+ return `ContinuumDAO: request detach veCTM ${id} ${end}`;
7367
+ case "proposeBravo": {
7368
+ const title = text(input.title);
7369
+ return title ? `ContinuumDAO: propose "${title}" (Bravo) ${end}` : `ContinuumDAO: propose governance proposal (Bravo) ${end}`;
7370
+ }
7371
+ case "proposeDelta": {
7372
+ const title = text(input.title);
7373
+ return title ? `ContinuumDAO: propose "${title}" (Delta) ${end}` : `ContinuumDAO: propose governance proposal (Delta) ${end}`;
7374
+ }
7375
+ case "castVoteBravo": {
7376
+ const label = proposalLabel(input);
7377
+ const support = bravoLabel(input.support);
7378
+ return support ? `ContinuumDAO: vote ${support} on "${label}" ${end}` : `ContinuumDAO: vote on "${label}" ${end}`;
7379
+ }
7380
+ case "castVoteDelta":
7381
+ return `ContinuumDAO: vote on "${proposalLabel(input)}" (Delta) ${end}`;
7382
+ case "execute":
7383
+ return `ContinuumDAO: execute "${proposalLabel(input)}" ${end}`;
7384
+ case "cancel":
7385
+ return `ContinuumDAO: cancel "${proposalLabel(input)}" ${end}`;
7386
+ case "forumSignIn": {
7387
+ const who = text(input.username);
7388
+ return who ? `ContinuumDAO: sign in to the forum as ${who} ${end}` : `ContinuumDAO: sign in to the forum ${end}`;
7389
+ }
7390
+ case "marketplaceCreateListing":
7391
+ return `ContinuumDAO: list veCTM ${id} for ${moneyFromWei(input.askWei, input.paymentToken)} until ${deadlineLabel(input.deadline)} ${end}`;
7392
+ case "marketplaceDelist":
7393
+ return `ContinuumDAO: delist veCTM ${id} ${end}`;
7394
+ case "marketplaceFulfillListing":
7395
+ return `ContinuumDAO: buy veCTM ${id} for ${moneyFromWei(input.priceWei, input.paymentToken)} ${end}`;
7396
+ case "marketplaceCreateOffering":
7397
+ return `ContinuumDAO: offer ${moneyFromWei(input.bidWei, input.paymentToken)} for veCTM ${id} until ${deadlineLabel(input.deadline)} ${end}`;
7398
+ case "marketplaceRescind":
7399
+ return `ContinuumDAO: rescind offer on veCTM ${id} ${end}`;
7400
+ case "marketplaceFulfillOffering":
7401
+ return `ContinuumDAO: accept offer of ${moneyFromWei(input.priceWei, input.paymentToken)} on veCTM ${id} ${end}`;
7402
+ case "marketplaceCreateAuction":
7403
+ return `ContinuumDAO: auction veCTM ${id} reserve ${moneyFromWei(input.reserveWei, input.paymentToken)}, minimum increment ${moneyFromWei(input.minIncrementWei, input.paymentToken)}, until ${deadlineLabel(input.deadline)} ${end}`;
7404
+ case "marketplaceCancelAuction":
7405
+ return `ContinuumDAO: cancel auction for veCTM ${id} ${end}`;
7406
+ case "marketplaceAuctionBid":
7407
+ return `ContinuumDAO: bid ${moneyFromWei(input.priceWei, input.paymentToken)} on veCTM ${id} ${end}`;
7408
+ case "marketplaceSettleAuction":
7409
+ return `ContinuumDAO: settle auction for veCTM ${id} ${end}`;
7410
+ default:
7411
+ return `ContinuumDAO: ${end}`;
7412
+ }
7413
+ }
7414
+ function preprocessContinuumDaoPurpose(action, raw) {
7415
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw;
7416
+ const o = { ...raw };
7417
+ const supplied = text(o.purposeText ?? o.purpose);
7418
+ if (supplied) {
7419
+ o.purposeText = supplied;
7420
+ return o;
7421
+ }
7422
+ o.purposeText = buildContinuumDaoMcpPurpose(action, o);
7423
+ return o;
7424
+ }
7425
+
7159
7426
  // src/protocols/evm/continuum-dao/index.ts
7160
7427
  registerProtocolModule(continuumDaoMarketplaceProtocolModule);
7161
7428
  var continuumDaoProtocolModule = {
@@ -7268,6 +7535,7 @@ exports.auctionStatusName = auctionStatusName;
7268
7535
  exports.bravoSupportLabel = bravoSupportLabel;
7269
7536
  exports.bucketGovernorState = bucketGovernorState;
7270
7537
  exports.buildBravoProposalArgs = buildBravoProposalArgs;
7538
+ exports.buildContinuumDaoMcpPurpose = buildContinuumDaoMcpPurpose;
7271
7539
  exports.buildDeltaProposalArgs = buildDeltaProposalArgs;
7272
7540
  exports.buildEvmMultisignBodyContinuumDaoAttachVeCtm = buildEvmMultisignBodyContinuumDaoAttachVeCtm;
7273
7541
  exports.buildEvmMultisignBodyContinuumDaoAttachVeCtmFromMcp = buildEvmMultisignBodyContinuumDaoAttachVeCtmFromMcp;
@@ -7424,6 +7692,7 @@ exports.preflightSplit = preflightSplit;
7424
7692
  exports.preflightTransfer = preflightTransfer;
7425
7693
  exports.preflightUndelegate = preflightUndelegate;
7426
7694
  exports.preflightWithdraw = preflightWithdraw;
7695
+ exports.preprocessContinuumDaoPurpose = preprocessContinuumDaoPurpose;
7427
7696
  exports.proposalCatalogCanonical = proposalCatalogCanonical;
7428
7697
  exports.proposalCatalogDocument = proposalCatalogDocument;
7429
7698
  exports.proposalDescriptionHash = proposalDescriptionHash;