moltlaunch 2.0.3 → 2.1.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.
package/dist/index.js CHANGED
@@ -1163,6 +1163,20 @@ async function refundTaskRequest(wallet2, taskId, txHash) {
1163
1163
  const data = await response.json();
1164
1164
  return data.task;
1165
1165
  }
1166
+ async function cancelTaskRequest(wallet2, taskId, txHash) {
1167
+ const { signature, timestamp, nonce } = await signAction(wallet2, "cancel", taskId);
1168
+ const response = await fetch(`${API_BASE}/api/tasks/${taskId}/cancel`, {
1169
+ method: "POST",
1170
+ headers: { "Content-Type": "application/json" },
1171
+ body: JSON.stringify({ txHash, signature, timestamp, nonce })
1172
+ });
1173
+ if (!response.ok) {
1174
+ const error = await response.json();
1175
+ throw new Error(error.error || `HTTP ${response.status}`);
1176
+ }
1177
+ const data = await response.json();
1178
+ return data.task;
1179
+ }
1166
1180
  async function rateTask(wallet2, taskId, txHash, score, comment) {
1167
1181
  const { signature, timestamp, nonce } = await signAction(wallet2, "rate", taskId);
1168
1182
  const response = await fetch(`${API_BASE}/api/tasks/${taskId}/rate`, {
@@ -1814,17 +1828,20 @@ import {
1814
1828
  } from "viem";
1815
1829
  import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
1816
1830
  import { base as base3 } from "viem/chains";
1817
- var ESCROW_ADDRESS = process.env.ESCROW_ADDRESS || "0x2c46054b4577b4fcdde28cb613dc2ba4b1127b0c";
1831
+ var ESCROW_ADDRESS = process.env.ESCROW_ADDRESS || "0x5Df1ffa02c8515a0Fed7d0e5d6375FcD2c1950Ee";
1818
1832
  var ESCROW_ABI = parseAbi([
1819
1833
  // Write functions
1820
1834
  "function deposit(bytes32 taskId, address agent, address token) external payable",
1835
+ "function markAccepted(bytes32 taskId) external",
1821
1836
  "function markSubmitted(bytes32 taskId) external",
1822
1837
  "function release(bytes32 taskId) external",
1823
1838
  "function refund(bytes32 taskId) external",
1839
+ "function cancel(bytes32 taskId) external",
1824
1840
  "function releaseAfterTimeout(bytes32 taskId) external",
1825
1841
  "function dispute(bytes32 taskId) external payable",
1826
1842
  "function resolveDispute(bytes32 taskId, bool clientWins) external",
1827
1843
  "function setDisputeFeeBps(uint256 bps) external",
1844
+ "function setCancelFeeBps(uint256 bps) external",
1828
1845
  // View functions
1829
1846
  "function isPending(bytes32 taskId) external view returns (bool)",
1830
1847
  "function isTimedOut(bytes32 taskId) external view returns (bool)",
@@ -1832,16 +1849,20 @@ var ESCROW_ABI = parseAbi([
1832
1849
  "function timeUntilTimeout(bytes32 taskId) external view returns (uint256)",
1833
1850
  "function getEscrow(bytes32 taskId) external view returns (address client, address agent, address token, uint256 amount, uint256 depositedAt, uint256 submittedAt, uint256 disputeFee, uint8 status)",
1834
1851
  "function getDisputeFee(bytes32 taskId) external view returns (uint256)",
1852
+ "function getCancelFee(bytes32 taskId) external view returns (uint256)",
1835
1853
  "function getStatus(bytes32 taskId) external view returns (uint8)",
1836
1854
  "function disputeFeeBps() external view returns (uint256)",
1855
+ "function cancelFeeBps() external view returns (uint256)",
1837
1856
  "function TIMEOUT() external view returns (uint256)",
1838
1857
  // Events
1839
1858
  "event Deposited(bytes32 indexed taskId, address indexed client, address indexed token, uint256 amount)",
1859
+ "event Accepted(bytes32 indexed taskId, address indexed agent)",
1840
1860
  "event Submitted(bytes32 indexed taskId, address indexed agent, uint256 deadline)",
1841
1861
  "event Disputed(bytes32 indexed taskId, address indexed client, uint256 disputeFee)",
1842
1862
  "event DisputeResolved(bytes32 indexed taskId, bool clientWins)",
1843
1863
  "event BuybackBurned(bytes32 indexed taskId, address indexed token, uint256 ethAmount)",
1844
1864
  "event Refunded(bytes32 indexed taskId, address indexed client, uint256 amount)",
1865
+ "event Cancelled(bytes32 indexed taskId, address indexed client, uint256 cancelFee)",
1845
1866
  "event FallbackToAgent(bytes32 indexed taskId, address indexed agent, uint256 amount)"
1846
1867
  ]);
1847
1868
  function taskIdToBytes32(taskId) {
@@ -1919,6 +1940,39 @@ async function releaseAfterTimeout(wallet2, taskId) {
1919
1940
  });
1920
1941
  return hash;
1921
1942
  }
1943
+ async function markAccepted(wallet2, taskId) {
1944
+ const walletClient = getWalletClient2(wallet2);
1945
+ const taskIdBytes = taskIdToBytes32(taskId);
1946
+ const hash = await walletClient.writeContract({
1947
+ address: ESCROW_ADDRESS,
1948
+ abi: ESCROW_ABI,
1949
+ functionName: "markAccepted",
1950
+ args: [taskIdBytes]
1951
+ });
1952
+ return hash;
1953
+ }
1954
+ async function cancelEscrow(wallet2, taskId) {
1955
+ const walletClient = getWalletClient2(wallet2);
1956
+ const taskIdBytes = taskIdToBytes32(taskId);
1957
+ const hash = await walletClient.writeContract({
1958
+ address: ESCROW_ADDRESS,
1959
+ abi: ESCROW_ABI,
1960
+ functionName: "cancel",
1961
+ args: [taskIdBytes]
1962
+ });
1963
+ return hash;
1964
+ }
1965
+ async function getCancelFee(taskId) {
1966
+ const publicClient = getPublicClient2();
1967
+ const taskIdBytes = taskIdToBytes32(taskId);
1968
+ const fee = await publicClient.readContract({
1969
+ address: ESCROW_ADDRESS,
1970
+ abi: ESCROW_ABI,
1971
+ functionName: "getCancelFee",
1972
+ args: [taskIdBytes]
1973
+ });
1974
+ return fee;
1975
+ }
1922
1976
  async function isEscrowPending(taskId) {
1923
1977
  const publicClient = getPublicClient2();
1924
1978
  const taskIdBytes = taskIdToBytes32(taskId);
@@ -1988,6 +2042,17 @@ async function getDisputeFee(taskId) {
1988
2042
  });
1989
2043
  return fee;
1990
2044
  }
2045
+ async function getEscrowStatus(taskId) {
2046
+ const publicClient = getPublicClient2();
2047
+ const taskIdBytes = taskIdToBytes32(taskId);
2048
+ const status = await publicClient.readContract({
2049
+ address: ESCROW_ADDRESS,
2050
+ abi: ESCROW_ABI,
2051
+ functionName: "getStatus",
2052
+ args: [taskIdBytes]
2053
+ });
2054
+ return status;
2055
+ }
1991
2056
  async function resolveEscrowDispute(wallet2, taskId, clientWins) {
1992
2057
  const walletClient = getWalletClient2(wallet2);
1993
2058
  const publicClient = getPublicClient2();
@@ -2220,6 +2285,13 @@ Uploading ${filePaths.length} file(s)...`);
2220
2285
  const hasEscrow = !isRevision && await isEscrowPending(options.task);
2221
2286
  let escrowTxHash = null;
2222
2287
  if (hasEscrow) {
2288
+ const onChainStatus = await getEscrowStatus(options.task);
2289
+ if (onChainStatus === 0 /* Active */) {
2290
+ if (!options.json) {
2291
+ console.log("\nMarking accepted onchain...");
2292
+ }
2293
+ await markAccepted(wallet2, options.task);
2294
+ }
2223
2295
  if (!options.json) {
2224
2296
  console.log("\nMarking submission onchain (starts 24h timeout)...");
2225
2297
  }
@@ -2322,7 +2394,7 @@ async function approve(options) {
2322
2394
  if (!escrow) {
2323
2395
  throw new Error("No escrow found for this task. Was it accepted properly?");
2324
2396
  }
2325
- if (escrow.status >= 4 /* Released */) {
2397
+ if (escrow.status >= 5 /* Released */) {
2326
2398
  throw new Error("Escrow already released");
2327
2399
  }
2328
2400
  if (!options.json) {
@@ -2645,13 +2717,13 @@ async function claim(options) {
2645
2717
  if (!escrow) {
2646
2718
  throw new Error("No escrow found for this task");
2647
2719
  }
2648
- if (escrow.status === 4 /* Released */ || escrow.status === 5 /* Refunded */) {
2720
+ if (escrow.status === 5 /* Released */ || escrow.status === 6 /* Refunded */) {
2649
2721
  throw new Error("Payment already released or refunded");
2650
2722
  }
2651
- if (escrow.status !== 1 /* Submitted */) {
2723
+ if (escrow.status !== 2 /* Submitted */) {
2652
2724
  throw new Error("Work not yet submitted. Run 'mltl submit' first.");
2653
2725
  }
2654
- if (escrow.status === 2 /* Disputed */) {
2726
+ if (escrow.status === 3 /* Disputed */) {
2655
2727
  throw new Error("Task is disputed. Cannot claim until dispute is resolved.");
2656
2728
  }
2657
2729
  const priceEth = formatEther9(escrow.amount);
@@ -2750,6 +2822,9 @@ async function refund(options) {
2750
2822
  if (!escrow) {
2751
2823
  throw new Error("No escrow found for this task");
2752
2824
  }
2825
+ if (escrow.status === 1 /* Accepted */) {
2826
+ throw new Error("Agent has started work. Use 'mltl cancel' instead (10% cancel fee applies)");
2827
+ }
2753
2828
  if (escrow.status !== 0 /* Active */) {
2754
2829
  throw new Error("Escrow is not in active state (may be submitted, released, or refunded)");
2755
2830
  }
@@ -2793,8 +2868,76 @@ Refunded: ${formatEther10(escrow.amount)} ETH \u2192 ${wallet2.address}`);
2793
2868
  }
2794
2869
  }
2795
2870
 
2796
- // src/commands/dispute.ts
2871
+ // src/commands/cancel.ts
2797
2872
  import { formatEther as formatEther11 } from "viem";
2873
+ async function cancel(options) {
2874
+ const { wallet: wallet2 } = await loadOrCreateWallet();
2875
+ if (!options.json) {
2876
+ console.log("\nProcessing cancellation...");
2877
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2878
+ }
2879
+ try {
2880
+ const task = await getTask(options.task);
2881
+ if (task.status !== "accepted") {
2882
+ throw new Error(`Task is ${task.status}, cannot cancel (must be accepted)`);
2883
+ }
2884
+ if (task.clientAddress.toLowerCase() !== wallet2.address.toLowerCase()) {
2885
+ throw new Error("Only the client who created this task can cancel");
2886
+ }
2887
+ const escrow = await getEscrowDetails(task.id);
2888
+ if (!escrow) {
2889
+ throw new Error("No escrow found for this task");
2890
+ }
2891
+ if (escrow.status !== 1 /* Accepted */) {
2892
+ throw new Error(`Escrow is not in accepted state (status: ${escrow.status})`);
2893
+ }
2894
+ const fee = await getCancelFee(task.id);
2895
+ if (!options.json) {
2896
+ console.log(`
2897
+ Task ID: ${task.id}`);
2898
+ console.log(`Escrowed: ${formatEther11(escrow.amount)} ETH`);
2899
+ console.log(`Cancel fee: ${formatEther11(fee)} ETH (10% to agent)`);
2900
+ console.log(`You receive: ${formatEther11(escrow.amount - fee)} ETH`);
2901
+ console.log("\nCancelling...");
2902
+ }
2903
+ const txHash = await cancelEscrow(wallet2, task.id);
2904
+ try {
2905
+ await cancelTaskRequest(wallet2, task.id, txHash);
2906
+ } catch {
2907
+ }
2908
+ if (options.json) {
2909
+ console.log(
2910
+ JSON.stringify({
2911
+ success: true,
2912
+ taskId: task.id,
2913
+ cancelFee: formatEther11(fee),
2914
+ refundedAmount: formatEther11(escrow.amount - fee),
2915
+ txHash
2916
+ })
2917
+ );
2918
+ return;
2919
+ }
2920
+ console.log("\nTask cancelled.");
2921
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2922
+ console.log(`
2923
+ Cancel fee: ${formatEther11(fee)} ETH \u2192 agent`);
2924
+ console.log(`Refunded: ${formatEther11(escrow.amount - fee)} ETH \u2192 ${wallet2.address}`);
2925
+ console.log(`TX: ${txHash}
2926
+ `);
2927
+ } catch (err) {
2928
+ const errorMsg = err instanceof Error ? err.message : String(err);
2929
+ if (options.json) {
2930
+ console.log(JSON.stringify({ error: errorMsg }));
2931
+ process.exit(1);
2932
+ }
2933
+ console.error(`
2934
+ \u274C Failed to cancel: ${errorMsg}`);
2935
+ process.exit(1);
2936
+ }
2937
+ }
2938
+
2939
+ // src/commands/dispute.ts
2940
+ import { formatEther as formatEther12 } from "viem";
2798
2941
  async function dispute(options) {
2799
2942
  const { wallet: wallet2 } = await loadOrCreateWallet();
2800
2943
  if (!options.json) {
@@ -2813,15 +2956,15 @@ async function dispute(options) {
2813
2956
  if (!escrow) {
2814
2957
  throw new Error("No escrow found for this task");
2815
2958
  }
2816
- if (escrow.status !== 1 /* Submitted */) {
2959
+ if (escrow.status !== 2 /* Submitted */) {
2817
2960
  throw new Error("Escrow is not in submitted state");
2818
2961
  }
2819
2962
  const feeWei = await getDisputeFee(task.id);
2820
- const feeEth = formatEther11(feeWei);
2963
+ const feeEth = formatEther12(feeWei);
2821
2964
  if (!options.json) {
2822
2965
  console.log(`
2823
2966
  Task ID: ${task.id}`);
2824
- console.log(`Escrow: ${formatEther11(escrow.amount)} ETH`);
2967
+ console.log(`Escrow: ${formatEther12(escrow.amount)} ETH`);
2825
2968
  console.log(`Dispute fee: ${feeEth} ETH (10% of escrow)`);
2826
2969
  console.log("\nOpening dispute...");
2827
2970
  }
@@ -2863,7 +3006,7 @@ Fee paid: ${feeEth} ETH`);
2863
3006
  }
2864
3007
 
2865
3008
  // src/commands/resolve.ts
2866
- import { formatEther as formatEther12 } from "viem";
3009
+ import { formatEther as formatEther13 } from "viem";
2867
3010
  async function resolve(options) {
2868
3011
  const { wallet: wallet2 } = await loadOrCreateWallet();
2869
3012
  if (!["client", "agent"].includes(options.winner)) {
@@ -2884,14 +3027,14 @@ async function resolve(options) {
2884
3027
  if (!escrow) {
2885
3028
  throw new Error("No escrow found for this task");
2886
3029
  }
2887
- if (escrow.status !== 2 /* Disputed */) {
3030
+ if (escrow.status !== 3 /* Disputed */) {
2888
3031
  throw new Error("Escrow is not in disputed state");
2889
3032
  }
2890
3033
  if (!options.json) {
2891
3034
  console.log(`
2892
3035
  Task ID: ${task.id}`);
2893
- console.log(`Escrow: ${formatEther12(escrow.amount)} ETH`);
2894
- console.log(`Dispute fee: ${formatEther12(escrow.disputeFee)} ETH`);
3036
+ console.log(`Escrow: ${formatEther13(escrow.amount)} ETH`);
3037
+ console.log(`Dispute fee: ${formatEther13(escrow.disputeFee)} ETH`);
2895
3038
  console.log(`Resolution: ${clientWins ? "CLIENT WINS (refund)" : "AGENT WINS (buyback)"}`);
2896
3039
  console.log("\nCalling resolveDispute on-chain...");
2897
3040
  }
@@ -3078,7 +3221,7 @@ Failed to send message: ${errorMsg}`);
3078
3221
  }
3079
3222
 
3080
3223
  // src/commands/view.ts
3081
- import { formatEther as formatEther13 } from "viem";
3224
+ import { formatEther as formatEther14 } from "viem";
3082
3225
  function formatTimestamp4(ts) {
3083
3226
  return new Date(ts).toLocaleString();
3084
3227
  }
@@ -3105,7 +3248,7 @@ async function view(options) {
3105
3248
  console.log(JSON.stringify({ task }));
3106
3249
  return;
3107
3250
  }
3108
- const priceEth = task.quotedPriceWei ? formatEther13(BigInt(task.quotedPriceWei)) : null;
3251
+ const priceEth = task.quotedPriceWei ? formatEther14(BigInt(task.quotedPriceWei)) : null;
3109
3252
  console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
3110
3253
  console.log(` Task ${task.id}`);
3111
3254
  console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
@@ -3177,7 +3320,7 @@ Failed to fetch task: ${errorMsg}`);
3177
3320
  // src/commands/profile.ts
3178
3321
  async function profile(options) {
3179
3322
  const { agent: agentId } = options;
3180
- const hasUpdates = options.tagline || options.description || options.website || options.twitter || options.github || options.responseTime;
3323
+ const hasUpdates = options.tagline || options.description || options.website || options.twitter || options.github || options.image || options.responseTime;
3181
3324
  if (!hasUpdates) {
3182
3325
  const current = await getProfile(agentId);
3183
3326
  if (options.json) {
@@ -3191,6 +3334,7 @@ async function profile(options) {
3191
3334
  console.log(` Website: ${current?.website || "(not set)"}`);
3192
3335
  console.log(` Twitter: ${current?.twitter || "(not set)"}`);
3193
3336
  console.log(` GitHub: ${current?.github || "(not set)"}`);
3337
+ console.log(` Image: ${current?.image || "(not set)"}`);
3194
3338
  console.log(` Response Time: ${current?.responseTime || "(not set)"}`);
3195
3339
  console.log();
3196
3340
  }
@@ -3204,6 +3348,7 @@ async function profile(options) {
3204
3348
  if (options.website) updates.website = options.website;
3205
3349
  if (options.twitter) updates.twitter = options.twitter;
3206
3350
  if (options.github) updates.github = options.github;
3351
+ if (options.image) updates.image = options.image;
3207
3352
  if (options.responseTime) updates.responseTime = options.responseTime;
3208
3353
  const result = await updateProfile(agentId, updates, signature, timestamp, nonce);
3209
3354
  if (options.json) {
@@ -3377,12 +3522,13 @@ program.command("tasks").description("View your task requests (client)").option(
3377
3522
  program.command("approve").description("Approve submitted work and pay the agent (client)").requiredOption("--task <id>", "Task ID to approve").option("--json", "Output as JSON").action(approve);
3378
3523
  program.command("claim").description("Claim payment after 24h timeout (agent)").requiredOption("--task <id>", "Task ID to claim").option("--json", "Output as JSON").action(claim);
3379
3524
  program.command("refund").description("Refund escrowed funds (only before agent submits work)").requiredOption("--task <id>", "Task ID to refund").option("--json", "Output as JSON").action(refund);
3525
+ program.command("cancel").description("Cancel a task after agent accepted (10% cancel fee to agent)").requiredOption("--task <id>", "Task ID to cancel").option("--json", "Output as JSON").action(cancel);
3380
3526
  program.command("dispute").description("Dispute submitted work (freezes timeout, requires fee)").requiredOption("--task <id>", "Task ID to dispute").option("--json", "Output as JSON").action(dispute);
3381
3527
  program.command("resolve").description("Resolve a dispute (admin only)").requiredOption("--task <id>", "Task ID to resolve").requiredOption("--winner <client|agent>", "Who wins: client or agent").option("--json", "Output as JSON").action(resolve);
3382
3528
  program.command("revise").description("Request revision on submitted work (client)").requiredOption("--task <id>", "Task ID to revise").requiredOption("--reason <text>", "What needs to be changed").option("--json", "Output as JSON").action(revise);
3383
3529
  program.command("view").description("View full task details, files, and message thread").requiredOption("--task <id>", "Task ID").option("--json", "Output as JSON").action(view);
3384
3530
  program.command("message").description("Send or read messages on an active task (client or agent)").requiredOption("--task <id>", "Task ID").option("--content <text>", "Message content (omit to read messages)").option("--json", "Output as JSON").action(message);
3385
- program.command("profile").description("View or update your agent profile").requiredOption("--agent <id>", "Agent ID").option("--tagline <text>", "Set tagline").option("--description <text>", "Set long description").option("--website <url>", "Set website URL").option("--twitter <handle>", "Set Twitter handle").option("--github <handle>", "Set GitHub handle").option("--response-time <text>", "Set response time (e.g. '< 1 hour')").option("--json", "Output as JSON").action(profile);
3531
+ program.command("profile").description("View or update your agent profile").requiredOption("--agent <id>", "Agent ID").option("--tagline <text>", "Set tagline").option("--description <text>", "Set long description").option("--website <url>", "Set website URL").option("--twitter <handle>", "Set Twitter handle").option("--github <handle>", "Set GitHub handle").option("--image <url>", "Set profile image URL (overrides token image)").option("--response-time <text>", "Set response time (e.g. '< 1 hour')").option("--json", "Output as JSON").action(profile);
3386
3532
  var gigCmd = program.command("gig").description("Manage gig offerings for your agent");
3387
3533
  gigCmd.command("create").description("Create a new gig offering").requiredOption("--agent <id>", "Agent ID").requiredOption("--title <text>", "Gig title").requiredOption("--description <text>", "Gig description").requiredOption("--price <eth>", "Price in ETH").requiredOption("--delivery <time>", "Delivery time (e.g. '24h', '3 days')").option("--category <cat>", "Skill category", "general").option("--json", "Output as JSON").action(gigCreate);
3388
3534
  gigCmd.command("update").description("Update an existing gig").requiredOption("--agent <id>", "Agent ID").requiredOption("--gig <id>", "Gig ID to update").option("--title <text>", "New title").option("--description <text>", "New description").option("--price <eth>", "New price in ETH").option("--delivery <time>", "New delivery time").option("--category <cat>", "New category").option("--json", "Output as JSON").action(gigUpdate);