@zoralabs/coins-sdk 0.2.3 → 0.2.5
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/CHANGELOG.md +13 -0
- package/dist/actions/createCoin.d.ts +11 -4
- package/dist/actions/createCoin.d.ts.map +1 -1
- package/dist/actions/updateCoinURI.d.ts +1 -1
- package/dist/actions/updateCoinURI.d.ts.map +1 -1
- package/dist/actions/updatePayoutRecipient.d.ts +1 -1
- package/dist/actions/updatePayoutRecipient.d.ts.map +1 -1
- package/dist/api/api-key.d.ts +2 -1
- package/dist/api/api-key.d.ts.map +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/internal.d.ts +2 -2
- package/dist/api/internal.d.ts.map +1 -1
- package/dist/index.cjs +301 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +320 -122
- package/dist/index.js.map +1 -1
- package/dist/metadata/cleanAndValidateMetadataURI.d.ts +1 -1
- package/dist/metadata/cleanAndValidateMetadataURI.d.ts.map +1 -1
- package/dist/metadata/index.d.ts +1 -1
- package/dist/metadata/index.d.ts.map +1 -1
- package/dist/metadata/validateMetadataURIContent.d.ts +1 -1
- package/dist/metadata/validateMetadataURIContent.d.ts.map +1 -1
- package/dist/uploader/index.d.ts +10 -0
- package/dist/uploader/index.d.ts.map +1 -0
- package/dist/uploader/metadata.d.ts +44 -0
- package/dist/uploader/metadata.d.ts.map +1 -0
- package/dist/uploader/providers/zora.d.ts +18 -0
- package/dist/uploader/providers/zora.d.ts.map +1 -0
- package/dist/uploader/types.d.ts +21 -0
- package/dist/uploader/types.d.ts.map +1 -0
- package/dist/utils/getPrepurchaseHook.d.ts +16 -0
- package/dist/utils/getPrepurchaseHook.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/actions/createCoin.ts +33 -7
- package/src/actions/updateCoinURI.ts +1 -1
- package/src/actions/updatePayoutRecipient.ts +1 -1
- package/src/api/api-key.ts +5 -1
- package/src/api/index.ts +1 -0
- package/src/api/internal.ts +3 -3
- package/src/index.ts +9 -9
- package/src/metadata/cleanAndValidateMetadataURI.ts +1 -5
- package/src/metadata/index.ts +1 -4
- package/src/metadata/validateMetadataURIContent.ts +2 -4
- package/src/uploader/index.ts +16 -0
- package/src/uploader/metadata.ts +214 -0
- package/src/uploader/providers/zora.ts +86 -0
- package/src/uploader/tests/metadata.test.ts +331 -0
- package/src/uploader/tests/providers.test.ts +131 -0
- package/src/uploader/types.ts +27 -0
- package/src/utils/getPrepurchaseHook.ts +59 -0
- package/dist/actions/tradeCoin.d.ts +0 -75
- package/dist/actions/tradeCoin.d.ts.map +0 -1
- package/src/actions/tradeCoin.ts +0 -182
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
keccak256 as keccak2562,
|
|
7
7
|
toBytes
|
|
8
8
|
} from "viem";
|
|
9
|
+
import { base as base5, baseSepolia as baseSepolia3 } from "viem/chains";
|
|
9
10
|
|
|
10
11
|
// src/constants.ts
|
|
11
12
|
import { coinFactoryAddress as zoraFactoryImplAddress } from "@zoralabs/protocol-deployments";
|
|
@@ -133,9 +134,6 @@ function getAttribution() {
|
|
|
133
134
|
return slice(hash, 0, 4);
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
// src/actions/createCoin.ts
|
|
137
|
-
import { base as base4, baseSepolia as baseSepolia3 } from "viem/chains";
|
|
138
|
-
|
|
139
137
|
// src/utils/poolConfigUtils.ts
|
|
140
138
|
import { encodeMultiCurvePoolConfig } from "@zoralabs/protocol-deployments";
|
|
141
139
|
import { parseUnits, zeroAddress } from "viem";
|
|
@@ -179,12 +177,54 @@ var COIN_ZORA_PAIR_POOL_CONFIG = {
|
|
|
179
177
|
})
|
|
180
178
|
};
|
|
181
179
|
|
|
180
|
+
// src/utils/getPrepurchaseHook.ts
|
|
181
|
+
import {
|
|
182
|
+
encodeBuySupplyWithMultiHopSwapRouterHookCall,
|
|
183
|
+
wethAddress
|
|
184
|
+
} from "@zoralabs/protocol-deployments";
|
|
185
|
+
import { concat, pad, toHex as toHex2 } from "viem";
|
|
186
|
+
import { base as base4 } from "viem/chains";
|
|
187
|
+
var BASE_UDSC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
188
|
+
var USDC_ZORA_FEE = 3e3;
|
|
189
|
+
var WETH_BASE_FEE = 3e3;
|
|
190
|
+
var encodeFee = (fee) => pad(toHex2(fee), { size: 3 });
|
|
191
|
+
var getPrepurchaseHook = async ({
|
|
192
|
+
payoutRecipient,
|
|
193
|
+
initialPurchase,
|
|
194
|
+
chainId
|
|
195
|
+
}) => {
|
|
196
|
+
if (initialPurchase.currency !== 1 /* ETH */ && chainId !== base4.id) {
|
|
197
|
+
throw new Error("Initial purchase currency and/or chain not supported");
|
|
198
|
+
}
|
|
199
|
+
const path = concat([
|
|
200
|
+
wethAddress[base4.id],
|
|
201
|
+
encodeFee(WETH_BASE_FEE),
|
|
202
|
+
BASE_UDSC_ADDRESS,
|
|
203
|
+
encodeFee(USDC_ZORA_FEE),
|
|
204
|
+
ZORA_ADDRESS
|
|
205
|
+
]);
|
|
206
|
+
return encodeBuySupplyWithMultiHopSwapRouterHookCall({
|
|
207
|
+
ethValue: initialPurchase.amount,
|
|
208
|
+
buyRecipient: payoutRecipient,
|
|
209
|
+
exactInputParams: {
|
|
210
|
+
path,
|
|
211
|
+
amountIn: initialPurchase.amount,
|
|
212
|
+
amountOutMinimum: initialPurchase.amountOutMinimum || 0n
|
|
213
|
+
},
|
|
214
|
+
chainId: base4.id
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
|
|
182
218
|
// src/actions/createCoin.ts
|
|
183
219
|
var DeployCurrency = /* @__PURE__ */ ((DeployCurrency2) => {
|
|
184
220
|
DeployCurrency2[DeployCurrency2["ZORA"] = 1] = "ZORA";
|
|
185
221
|
DeployCurrency2[DeployCurrency2["ETH"] = 2] = "ETH";
|
|
186
222
|
return DeployCurrency2;
|
|
187
223
|
})(DeployCurrency || {});
|
|
224
|
+
var InitialPurchaseCurrency = /* @__PURE__ */ ((InitialPurchaseCurrency2) => {
|
|
225
|
+
InitialPurchaseCurrency2[InitialPurchaseCurrency2["ETH"] = 1] = "ETH";
|
|
226
|
+
return InitialPurchaseCurrency2;
|
|
227
|
+
})(InitialPurchaseCurrency || {});
|
|
188
228
|
function getPoolConfig(currency, chainId) {
|
|
189
229
|
if (currency === 1 /* ZORA */ && chainId == baseSepolia3.id) {
|
|
190
230
|
throw new Error("ZORA is not supported on Base Sepolia");
|
|
@@ -205,17 +245,30 @@ async function createCoinCall({
|
|
|
205
245
|
owners,
|
|
206
246
|
payoutRecipient,
|
|
207
247
|
currency,
|
|
208
|
-
chainId =
|
|
209
|
-
platformReferrer = "0x0000000000000000000000000000000000000000"
|
|
248
|
+
chainId = base5.id,
|
|
249
|
+
platformReferrer = "0x0000000000000000000000000000000000000000",
|
|
250
|
+
initialPurchase
|
|
210
251
|
}) {
|
|
211
252
|
if (!owners) {
|
|
212
253
|
owners = [payoutRecipient];
|
|
213
254
|
}
|
|
214
255
|
if (!currency) {
|
|
215
|
-
currency = chainId !==
|
|
256
|
+
currency = chainId !== base5.id ? 2 /* ETH */ : 1 /* ZORA */;
|
|
216
257
|
}
|
|
217
258
|
const poolConfig = getPoolConfig(currency, chainId);
|
|
218
259
|
await validateMetadataURIContent(uri);
|
|
260
|
+
let deployHook = {
|
|
261
|
+
hook: zeroAddress2,
|
|
262
|
+
hookData: "0x",
|
|
263
|
+
value: 0n
|
|
264
|
+
};
|
|
265
|
+
if (initialPurchase) {
|
|
266
|
+
deployHook = await getPrepurchaseHook({
|
|
267
|
+
initialPurchase,
|
|
268
|
+
payoutRecipient,
|
|
269
|
+
chainId
|
|
270
|
+
});
|
|
271
|
+
}
|
|
219
272
|
return {
|
|
220
273
|
abi: zoraFactoryImplABI,
|
|
221
274
|
functionName: "deploy",
|
|
@@ -228,13 +281,12 @@ async function createCoinCall({
|
|
|
228
281
|
symbol,
|
|
229
282
|
poolConfig,
|
|
230
283
|
platformReferrer,
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
"0x",
|
|
234
|
-
// hookData
|
|
284
|
+
deployHook.hook,
|
|
285
|
+
deployHook.hookData,
|
|
235
286
|
keccak2562(toBytes(Math.random().toString()))
|
|
236
287
|
// coinSalt
|
|
237
288
|
],
|
|
289
|
+
value: deployHook.value,
|
|
238
290
|
dataSuffix: getAttribution()
|
|
239
291
|
};
|
|
240
292
|
}
|
|
@@ -266,109 +318,17 @@ async function createCoin(call, walletClient, publicClient, options) {
|
|
|
266
318
|
};
|
|
267
319
|
}
|
|
268
320
|
|
|
269
|
-
// src/actions/tradeCoin.ts
|
|
270
|
-
import { coinABI } from "@zoralabs/protocol-deployments";
|
|
271
|
-
import {
|
|
272
|
-
parseEther,
|
|
273
|
-
zeroAddress as zeroAddress3,
|
|
274
|
-
parseEventLogs as parseEventLogs2
|
|
275
|
-
} from "viem";
|
|
276
|
-
import { baseSepolia as baseSepolia4 } from "viem/chains";
|
|
277
|
-
var OP_BRIDGE_ADDRESS = "0x4200000000000000000000000000000000000016";
|
|
278
|
-
async function simulateBuy({
|
|
279
|
-
target,
|
|
280
|
-
requestedOrderSize,
|
|
281
|
-
publicClient
|
|
282
|
-
}) {
|
|
283
|
-
const numberResult = await publicClient.simulateContract({
|
|
284
|
-
address: target,
|
|
285
|
-
abi: coinABI,
|
|
286
|
-
functionName: "buy",
|
|
287
|
-
dataSuffix: getAttribution(),
|
|
288
|
-
args: [
|
|
289
|
-
OP_BRIDGE_ADDRESS,
|
|
290
|
-
requestedOrderSize,
|
|
291
|
-
0n,
|
|
292
|
-
// minAmountOut
|
|
293
|
-
0n,
|
|
294
|
-
// sqrtPriceLimitX96
|
|
295
|
-
zeroAddress3
|
|
296
|
-
// tradeReferrer
|
|
297
|
-
],
|
|
298
|
-
// We want to ensure that the multicall3 contract has enough ETH to buy in the simulation
|
|
299
|
-
stateOverride: [
|
|
300
|
-
{
|
|
301
|
-
address: baseSepolia4.contracts.multicall3.address,
|
|
302
|
-
balance: parseEther("10000000")
|
|
303
|
-
}
|
|
304
|
-
]
|
|
305
|
-
});
|
|
306
|
-
const orderSize = numberResult.result[0];
|
|
307
|
-
const amountOut = numberResult.result[1];
|
|
308
|
-
return { orderSize, amountOut };
|
|
309
|
-
}
|
|
310
|
-
function tradeCoinCall({
|
|
311
|
-
target,
|
|
312
|
-
direction,
|
|
313
|
-
args: {
|
|
314
|
-
recipient,
|
|
315
|
-
orderSize,
|
|
316
|
-
minAmountOut = 0n,
|
|
317
|
-
sqrtPriceLimitX96 = 0n,
|
|
318
|
-
tradeReferrer = zeroAddress3
|
|
319
|
-
}
|
|
320
|
-
}) {
|
|
321
|
-
return {
|
|
322
|
-
abi: coinABI,
|
|
323
|
-
functionName: direction,
|
|
324
|
-
address: target,
|
|
325
|
-
args: [
|
|
326
|
-
recipient,
|
|
327
|
-
orderSize,
|
|
328
|
-
minAmountOut,
|
|
329
|
-
sqrtPriceLimitX96,
|
|
330
|
-
tradeReferrer
|
|
331
|
-
],
|
|
332
|
-
value: direction === "buy" ? orderSize : 0n
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
function getTradeFromLogs(receipt, direction) {
|
|
336
|
-
const eventLogs = parseEventLogs2({
|
|
337
|
-
abi: coinABI,
|
|
338
|
-
logs: receipt.logs
|
|
339
|
-
});
|
|
340
|
-
if (direction === "buy") {
|
|
341
|
-
return eventLogs.find((log) => log.eventName === "CoinBuy")?.args;
|
|
342
|
-
}
|
|
343
|
-
return eventLogs.find((log) => log.eventName === "CoinSell")?.args;
|
|
344
|
-
}
|
|
345
|
-
async function tradeCoin(params, walletClient, publicClient) {
|
|
346
|
-
validateClientNetwork(publicClient);
|
|
347
|
-
const { request } = await publicClient.simulateContract({
|
|
348
|
-
...tradeCoinCall(params),
|
|
349
|
-
account: walletClient.account
|
|
350
|
-
});
|
|
351
|
-
const hash = await walletClient.writeContract(request);
|
|
352
|
-
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
353
|
-
const trade = getTradeFromLogs(receipt, params.direction);
|
|
354
|
-
return {
|
|
355
|
-
hash,
|
|
356
|
-
receipt,
|
|
357
|
-
trade
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
|
|
361
321
|
// src/actions/getOnchainCoinDetails.ts
|
|
362
|
-
import { coinABI
|
|
322
|
+
import { coinABI, iUniswapV3PoolABI } from "@zoralabs/protocol-deployments";
|
|
363
323
|
import {
|
|
364
324
|
erc20Abi,
|
|
365
325
|
formatEther,
|
|
366
326
|
isAddressEqual,
|
|
367
|
-
zeroAddress as
|
|
327
|
+
zeroAddress as zeroAddress3
|
|
368
328
|
} from "viem";
|
|
369
329
|
async function getOnchainCoinDetails({
|
|
370
330
|
coin,
|
|
371
|
-
user =
|
|
331
|
+
user = zeroAddress3,
|
|
372
332
|
publicClient
|
|
373
333
|
}) {
|
|
374
334
|
validateClientNetwork(publicClient);
|
|
@@ -377,23 +337,23 @@ async function getOnchainCoinDetails({
|
|
|
377
337
|
contracts: [
|
|
378
338
|
{
|
|
379
339
|
address: coin,
|
|
380
|
-
abi:
|
|
340
|
+
abi: coinABI,
|
|
381
341
|
functionName: "balanceOf",
|
|
382
342
|
args: [user]
|
|
383
343
|
},
|
|
384
344
|
{
|
|
385
345
|
address: coin,
|
|
386
|
-
abi:
|
|
346
|
+
abi: coinABI,
|
|
387
347
|
functionName: "poolAddress"
|
|
388
348
|
},
|
|
389
349
|
{
|
|
390
350
|
address: coin,
|
|
391
|
-
abi:
|
|
351
|
+
abi: coinABI,
|
|
392
352
|
functionName: "owners"
|
|
393
353
|
},
|
|
394
354
|
{
|
|
395
355
|
address: coin,
|
|
396
|
-
abi:
|
|
356
|
+
abi: coinABI,
|
|
397
357
|
functionName: "payoutRecipient"
|
|
398
358
|
}
|
|
399
359
|
],
|
|
@@ -428,7 +388,7 @@ async function getOnchainCoinDetails({
|
|
|
428
388
|
},
|
|
429
389
|
{
|
|
430
390
|
address: coin,
|
|
431
|
-
abi:
|
|
391
|
+
abi: coinABI,
|
|
432
392
|
functionName: "totalSupply"
|
|
433
393
|
},
|
|
434
394
|
{
|
|
@@ -504,9 +464,9 @@ function uniswapV3SqrtPriceToBigIntScaled(sqrtPriceX96, token0Decimals, token1De
|
|
|
504
464
|
}
|
|
505
465
|
|
|
506
466
|
// src/actions/updateCoinURI.ts
|
|
507
|
-
import { coinABI as
|
|
467
|
+
import { coinABI as coinABI2 } from "@zoralabs/protocol-deployments";
|
|
508
468
|
import {
|
|
509
|
-
parseEventLogs as
|
|
469
|
+
parseEventLogs as parseEventLogs2
|
|
510
470
|
} from "viem";
|
|
511
471
|
function updateCoinURICall({
|
|
512
472
|
newURI,
|
|
@@ -516,7 +476,7 @@ function updateCoinURICall({
|
|
|
516
476
|
throw new Error("URI needs to be an ipfs:// prefix uri");
|
|
517
477
|
}
|
|
518
478
|
return {
|
|
519
|
-
abi:
|
|
479
|
+
abi: coinABI2,
|
|
520
480
|
address: coin,
|
|
521
481
|
functionName: "setContractURI",
|
|
522
482
|
args: [newURI],
|
|
@@ -532,7 +492,7 @@ async function updateCoinURI(args, walletClient, publicClient) {
|
|
|
532
492
|
});
|
|
533
493
|
const hash = await walletClient.writeContract(request);
|
|
534
494
|
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
535
|
-
const eventLogs =
|
|
495
|
+
const eventLogs = parseEventLogs2({ abi: coinABI2, logs: receipt.logs });
|
|
536
496
|
const uriUpdated = eventLogs.find(
|
|
537
497
|
(log) => log.eventName === "ContractURIUpdated"
|
|
538
498
|
);
|
|
@@ -540,16 +500,16 @@ async function updateCoinURI(args, walletClient, publicClient) {
|
|
|
540
500
|
}
|
|
541
501
|
|
|
542
502
|
// src/actions/updatePayoutRecipient.ts
|
|
543
|
-
import { coinABI as
|
|
503
|
+
import { coinABI as coinABI3 } from "@zoralabs/protocol-deployments";
|
|
544
504
|
import {
|
|
545
|
-
parseEventLogs as
|
|
505
|
+
parseEventLogs as parseEventLogs3
|
|
546
506
|
} from "viem";
|
|
547
507
|
function updatePayoutRecipientCall({
|
|
548
508
|
newPayoutRecipient,
|
|
549
509
|
coin
|
|
550
510
|
}) {
|
|
551
511
|
return {
|
|
552
|
-
abi:
|
|
512
|
+
abi: coinABI3,
|
|
553
513
|
address: coin,
|
|
554
514
|
functionName: "setPayoutRecipient",
|
|
555
515
|
args: [newPayoutRecipient],
|
|
@@ -565,7 +525,7 @@ async function updatePayoutRecipient(args, walletClient, publicClient) {
|
|
|
565
525
|
});
|
|
566
526
|
const hash = await walletClient.writeContract(request);
|
|
567
527
|
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
568
|
-
const eventLogs =
|
|
528
|
+
const eventLogs = parseEventLogs3({ abi: coinABI3, logs: receipt.logs });
|
|
569
529
|
const payoutRecipientUpdated = eventLogs.find(
|
|
570
530
|
(log) => log.eventName === "CoinPayoutRecipientUpdated"
|
|
571
531
|
);
|
|
@@ -620,6 +580,22 @@ var getCoins = (options) => {
|
|
|
620
580
|
...options
|
|
621
581
|
});
|
|
622
582
|
};
|
|
583
|
+
var setCreateUploadJwt = (options) => {
|
|
584
|
+
return (options?.client ?? client).post({
|
|
585
|
+
security: [
|
|
586
|
+
{
|
|
587
|
+
name: "api-key",
|
|
588
|
+
type: "apiKey"
|
|
589
|
+
}
|
|
590
|
+
],
|
|
591
|
+
url: "/createUploadJWT",
|
|
592
|
+
...options,
|
|
593
|
+
headers: {
|
|
594
|
+
"Content-Type": "application/json",
|
|
595
|
+
...options?.headers
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
};
|
|
623
599
|
var getExplore = (options) => {
|
|
624
600
|
return (options.client ?? client).get({
|
|
625
601
|
security: [
|
|
@@ -674,6 +650,9 @@ var apiKey;
|
|
|
674
650
|
function setApiKey(key) {
|
|
675
651
|
apiKey = key;
|
|
676
652
|
}
|
|
653
|
+
function getApiKey() {
|
|
654
|
+
return apiKey;
|
|
655
|
+
}
|
|
677
656
|
function getApiKeyMeta() {
|
|
678
657
|
if (!apiKey) {
|
|
679
658
|
return {};
|
|
@@ -743,11 +722,232 @@ var getCoinsMostValuable = (query = {}, options) => createExploreQuery(query, "M
|
|
|
743
722
|
var getCoinsNew = (query = {}, options) => createExploreQuery(query, "NEW", options);
|
|
744
723
|
var getCoinsLastTraded = (query = {}, options) => createExploreQuery(query, "LAST_TRADED", options);
|
|
745
724
|
var getCoinsLastTradedUnique = (query = {}, options) => createExploreQuery(query, "LAST_TRADED_UNIQUE", options);
|
|
725
|
+
|
|
726
|
+
// src/uploader/metadata.ts
|
|
727
|
+
function validateImageMimeType(mimeType) {
|
|
728
|
+
if (![
|
|
729
|
+
"image/png",
|
|
730
|
+
"image/jpeg",
|
|
731
|
+
"image/jpg",
|
|
732
|
+
"image/gif",
|
|
733
|
+
"image/svg+xml"
|
|
734
|
+
].includes(mimeType)) {
|
|
735
|
+
throw new Error("Image must be a PNG, JPEG, JPG, GIF or SVG");
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
function getURLFromUploadResult(uploadResult) {
|
|
739
|
+
return new URL(uploadResult.url);
|
|
740
|
+
}
|
|
741
|
+
var CoinMetadataBuilder = class {
|
|
742
|
+
withName(name) {
|
|
743
|
+
this.name = name;
|
|
744
|
+
if (typeof name !== "string") {
|
|
745
|
+
throw new Error("Name must be a string");
|
|
746
|
+
}
|
|
747
|
+
return this;
|
|
748
|
+
}
|
|
749
|
+
withSymbol(symbol) {
|
|
750
|
+
this.symbol = symbol;
|
|
751
|
+
if (typeof symbol !== "string") {
|
|
752
|
+
throw new Error("Symbol must be a string");
|
|
753
|
+
}
|
|
754
|
+
return this;
|
|
755
|
+
}
|
|
756
|
+
withDescription(description) {
|
|
757
|
+
this.description = description;
|
|
758
|
+
if (typeof description !== "string") {
|
|
759
|
+
throw new Error("Description must be a string");
|
|
760
|
+
}
|
|
761
|
+
return this;
|
|
762
|
+
}
|
|
763
|
+
withImage(image) {
|
|
764
|
+
if (this.imageURL) {
|
|
765
|
+
throw new Error("Image URL already set");
|
|
766
|
+
}
|
|
767
|
+
if (!(image instanceof File)) {
|
|
768
|
+
throw new Error("Image must be a File");
|
|
769
|
+
}
|
|
770
|
+
validateImageMimeType(image.type);
|
|
771
|
+
this.imageFile = image;
|
|
772
|
+
return this;
|
|
773
|
+
}
|
|
774
|
+
withImageURI(imageURI) {
|
|
775
|
+
if (this.imageFile) {
|
|
776
|
+
throw new Error("Image file already set");
|
|
777
|
+
}
|
|
778
|
+
if (typeof imageURI !== "string") {
|
|
779
|
+
throw new Error("Image URI must be a string");
|
|
780
|
+
}
|
|
781
|
+
const url = new URL(imageURI);
|
|
782
|
+
this.imageURL = url;
|
|
783
|
+
return this;
|
|
784
|
+
}
|
|
785
|
+
withProperties(properties) {
|
|
786
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
787
|
+
if (typeof key !== "string") {
|
|
788
|
+
throw new Error("Property key must be a string");
|
|
789
|
+
}
|
|
790
|
+
if (typeof value !== "string") {
|
|
791
|
+
throw new Error("Property value must be a string");
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
if (!this.properties) {
|
|
795
|
+
this.properties = {};
|
|
796
|
+
}
|
|
797
|
+
this.properties = { ...this.properties, ...properties };
|
|
798
|
+
return this;
|
|
799
|
+
}
|
|
800
|
+
withMedia(media) {
|
|
801
|
+
if (this.mediaURL) {
|
|
802
|
+
throw new Error("Media URL already set");
|
|
803
|
+
}
|
|
804
|
+
if (!(media instanceof File)) {
|
|
805
|
+
throw new Error("Media must be a File");
|
|
806
|
+
}
|
|
807
|
+
this.mediaMimeType = media.type;
|
|
808
|
+
this.mediaFile = media;
|
|
809
|
+
return this;
|
|
810
|
+
}
|
|
811
|
+
withMediaURI(mediaURI, mediaMimeType) {
|
|
812
|
+
if (this.mediaFile) {
|
|
813
|
+
throw new Error("Media file already set");
|
|
814
|
+
}
|
|
815
|
+
if (typeof mediaURI !== "string") {
|
|
816
|
+
throw new Error("Media URI must be a string");
|
|
817
|
+
}
|
|
818
|
+
const url = new URL(mediaURI);
|
|
819
|
+
this.mediaURL = url;
|
|
820
|
+
this.mediaMimeType = mediaMimeType;
|
|
821
|
+
return this;
|
|
822
|
+
}
|
|
823
|
+
validate() {
|
|
824
|
+
if (!this.name) {
|
|
825
|
+
throw new Error("Name is required");
|
|
826
|
+
}
|
|
827
|
+
if (!this.symbol) {
|
|
828
|
+
throw new Error("Symbol is required");
|
|
829
|
+
}
|
|
830
|
+
if (!this.imageFile && !this.imageURL) {
|
|
831
|
+
throw new Error("Image is required");
|
|
832
|
+
}
|
|
833
|
+
return this;
|
|
834
|
+
}
|
|
835
|
+
generateMetadata() {
|
|
836
|
+
return {
|
|
837
|
+
name: this.name,
|
|
838
|
+
symbol: this.symbol,
|
|
839
|
+
description: this.description,
|
|
840
|
+
image: this.imageURL.toString(),
|
|
841
|
+
animation_url: this.mediaURL?.toString(),
|
|
842
|
+
content: this.mediaURL ? {
|
|
843
|
+
uri: this.mediaURL?.toString(),
|
|
844
|
+
mime: this.mediaMimeType
|
|
845
|
+
} : void 0,
|
|
846
|
+
properties: this.properties
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
async upload(uploader) {
|
|
850
|
+
this.validate();
|
|
851
|
+
if (this.imageFile) {
|
|
852
|
+
const uploadResult2 = await uploader.upload(this.imageFile);
|
|
853
|
+
this.imageURL = getURLFromUploadResult(uploadResult2);
|
|
854
|
+
}
|
|
855
|
+
if (this.mediaFile) {
|
|
856
|
+
const uploadResult2 = await uploader.upload(this.mediaFile);
|
|
857
|
+
this.mediaURL = getURLFromUploadResult(uploadResult2);
|
|
858
|
+
}
|
|
859
|
+
const metadata = this.generateMetadata();
|
|
860
|
+
const uploadResult = await uploader.upload(
|
|
861
|
+
new File([JSON.stringify(metadata)], "metadata.json", {
|
|
862
|
+
type: "application/json"
|
|
863
|
+
})
|
|
864
|
+
);
|
|
865
|
+
return {
|
|
866
|
+
url: getURLFromUploadResult(uploadResult).toString(),
|
|
867
|
+
createMetadataParameters: {
|
|
868
|
+
name: this.name,
|
|
869
|
+
symbol: this.symbol,
|
|
870
|
+
uri: uploadResult.url
|
|
871
|
+
},
|
|
872
|
+
metadata
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
function createMetadataBuilder() {
|
|
877
|
+
return new CoinMetadataBuilder();
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// src/api/internal.ts
|
|
881
|
+
var setCreateUploadJwt2 = async (body, options) => {
|
|
882
|
+
return await setCreateUploadJwt({
|
|
883
|
+
body,
|
|
884
|
+
...getApiKeyMeta(),
|
|
885
|
+
...options
|
|
886
|
+
});
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
// src/uploader/providers/zora.ts
|
|
890
|
+
var ZoraUploader = class {
|
|
891
|
+
constructor(creatorAddress) {
|
|
892
|
+
this.creatorAddress = creatorAddress;
|
|
893
|
+
if (!getApiKey()) {
|
|
894
|
+
throw new Error("API key is required for metadata interactions");
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
async getJWTApiKey() {
|
|
898
|
+
if (this.jwtApiKey && this.jwtApiKeyExpiresAt && this.jwtApiKeyExpiresAt > Date.now()) {
|
|
899
|
+
return this.jwtApiKey;
|
|
900
|
+
}
|
|
901
|
+
this.jwtApiKeyExpiresAt = Date.now() + 1e3 * 60 * 60;
|
|
902
|
+
const response = await setCreateUploadJwt2({
|
|
903
|
+
creatorAddress: this.creatorAddress
|
|
904
|
+
});
|
|
905
|
+
this.jwtApiKey = response.data?.createUploadJwtFromApiKey;
|
|
906
|
+
if (!this.jwtApiKey) {
|
|
907
|
+
throw new Error("Failed to create upload JWT");
|
|
908
|
+
}
|
|
909
|
+
return this.jwtApiKey;
|
|
910
|
+
}
|
|
911
|
+
async upload(file) {
|
|
912
|
+
const jwtApiKey = await this.getJWTApiKey();
|
|
913
|
+
const formData = new FormData();
|
|
914
|
+
formData.append("file", file, file.name);
|
|
915
|
+
const response = await fetch(
|
|
916
|
+
"https://ipfs-uploader.zora.co/api/v0/add?cid-version=1",
|
|
917
|
+
{
|
|
918
|
+
method: "POST",
|
|
919
|
+
headers: {
|
|
920
|
+
Authorization: `Bearer ${jwtApiKey}`,
|
|
921
|
+
Accept: "*/*"
|
|
922
|
+
},
|
|
923
|
+
body: formData
|
|
924
|
+
}
|
|
925
|
+
);
|
|
926
|
+
if (!response.ok) {
|
|
927
|
+
console.error(await response.text());
|
|
928
|
+
throw new Error(`Failed to upload file: ${response.statusText}`);
|
|
929
|
+
}
|
|
930
|
+
const data = await response.json();
|
|
931
|
+
return {
|
|
932
|
+
url: `ipfs://${data.cid}`,
|
|
933
|
+
size: data.size,
|
|
934
|
+
mimeType: data.mimeType
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
function createZoraUploaderForCreator(creatorAddress) {
|
|
939
|
+
return new ZoraUploader(creatorAddress);
|
|
940
|
+
}
|
|
746
941
|
export {
|
|
942
|
+
CoinMetadataBuilder,
|
|
747
943
|
DeployCurrency,
|
|
944
|
+
InitialPurchaseCurrency,
|
|
945
|
+
ZoraUploader,
|
|
748
946
|
cleanAndValidateMetadataURI,
|
|
749
947
|
createCoin,
|
|
750
948
|
createCoinCall,
|
|
949
|
+
createMetadataBuilder,
|
|
950
|
+
createZoraUploaderForCreator,
|
|
751
951
|
getCoin2 as getCoin,
|
|
752
952
|
getCoinComments2 as getCoinComments,
|
|
753
953
|
getCoinCreateFromLogs,
|
|
@@ -762,15 +962,13 @@ export {
|
|
|
762
962
|
getProfile2 as getProfile,
|
|
763
963
|
getProfileBalances2 as getProfileBalances,
|
|
764
964
|
getProfileCoins2 as getProfileCoins,
|
|
765
|
-
|
|
965
|
+
getURLFromUploadResult,
|
|
766
966
|
setApiKey,
|
|
767
|
-
simulateBuy,
|
|
768
|
-
tradeCoin,
|
|
769
|
-
tradeCoinCall,
|
|
770
967
|
updateCoinURI,
|
|
771
968
|
updateCoinURICall,
|
|
772
969
|
updatePayoutRecipient,
|
|
773
970
|
updatePayoutRecipientCall,
|
|
971
|
+
validateImageMimeType,
|
|
774
972
|
validateMetadataJSON,
|
|
775
973
|
validateMetadataURIContent
|
|
776
974
|
};
|