mint-day 0.4.3 → 0.4.4

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.
@@ -15,6 +15,7 @@ export declare const mintSchema: {
15
15
  animation_url: z.ZodOptional<z.ZodString>;
16
16
  mintId: z.ZodOptional<z.ZodString>;
17
17
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
18
+ selfSign: z.ZodOptional<z.ZodBoolean>;
18
19
  platform: z.ZodOptional<z.ZodEnum<{
19
20
  superrare: "superrare";
20
21
  mintday: "mintday";
@@ -29,6 +30,7 @@ export declare function handleMint(params: {
29
30
  animation_url?: string;
30
31
  mintId?: string;
31
32
  metadata?: Record<string, unknown>;
33
+ selfSign?: boolean;
32
34
  platform?: string;
33
35
  }, calldataService: CalldataService, defaultRecipient: string, userKey?: string): Promise<{
34
36
  content: {
@@ -5,15 +5,15 @@ import { TokenType, TOKEN_TYPE_NAMES } from "../types.js";
5
5
  import { classifyIntent } from "../services/classifier.js";
6
6
  import { resolveImage } from "../services/image-upload.js";
7
7
  import { mintOnRareProtocol } from "../services/rare-protocol.js";
8
- // Intent cache: preview mintId -> frozen intent + platform
8
+ // Intent cache: preview mintId -> frozen intent + platform + options
9
9
  const intentCache = new Map();
10
10
  const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
11
- function cacheMintId(intent, platform = "mintday") {
11
+ function cacheMintId(intent, platform = "mintday", selfSign = false) {
12
12
  const hash = createHash("sha256")
13
13
  .update(JSON.stringify(intent))
14
14
  .digest("hex")
15
15
  .slice(0, 12);
16
- intentCache.set(hash, { intent, platform, expiresAt: Date.now() + CACHE_TTL_MS });
16
+ intentCache.set(hash, { intent, platform, selfSign, expiresAt: Date.now() + CACHE_TTL_MS });
17
17
  return hash;
18
18
  }
19
19
  function getCachedEntry(mintId) {
@@ -24,7 +24,7 @@ function getCachedEntry(mintId) {
24
24
  intentCache.delete(mintId);
25
25
  return null;
26
26
  }
27
- return { intent: entry.intent, platform: entry.platform };
27
+ return { intent: entry.intent, platform: entry.platform, selfSign: entry.selfSign };
28
28
  }
29
29
  export const mintSchema = {
30
30
  description: z
@@ -59,6 +59,10 @@ export const mintSchema = {
59
59
  .record(z.string(), z.unknown())
60
60
  .optional()
61
61
  .describe("Additional key-value metadata. Supports strings, arrays, and objects (e.g. capabilities: ['mint'])."),
62
+ selfSign: z
63
+ .boolean()
64
+ .optional()
65
+ .describe("Sign and submit from your own wallet instead of using sponsored gas. Requires PRIVATE_KEY env var or ~/.mint-day/credentials."),
62
66
  platform: z
63
67
  .enum(["mintday", "superrare"])
64
68
  .optional()
@@ -117,8 +121,8 @@ export async function handleMint(params, calldataService, defaultRecipient, user
117
121
  const cached = entry.intent;
118
122
  const cachedPlatform = entry.platform;
119
123
  intentCache.delete(params.mintId);
120
- // Mode detection using cached recipient
121
124
  const hasRecipient = !!cached.recipient;
125
+ const selfSign = !!entry.selfSign;
122
126
  const privateKey = userKey;
123
127
  // Rare Protocol path: mint via SuperRare contracts on Base
124
128
  if (cachedPlatform === "superrare") {
@@ -150,8 +154,8 @@ export async function handleMint(params, calldataService, defaultRecipient, user
150
154
  }
151
155
  }
152
156
  const result = await calldataService.buildMintCalldata(cached);
153
- // If we have a private key, sign and submit directly
154
- if (privateKey) {
157
+ // Self-sign: user explicitly opted in and has a private key
158
+ if (selfSign && privateKey) {
155
159
  try {
156
160
  const wallet = new ethers.Wallet(privateKey, calldataService.provider);
157
161
  const tx = await wallet.sendTransaction({
@@ -161,21 +165,20 @@ export async function handleMint(params, calldataService, defaultRecipient, user
161
165
  gasLimit: result.estimatedGas,
162
166
  });
163
167
  const receipt = await tx.wait();
164
- const response = {
165
- status: "minted",
166
- txHash: receipt.hash,
167
- blockNumber: receipt.blockNumber,
168
- gasUsed: receipt.gasUsed.toString(),
169
- tokenType: result.tokenType,
170
- soulbound: result.soulbound,
171
- recipient: cached.recipient,
172
- chain: "Base",
173
- explorer: `https://basescan.org/tx/${receipt.hash}`,
174
- };
175
168
  return {
176
169
  content: [{
177
170
  type: "text",
178
- text: JSON.stringify(response, null, 2),
171
+ text: JSON.stringify({
172
+ status: "minted",
173
+ txHash: receipt.hash,
174
+ blockNumber: receipt.blockNumber,
175
+ gasUsed: receipt.gasUsed.toString(),
176
+ tokenType: result.tokenType,
177
+ soulbound: result.soulbound,
178
+ recipient: cached.recipient,
179
+ chain: "Base",
180
+ explorer: `https://basescan.org/tx/${receipt.hash}`,
181
+ }, null, 2),
179
182
  }],
180
183
  };
181
184
  }
@@ -189,7 +192,15 @@ export async function handleMint(params, calldataService, defaultRecipient, user
189
192
  };
190
193
  }
191
194
  }
192
- // No user key but has recipient: try sponsored gas
195
+ if (selfSign && !privateKey) {
196
+ return {
197
+ content: [{
198
+ type: "text",
199
+ text: JSON.stringify({ error: "selfSign requires a private key. Set PRIVATE_KEY env var or save to ~/.mint-day/credentials." }, null, 2),
200
+ }],
201
+ };
202
+ }
203
+ // Default: sponsored gas
193
204
  if (hasRecipient) {
194
205
  const sponsored = await sponsoredMint(result, cached.recipient);
195
206
  if (sponsored && !sponsored.error) {
@@ -351,7 +362,7 @@ export async function handleMint(params, calldataService, defaultRecipient, user
351
362
  }
352
363
  // Cache intent and return preview
353
364
  const selectedPlatform = params.platform || "mintday";
354
- const mintId = cacheMintId(intent, selectedPlatform);
365
+ const mintId = cacheMintId(intent, selectedPlatform, !!params.selfSign);
355
366
  const preview = {
356
367
  status: "preview",
357
368
  mintId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mint-day",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "Agent-native minting on Base. One tool call, any token type.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/tools/mint.ts CHANGED
@@ -7,27 +7,27 @@ import { CalldataService } from "../services/calldata.js";
7
7
  import { resolveImage } from "../services/image-upload.js";
8
8
  import { mintOnRareProtocol } from "../services/rare-protocol.js";
9
9
 
10
- // Intent cache: preview mintId -> frozen intent + platform
11
- const intentCache = new Map<string, { intent: MintIntent; platform: string; expiresAt: number }>();
10
+ // Intent cache: preview mintId -> frozen intent + platform + options
11
+ const intentCache = new Map<string, { intent: MintIntent; platform: string; selfSign: boolean; expiresAt: number }>();
12
12
  const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
13
13
 
14
- function cacheMintId(intent: MintIntent, platform: string = "mintday"): string {
14
+ function cacheMintId(intent: MintIntent, platform: string = "mintday", selfSign: boolean = false): string {
15
15
  const hash = createHash("sha256")
16
16
  .update(JSON.stringify(intent))
17
17
  .digest("hex")
18
18
  .slice(0, 12);
19
- intentCache.set(hash, { intent, platform, expiresAt: Date.now() + CACHE_TTL_MS });
19
+ intentCache.set(hash, { intent, platform, selfSign, expiresAt: Date.now() + CACHE_TTL_MS });
20
20
  return hash;
21
21
  }
22
22
 
23
- function getCachedEntry(mintId: string): { intent: MintIntent; platform: string } | null {
23
+ function getCachedEntry(mintId: string): { intent: MintIntent; platform: string; selfSign: boolean } | null {
24
24
  const entry = intentCache.get(mintId);
25
25
  if (!entry) return null;
26
26
  if (Date.now() > entry.expiresAt) {
27
27
  intentCache.delete(mintId);
28
28
  return null;
29
29
  }
30
- return { intent: entry.intent, platform: entry.platform };
30
+ return { intent: entry.intent, platform: entry.platform, selfSign: entry.selfSign };
31
31
  }
32
32
 
33
33
  export const mintSchema = {
@@ -63,6 +63,10 @@ export const mintSchema = {
63
63
  .record(z.string(), z.unknown())
64
64
  .optional()
65
65
  .describe("Additional key-value metadata. Supports strings, arrays, and objects (e.g. capabilities: ['mint'])."),
66
+ selfSign: z
67
+ .boolean()
68
+ .optional()
69
+ .describe("Sign and submit from your own wallet instead of using sponsored gas. Requires PRIVATE_KEY env var or ~/.mint-day/credentials."),
66
70
  platform: z
67
71
  .enum(["mintday", "superrare"])
68
72
  .optional()
@@ -119,6 +123,7 @@ export async function handleMint(
119
123
  animation_url?: string;
120
124
  mintId?: string;
121
125
  metadata?: Record<string, unknown>;
126
+ selfSign?: boolean;
122
127
  platform?: string;
123
128
  },
124
129
  calldataService: CalldataService,
@@ -141,8 +146,8 @@ export async function handleMint(
141
146
  const cachedPlatform = entry.platform;
142
147
  intentCache.delete(params.mintId);
143
148
 
144
- // Mode detection using cached recipient
145
149
  const hasRecipient = !!cached.recipient;
150
+ const selfSign = !!entry.selfSign;
146
151
  const privateKey = userKey;
147
152
 
148
153
  // Rare Protocol path: mint via SuperRare contracts on Base
@@ -176,8 +181,8 @@ export async function handleMint(
176
181
 
177
182
  const result = await calldataService.buildMintCalldata(cached);
178
183
 
179
- // If we have a private key, sign and submit directly
180
- if (privateKey) {
184
+ // Self-sign: user explicitly opted in and has a private key
185
+ if (selfSign && privateKey) {
181
186
  try {
182
187
  const wallet = new ethers.Wallet(privateKey, calldataService.provider);
183
188
  const tx = await wallet.sendTransaction({
@@ -187,7 +192,10 @@ export async function handleMint(
187
192
  gasLimit: result.estimatedGas,
188
193
  });
189
194
  const receipt = await tx.wait();
190
- const response: Record<string, unknown> = {
195
+ return {
196
+ content: [{
197
+ type: "text" as const,
198
+ text: JSON.stringify({
191
199
  status: "minted",
192
200
  txHash: receipt!.hash,
193
201
  blockNumber: receipt!.blockNumber,
@@ -197,11 +205,7 @@ export async function handleMint(
197
205
  recipient: cached.recipient,
198
206
  chain: "Base",
199
207
  explorer: `https://basescan.org/tx/${receipt!.hash}`,
200
- };
201
- return {
202
- content: [{
203
- type: "text" as const,
204
- text: JSON.stringify(response, null, 2),
208
+ }, null, 2),
205
209
  }],
206
210
  };
207
211
  } catch (err: unknown) {
@@ -215,7 +219,16 @@ export async function handleMint(
215
219
  }
216
220
  }
217
221
 
218
- // No user key but has recipient: try sponsored gas
222
+ if (selfSign && !privateKey) {
223
+ return {
224
+ content: [{
225
+ type: "text" as const,
226
+ text: JSON.stringify({ error: "selfSign requires a private key. Set PRIVATE_KEY env var or save to ~/.mint-day/credentials." }, null, 2),
227
+ }],
228
+ };
229
+ }
230
+
231
+ // Default: sponsored gas
219
232
  if (hasRecipient) {
220
233
  const sponsored = await sponsoredMint(result, cached.recipient);
221
234
  if (sponsored && !sponsored.error) {
@@ -381,7 +394,7 @@ export async function handleMint(
381
394
 
382
395
  // Cache intent and return preview
383
396
  const selectedPlatform = params.platform || "mintday";
384
- const mintId = cacheMintId(intent, selectedPlatform);
397
+ const mintId = cacheMintId(intent, selectedPlatform, !!params.selfSign);
385
398
 
386
399
  const preview: Record<string, unknown> = {
387
400
  status: "preview",