opensea-cli 0.1.6 → 0.2.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/package.json +3 -42
- package/postinstall.js +11 -0
- package/LICENSE +0 -7
- package/README.md +0 -343
- package/dist/cli.js +0 -705
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts +0 -596
- package/dist/index.js +0 -455
- package/dist/index.js.map +0 -1
package/dist/cli.js
DELETED
|
@@ -1,705 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/cli.ts
|
|
4
|
-
import { Command as Command10 } from "commander";
|
|
5
|
-
|
|
6
|
-
// src/client.ts
|
|
7
|
-
var DEFAULT_BASE_URL = "https://api.opensea.io";
|
|
8
|
-
var DEFAULT_GRAPHQL_URL = "https://gql.opensea.io/graphql";
|
|
9
|
-
var OpenSeaClient = class {
|
|
10
|
-
apiKey;
|
|
11
|
-
baseUrl;
|
|
12
|
-
graphqlUrl;
|
|
13
|
-
defaultChain;
|
|
14
|
-
constructor(config) {
|
|
15
|
-
this.apiKey = config.apiKey;
|
|
16
|
-
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
17
|
-
this.graphqlUrl = config.graphqlUrl ?? DEFAULT_GRAPHQL_URL;
|
|
18
|
-
this.defaultChain = config.chain ?? "ethereum";
|
|
19
|
-
}
|
|
20
|
-
async get(path, params) {
|
|
21
|
-
const url = new URL(`${this.baseUrl}${path}`);
|
|
22
|
-
if (params) {
|
|
23
|
-
for (const [key, value] of Object.entries(params)) {
|
|
24
|
-
if (value !== void 0 && value !== null) {
|
|
25
|
-
url.searchParams.set(key, String(value));
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
const response = await fetch(url.toString(), {
|
|
30
|
-
method: "GET",
|
|
31
|
-
headers: {
|
|
32
|
-
Accept: "application/json",
|
|
33
|
-
"x-api-key": this.apiKey
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
if (!response.ok) {
|
|
37
|
-
const body = await response.text();
|
|
38
|
-
throw new OpenSeaAPIError(response.status, body, path);
|
|
39
|
-
}
|
|
40
|
-
return response.json();
|
|
41
|
-
}
|
|
42
|
-
async post(path) {
|
|
43
|
-
const url = new URL(`${this.baseUrl}${path}`);
|
|
44
|
-
const response = await fetch(url.toString(), {
|
|
45
|
-
method: "POST",
|
|
46
|
-
headers: {
|
|
47
|
-
Accept: "application/json",
|
|
48
|
-
"x-api-key": this.apiKey
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
if (!response.ok) {
|
|
52
|
-
const body = await response.text();
|
|
53
|
-
throw new OpenSeaAPIError(response.status, body, path);
|
|
54
|
-
}
|
|
55
|
-
return response.json();
|
|
56
|
-
}
|
|
57
|
-
async graphql(query, variables) {
|
|
58
|
-
const response = await fetch(this.graphqlUrl, {
|
|
59
|
-
method: "POST",
|
|
60
|
-
headers: {
|
|
61
|
-
"Content-Type": "application/json",
|
|
62
|
-
Accept: "application/json",
|
|
63
|
-
"x-api-key": this.apiKey
|
|
64
|
-
},
|
|
65
|
-
body: JSON.stringify({ query, variables })
|
|
66
|
-
});
|
|
67
|
-
if (!response.ok) {
|
|
68
|
-
const body = await response.text();
|
|
69
|
-
throw new OpenSeaAPIError(response.status, body, "graphql");
|
|
70
|
-
}
|
|
71
|
-
const json = await response.json();
|
|
72
|
-
if (json.errors?.length) {
|
|
73
|
-
throw new OpenSeaAPIError(
|
|
74
|
-
400,
|
|
75
|
-
json.errors.map((e) => e.message).join("; "),
|
|
76
|
-
"graphql"
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
if (!json.data) {
|
|
80
|
-
throw new OpenSeaAPIError(500, "GraphQL response missing data", "graphql");
|
|
81
|
-
}
|
|
82
|
-
return json.data;
|
|
83
|
-
}
|
|
84
|
-
getDefaultChain() {
|
|
85
|
-
return this.defaultChain;
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
var OpenSeaAPIError = class extends Error {
|
|
89
|
-
constructor(statusCode, responseBody, path) {
|
|
90
|
-
super(`OpenSea API error ${statusCode} on ${path}: ${responseBody}`);
|
|
91
|
-
this.statusCode = statusCode;
|
|
92
|
-
this.responseBody = responseBody;
|
|
93
|
-
this.path = path;
|
|
94
|
-
this.name = "OpenSeaAPIError";
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// src/commands/accounts.ts
|
|
99
|
-
import { Command } from "commander";
|
|
100
|
-
|
|
101
|
-
// src/output.ts
|
|
102
|
-
function formatOutput(data, format) {
|
|
103
|
-
if (format === "table") {
|
|
104
|
-
return formatTable(data);
|
|
105
|
-
}
|
|
106
|
-
return JSON.stringify(data, null, 2);
|
|
107
|
-
}
|
|
108
|
-
function formatTable(data) {
|
|
109
|
-
if (Array.isArray(data)) {
|
|
110
|
-
if (data.length === 0) return "(empty)";
|
|
111
|
-
const keys = Object.keys(data[0]);
|
|
112
|
-
const widths = keys.map(
|
|
113
|
-
(key) => Math.max(
|
|
114
|
-
key.length,
|
|
115
|
-
...data.map((row) => {
|
|
116
|
-
const val = row[key];
|
|
117
|
-
return String(val ?? "").length;
|
|
118
|
-
})
|
|
119
|
-
)
|
|
120
|
-
);
|
|
121
|
-
const header = keys.map((key, i) => key.padEnd(widths[i])).join(" ");
|
|
122
|
-
const separator = widths.map((w) => "-".repeat(w)).join(" ");
|
|
123
|
-
const rows = data.map(
|
|
124
|
-
(row) => keys.map((key, i) => {
|
|
125
|
-
const val = row[key];
|
|
126
|
-
return String(val ?? "").padEnd(widths[i]);
|
|
127
|
-
}).join(" ")
|
|
128
|
-
);
|
|
129
|
-
return [header, separator, ...rows].join("\n");
|
|
130
|
-
}
|
|
131
|
-
if (data && typeof data === "object") {
|
|
132
|
-
const entries = Object.entries(data);
|
|
133
|
-
const maxKeyLength = Math.max(...entries.map(([k]) => k.length));
|
|
134
|
-
return entries.map(([key, value]) => {
|
|
135
|
-
const displayValue = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value ?? "");
|
|
136
|
-
return `${key.padEnd(maxKeyLength)} ${displayValue}`;
|
|
137
|
-
}).join("\n");
|
|
138
|
-
}
|
|
139
|
-
return String(data);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// src/commands/accounts.ts
|
|
143
|
-
function accountsCommand(getClient2, getFormat2) {
|
|
144
|
-
const cmd = new Command("accounts").description("Query accounts");
|
|
145
|
-
cmd.command("get").description("Get an account by address").argument("<address>", "Wallet address").action(async (address) => {
|
|
146
|
-
const client = getClient2();
|
|
147
|
-
const result = await client.get(`/api/v2/accounts/${address}`);
|
|
148
|
-
console.log(formatOutput(result, getFormat2()));
|
|
149
|
-
});
|
|
150
|
-
return cmd;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// src/commands/collections.ts
|
|
154
|
-
import { Command as Command2 } from "commander";
|
|
155
|
-
function collectionsCommand(getClient2, getFormat2) {
|
|
156
|
-
const cmd = new Command2("collections").description(
|
|
157
|
-
"Manage and query NFT collections"
|
|
158
|
-
);
|
|
159
|
-
cmd.command("get").description("Get a single collection by slug").argument("<slug>", "Collection slug").action(async (slug) => {
|
|
160
|
-
const client = getClient2();
|
|
161
|
-
const result = await client.get(`/api/v2/collections/${slug}`);
|
|
162
|
-
console.log(formatOutput(result, getFormat2()));
|
|
163
|
-
});
|
|
164
|
-
cmd.command("list").description("List collections").option("--chain <chain>", "Filter by chain").option(
|
|
165
|
-
"--order-by <orderBy>",
|
|
166
|
-
"Order by field (created_date, one_day_change, seven_day_volume, seven_day_change, num_owners, market_cap)"
|
|
167
|
-
).option("--creator <username>", "Filter by creator username").option("--include-hidden", "Include hidden collections").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
168
|
-
async (options) => {
|
|
169
|
-
const client = getClient2();
|
|
170
|
-
const result = await client.get("/api/v2/collections", {
|
|
171
|
-
chain: options.chain,
|
|
172
|
-
order_by: options.orderBy,
|
|
173
|
-
creator_username: options.creator,
|
|
174
|
-
include_hidden: options.includeHidden,
|
|
175
|
-
limit: Number.parseInt(options.limit, 10),
|
|
176
|
-
next: options.next
|
|
177
|
-
});
|
|
178
|
-
console.log(formatOutput(result, getFormat2()));
|
|
179
|
-
}
|
|
180
|
-
);
|
|
181
|
-
cmd.command("stats").description("Get collection stats").argument("<slug>", "Collection slug").action(async (slug) => {
|
|
182
|
-
const client = getClient2();
|
|
183
|
-
const result = await client.get(
|
|
184
|
-
`/api/v2/collections/${slug}/stats`
|
|
185
|
-
);
|
|
186
|
-
console.log(formatOutput(result, getFormat2()));
|
|
187
|
-
});
|
|
188
|
-
cmd.command("traits").description("Get collection traits").argument("<slug>", "Collection slug").action(async (slug) => {
|
|
189
|
-
const client = getClient2();
|
|
190
|
-
const result = await client.get(
|
|
191
|
-
`/api/v2/traits/${slug}`
|
|
192
|
-
);
|
|
193
|
-
console.log(formatOutput(result, getFormat2()));
|
|
194
|
-
});
|
|
195
|
-
return cmd;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// src/commands/events.ts
|
|
199
|
-
import { Command as Command3 } from "commander";
|
|
200
|
-
function eventsCommand(getClient2, getFormat2) {
|
|
201
|
-
const cmd = new Command3("events").description("Query marketplace events");
|
|
202
|
-
cmd.command("list").description("List events").option(
|
|
203
|
-
"--event-type <type>",
|
|
204
|
-
"Event type (sale, transfer, mint, listing, offer, trait_offer, collection_offer)"
|
|
205
|
-
).option("--after <timestamp>", "Filter events after this Unix timestamp").option("--before <timestamp>", "Filter events before this Unix timestamp").option("--chain <chain>", "Filter by chain").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
206
|
-
async (options) => {
|
|
207
|
-
const client = getClient2();
|
|
208
|
-
const result = await client.get("/api/v2/events", {
|
|
209
|
-
event_type: options.eventType,
|
|
210
|
-
after: options.after ? Number.parseInt(options.after, 10) : void 0,
|
|
211
|
-
before: options.before ? Number.parseInt(options.before, 10) : void 0,
|
|
212
|
-
chain: options.chain,
|
|
213
|
-
limit: Number.parseInt(options.limit, 10),
|
|
214
|
-
next: options.next
|
|
215
|
-
});
|
|
216
|
-
console.log(formatOutput(result, getFormat2()));
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
cmd.command("by-account").description("Get events for an account").argument("<address>", "Account address").option("--event-type <type>", "Event type").option("--chain <chain>", "Filter by chain").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
220
|
-
async (address, options) => {
|
|
221
|
-
const client = getClient2();
|
|
222
|
-
const result = await client.get(`/api/v2/events/accounts/${address}`, {
|
|
223
|
-
event_type: options.eventType,
|
|
224
|
-
chain: options.chain,
|
|
225
|
-
limit: Number.parseInt(options.limit, 10),
|
|
226
|
-
next: options.next
|
|
227
|
-
});
|
|
228
|
-
console.log(formatOutput(result, getFormat2()));
|
|
229
|
-
}
|
|
230
|
-
);
|
|
231
|
-
cmd.command("by-collection").description("Get events for a collection").argument("<slug>", "Collection slug").option("--event-type <type>", "Event type").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
232
|
-
async (slug, options) => {
|
|
233
|
-
const client = getClient2();
|
|
234
|
-
const result = await client.get(`/api/v2/events/collection/${slug}`, {
|
|
235
|
-
event_type: options.eventType,
|
|
236
|
-
limit: Number.parseInt(options.limit, 10),
|
|
237
|
-
next: options.next
|
|
238
|
-
});
|
|
239
|
-
console.log(formatOutput(result, getFormat2()));
|
|
240
|
-
}
|
|
241
|
-
);
|
|
242
|
-
cmd.command("by-nft").description("Get events for a specific NFT").argument("<chain>", "Chain").argument("<contract>", "Contract address").argument("<token-id>", "Token ID").option("--event-type <type>", "Event type").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
243
|
-
async (chain, contract, tokenId, options) => {
|
|
244
|
-
const client = getClient2();
|
|
245
|
-
const result = await client.get(
|
|
246
|
-
`/api/v2/events/chain/${chain}/contract/${contract}/nfts/${tokenId}`,
|
|
247
|
-
{
|
|
248
|
-
event_type: options.eventType,
|
|
249
|
-
limit: Number.parseInt(options.limit, 10),
|
|
250
|
-
next: options.next
|
|
251
|
-
}
|
|
252
|
-
);
|
|
253
|
-
console.log(formatOutput(result, getFormat2()));
|
|
254
|
-
}
|
|
255
|
-
);
|
|
256
|
-
return cmd;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// src/commands/listings.ts
|
|
260
|
-
import { Command as Command4 } from "commander";
|
|
261
|
-
function listingsCommand(getClient2, getFormat2) {
|
|
262
|
-
const cmd = new Command4("listings").description("Query NFT listings");
|
|
263
|
-
cmd.command("all").description("Get all listings for a collection").argument("<collection>", "Collection slug").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
264
|
-
async (collection, options) => {
|
|
265
|
-
const client = getClient2();
|
|
266
|
-
const result = await client.get(`/api/v2/listings/collection/${collection}/all`, {
|
|
267
|
-
limit: Number.parseInt(options.limit, 10),
|
|
268
|
-
next: options.next
|
|
269
|
-
});
|
|
270
|
-
console.log(formatOutput(result, getFormat2()));
|
|
271
|
-
}
|
|
272
|
-
);
|
|
273
|
-
cmd.command("best").description("Get best listings for a collection").argument("<collection>", "Collection slug").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
274
|
-
async (collection, options) => {
|
|
275
|
-
const client = getClient2();
|
|
276
|
-
const result = await client.get(`/api/v2/listings/collection/${collection}/best`, {
|
|
277
|
-
limit: Number.parseInt(options.limit, 10),
|
|
278
|
-
next: options.next
|
|
279
|
-
});
|
|
280
|
-
console.log(formatOutput(result, getFormat2()));
|
|
281
|
-
}
|
|
282
|
-
);
|
|
283
|
-
cmd.command("best-for-nft").description("Get best listing for a specific NFT").argument("<collection>", "Collection slug").argument("<token-id>", "Token ID").action(async (collection, tokenId) => {
|
|
284
|
-
const client = getClient2();
|
|
285
|
-
const result = await client.get(
|
|
286
|
-
`/api/v2/listings/collection/${collection}/nfts/${tokenId}/best`
|
|
287
|
-
);
|
|
288
|
-
console.log(formatOutput(result, getFormat2()));
|
|
289
|
-
});
|
|
290
|
-
return cmd;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// src/commands/nfts.ts
|
|
294
|
-
import { Command as Command5 } from "commander";
|
|
295
|
-
function nftsCommand(getClient2, getFormat2) {
|
|
296
|
-
const cmd = new Command5("nfts").description("Query NFTs");
|
|
297
|
-
cmd.command("get").description("Get a single NFT").argument("<chain>", "Chain (e.g. ethereum, base)").argument("<contract>", "Contract address").argument("<token-id>", "Token ID").action(async (chain, contract, tokenId) => {
|
|
298
|
-
const client = getClient2();
|
|
299
|
-
const result = await client.get(
|
|
300
|
-
`/api/v2/chain/${chain}/contract/${contract}/nfts/${tokenId}`
|
|
301
|
-
);
|
|
302
|
-
console.log(formatOutput(result, getFormat2()));
|
|
303
|
-
});
|
|
304
|
-
cmd.command("list-by-collection").description("List NFTs in a collection").argument("<slug>", "Collection slug").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(async (slug, options) => {
|
|
305
|
-
const client = getClient2();
|
|
306
|
-
const result = await client.get(
|
|
307
|
-
`/api/v2/collection/${slug}/nfts`,
|
|
308
|
-
{
|
|
309
|
-
limit: Number.parseInt(options.limit, 10),
|
|
310
|
-
next: options.next
|
|
311
|
-
}
|
|
312
|
-
);
|
|
313
|
-
console.log(formatOutput(result, getFormat2()));
|
|
314
|
-
});
|
|
315
|
-
cmd.command("list-by-contract").description("List NFTs by contract address").argument("<chain>", "Chain").argument("<contract>", "Contract address").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
316
|
-
async (chain, contract, options) => {
|
|
317
|
-
const client = getClient2();
|
|
318
|
-
const result = await client.get(
|
|
319
|
-
`/api/v2/chain/${chain}/contract/${contract}/nfts`,
|
|
320
|
-
{
|
|
321
|
-
limit: Number.parseInt(options.limit, 10),
|
|
322
|
-
next: options.next
|
|
323
|
-
}
|
|
324
|
-
);
|
|
325
|
-
console.log(formatOutput(result, getFormat2()));
|
|
326
|
-
}
|
|
327
|
-
);
|
|
328
|
-
cmd.command("list-by-account").description("List NFTs owned by an account").argument("<chain>", "Chain").argument("<address>", "Account address").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
329
|
-
async (chain, address, options) => {
|
|
330
|
-
const client = getClient2();
|
|
331
|
-
const result = await client.get(
|
|
332
|
-
`/api/v2/chain/${chain}/account/${address}/nfts`,
|
|
333
|
-
{
|
|
334
|
-
limit: Number.parseInt(options.limit, 10),
|
|
335
|
-
next: options.next
|
|
336
|
-
}
|
|
337
|
-
);
|
|
338
|
-
console.log(formatOutput(result, getFormat2()));
|
|
339
|
-
}
|
|
340
|
-
);
|
|
341
|
-
cmd.command("refresh").description("Refresh NFT metadata").argument("<chain>", "Chain").argument("<contract>", "Contract address").argument("<token-id>", "Token ID").action(async (chain, contract, tokenId) => {
|
|
342
|
-
const client = getClient2();
|
|
343
|
-
await client.post(
|
|
344
|
-
`/api/v2/chain/${chain}/contract/${contract}/nfts/${tokenId}/refresh`
|
|
345
|
-
);
|
|
346
|
-
console.log(
|
|
347
|
-
formatOutput(
|
|
348
|
-
{ status: "ok", message: "Metadata refresh requested" },
|
|
349
|
-
getFormat2()
|
|
350
|
-
)
|
|
351
|
-
);
|
|
352
|
-
});
|
|
353
|
-
cmd.command("contract").description("Get contract details").argument("<chain>", "Chain").argument("<address>", "Contract address").action(async (chain, address) => {
|
|
354
|
-
const client = getClient2();
|
|
355
|
-
const result = await client.get(
|
|
356
|
-
`/api/v2/chain/${chain}/contract/${address}`
|
|
357
|
-
);
|
|
358
|
-
console.log(formatOutput(result, getFormat2()));
|
|
359
|
-
});
|
|
360
|
-
return cmd;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// src/commands/offers.ts
|
|
364
|
-
import { Command as Command6 } from "commander";
|
|
365
|
-
function offersCommand(getClient2, getFormat2) {
|
|
366
|
-
const cmd = new Command6("offers").description("Query NFT offers");
|
|
367
|
-
cmd.command("all").description("Get all offers for a collection").argument("<collection>", "Collection slug").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
368
|
-
async (collection, options) => {
|
|
369
|
-
const client = getClient2();
|
|
370
|
-
const result = await client.get(`/api/v2/offers/collection/${collection}/all`, {
|
|
371
|
-
limit: Number.parseInt(options.limit, 10),
|
|
372
|
-
next: options.next
|
|
373
|
-
});
|
|
374
|
-
console.log(formatOutput(result, getFormat2()));
|
|
375
|
-
}
|
|
376
|
-
);
|
|
377
|
-
cmd.command("collection").description("Get collection offers").argument("<collection>", "Collection slug").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
378
|
-
async (collection, options) => {
|
|
379
|
-
const client = getClient2();
|
|
380
|
-
const result = await client.get(`/api/v2/offers/collection/${collection}`, {
|
|
381
|
-
limit: Number.parseInt(options.limit, 10),
|
|
382
|
-
next: options.next
|
|
383
|
-
});
|
|
384
|
-
console.log(formatOutput(result, getFormat2()));
|
|
385
|
-
}
|
|
386
|
-
);
|
|
387
|
-
cmd.command("best-for-nft").description("Get best offer for a specific NFT").argument("<collection>", "Collection slug").argument("<token-id>", "Token ID").action(async (collection, tokenId) => {
|
|
388
|
-
const client = getClient2();
|
|
389
|
-
const result = await client.get(
|
|
390
|
-
`/api/v2/offers/collection/${collection}/nfts/${tokenId}/best`
|
|
391
|
-
);
|
|
392
|
-
console.log(formatOutput(result, getFormat2()));
|
|
393
|
-
});
|
|
394
|
-
cmd.command("traits").description("Get trait offers for a collection").argument("<collection>", "Collection slug").requiredOption("--type <type>", "Trait type (required)").requiredOption("--value <value>", "Trait value (required)").option("--limit <limit>", "Number of results", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
395
|
-
async (collection, options) => {
|
|
396
|
-
const client = getClient2();
|
|
397
|
-
const result = await client.get(`/api/v2/offers/collection/${collection}/traits`, {
|
|
398
|
-
type: options.type,
|
|
399
|
-
value: options.value,
|
|
400
|
-
limit: Number.parseInt(options.limit, 10),
|
|
401
|
-
next: options.next
|
|
402
|
-
});
|
|
403
|
-
console.log(formatOutput(result, getFormat2()));
|
|
404
|
-
}
|
|
405
|
-
);
|
|
406
|
-
return cmd;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// src/commands/search.ts
|
|
410
|
-
import { Command as Command7 } from "commander";
|
|
411
|
-
|
|
412
|
-
// src/queries.ts
|
|
413
|
-
var SEARCH_COLLECTIONS_QUERY = `
|
|
414
|
-
query SearchCollections($query: String!, $limit: Int, $chains: [ChainIdentifier!]) {
|
|
415
|
-
collectionsByQuery(query: $query, limit: $limit, chains: $chains) {
|
|
416
|
-
slug
|
|
417
|
-
name
|
|
418
|
-
description
|
|
419
|
-
imageUrl
|
|
420
|
-
chain {
|
|
421
|
-
identifier
|
|
422
|
-
name
|
|
423
|
-
}
|
|
424
|
-
stats {
|
|
425
|
-
totalSupply
|
|
426
|
-
ownerCount
|
|
427
|
-
volume {
|
|
428
|
-
usd
|
|
429
|
-
}
|
|
430
|
-
sales
|
|
431
|
-
}
|
|
432
|
-
floorPrice {
|
|
433
|
-
pricePerItem {
|
|
434
|
-
usd
|
|
435
|
-
native {
|
|
436
|
-
unit
|
|
437
|
-
symbol
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}`;
|
|
443
|
-
var SEARCH_NFTS_QUERY = `
|
|
444
|
-
query SearchItems($query: String!, $collectionSlug: String, $limit: Int, $chains: [ChainIdentifier!]) {
|
|
445
|
-
itemsByQuery(query: $query, collectionSlug: $collectionSlug, limit: $limit, chains: $chains) {
|
|
446
|
-
tokenId
|
|
447
|
-
name
|
|
448
|
-
description
|
|
449
|
-
imageUrl
|
|
450
|
-
contractAddress
|
|
451
|
-
collection {
|
|
452
|
-
slug
|
|
453
|
-
name
|
|
454
|
-
}
|
|
455
|
-
chain {
|
|
456
|
-
identifier
|
|
457
|
-
name
|
|
458
|
-
}
|
|
459
|
-
bestListing {
|
|
460
|
-
pricePerItem {
|
|
461
|
-
usd
|
|
462
|
-
native {
|
|
463
|
-
unit
|
|
464
|
-
symbol
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
owner {
|
|
469
|
-
address
|
|
470
|
-
displayName
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}`;
|
|
474
|
-
var SEARCH_TOKENS_QUERY = `
|
|
475
|
-
query SearchCurrencies($query: String!, $limit: Int, $chain: ChainIdentifier) {
|
|
476
|
-
currenciesByQuery(query: $query, limit: $limit, chain: $chain, allowlistOnly: false) {
|
|
477
|
-
name
|
|
478
|
-
symbol
|
|
479
|
-
imageUrl
|
|
480
|
-
usdPrice
|
|
481
|
-
contractAddress
|
|
482
|
-
chain {
|
|
483
|
-
identifier
|
|
484
|
-
name
|
|
485
|
-
}
|
|
486
|
-
stats {
|
|
487
|
-
marketCapUsd
|
|
488
|
-
oneDay {
|
|
489
|
-
priceChange
|
|
490
|
-
volume
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}`;
|
|
495
|
-
var SEARCH_ACCOUNTS_QUERY = `
|
|
496
|
-
query SearchAccounts($query: String!, $limit: Int) {
|
|
497
|
-
accountsByQuery(query: $query, limit: $limit) {
|
|
498
|
-
address
|
|
499
|
-
username
|
|
500
|
-
imageUrl
|
|
501
|
-
isVerified
|
|
502
|
-
}
|
|
503
|
-
}`;
|
|
504
|
-
|
|
505
|
-
// src/commands/search.ts
|
|
506
|
-
function searchCommand(getClient2, getFormat2) {
|
|
507
|
-
const cmd = new Command7("search").description(
|
|
508
|
-
"Search for collections, NFTs, tokens, and accounts"
|
|
509
|
-
);
|
|
510
|
-
cmd.command("collections").description("Search collections by name or slug").argument("<query>", "Search query").option("--chains <chains>", "Filter by chains (comma-separated)").option("--limit <limit>", "Number of results", "10").action(
|
|
511
|
-
async (query, options) => {
|
|
512
|
-
const client = getClient2();
|
|
513
|
-
const result = await client.graphql(SEARCH_COLLECTIONS_QUERY, {
|
|
514
|
-
query,
|
|
515
|
-
limit: Number.parseInt(options.limit, 10),
|
|
516
|
-
chains: options.chains?.split(",")
|
|
517
|
-
});
|
|
518
|
-
console.log(formatOutput(result.collectionsByQuery, getFormat2()));
|
|
519
|
-
}
|
|
520
|
-
);
|
|
521
|
-
cmd.command("nfts").description("Search NFTs by name").argument("<query>", "Search query").option("--collection <slug>", "Filter by collection slug").option("--chains <chains>", "Filter by chains (comma-separated)").option("--limit <limit>", "Number of results", "10").action(
|
|
522
|
-
async (query, options) => {
|
|
523
|
-
const client = getClient2();
|
|
524
|
-
const result = await client.graphql(SEARCH_NFTS_QUERY, {
|
|
525
|
-
query,
|
|
526
|
-
collectionSlug: options.collection,
|
|
527
|
-
limit: Number.parseInt(options.limit, 10),
|
|
528
|
-
chains: options.chains?.split(",")
|
|
529
|
-
});
|
|
530
|
-
console.log(formatOutput(result.itemsByQuery, getFormat2()));
|
|
531
|
-
}
|
|
532
|
-
);
|
|
533
|
-
cmd.command("tokens").description("Search tokens/currencies by name or symbol").argument("<query>", "Search query").option("--chain <chain>", "Filter by chain").option("--limit <limit>", "Number of results", "10").action(
|
|
534
|
-
async (query, options) => {
|
|
535
|
-
const client = getClient2();
|
|
536
|
-
const result = await client.graphql(SEARCH_TOKENS_QUERY, {
|
|
537
|
-
query,
|
|
538
|
-
limit: Number.parseInt(options.limit, 10),
|
|
539
|
-
chain: options.chain
|
|
540
|
-
});
|
|
541
|
-
console.log(formatOutput(result.currenciesByQuery, getFormat2()));
|
|
542
|
-
}
|
|
543
|
-
);
|
|
544
|
-
cmd.command("accounts").description("Search accounts by username or address").argument("<query>", "Search query").option("--limit <limit>", "Number of results", "10").action(async (query, options) => {
|
|
545
|
-
const client = getClient2();
|
|
546
|
-
const result = await client.graphql(SEARCH_ACCOUNTS_QUERY, {
|
|
547
|
-
query,
|
|
548
|
-
limit: Number.parseInt(options.limit, 10)
|
|
549
|
-
});
|
|
550
|
-
console.log(formatOutput(result.accountsByQuery, getFormat2()));
|
|
551
|
-
});
|
|
552
|
-
return cmd;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
// src/commands/swaps.ts
|
|
556
|
-
import { Command as Command8 } from "commander";
|
|
557
|
-
function swapsCommand(getClient2, getFormat2) {
|
|
558
|
-
const cmd = new Command8("swaps").description(
|
|
559
|
-
"Get swap quotes for token trading"
|
|
560
|
-
);
|
|
561
|
-
cmd.command("quote").description(
|
|
562
|
-
"Get a quote for swapping tokens, including price details and executable transaction data"
|
|
563
|
-
).requiredOption("--from-chain <chain>", "Chain of the token to swap from").requiredOption(
|
|
564
|
-
"--from-address <address>",
|
|
565
|
-
"Contract address of the token to swap from"
|
|
566
|
-
).requiredOption("--to-chain <chain>", "Chain of the token to swap to").requiredOption(
|
|
567
|
-
"--to-address <address>",
|
|
568
|
-
"Contract address of the token to swap to"
|
|
569
|
-
).requiredOption("--quantity <quantity>", "Amount to swap (in token units)").requiredOption("--address <address>", "Wallet address executing the swap").option(
|
|
570
|
-
"--slippage <slippage>",
|
|
571
|
-
"Slippage tolerance (0.0 to 0.5, default: 0.01)"
|
|
572
|
-
).option(
|
|
573
|
-
"--recipient <recipient>",
|
|
574
|
-
"Recipient address (defaults to sender address)"
|
|
575
|
-
).action(
|
|
576
|
-
async (options) => {
|
|
577
|
-
const client = getClient2();
|
|
578
|
-
const result = await client.get(
|
|
579
|
-
"/api/v2/swap/quote",
|
|
580
|
-
{
|
|
581
|
-
from_chain: options.fromChain,
|
|
582
|
-
from_address: options.fromAddress,
|
|
583
|
-
to_chain: options.toChain,
|
|
584
|
-
to_address: options.toAddress,
|
|
585
|
-
quantity: options.quantity,
|
|
586
|
-
address: options.address,
|
|
587
|
-
slippage: options.slippage ? Number.parseFloat(options.slippage) : void 0,
|
|
588
|
-
recipient: options.recipient
|
|
589
|
-
}
|
|
590
|
-
);
|
|
591
|
-
console.log(formatOutput(result, getFormat2()));
|
|
592
|
-
}
|
|
593
|
-
);
|
|
594
|
-
return cmd;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// src/commands/tokens.ts
|
|
598
|
-
import { Command as Command9 } from "commander";
|
|
599
|
-
function tokensCommand(getClient2, getFormat2) {
|
|
600
|
-
const cmd = new Command9("tokens").description(
|
|
601
|
-
"Query trending tokens, top tokens, and token details"
|
|
602
|
-
);
|
|
603
|
-
cmd.command("trending").description("Get trending tokens based on OpenSea's trending score").option("--chains <chains>", "Comma-separated list of chains to filter by").option("--limit <limit>", "Number of results (max 100)", "20").option("--cursor <cursor>", "Pagination cursor").action(
|
|
604
|
-
async (options) => {
|
|
605
|
-
const client = getClient2();
|
|
606
|
-
const result = await client.get(
|
|
607
|
-
"/api/v2/tokens/trending",
|
|
608
|
-
{
|
|
609
|
-
chains: options.chains,
|
|
610
|
-
limit: Number.parseInt(options.limit, 10),
|
|
611
|
-
cursor: options.cursor
|
|
612
|
-
}
|
|
613
|
-
);
|
|
614
|
-
console.log(formatOutput(result, getFormat2()));
|
|
615
|
-
}
|
|
616
|
-
);
|
|
617
|
-
cmd.command("top").description("Get top tokens ranked by 24-hour trading volume").option("--chains <chains>", "Comma-separated list of chains to filter by").option("--limit <limit>", "Number of results (max 100)", "20").option("--cursor <cursor>", "Pagination cursor").action(
|
|
618
|
-
async (options) => {
|
|
619
|
-
const client = getClient2();
|
|
620
|
-
const result = await client.get(
|
|
621
|
-
"/api/v2/tokens/top",
|
|
622
|
-
{
|
|
623
|
-
chains: options.chains,
|
|
624
|
-
limit: Number.parseInt(options.limit, 10),
|
|
625
|
-
cursor: options.cursor
|
|
626
|
-
}
|
|
627
|
-
);
|
|
628
|
-
console.log(formatOutput(result, getFormat2()));
|
|
629
|
-
}
|
|
630
|
-
);
|
|
631
|
-
cmd.command("get").description("Get detailed information about a specific token").argument("<chain>", "Blockchain chain").argument("<address>", "Token contract address").action(async (chain, address) => {
|
|
632
|
-
const client = getClient2();
|
|
633
|
-
const result = await client.get(
|
|
634
|
-
`/api/v2/chain/${chain}/token/${address}`
|
|
635
|
-
);
|
|
636
|
-
console.log(formatOutput(result, getFormat2()));
|
|
637
|
-
});
|
|
638
|
-
return cmd;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
// src/cli.ts
|
|
642
|
-
var BANNER = `
|
|
643
|
-
____ _____
|
|
644
|
-
/ __ \\ / ____|
|
|
645
|
-
| | | |_ __ ___ _ _| (___ ___ __ _
|
|
646
|
-
| | | | '_ \\ / _ \\ '_ \\___ \\ / _ \\/ _\` |
|
|
647
|
-
| |__| | |_) | __/ | | |___) | __/ (_| |
|
|
648
|
-
\\____/| .__/ \\___|_| |_|____/ \\___|\\__,_|
|
|
649
|
-
| |
|
|
650
|
-
|_|
|
|
651
|
-
`;
|
|
652
|
-
var program = new Command10();
|
|
653
|
-
program.name("opensea").description("OpenSea CLI - Query the OpenSea API from the command line").version(process.env.npm_package_version ?? "0.0.0").addHelpText("before", BANNER).option("--api-key <key>", "OpenSea API key (or set OPENSEA_API_KEY env var)").option("--chain <chain>", "Default chain", "ethereum").option("--format <format>", "Output format (json or table)", "json").option("--base-url <url>", "API base URL");
|
|
654
|
-
function getClient() {
|
|
655
|
-
const opts = program.opts();
|
|
656
|
-
const apiKey = opts.apiKey ?? process.env.OPENSEA_API_KEY;
|
|
657
|
-
if (!apiKey) {
|
|
658
|
-
console.error(
|
|
659
|
-
"Error: API key required. Use --api-key or set OPENSEA_API_KEY environment variable."
|
|
660
|
-
);
|
|
661
|
-
process.exit(2);
|
|
662
|
-
}
|
|
663
|
-
return new OpenSeaClient({
|
|
664
|
-
apiKey,
|
|
665
|
-
chain: opts.chain,
|
|
666
|
-
baseUrl: opts.baseUrl
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
function getFormat() {
|
|
670
|
-
const opts = program.opts();
|
|
671
|
-
return opts.format === "table" ? "table" : "json";
|
|
672
|
-
}
|
|
673
|
-
program.addCommand(collectionsCommand(getClient, getFormat));
|
|
674
|
-
program.addCommand(nftsCommand(getClient, getFormat));
|
|
675
|
-
program.addCommand(listingsCommand(getClient, getFormat));
|
|
676
|
-
program.addCommand(offersCommand(getClient, getFormat));
|
|
677
|
-
program.addCommand(eventsCommand(getClient, getFormat));
|
|
678
|
-
program.addCommand(accountsCommand(getClient, getFormat));
|
|
679
|
-
program.addCommand(tokensCommand(getClient, getFormat));
|
|
680
|
-
program.addCommand(searchCommand(getClient, getFormat));
|
|
681
|
-
program.addCommand(swapsCommand(getClient, getFormat));
|
|
682
|
-
async function main() {
|
|
683
|
-
try {
|
|
684
|
-
await program.parseAsync(process.argv);
|
|
685
|
-
} catch (error) {
|
|
686
|
-
if (error instanceof OpenSeaAPIError) {
|
|
687
|
-
console.error(
|
|
688
|
-
JSON.stringify(
|
|
689
|
-
{
|
|
690
|
-
error: "API Error",
|
|
691
|
-
status: error.statusCode,
|
|
692
|
-
path: error.path,
|
|
693
|
-
message: error.responseBody
|
|
694
|
-
},
|
|
695
|
-
null,
|
|
696
|
-
2
|
|
697
|
-
)
|
|
698
|
-
);
|
|
699
|
-
process.exit(1);
|
|
700
|
-
}
|
|
701
|
-
throw error;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
main();
|
|
705
|
-
//# sourceMappingURL=cli.js.map
|