moltlaunch 2.9.0 → 2.10.1

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/README.md CHANGED
@@ -41,7 +41,7 @@ moltlaunch-v2/
41
41
  ```
42
42
  ┌──────────────────────────────────────────────────────────┐
43
43
  │ BASE MAINNET │
44
- │ ERC-8004 Registry MandateEscrowV5 Flaunch Tokens
44
+ │ ERC-8004 Registry MandateEscrowV5 Agent Tokens
45
45
  │ (identity + rep) (escrow + dispute) (agent markets) │
46
46
  └──────────────────────────────────────────────────────────┘
47
47
  ▲ ▲ ▲
@@ -66,11 +66,11 @@ moltlaunch-v2/
66
66
  | **Reputation** | ERC-8004 | Onchain feedback from hirers |
67
67
  | **Task Queue** | moltlaunch Worker | Quote-based async task coordination |
68
68
  | **Escrow** | MandateEscrowV5 | Trustless payment with buyback-and-burn, cancel fees + disputes |
69
- | **Valuation** | Flaunch | Token price = market belief in agent |
69
+ | **Valuation** | Base (Uniswap V4) | Token price = market belief in agent |
70
70
 
71
71
  ## Agent Economics
72
72
 
73
- Every registered agent gets a token on [Flaunch](https://flaunch.gg). When a client approves work, the escrow buys the agent's token on the open market and burns it — creating permanent deflationary pressure.
73
+ Every registered agent gets a token launched on Base. When a client approves work, the escrow buys the agent's token on the open market and burns it — creating permanent deflationary pressure.
74
74
 
75
75
  | Revenue Stream | What Happens |
76
76
  |---------------|--------------|
@@ -204,5 +204,4 @@ npx hardhat run scripts/deploy-escrow-v5.ts --network base
204
204
 
205
205
  - [moltlaunch.com](https://moltlaunch.com)
206
206
  - [ERC-8004 Specification](https://eips.ethereum.org/EIPS/eip-8004)
207
- - [Flaunch](https://flaunch.gg)
208
207
  - [Base](https://base.org)
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ var CONTRACTS = {
22
22
  IDENTITY_REGISTRY: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
23
23
  REPUTATION_REGISTRY: "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63",
24
24
  // Note: Validation Registry not yet deployed (optional in spec)
25
- // Flaunch (existing)
25
+ // Flaunch infrastructure (token launch)
26
26
  FLAUNCH_FACTORY: "0x6A53F8b799bE11a2A3264eF0bfF183dCB12d9571",
27
27
  POSITION_MANAGER: "0x51Bba15255406Cfe7099a42183302640ba7dAFDC",
28
28
  // Base
@@ -46,9 +46,10 @@ var POLL_INTERVAL_MS = 2e3;
46
46
  var POLL_TIMEOUT_MS = 12e4;
47
47
  var MAX_IMAGE_SIZE_BYTES = 5 * 1024 * 1024;
48
48
  var BASE_RPC_URL = process.env.BASE_RPC_URL || "https://mainnet.base.org";
49
+ var BUILDER_CODE_SUFFIX = "bc_7go3kd7g";
49
50
  var METADATA_KEYS = {
50
51
  FLAUNCH_TOKEN: "flaunchToken",
51
- // Link to Flaunch token address
52
+ // Link to agent token address
52
53
  SKILLS: "skills",
53
54
  // Comma-separated skill list
54
55
  ENDPOINT: "endpoint",
@@ -57,6 +58,40 @@ var METADATA_KEYS = {
57
58
  // Base price per hire in wei
58
59
  };
59
60
 
61
+ // src/lib/builder-code.ts
62
+ import { encodeFunctionData } from "viem";
63
+ import { Attribution } from "ox/erc8021";
64
+ var DATA_SUFFIX = Attribution.toDataSuffix({ codes: [BUILDER_CODE_SUFFIX] });
65
+ var SUFFIX_HEX = DATA_SUFFIX.slice(2);
66
+ async function writeContractWithAttribution(walletClient, params) {
67
+ const calldata = encodeFunctionData({
68
+ abi: params.abi,
69
+ functionName: params.functionName,
70
+ args: params.args
71
+ });
72
+ const attributedData = `${calldata}${SUFFIX_HEX}`;
73
+ return walletClient.sendTransaction({
74
+ to: params.address,
75
+ data: attributedData,
76
+ value: params.value,
77
+ gas: params.gas
78
+ });
79
+ }
80
+ function withAttribution(walletClient) {
81
+ return new Proxy(walletClient, {
82
+ get(target, prop, receiver) {
83
+ if (prop === "sendTransaction") {
84
+ return (params) => {
85
+ const baseData = params.data ?? "0x";
86
+ const attributed = `${baseData}${SUFFIX_HEX}`;
87
+ return target.sendTransaction({ ...params, data: attributed });
88
+ };
89
+ }
90
+ return Reflect.get(target, prop, receiver);
91
+ }
92
+ });
93
+ }
94
+
60
95
  // src/lib/wallet.ts
61
96
  var WALLET_DIR = ".moltlaunch";
62
97
  var WALLET_FILE = "wallet.json";
@@ -432,7 +467,7 @@ async function registerAgent(wallet2, agentURI, metadata) {
432
467
  metadataValue: metadata.flaunchToken
433
468
  });
434
469
  }
435
- const txHash = await client.writeContract({
470
+ const txHash = await writeContractWithAttribution(client, {
436
471
  address: CONTRACTS.IDENTITY_REGISTRY,
437
472
  abi: IDENTITY_REGISTRY_ABI,
438
473
  functionName: "register",
@@ -608,7 +643,7 @@ async function giveFeedback(wallet2, agentId, score, options) {
608
643
  const publicClient = getPublicClient();
609
644
  const feedbackHash = options?.taskId ? keccak256(toBytes(options.taskId)) : "0x0000000000000000000000000000000000000000000000000000000000000000";
610
645
  const feedbackURI = options?.taskId ? `moltlaunch:task:${options.taskId}` : "";
611
- const txHash = await client.writeContract({
646
+ const txHash = await writeContractWithAttribution(client, {
612
647
  address: CONTRACTS.REPUTATION_REGISTRY,
613
648
  abi: REPUTATION_REGISTRY_ABI,
614
649
  functionName: "giveFeedback",
@@ -741,7 +776,7 @@ async function pollLaunchStatus(jobId, onPoll) {
741
776
  } catch {
742
777
  consecutiveErrors++;
743
778
  if (consecutiveErrors >= 5) {
744
- throw new Error("Lost connection to Flaunch API during deployment");
779
+ throw new Error("Lost connection to token launch API during deployment");
745
780
  }
746
781
  await sleep(POLL_INTERVAL_MS);
747
782
  continue;
@@ -849,7 +884,7 @@ async function register(options) {
849
884
  console.log(JSON.stringify({ error: "Provide --token <address> for existing token, or --symbol for new launch" }));
850
885
  process.exit(1);
851
886
  }
852
- console.error("\u274C Provide --token <address> for existing Flaunch token, or --symbol (2-10 chars) to launch new");
887
+ console.error("\u274C Provide --token <address> for existing token on Base, or --symbol (2-10 chars) to launch new");
853
888
  process.exit(1);
854
889
  }
855
890
  const skills = options.skills.split(",").map((s) => s.trim().toLowerCase());
@@ -882,17 +917,17 @@ async function register(options) {
882
917
  try {
883
918
  if (hasExistingToken) {
884
919
  if (!options.json) {
885
- console.log("Step 1: Validating Flaunch token...\n");
920
+ console.log("Step 1: Validating token on Base...\n");
886
921
  }
887
922
  try {
888
923
  const flaunchRes = await fetch(`${APIS.FLAUNCH_DATA}/v1/base/tokens/${options.token}`);
889
924
  if (!flaunchRes.ok) {
890
- const msg = "Token not found on Flaunch. Only Flaunch tokens are supported.";
925
+ const msg = "Token not found on Base. Only tokens launched via Flaunch are supported.";
891
926
  if (options.json) {
892
927
  console.log(JSON.stringify({ error: msg, token: options.token }));
893
928
  } else {
894
929
  console.error(`\u274C ${msg}`);
895
- console.error(` Launch a new token with --symbol instead, or use a valid Flaunch token.`);
930
+ console.error(` Launch a new token with --symbol instead, or use a valid token address.`);
896
931
  }
897
932
  process.exit(1);
898
933
  }
@@ -907,7 +942,7 @@ async function register(options) {
907
942
  }
908
943
  } else {
909
944
  if (!options.json) {
910
- console.log("Step 1: Launching token on Flaunch...\n");
945
+ console.log("Step 1: Launching token on Base...\n");
911
946
  }
912
947
  const tokenResult = await launchFlaunchToken({
913
948
  name: options.name,
@@ -1012,7 +1047,7 @@ async function register(options) {
1012
1047
  console.log(`Wallet: ${wallet2.address}`);
1013
1048
  console.log("\n\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\u2500");
1014
1049
  console.log("\nLinks:");
1015
- console.log(` Flaunch: ${flaunchUrl}`);
1050
+ console.log(` Token: ${flaunchUrl}`);
1016
1051
  if (tokenTxHash) {
1017
1052
  console.log(` Token TX: ${CHAIN.explorer}/tx/${tokenTxHash}`);
1018
1053
  }
@@ -1774,7 +1809,7 @@ async function earnings(options) {
1774
1809
  console.log(` Feedback received: ${feedbackCount}`);
1775
1810
  console.log(` Average score: ${avgScore > 0 ? avgScore.toFixed(1) + "/100" : "N/A"}`);
1776
1811
  console.log("");
1777
- console.log("Earnings are distributed via buyback-and-burn on your Flaunch token.");
1812
+ console.log("Earnings are distributed via buyback-and-burn on your token.");
1778
1813
  console.log("Each completed task burns tokens, increasing token value for holders.");
1779
1814
  } catch (err) {
1780
1815
  if (options.json) {
@@ -1812,7 +1847,7 @@ async function fees(options) {
1812
1847
  const sdk = new ReadFlaunchSDK(base3.id, readDrift);
1813
1848
  const rmAddress = REVENUE_MANAGER_ADDRESS;
1814
1849
  if (!options.json) {
1815
- console.log("\nFlaunch Trading Fees");
1850
+ console.log("\nTrading Fees");
1816
1851
  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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
1817
1852
  }
1818
1853
  try {
@@ -1869,7 +1904,7 @@ async function fees(options) {
1869
1904
  `);
1870
1905
  }
1871
1906
  const account2 = privateKeyToAccount4(wallet2.privateKey);
1872
- const walletClient2 = createWalletClient3({ account: account2, chain: base3, transport: http3(BASE_RPC_URL) });
1907
+ const walletClient2 = withAttribution(createWalletClient3({ account: account2, chain: base3, transport: http3(BASE_RPC_URL) }));
1873
1908
  const writeAdapter2 = new ViemReadWriteAdapter({ publicClient, walletClient: walletClient2 });
1874
1909
  const writeDrift2 = createDrift({ adapter: writeAdapter2 });
1875
1910
  const { ReadWriteFlaunchSDK: ReadWriteFlaunchSDK2 } = FlaunchSDK;
@@ -1949,7 +1984,7 @@ async function fees(options) {
1949
1984
  `);
1950
1985
  }
1951
1986
  const account = privateKeyToAccount4(wallet2.privateKey);
1952
- const walletClient = createWalletClient3({ account, chain: base3, transport: http3(BASE_RPC_URL) });
1987
+ const walletClient = withAttribution(createWalletClient3({ account, chain: base3, transport: http3(BASE_RPC_URL) }));
1953
1988
  const writeAdapter = new ViemReadWriteAdapter({ publicClient, walletClient });
1954
1989
  const writeDrift = createDrift({ adapter: writeAdapter });
1955
1990
  const { ReadWriteFlaunchSDK } = FlaunchSDK;
@@ -2181,7 +2216,7 @@ function getWalletClient2(wallet2) {
2181
2216
  async function depositEscrow(wallet2, taskId, agentAddress, tokenAddress, amountWei) {
2182
2217
  const walletClient = getWalletClient2(wallet2);
2183
2218
  const taskIdBytes = taskIdToBytes32(taskId);
2184
- const hash = await walletClient.writeContract({
2219
+ const hash = await writeContractWithAttribution(walletClient, {
2185
2220
  address: ESCROW_ADDRESS,
2186
2221
  abi: ESCROW_ABI,
2187
2222
  functionName: "deposit",
@@ -2193,7 +2228,7 @@ async function depositEscrow(wallet2, taskId, agentAddress, tokenAddress, amount
2193
2228
  async function markSubmitted(wallet2, taskId) {
2194
2229
  const walletClient = getWalletClient2(wallet2);
2195
2230
  const taskIdBytes = taskIdToBytes32(taskId);
2196
- const hash = await walletClient.writeContract({
2231
+ const hash = await writeContractWithAttribution(walletClient, {
2197
2232
  address: ESCROW_ADDRESS,
2198
2233
  abi: ESCROW_ABI,
2199
2234
  functionName: "markSubmitted",
@@ -2204,7 +2239,7 @@ async function markSubmitted(wallet2, taskId) {
2204
2239
  async function releaseEscrow(wallet2, taskId) {
2205
2240
  const walletClient = getWalletClient2(wallet2);
2206
2241
  const taskIdBytes = taskIdToBytes32(taskId);
2207
- const hash = await walletClient.writeContract({
2242
+ const hash = await writeContractWithAttribution(walletClient, {
2208
2243
  address: ESCROW_ADDRESS,
2209
2244
  abi: ESCROW_ABI,
2210
2245
  functionName: "release",
@@ -2217,7 +2252,7 @@ async function releaseEscrow(wallet2, taskId) {
2217
2252
  async function refundEscrow(wallet2, taskId) {
2218
2253
  const walletClient = getWalletClient2(wallet2);
2219
2254
  const taskIdBytes = taskIdToBytes32(taskId);
2220
- const hash = await walletClient.writeContract({
2255
+ const hash = await writeContractWithAttribution(walletClient, {
2221
2256
  address: ESCROW_ADDRESS,
2222
2257
  abi: ESCROW_ABI,
2223
2258
  functionName: "refund",
@@ -2228,7 +2263,7 @@ async function refundEscrow(wallet2, taskId) {
2228
2263
  async function releaseAfterTimeout(wallet2, taskId) {
2229
2264
  const walletClient = getWalletClient2(wallet2);
2230
2265
  const taskIdBytes = taskIdToBytes32(taskId);
2231
- const hash = await walletClient.writeContract({
2266
+ const hash = await writeContractWithAttribution(walletClient, {
2232
2267
  address: ESCROW_ADDRESS,
2233
2268
  abi: ESCROW_ABI,
2234
2269
  functionName: "releaseAfterTimeout",
@@ -2239,7 +2274,7 @@ async function releaseAfterTimeout(wallet2, taskId) {
2239
2274
  async function markAccepted(wallet2, taskId) {
2240
2275
  const walletClient = getWalletClient2(wallet2);
2241
2276
  const taskIdBytes = taskIdToBytes32(taskId);
2242
- const hash = await walletClient.writeContract({
2277
+ const hash = await writeContractWithAttribution(walletClient, {
2243
2278
  address: ESCROW_ADDRESS,
2244
2279
  abi: ESCROW_ABI,
2245
2280
  functionName: "markAccepted",
@@ -2250,7 +2285,7 @@ async function markAccepted(wallet2, taskId) {
2250
2285
  async function cancelEscrow(wallet2, taskId) {
2251
2286
  const walletClient = getWalletClient2(wallet2);
2252
2287
  const taskIdBytes = taskIdToBytes32(taskId);
2253
- const hash = await walletClient.writeContract({
2288
+ const hash = await writeContractWithAttribution(walletClient, {
2254
2289
  address: ESCROW_ADDRESS,
2255
2290
  abi: ESCROW_ABI,
2256
2291
  functionName: "cancel",
@@ -2318,7 +2353,7 @@ async function getEscrowDetails(taskId) {
2318
2353
  async function disputeEscrow(wallet2, taskId, feeWei) {
2319
2354
  const walletClient = getWalletClient2(wallet2);
2320
2355
  const taskIdBytes = taskIdToBytes32(taskId);
2321
- const hash = await walletClient.writeContract({
2356
+ const hash = await writeContractWithAttribution(walletClient, {
2322
2357
  address: ESCROW_ADDRESS,
2323
2358
  abi: ESCROW_ABI,
2324
2359
  functionName: "dispute",
@@ -2353,7 +2388,7 @@ async function resolveEscrowDispute(wallet2, taskId, clientWins) {
2353
2388
  const walletClient = getWalletClient2(wallet2);
2354
2389
  const publicClient = getPublicClient2();
2355
2390
  const taskIdBytes = taskIdToBytes32(taskId);
2356
- const hash = await walletClient.writeContract({
2391
+ const hash = await writeContractWithAttribution(walletClient, {
2357
2392
  address: ESCROW_ADDRESS,
2358
2393
  abi: ESCROW_ABI,
2359
2394
  functionName: "resolveDispute",
@@ -2395,7 +2430,7 @@ async function accept(options) {
2395
2430
  }
2396
2431
  const agentToken = agent.flaunchToken;
2397
2432
  if (!agentToken) {
2398
- throw new Error("Agent has no Flaunch token linked. Cannot deposit to escrow without token for buyback.");
2433
+ throw new Error("Agent has no token linked. Cannot deposit to escrow without token for buyback.");
2399
2434
  }
2400
2435
  const priceWei = BigInt(taskBefore.quotedPriceWei || "0");
2401
2436
  const balance = await getWalletBalance(wallet2.address);
@@ -4044,7 +4079,7 @@ async function verifyX(options) {
4044
4079
  // src/index.ts
4045
4080
  var program = new Command();
4046
4081
  program.name("mltl").description("moltlaunch \u2014 hire AI agents with onchain reputation").version("2.8.0");
4047
- program.command("register").description("Register an agent (launches token + registers identity)").requiredOption("--name <name>", "Agent name").option("--symbol <symbol>", "Token symbol for NEW token (2-10 chars)").option("--token <address>", "Existing Flaunch token address (skips token launch)").requiredOption("--description <desc>", "Agent description").requiredOption("--skills <skills>", "Comma-separated skills (e.g., code,research,review)").option("--endpoint <url>", "x402 endpoint URL (optional - can use task queue instead)").option("--image <path>", "Image file path (PNG, JPG, etc.)").option("--price <eth>", "Price per hire in ETH", "0.001").option("--website <url>", "Website URL").option("--json", "Output as JSON").action(register);
4082
+ program.command("register").description("Register an agent (launches token + registers identity)").requiredOption("--name <name>", "Agent name").option("--symbol <symbol>", "Token symbol for NEW token (2-10 chars)").option("--token <address>", "Existing token address on Base (skips token launch)").requiredOption("--description <desc>", "Agent description").requiredOption("--skills <skills>", "Comma-separated skills (e.g., code,research,review)").option("--endpoint <url>", "x402 endpoint URL (optional - can use task queue instead)").option("--image <path>", "Image file path (PNG, JPG, etc.)").option("--price <eth>", "Price per hire in ETH", "0.001").option("--website <url>", "Website URL").option("--json", "Output as JSON").action(register);
4048
4083
  program.command("hire").description("Request work from an agent (they will quote a price)").requiredOption("--agent <id>", "Agent ID (ERC-8004 token ID)").requiredOption("--task <description>", "Task description").option("--json", "Output as JSON").action(hire);
4049
4084
  program.command("feedback").description("Submit verified feedback for an agent (linked to completed task)").option("--agent <id>", "Agent ID (auto-resolved if --task provided)").option("--task <taskId>", "Task ID to link feedback to (verifies completion)").requiredOption("--score <0-100>", "Score from 0-100").option("--comment <text>", "Optional feedback comment").option("--json", "Output as JSON").action(feedback);
4050
4085
  program.command("agents").description("Browse registered agents").option("--skill <skill>", "Filter by skill").option("--sort <field>", "Sort by: reputation, price, hires", "reputation").option("--limit <n>", "Number of results", "20").option("--json", "Output as JSON").action(agents);