@medialane/sdk 0.198.0 → 0.200.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.
Files changed (92) hide show
  1. package/README.md +86 -41
  2. package/dist/chains-CmwjZVU7.d.cts +85 -0
  3. package/dist/chains-CmwjZVU7.d.ts +85 -0
  4. package/dist/chunk-3HPMEDYH.cjs +967 -0
  5. package/dist/chunk-3HPMEDYH.cjs.map +1 -0
  6. package/dist/{chunk-3ME5YKTW.js → chunk-5KY6P434.js} +2 -2
  7. package/dist/chunk-5KY6P434.js.map +1 -0
  8. package/dist/chunk-F7W6IWTL.js +660 -0
  9. package/dist/chunk-F7W6IWTL.js.map +1 -0
  10. package/dist/chunk-GIBIHGSV.js +916 -0
  11. package/dist/chunk-GIBIHGSV.js.map +1 -0
  12. package/dist/chunk-GV4A2WNO.js +444 -0
  13. package/dist/chunk-GV4A2WNO.js.map +1 -0
  14. package/dist/{chunk-7EYJC5CB.cjs → chunk-H2NJB3AK.cjs} +2 -2
  15. package/dist/chunk-H2NJB3AK.cjs.map +1 -0
  16. package/dist/chunk-KGAGWULG.js +932 -0
  17. package/dist/chunk-KGAGWULG.js.map +1 -0
  18. package/dist/chunk-MEJ47LC3.cjs +463 -0
  19. package/dist/chunk-MEJ47LC3.cjs.map +1 -0
  20. package/dist/chunk-W76AZ5WC.cjs +376 -0
  21. package/dist/chunk-W76AZ5WC.cjs.map +1 -0
  22. package/dist/chunk-WRBXQPRL.js +323 -0
  23. package/dist/chunk-WRBXQPRL.js.map +1 -0
  24. package/dist/chunk-ZLMIHQWM.cjs +975 -0
  25. package/dist/chunk-ZLMIHQWM.cjs.map +1 -0
  26. package/dist/chunk-ZVANOWIB.cjs +688 -0
  27. package/dist/chunk-ZVANOWIB.cjs.map +1 -0
  28. package/dist/contract/index.cjs +88 -261
  29. package/dist/contract/index.cjs.map +1 -1
  30. package/dist/contract/index.d.cts +139 -4
  31. package/dist/contract/index.d.ts +139 -4
  32. package/dist/contract/index.js +4 -220
  33. package/dist/contract/index.js.map +1 -1
  34. package/dist/evm/index.cjs +3 -3
  35. package/dist/evm/index.d.cts +2 -1
  36. package/dist/evm/index.d.ts +2 -1
  37. package/dist/evm/index.js +1 -1
  38. package/dist/fetch-Cx9Pr7-B.d.cts +3 -0
  39. package/dist/fetch-Cx9Pr7-B.d.ts +3 -0
  40. package/dist/index.cjs +177 -833
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +54 -132
  43. package/dist/index.d.ts +54 -132
  44. package/dist/index.js +6 -659
  45. package/dist/index.js.map +1 -1
  46. package/dist/passkey-errors-B0HGcjPc.d.ts +981 -0
  47. package/dist/passkey-errors-yndCFeHv.d.cts +981 -0
  48. package/dist/provisioning-CwRkCN8D.d.cts +14 -0
  49. package/dist/provisioning-CwRkCN8D.d.ts +14 -0
  50. package/dist/{provisioning-BUYiU8Tr.d.ts → responses-D3nBY71f.d.cts} +40 -48
  51. package/dist/{provisioning-BUYiU8Tr.d.cts → responses-D3nBY71f.d.ts} +40 -48
  52. package/dist/server/index.cjs +117 -0
  53. package/dist/server/index.cjs.map +1 -0
  54. package/dist/server/index.d.cts +98 -0
  55. package/dist/server/index.d.ts +98 -0
  56. package/dist/server/index.js +4 -0
  57. package/dist/server/index.js.map +1 -0
  58. package/dist/services-B15RJBSW.d.cts +728 -0
  59. package/dist/services-BAnTJhwt.d.ts +728 -0
  60. package/dist/solana/index.cjs +2 -2
  61. package/dist/solana/index.d.cts +2 -1
  62. package/dist/solana/index.d.ts +2 -1
  63. package/dist/solana/index.js +1 -1
  64. package/dist/starknet/index.cjs +898 -1729
  65. package/dist/starknet/index.cjs.map +1 -1
  66. package/dist/starknet/index.d.cts +98 -467
  67. package/dist/starknet/index.d.ts +98 -467
  68. package/dist/starknet/index.js +704 -1680
  69. package/dist/starknet/index.js.map +1 -1
  70. package/dist/stellar/index.cjs +2 -2
  71. package/dist/stellar/index.d.cts +2 -1
  72. package/dist/stellar/index.d.ts +2 -1
  73. package/dist/stellar/index.js +1 -1
  74. package/dist/types-BW6ktwcT.d.ts +71 -0
  75. package/dist/types-BftPOVEJ.d.cts +71 -0
  76. package/dist/wallet/index.cjs +240 -0
  77. package/dist/wallet/index.cjs.map +1 -0
  78. package/dist/wallet/index.d.cts +319 -0
  79. package/dist/wallet/index.d.ts +319 -0
  80. package/dist/wallet/index.js +7 -0
  81. package/dist/wallet/index.js.map +1 -0
  82. package/package.json +13 -2
  83. package/dist/chunk-2R7XBA34.cjs +0 -1938
  84. package/dist/chunk-2R7XBA34.cjs.map +0 -1
  85. package/dist/chunk-3ME5YKTW.js.map +0 -1
  86. package/dist/chunk-6WVUUBFI.js +0 -1853
  87. package/dist/chunk-6WVUUBFI.js.map +0 -1
  88. package/dist/chunk-7EYJC5CB.cjs.map +0 -1
  89. package/dist/errors-CZm-NZK0.d.cts +0 -1754
  90. package/dist/errors-h6H6cj3Q.d.ts +0 -1754
  91. package/dist/types-DC4jNPAF.d.cts +0 -153
  92. package/dist/types-DC4jNPAF.d.ts +0 -153
@@ -1,44 +1,44 @@
1
- import { normalizeAddress, collectionHref, dropHref, resolveConfig, ApiClient, UserFacingError, getService, STARKNET_MEDIAWALLET_CLASS_HASH, computeAccountAddress, ownerConstructorCalldata, getTokenBySymbol, signWithPrivateKey, stringifyBigInts, SUPPORTED_TOKENS, MedialaneApiError, starkKeyPairFromPrivateKey } from '../chunk-6WVUUBFI.js';
2
- export { DeviceKeyMissingError, InvalidStarkPrivateKeyError, PasskeyCancelledError, PasskeyUnsupportedError, UserFacingError, computeAccountAddress, createPasskeyOwner, deriveAesKey, generateStarkKeyPair, indexedDbDeviceKeys, ownerConstructorCalldata, sealPrivateKey, signWithPrivateKey, starkKeyPairFromPrivateKey, unsealPrivateKey } from '../chunk-6WVUUBFI.js';
3
- import { getStarknetCoordinates, getCoordinates } from '../chunk-3ME5YKTW.js';
1
+ import { resolveConfig, getService, collectionHref, dropHref, stringifyBigInts } from '../chunk-GV4A2WNO.js';
2
+ export { InvalidPairingPayloadError, InvalidRecoveryKeyError, InvalidStarkPrivateKeyError, SponsoredCallRejectedError, accountFor, allowsFallbackFunding, buildAddOwnerCall, buildCancelEscapeCall, buildCompleteEscapeOwnerCall, buildDeployAccountParams, buildRemoveOwnerByGuidCall, buildRemoveOwnerCall, buildSetFirstGuardianCall, buildTriggerEscapeOwnerCall, canRemoveDevice, claimSessionWallet, completeDeployment, computeAccountAddress, computeOwnerGuid, createDeploymentCoordinator, createMediaWallet, createOwnerStore, createPasskeyOwner, createSelfFundConsent, decodeEscapeAndStatus, decodeGuardiansInfo, deploySelfFunded, deploySponsored, deriveAesKey, deriveOwnerKeyPair, describeDevices, describeGuardianStatus, describeRecoveryAction, encodePairingPayload, encodeRecoveryKey, erc20Balance, estimateSelfFundedFee, executeSponsored, generateStarkKeyPair, getEscape, getEscapeSecurityPeriod, getGuardians, getOwners, indexedDbDeviceKeys, isDeployed, isValidStarknetAddress, normalizeWalletAddress, ownerConstructorCalldata, parseAccountAddress, parsePairingPayload, parseRecoveryKey, sealPrivateKey, selfFundedExecutor, signWithPrivateKey, sponsoredExecutor, starkKeyPairFromPrivateKey, unsealPrivateKey, waitUntilDeployed } from '../chunk-GIBIHGSV.js';
3
+ import { ApiClient, UserFacingError, normalizeAddress, SUPPORTED_TOKENS, MedialaneError, MedialaneApiError } from '../chunk-KGAGWULG.js';
4
+ export { DeviceKeyMissingError, MedialaneError, PasskeyCancelledError, PasskeyUnsupportedError, UserFacingError } from '../chunk-KGAGWULG.js';
5
+ import { getStarknetCoordinates } from '../chunk-5KY6P434.js';
6
+ import '../chunk-WRBXQPRL.js';
4
7
  import '../chunk-PZ5AY32C.js';
5
- import { CallData, hash, cairo, uint256, CairoOption, CairoOptionVariant, RpcProvider, num, ec, validateAndParseAddress, Account, typedData, stark, byteArray, Contract, TypedDataRevision, constants, shortString } from 'starknet';
6
- import { extract, expand } from '@noble/hashes/hkdf.js';
7
- import { sha256 } from '@noble/hashes/sha2.js';
8
+ import { hash, CallData, RpcProvider, cairo, num, CairoOption, CairoOptionVariant, uint256, TypedDataRevision, Contract, byteArray, constants, shortString } from 'starknet';
8
9
 
9
- // src/starknet/marketplace/errors.ts
10
- var MedialaneError = class extends Error {
11
- constructor(message, code = "UNKNOWN", cause) {
12
- super(message);
13
- this.code = code;
14
- this.cause = cause;
15
- this.name = "MedialaneError";
16
- }
17
- };
18
-
19
- // src/starknet/marketplace/utils.ts
20
- var START_TIME_BUFFER_SECS = 30;
21
- function newContract(abi, address, providerOrAccount) {
22
- const C = Contract;
23
- return C.length === 1 ? new Contract({ abi, address, providerOrAccount }) : new Contract(
24
- abi,
25
- address,
26
- providerOrAccount
27
- );
10
+ function createChainProvider(backendUrl, apiKey) {
11
+ return new RpcProvider({
12
+ nodeUrl: `${backendUrl.replace(/\/$/, "")}/v1/rpc`,
13
+ headers: apiKey ? { "x-api-key": apiKey } : {},
14
+ blockIdentifier: "latest"
15
+ });
28
16
  }
29
- function getChainId(config) {
30
- if (config.chain !== "STARKNET") {
31
- throw new Error(`SNIP-12 signing is Starknet-only; got chain "${config.chain}"`);
17
+
18
+ // src/starknet/client.ts
19
+ var NO_BACKEND = "backendUrl not configured. Pass backendUrl to MedialaneClient to use";
20
+ var MedialaneClient = class {
21
+ constructor(rawConfig = {}) {
22
+ this.config = resolveConfig(rawConfig);
23
+ const config = this.config;
24
+ this.api = config.backendUrl ? new ApiClient({ baseUrl: config.backendUrl, apiKey: config.apiKey, retry: config.retryOptions, chain: config.chain }) : new ApiClient({
25
+ baseUrl: "https://medialane-sdk-no-backend.invalid",
26
+ apiKey: config.apiKey,
27
+ fetch: () => {
28
+ throw new Error(`${NO_BACKEND} .api`);
29
+ }
30
+ });
32
31
  }
33
- return constants.StarknetChainId.SN_MAIN;
34
- }
35
- function resolveToken(currency) {
36
- const token = SUPPORTED_TOKENS.find(
37
- (t) => t.symbol === currency.toUpperCase() || t.address.toLowerCase() === currency.toLowerCase()
38
- );
39
- if (!token) throw new MedialaneError(`Unsupported currency: ${currency}`, "INVALID_PARAMS");
40
- return token;
41
- }
32
+ get chain() {
33
+ return this.config.chain;
34
+ }
35
+ get provider() {
36
+ if (!this.config.backendUrl) {
37
+ throw new Error(`${NO_BACKEND} .provider`);
38
+ }
39
+ return this._provider ?? (this._provider = createChainProvider(this.config.backendUrl, this.config.apiKey));
40
+ }
41
+ };
42
42
 
43
43
  // src/starknet/abis/ipMarketplace.ts
44
44
  var IPMarketplaceABI = [
@@ -10376,975 +10376,148 @@ var IPGenesisABI = [
10376
10376
  ]
10377
10377
  }
10378
10378
  ];
10379
- var FRAGMENT_KEY = "pop-proof";
10380
- var toHex = (x) => "0x" + x.toString(16).padStart(64, "0");
10381
- var poseidon = (xs) => BigInt(hash.computePoseidonHashOnElements(xs.map((x) => "0x" + x.toString(16))));
10382
- var nodeHash = (a, b) => a < b ? poseidon([a, b]) : poseidon([b, a]);
10383
- function popLeafHash(address) {
10384
- return poseidon([poseidon([BigInt(address)])]);
10379
+ var START_TIME_BUFFER_SECS = 30;
10380
+ function newContract(abi, address, providerOrAccount) {
10381
+ const C = Contract;
10382
+ return C.length === 1 ? new Contract({ abi, address, providerOrAccount }) : new Contract(
10383
+ abi,
10384
+ address,
10385
+ providerOrAccount
10386
+ );
10385
10387
  }
10386
- function merkleTree(leafHashes) {
10387
- const leaves = [...leafHashes].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
10388
- const tree = new Array(2 * leaves.length - 1);
10389
- leaves.forEach((leaf, i) => tree[tree.length - 1 - i] = leaf);
10390
- for (let i = tree.length - 1 - leaves.length; i >= 0; i--) {
10391
- tree[i] = nodeHash(tree[2 * i + 1], tree[2 * i + 2]);
10388
+ function getChainId(config) {
10389
+ if (config.chain !== "STARKNET") {
10390
+ throw new Error(`SNIP-12 signing is Starknet-only; got chain "${config.chain}"`);
10392
10391
  }
10392
+ return constants.StarknetChainId.SN_MAIN;
10393
+ }
10394
+ function resolveToken(currency) {
10395
+ const token = SUPPORTED_TOKENS.find(
10396
+ (t) => t.symbol === currency.toUpperCase() || t.address.toLowerCase() === currency.toLowerCase()
10397
+ );
10398
+ if (!token) throw new MedialaneError(`Unsupported currency: ${currency}`, "INVALID_PARAMS");
10399
+ return token;
10400
+ }
10401
+ var STARKNET_DOMAIN = [
10402
+ { name: "name", type: "shortstring" },
10403
+ { name: "version", type: "shortstring" },
10404
+ { name: "chainId", type: "shortstring" },
10405
+ { name: "revision", type: "shortstring" }
10406
+ ];
10407
+ var OFFER_ITEM = [
10408
+ { name: "item_type", type: "shortstring" },
10409
+ { name: "token", type: "ContractAddress" },
10410
+ { name: "identifier_or_criteria", type: "felt" },
10411
+ { name: "amount", type: "felt" }
10412
+ ];
10413
+ var CONSIDERATION_ITEM = [
10414
+ { name: "item_type", type: "shortstring" },
10415
+ { name: "token", type: "ContractAddress" },
10416
+ { name: "identifier_or_criteria", type: "felt" },
10417
+ { name: "amount", type: "felt" },
10418
+ { name: "recipient", type: "ContractAddress" }
10419
+ ];
10420
+ var ORDER_PARAMETERS = [
10421
+ { name: "offerer", type: "ContractAddress" },
10422
+ { name: "marketplace", type: "ContractAddress" },
10423
+ { name: "offer", type: "OfferItem" },
10424
+ { name: "consideration", type: "ConsiderationItem" },
10425
+ { name: "royalty_max_bps", type: "felt" },
10426
+ { name: "start_time", type: "felt" },
10427
+ { name: "end_time", type: "felt" },
10428
+ { name: "salt", type: "felt" },
10429
+ { name: "counter", type: "felt" }
10430
+ ];
10431
+ var ORDER_CANCELLATION = [
10432
+ { name: "order_hash", type: "felt" },
10433
+ { name: "offerer", type: "ContractAddress" }
10434
+ ];
10435
+ var DOMAIN_VERSION = {
10436
+ erc721: "5",
10437
+ erc1155: "4"
10438
+ };
10439
+ function buildDomain(standard, chainId) {
10393
10440
  return {
10394
- root: tree[0],
10395
- proof(leaf) {
10396
- let i = tree.lastIndexOf(leaf);
10397
- if (i < tree.length - leaves.length) throw new Error("Not a leaf of this tree");
10398
- const proof = [];
10399
- while (i > 0) {
10400
- proof.push(tree[i % 2 === 1 ? i + 1 : i - 1]);
10401
- i = Math.floor((i - 1) / 2);
10402
- }
10403
- return proof;
10404
- }
10441
+ name: "Medialane",
10442
+ version: DOMAIN_VERSION[standard],
10443
+ chainId,
10444
+ revision: TypedDataRevision.ACTIVE
10405
10445
  };
10406
10446
  }
10407
- function buildPopAllowlist(addresses) {
10408
- const unique = [...new Set(addresses.map((a) => normalizeAddress("STARKNET", a)))];
10409
- if (unique.length === 0) throw new Error("An allowlist needs at least one address");
10410
- const leaves = unique.map((address) => ({ address, leaf: popLeafHash(address) }));
10411
- const tree = merkleTree(leaves.map((l) => l.leaf));
10412
- const proofs = {};
10413
- for (const { address, leaf } of leaves) proofs[address] = tree.proof(leaf).map(toHex);
10414
- return { root: toHex(tree.root), proofs };
10415
- }
10416
- function verifyPopProof(root, address, proof) {
10417
- let computed = popLeafHash(address);
10418
- for (const sibling of proof) computed = nodeHash(computed, BigInt(sibling));
10419
- return computed === BigInt(root);
10447
+ function buildOrderTypedData(message, chainId) {
10448
+ return {
10449
+ domain: buildDomain("erc721", chainId),
10450
+ primaryType: "OrderParameters",
10451
+ types: {
10452
+ StarknetDomain: STARKNET_DOMAIN,
10453
+ OrderParameters: ORDER_PARAMETERS,
10454
+ OfferItem: OFFER_ITEM,
10455
+ ConsiderationItem: CONSIDERATION_ITEM
10456
+ },
10457
+ message
10458
+ };
10420
10459
  }
10421
- function encodePopClaimFragment(proof) {
10422
- return `#${FRAGMENT_KEY}=${proof.join(",")}`;
10460
+ function build1155OrderTypedData(message, chainId) {
10461
+ return {
10462
+ domain: buildDomain("erc1155", chainId),
10463
+ primaryType: "OrderParameters",
10464
+ types: {
10465
+ StarknetDomain: STARKNET_DOMAIN,
10466
+ OrderParameters: ORDER_PARAMETERS,
10467
+ OfferItem: OFFER_ITEM,
10468
+ ConsiderationItem: CONSIDERATION_ITEM
10469
+ },
10470
+ message
10471
+ };
10423
10472
  }
10424
- function decodePopClaimFragment(fragment) {
10425
- const raw = new URLSearchParams(fragment.replace(/^#/, "")).get(FRAGMENT_KEY);
10426
- if (raw === null) return null;
10427
- if (raw === "") return [];
10428
- const parts = raw.split(",");
10429
- return parts.every((p) => /^0x[0-9a-fA-F]{1,64}$/.test(p)) ? parts : null;
10473
+ function buildCancellationTypedData(message, chainId) {
10474
+ return {
10475
+ domain: buildDomain("erc721", chainId),
10476
+ primaryType: "OrderCancellation",
10477
+ types: {
10478
+ StarknetDomain: STARKNET_DOMAIN,
10479
+ OrderCancellation: ORDER_CANCELLATION
10480
+ },
10481
+ message
10482
+ };
10430
10483
  }
10431
-
10432
- // src/starknet/pop-claim.ts
10433
- function popClaimLinks(origin, collection, list) {
10434
- const base = `${origin}${collectionHref("STARKNET", collection)}`;
10435
- return Object.entries(list.proofs).map(([address, proof]) => ({
10436
- address,
10437
- url: `${base}${encodePopClaimFragment(proof)}`
10438
- }));
10484
+ function build1155CancellationTypedData(message, chainId) {
10485
+ return {
10486
+ domain: buildDomain("erc1155", chainId),
10487
+ primaryType: "OrderCancellation",
10488
+ types: {
10489
+ StarknetDomain: STARKNET_DOMAIN,
10490
+ OrderCancellation: ORDER_CANCELLATION
10491
+ },
10492
+ message
10493
+ };
10439
10494
  }
10440
- function popClaimLinksCsv(links) {
10441
- return ["address,claim_link", ...links.map((l) => `${l.address},${l.url}`)].join("\n");
10495
+ function feeBps(surface, cfg) {
10496
+ if (!cfg.enabled || !cfg.fundAddress) return 0;
10497
+ return surface === "marketplace" ? cfg.marketplaceBps : surface === "launchpad" ? cfg.launchpadBps : cfg.sponsorshipBps;
10442
10498
  }
10443
- async function popClaimInfo(provider, collection) {
10444
- const contractAddress = normalizeAddress("STARKNET", collection);
10445
- const [root, end] = await Promise.all([
10446
- provider.callContract({ contractAddress, entrypoint: "allowlist_root", calldata: [] }),
10447
- provider.callContract({ contractAddress, entrypoint: "claim_end_time", calldata: [] })
10448
- ]);
10449
- return { root: root[0] ?? "0x0", claimEndTime: Number(BigInt(end[0] ?? "0x0")) };
10499
+ function feeAmount(grossAmount, bps) {
10500
+ return bps <= 0 ? 0n : grossAmount * BigInt(bps) / 10000n;
10450
10501
  }
10451
- function popClaimState(input) {
10452
- const { hasClaimed, proof, wallet, info } = input;
10453
- if (hasClaimed === true) return "claimed";
10454
- if (hasClaimed === null || info === null) return "loading";
10455
- if (BigInt(info.root) === 0n) return "closed";
10456
- if (info.claimEndTime !== 0 && info.now > info.claimEndTime) return "ended";
10457
- if (proof === null) return "no-link";
10458
- if (!wallet || !verifyPopProof(info.root, wallet, proof)) return "wrong-wallet";
10459
- return "ready";
10460
- }
10461
- var addr = (a) => normalizeAddress("STARKNET", a);
10462
- var byteArrayFelts = (s) => CallData.compile([byteArray.byteArrayFromString(s)]);
10463
- var popCalls = {
10464
- claim(collection, proof) {
10465
- return { contractAddress: addr(collection), entrypoint: "claim", calldata: [String(proof.length), ...proof] };
10466
- },
10467
- /** An empty `tokenUri` uses the collection's URI. */
10468
- issue(collection, recipient, tokenUri = "") {
10469
- return { contractAddress: addr(collection), entrypoint: "issue", calldata: [addr(recipient), ...byteArrayFelts(tokenUri)] };
10470
- },
10471
- /** Only the token's holder can burn it. */
10472
- burn(collection, tokenId) {
10473
- const id = cairo.uint256(BigInt(tokenId));
10474
- return { contractAddress: addr(collection), entrypoint: "burn", calldata: [String(id.low), String(id.high)] };
10475
- },
10476
- setAllowlistRoot(collection, root) {
10477
- return { contractAddress: addr(collection), entrypoint: "set_allowlist_root", calldata: [root] };
10478
- }
10479
- };
10480
-
10481
- // src/starknet/services/pop.ts
10482
- var PopService = class {
10483
- constructor(config) {
10484
- this.factoryAddress = getStarknetCoordinates(config.chain).popFactory;
10485
- }
10486
- async createCollection(account, params) {
10487
- const factory = newContract(POPFactoryABI, this.factoryAddress, account);
10488
- const call = factory.populate("create_collection", [params.name, params.symbol, params.baseUri, params.claimEndTime]);
10489
- const res = await account.execute([call]);
10490
- return { txHash: res.transaction_hash };
10491
- }
10492
- async setAllowlistRoot(account, params) {
10493
- const call = popCalls.setAllowlistRoot(params.collection, params.root);
10494
- const res = await account.execute([call]);
10495
- return { txHash: res.transaction_hash };
10496
- }
10497
- async claim(account, params) {
10498
- const call = popCalls.claim(params.collection, params.proof);
10499
- const res = await account.execute([call]);
10500
- return { txHash: res.transaction_hash };
10501
- }
10502
- async issue(account, params) {
10503
- const call = popCalls.issue(params.collection, params.recipient, params.tokenUri);
10504
- const res = await account.execute([call]);
10505
- return { txHash: res.transaction_hash };
10506
- }
10507
- /** Destroys the caller's own credential; the address cannot receive another from this collection. */
10508
- async burn(account, params) {
10509
- const call = popCalls.burn(params.collection, params.tokenId);
10510
- const res = await account.execute([call]);
10511
- return { txHash: res.transaction_hash };
10512
- }
10513
- };
10514
- async function popHasClaimed(provider, collection, address) {
10515
- const res = await provider.callContract({
10516
- contractAddress: normalizeAddress("STARKNET", collection),
10517
- entrypoint: "has_claimed",
10518
- calldata: [normalizeAddress("STARKNET", address)]
10519
- });
10520
- return BigInt(res[0] ?? "0x0") !== 0n;
10521
- }
10522
- function feeBps(surface, cfg) {
10523
- if (!cfg.enabled || !cfg.fundAddress) return 0;
10524
- return surface === "marketplace" ? cfg.marketplaceBps : surface === "launchpad" ? cfg.launchpadBps : cfg.sponsorshipBps;
10525
- }
10526
- function feeAmount(grossAmount, bps) {
10527
- return bps <= 0 ? 0n : grossAmount * BigInt(bps) / 10000n;
10528
- }
10529
- function buildFeeCall(p, cfg) {
10530
- const fee = feeAmount(p.grossAmount, feeBps(p.surface, cfg));
10531
- if (fee <= 0n) return null;
10532
- const u = cairo.uint256(fee.toString());
10533
- return {
10534
- contractAddress: p.token,
10535
- entrypoint: "transfer",
10536
- calldata: [cfg.fundAddress, u.low.toString(), u.high.toString()]
10537
- };
10538
- }
10539
- var DROP_MAX_CLAIM_QUANTITY = 50n;
10540
- var addr2 = (a) => normalizeAddress("STARKNET", a);
10541
- var factoryData = new CallData(DropFactoryABI);
10542
- var collectionData = new CallData(DropCollectionABI);
10543
- function toContractTerms(t) {
10544
- const price = BigInt(t.price);
10545
- return {
10546
- start_time: t.startTime,
10547
- end_time: t.endTime,
10548
- price: cairo.uint256(price),
10549
- payment_token: price === 0n ? "0x0" : addr2(t.paymentToken),
10550
- max_per_wallet: cairo.uint256(BigInt(t.maxPerWallet))
10551
- };
10552
- }
10553
- var dropCalls = {
10554
- create(factory, p) {
10555
- return {
10556
- contractAddress: addr2(factory),
10557
- entrypoint: "create_drop",
10558
- calldata: factoryData.compile("create_drop", {
10559
- name: p.name,
10560
- symbol: p.symbol,
10561
- base_uri: p.baseUri,
10562
- max_supply: cairo.uint256(BigInt(p.maxSupply)),
10563
- terms: toContractTerms(p.terms),
10564
- allowlist_root: p.allowlistRoot ?? "0x0"
10565
- })
10566
- };
10567
- },
10568
- /** Approve (paid drops) and claim. The platform fee call is added by the caller. */
10569
- claim(collection, p) {
10570
- const quantity = BigInt(p.quantity);
10571
- if (quantity < 1n || quantity > DROP_MAX_CLAIM_QUANTITY) throw new RangeError(`quantity must be 1 to ${DROP_MAX_CLAIM_QUANTITY}`);
10572
- const total = BigInt(p.price) * quantity;
10573
- const calls = [];
10574
- if (total > 0n) {
10575
- calls.push({
10576
- contractAddress: addr2(p.paymentToken),
10577
- entrypoint: "approve",
10578
- calldata: CallData.compile([addr2(collection), cairo.uint256(total)])
10579
- });
10580
- }
10581
- calls.push({
10582
- contractAddress: addr2(collection),
10583
- entrypoint: "claim",
10584
- calldata: collectionData.compile("claim", { quantity: cairo.uint256(quantity), proof: p.proof ?? [] })
10585
- });
10586
- return calls;
10587
- },
10588
- /** Organizer only: free mint within the supply cap. */
10589
- issue(collection, recipient, quantity) {
10590
- const q = BigInt(quantity);
10591
- if (q < 1n) throw new RangeError("quantity must be at least 1");
10592
- return {
10593
- contractAddress: addr2(collection),
10594
- entrypoint: "issue",
10595
- calldata: collectionData.compile("issue", { recipient: addr2(recipient), quantity: cairo.uint256(q) })
10596
- };
10597
- },
10598
- /** Organizer only. 0 opens the drop to everyone. */
10599
- setAllowlistRoot(collection, root) {
10600
- return { contractAddress: addr2(collection), entrypoint: "set_allowlist_root", calldata: collectionData.compile("set_allowlist_root", { root }) };
10601
- }
10602
- };
10603
- function dropMintCost(price, quantity, feeBps2) {
10604
- const subtotal = BigInt(price) * BigInt(quantity);
10605
- const fee = feeAmount(subtotal, feeBps2);
10606
- return { subtotal, fee, total: subtotal + fee };
10607
- }
10608
-
10609
- // src/starknet/drop-state.ts
10610
- var hex = (v) => normalizeAddress("STARKNET", v ?? "0x0");
10611
- var u256 = (low, high) => BigInt(low ?? "0x0") + (BigInt(high ?? "0x0") << 128n);
10612
- async function readDrop(provider, collection) {
10613
- const contractAddress = hex(collection);
10614
- const read = (entrypoint) => provider.callContract({ contractAddress, entrypoint, calldata: [] });
10615
- const [organizer, terms, root, max, minted] = await Promise.all([
10616
- read("organizer"),
10617
- read("terms"),
10618
- read("allowlist_root"),
10619
- read("max_supply"),
10620
- read("total_minted")
10621
- ]);
10622
- return {
10623
- organizer: hex(organizer[0]),
10624
- startTime: Number(BigInt(terms[0] ?? "0x0")),
10625
- endTime: Number(BigInt(terms[1] ?? "0x0")),
10626
- price: u256(terms[2], terms[3]),
10627
- paymentToken: hex(terms[4]),
10628
- maxPerWallet: u256(terms[5], terms[6]),
10629
- allowlistRoot: root[0] ?? "0x0",
10630
- maxSupply: u256(max[0], max[1]),
10631
- totalMinted: u256(minted[0], minted[1])
10632
- };
10633
- }
10634
- async function dropClaimedBy(provider, collection, wallet) {
10635
- const res = await provider.callContract({ contractAddress: hex(collection), entrypoint: "claimed_by", calldata: [hex(wallet)] });
10636
- return u256(res[0], res[1]);
10637
- }
10638
- function dropMintState(input) {
10639
- const none = (state) => ({ state, maxQuantity: 0n });
10640
- const { drop, wallet, claimed, proof, balance, now } = input;
10641
- if (!drop) return none("loading");
10642
- if (drop.startTime !== 0 && now < drop.startTime) return none("upcoming");
10643
- if (drop.endTime !== 0 && now > drop.endTime) return none("ended");
10644
- const supplyLeft = drop.maxSupply === 0n ? null : drop.maxSupply - drop.totalMinted;
10645
- if (supplyLeft !== null && supplyLeft <= 0n) return none("sold-out");
10646
- if (!wallet) return none("no-wallet");
10647
- if (BigInt(drop.allowlistRoot) !== 0n) {
10648
- if (proof === null) return none("no-link");
10649
- if (!verifyPopProof(drop.allowlistRoot, wallet, proof)) return none("not-on-list");
10650
- }
10651
- if (claimed === null) return none("loading");
10652
- const walletLeft = drop.maxPerWallet === 0n ? null : drop.maxPerWallet - claimed;
10653
- if (walletLeft !== null && walletLeft <= 0n) return none("limit-reached");
10654
- let max = DROP_MAX_CLAIM_QUANTITY;
10655
- if (supplyLeft !== null && supplyLeft < max) max = supplyLeft;
10656
- if (walletLeft !== null && walletLeft < max) max = walletLeft;
10657
- if (drop.price > 0n) {
10658
- if (balance === null) return none("loading");
10659
- while (max > 0n && dropMintCost(drop.price, max, input.feeBps).total > balance) max--;
10660
- if (max === 0n) return none("insufficient-balance");
10661
- }
10662
- return { state: "ready", maxQuantity: max };
10663
- }
10664
- function dropClaimLinks(origin, collection, list) {
10665
- const base = `${origin}${dropHref(collection)}`;
10666
- return Object.entries(list.proofs).map(([address, proof]) => ({
10667
- address,
10668
- url: `${base}${encodePopClaimFragment(proof)}`
10669
- }));
10670
- }
10671
-
10672
- // src/starknet/services/drop.ts
10673
- var DropService = class {
10674
- constructor(config) {
10675
- this.factoryAddress = getStarknetCoordinates(config.chain).dropFactory;
10676
- this.config = config;
10677
- }
10678
- async createDrop(account, params) {
10679
- const res = await account.execute([dropCalls.create(this.factoryAddress, params)]);
10680
- return { txHash: res.transaction_hash };
10681
- }
10682
- /** Mints `quantity` to the account, paying the drop's price and the platform fee. */
10683
- async claim(account, params) {
10684
- const drop = await readDrop(account.provider, params.collection);
10685
- const calls = dropCalls.claim(params.collection, {
10686
- quantity: params.quantity,
10687
- proof: params.proof,
10688
- price: drop.price,
10689
- paymentToken: drop.paymentToken
10690
- });
10691
- const fee = drop.price > 0n ? buildFeeCall(
10692
- { surface: "launchpad", token: drop.paymentToken, grossAmount: drop.price * BigInt(params.quantity) },
10693
- this.config.feeConfig
10694
- ) : null;
10695
- const res = await account.execute(fee ? [...calls, fee] : calls);
10696
- return { txHash: res.transaction_hash };
10697
- }
10698
- async issue(account, params) {
10699
- const res = await account.execute([dropCalls.issue(params.collection, params.recipient, params.quantity)]);
10700
- return { txHash: res.transaction_hash };
10701
- }
10702
- async setAllowlistRoot(account, params) {
10703
- const res = await account.execute([dropCalls.setAllowlistRoot(params.collection, params.root)]);
10704
- return { txHash: res.transaction_hash };
10705
- }
10706
- };
10707
-
10708
- // src/starknet/services/erc1155collection.ts
10709
- var ERC1155CollectionService = class {
10710
- constructor(config) {
10711
- this.factoryAddress = config.collection1155Contract ?? getStarknetCoordinates(config.chain).collection1155;
10712
- }
10713
- _factory(account) {
10714
- return newContract(
10715
- IPCollection1155FactoryABI,
10716
- normalizeAddress("STARKNET", this.factoryAddress),
10717
- account
10718
- );
10719
- }
10720
- _collection(address, account) {
10721
- return newContract(
10722
- IPCollection1155ABI,
10723
- normalizeAddress("STARKNET", address),
10724
- account
10725
- );
10726
- }
10727
- async deployCollection(account, params) {
10728
- const factory = this._factory(account);
10729
- const call = factory.populate("deploy_collection", [params.name, params.symbol, params.baseUri]);
10730
- const res = await account.execute([call]);
10731
- return { txHash: res.transaction_hash };
10732
- }
10733
- async mintEdition(account, params) {
10734
- const collection = this._collection(params.collection, account);
10735
- const call = collection.populate("mint_edition", [
10736
- params.to,
10737
- BigInt(params.value),
10738
- params.tokenUri
10739
- ]);
10740
- const res = await account.execute([call]);
10741
- return { txHash: res.transaction_hash };
10742
- }
10743
- async batchMintEdition(account, params) {
10744
- const collection = this._collection(params.collection, account);
10745
- const values = params.items.map((i) => BigInt(i.value));
10746
- const tokenUris = params.items.map((i) => i.tokenUri);
10747
- const call = collection.populate("batch_mint_edition", [
10748
- params.to,
10749
- values,
10750
- tokenUris
10751
- ]);
10752
- const res = await account.execute([call]);
10753
- return { txHash: res.transaction_hash };
10754
- }
10755
- async addSupply(account, params) {
10756
- const collection = this._collection(params.collection, account);
10757
- const call = collection.populate("add_supply", [
10758
- params.to,
10759
- BigInt(params.tokenId),
10760
- BigInt(params.value)
10761
- ]);
10762
- const res = await account.execute([call]);
10763
- return { txHash: res.transaction_hash };
10764
- }
10765
- async setDefaultRoyalty(account, params) {
10766
- const collection = this._collection(params.collection, account);
10767
- const call = collection.populate("set_default_royalty", [
10768
- params.receiver,
10769
- BigInt(params.feeNumerator)
10770
- ]);
10771
- const res = await account.execute([call]);
10772
- return { txHash: res.transaction_hash };
10773
- }
10774
- async setTokenRoyalty(account, params) {
10775
- const collection = this._collection(params.collection, account);
10776
- const call = collection.populate("set_token_royalty", [
10777
- BigInt(params.tokenId),
10778
- params.receiver,
10779
- BigInt(params.feeNumerator)
10780
- ]);
10781
- const res = await account.execute([call]);
10782
- return { txHash: res.transaction_hash };
10783
- }
10784
- async setApprovalForAll(account, params) {
10785
- const collection = this._collection(params.collection, account);
10786
- const call = collection.populate("set_approval_for_all", [
10787
- params.operator,
10788
- params.approved
10789
- ]);
10790
- const res = await account.execute([call]);
10791
- return { txHash: res.transaction_hash };
10792
- }
10793
- };
10794
-
10795
- // src/starknet/services/coinLaunchMath.ts
10796
- var COIN_DECIMALS = 18;
10797
- var SUGGESTED_DEFAULT_PRICE = 0.01;
10798
- var MIN_SUPPLY = 1000n;
10799
- var MAX_SUPPLY = 1000000000000n;
10800
- var MAX_FELT_BYTES = 31;
10801
- function byteLen(s) {
10802
- return new TextEncoder().encode(s).length;
10803
- }
10804
- function validateName(s) {
10805
- if (!s.trim()) return "Name is required";
10806
- if (byteLen(s) > MAX_FELT_BYTES) return `Name must be at most ${MAX_FELT_BYTES} bytes`;
10807
- return null;
10808
- }
10809
- function validateSymbol(s) {
10810
- if (!s.trim()) return "Symbol is required";
10811
- if (byteLen(s) > MAX_FELT_BYTES) return `Symbol must be at most ${MAX_FELT_BYTES} bytes`;
10812
- return null;
10813
- }
10814
- function validateSupply(human) {
10815
- if (!/^\d+$/.test(human.trim())) return "Supply must be a whole number";
10816
- const v = BigInt(human.trim());
10817
- if (v < MIN_SUPPLY) return `Supply must be at least ${MIN_SUPPLY.toString()}`;
10818
- if (v > MAX_SUPPLY) return `Supply must be at most ${MAX_SUPPLY.toString()}`;
10819
- return null;
10820
- }
10821
- function toRaw(human, decimals = COIN_DECIMALS) {
10822
- return human * 10n ** BigInt(decimals);
10823
- }
10824
- function teamCoinsRaw(supplyRaw, pct) {
10825
- const bps = BigInt(Math.round(pct * 100));
10826
- return supplyRaw * bps / 10000n;
10827
- }
10828
- var PRICE_SCALE = 1000000000000n;
10829
- function buybackQuoteRaw(teamCoinsRawValue, price, quoteDecimals) {
10830
- const priceScaled = BigInt(Math.round(price * Number(PRICE_SCALE)));
10831
- return teamCoinsRawValue * priceScaled * 10n ** BigInt(quoteDecimals) / (PRICE_SCALE * 10n ** BigInt(COIN_DECIMALS));
10832
- }
10833
- function fdvHuman(supplyHuman, price) {
10834
- return supplyHuman * price;
10835
- }
10836
-
10837
- // src/starknet/services/creatorCoin.ts
10838
- var VALIDATED_EKUBO_PARAMS = {
10839
- fee: "0xc49ba5e353f7d00000000000000000",
10840
- tickSpacing: 5982n,
10841
- startingPrice: { mag: 4600158n, sign: true },
10842
- bound: 88719042n
10843
- };
10844
- var TICK_BASE = 1.000001;
10845
- function priceToEkuboParams(quoteDecimals, price = SUGGESTED_DEFAULT_PRICE) {
10846
- const decAdj = 10 ** (COIN_DECIMALS - quoteDecimals);
10847
- const rawRatio = price / decAdj;
10848
- const tickSpacing = Number(VALIDATED_EKUBO_PARAMS.tickSpacing);
10849
- const rawTick = Math.log(rawRatio) / Math.log(TICK_BASE);
10850
- const roundedTick = Math.trunc(rawTick / tickSpacing) * tickSpacing;
10851
- return {
10852
- fee: VALIDATED_EKUBO_PARAMS.fee,
10853
- tickSpacing: VALIDATED_EKUBO_PARAMS.tickSpacing,
10854
- startingPrice: { mag: BigInt(Math.abs(roundedTick)), sign: roundedTick < 0 },
10855
- bound: VALIDATED_EKUBO_PARAMS.bound
10856
- };
10857
- }
10858
- function validatePrice(quoteDecimals, price) {
10859
- if (!isFinite(price) || price <= 0) return "Price must be a positive number";
10860
- const decAdj = 10 ** (COIN_DECIMALS - quoteDecimals);
10861
- const rawRatio = price / decAdj;
10862
- if (!isFinite(rawRatio) || rawRatio <= 0) return "Price must be a positive number";
10863
- const rawTick = Math.log(rawRatio) / Math.log(TICK_BASE);
10864
- if (!isFinite(rawTick)) return "Price is outside the supported range";
10865
- const bound = Number(VALIDATED_EKUBO_PARAMS.bound);
10866
- if (Math.abs(rawTick) >= bound) return "Price is outside the supported range";
10867
- return null;
10868
- }
10869
- var MAX_TEAM_ALLOCATION_PERCENT = 10;
10870
- var MAX_HOLDERS_AT_LAUNCH = 10;
10871
- function u2562(parts, offset = 0) {
10872
- return BigInt(parts[offset] ?? "0x0") + (BigInt(parts[offset + 1] ?? "0x0") << 128n);
10873
- }
10874
- async function getCreatorCoinGuarantees(coinAddress, provider) {
10875
- const call = (entrypoint) => provider.callContract({ contractAddress: coinAddress, entrypoint, calldata: [] });
10876
- const [launchedRes, allocRes] = await Promise.all([
10877
- call("is_launched").catch(() => null),
10878
- call("get_team_allocation").catch(() => null)
10879
- ]);
10880
- if (!launchedRes || !allocRes) return null;
10881
- const [supplyRes, blockRes, liquidityRes] = await Promise.all([
10882
- call("total_supply"),
10883
- call("launched_at_block_number").catch(() => null),
10884
- call("liquidity_type").catch(() => null)
10885
- ]);
10886
- const isLaunched = BigInt(launchedRes[0] ?? "0x0") !== 0n;
10887
- const totalSupply = u2562(supplyRes);
10888
- const teamAllocation = u2562(allocRes);
10889
- const teamAllocationPercent = totalSupply > 0n ? Number(teamAllocation * 10000n / totalSupply) / 100 : null;
10890
- const launchedAtBlock = isLaunched && blockRes?.[0] != null ? Number(BigInt(blockRes[0])) : null;
10891
- const liquidityPositionId = liquidityRes && BigInt(liquidityRes[0] ?? "0x1") === 0n && liquidityRes[2] != null ? BigInt(liquidityRes[2]).toString() : null;
10892
- return {
10893
- isLaunched,
10894
- launchedAtBlock,
10895
- totalSupplyRaw: totalSupply.toString(),
10896
- teamAllocationRaw: teamAllocation.toString(),
10897
- teamAllocationPercent,
10898
- liquidityPositionId
10899
- };
10900
- }
10901
- var _factoryContract = null;
10902
- function factoryContract() {
10903
- if (!_factoryContract) {
10904
- _factoryContract = newContract(
10905
- CreatorCoinFactoryABI,
10906
- getStarknetCoordinates("STARKNET").creatorCoinFactory
10907
- );
10908
- }
10909
- return _factoryContract;
10910
- }
10911
- function buildCreateCreatorCoinCall(params) {
10912
- const salt = params.salt ?? BigInt("0x" + Date.now().toString(16));
10913
- return factoryContract().populate("create_creator_coin", [
10914
- params.owner,
10915
- params.name,
10916
- params.symbol,
10917
- BigInt(params.initialSupply),
10918
- BigInt(salt)
10919
- ]);
10920
- }
10921
- function buildLaunchOnEkuboCalls(params) {
10922
- const ek = params.ekubo;
10923
- const launchParameters = {
10924
- creator_coin_address: params.creatorCoin,
10925
- transfer_restriction_delay: params.transferRestrictionDelay ?? 0,
10926
- max_percentage_buy_launch: params.maxPercentageBuyLaunch ?? 200,
10927
- quote_address: params.quoteToken,
10928
- initial_holders: params.initialHolders,
10929
- initial_holders_amounts: params.initialHoldersAmounts.map((a) => BigInt(a))
10930
- };
10931
- const ekuboParameters = {
10932
- fee: BigInt(ek.fee),
10933
- tick_spacing: BigInt(ek.tickSpacing),
10934
- starting_price: { mag: BigInt(ek.startingPrice.mag), sign: ek.startingPrice.sign },
10935
- bound: BigInt(ek.bound)
10936
- };
10937
- const calls = [];
10938
- if (params.quoteFundAmount !== void 0) {
10939
- const amt = uint256.bnToUint256(BigInt(params.quoteFundAmount));
10940
- calls.push({
10941
- contractAddress: params.quoteToken,
10942
- entrypoint: "transfer",
10943
- calldata: [getStarknetCoordinates("STARKNET").creatorCoinFactory, amt.low, amt.high]
10944
- });
10945
- }
10946
- calls.push(factoryContract().populate("launch_on_ekubo", [launchParameters, ekuboParameters]));
10947
- return calls;
10948
- }
10949
- var CREATOR_COIN_CREATED_SELECTOR = hash.getSelectorFromName("CreatorCoinCreated");
10950
- function parseCreatorCoinCreated(receipt) {
10951
- const factory = normalizeAddress("STARKNET", getStarknetCoordinates("STARKNET").creatorCoinFactory);
10952
- for (const ev of receipt?.events ?? []) {
10953
- let from;
10954
- try {
10955
- from = normalizeAddress("STARKNET", ev.from_address ?? "");
10956
- } catch {
10957
- continue;
10958
- }
10959
- if (from !== factory) continue;
10960
- const k0 = ev.keys?.[0];
10961
- if (!k0 || normalizeAddress("STARKNET", k0) !== normalizeAddress("STARKNET", CREATOR_COIN_CREATED_SELECTOR)) continue;
10962
- const data = ev.data ?? [];
10963
- if (data.length < 1) continue;
10964
- return normalizeAddress("STARKNET", data[data.length - 1]);
10965
- }
10966
- throw new Error("Coin deployed but the coin address could not be read from the receipt");
10967
- }
10968
- var CreatorCoinService = class {
10969
- constructor(config) {
10970
- this.factoryAddress = getStarknetCoordinates(config.chain).creatorCoinFactory;
10971
- }
10972
- _factory(account) {
10973
- return newContract(CreatorCoinFactoryABI, this.factoryAddress, account);
10974
- }
10975
- async createCreatorCoin(account, params) {
10976
- const res = await account.execute([buildCreateCreatorCoinCall(params)]);
10977
- return { txHash: res.transaction_hash };
10978
- }
10979
- async launchOnEkubo(account, params) {
10980
- const res = await account.execute(buildLaunchOnEkuboCalls(params));
10981
- return { txHash: res.transaction_hash };
10982
- }
10983
- async isCreatorCoin(address, account) {
10984
- const r = await this._factory(account).is_creator_coin(address);
10985
- return BigInt(r) === 1n;
10986
- }
10987
- };
10988
- var TicketService = class {
10989
- constructor(config) {
10990
- this.factoryAddress = getStarknetCoordinates(config.chain).ipTicketsFactory;
10991
- }
10992
- _factory(account, factoryAddress) {
10993
- const address = factoryAddress ?? this.factoryAddress;
10994
- if (!address) throw new Error("IP-Tickets factory address not configured for this chain");
10995
- return newContract(IPTicketCollectionFactoryABI, normalizeAddress("STARKNET", address), account);
10996
- }
10997
- _collection(address, account) {
10998
- return newContract(IPTicketCollectionABI, normalizeAddress("STARKNET", address), account);
10999
- }
11000
- async deployCollection(account, params) {
11001
- const call = this._factory(account, params.factoryAddress).populate("deploy_collection", [
11002
- params.name,
11003
- params.symbol,
11004
- params.baseUri
11005
- ]);
11006
- const res = await account.execute([call]);
11007
- return { txHash: res.transaction_hash };
11008
- }
11009
- async createTicket(account, params) {
11010
- const startTime = params.startTime != null ? new CairoOption(CairoOptionVariant.Some, params.startTime) : new CairoOption(CairoOptionVariant.None);
11011
- const endTime = params.endTime != null ? new CairoOption(CairoOptionVariant.Some, params.endTime) : new CairoOption(CairoOptionVariant.None);
11012
- const call = this._collection(params.collection, account).populate("create_ticket", [
11013
- cairo.uint256(params.maxSupply),
11014
- startTime,
11015
- endTime,
11016
- params.royaltyBps,
11017
- params.metadataUri
11018
- ]);
11019
- const res = await account.execute([call]);
11020
- return { txHash: res.transaction_hash };
11021
- }
11022
- async mint(account, params) {
11023
- const call = this._collection(params.collection, account).populate("mint", [
11024
- params.to,
11025
- cairo.uint256(params.tokenId),
11026
- cairo.uint256(params.amount)
11027
- ]);
11028
- const res = await account.execute([call]);
11029
- return { txHash: res.transaction_hash };
11030
- }
11031
- };
11032
- var ClubService = class {
11033
- constructor(config) {
11034
- this.factoryAddress = getStarknetCoordinates(config.chain).ipClubFactory;
11035
- }
11036
- _factory(account, factoryAddress) {
11037
- const address = factoryAddress ?? this.factoryAddress;
11038
- if (!address) throw new Error("IP-Club factory address not configured for this chain");
11039
- return newContract(IPClubFactoryABI, normalizeAddress("STARKNET", address), account);
11040
- }
11041
- _collection(address, account) {
11042
- return newContract(IPClubCollectionABI, normalizeAddress("STARKNET", address), account);
11043
- }
11044
- async deployCollection(account, params) {
11045
- const call = this._factory(account, params.factoryAddress).populate("deploy_collection", [
11046
- params.name,
11047
- params.symbol,
11048
- params.baseUri
11049
- ]);
11050
- const res = await account.execute([call]);
11051
- return { txHash: res.transaction_hash };
11052
- }
11053
- async createMembership(account, params) {
11054
- const startTime = params.startTime != null ? new CairoOption(CairoOptionVariant.Some, params.startTime) : new CairoOption(CairoOptionVariant.None);
11055
- const endTime = params.endTime != null ? new CairoOption(CairoOptionVariant.Some, params.endTime) : new CairoOption(CairoOptionVariant.None);
11056
- const call = this._collection(params.collection, account).populate("create_membership", [
11057
- cairo.uint256(params.maxSupply),
11058
- startTime,
11059
- endTime,
11060
- params.royaltyBps,
11061
- params.metadataUri
11062
- ]);
11063
- const res = await account.execute([call]);
11064
- return { txHash: res.transaction_hash };
11065
- }
11066
- async mint(account, params) {
11067
- const call = this._collection(params.collection, account).populate("mint", [
11068
- params.to,
11069
- cairo.uint256(params.tokenId),
11070
- cairo.uint256(params.amount)
11071
- ]);
11072
- const res = await account.execute([call]);
11073
- return { txHash: res.transaction_hash };
11074
- }
11075
- };
11076
- var SponsorshipService = class {
11077
- constructor(config) {
11078
- this.sponsorshipAddress = getStarknetCoordinates(config.chain).ipSponsorship;
11079
- }
11080
- _contract(account, address) {
11081
- const resolved = address ?? this.sponsorshipAddress;
11082
- if (!resolved) {
11083
- throw new Error("IP-Sponsorship address not configured for this chain");
11084
- }
11085
- return newContract(IPSponsorshipABI, normalizeAddress("STARKNET", resolved), account);
11086
- }
11087
- async createOffer(account, params) {
11088
- const specificSponsor = params.specificSponsor ? new CairoOption(CairoOptionVariant.Some, params.specificSponsor) : new CairoOption(CairoOptionVariant.None);
11089
- const call = this._contract(account, params.sponsorshipAddress).populate("create_offer", [
11090
- params.nftContract,
11091
- cairo.uint256(params.tokenId),
11092
- cairo.uint256(params.minAmount),
11093
- params.duration,
11094
- params.paymentToken,
11095
- params.licenseTermsUri,
11096
- params.transferable,
11097
- cairo.uint256(params.royaltyBps),
11098
- specificSponsor
11099
- ]);
11100
- const res = await account.execute([call]);
11101
- return { txHash: res.transaction_hash };
11102
- }
11103
- async setOfferOpen(account, params) {
11104
- const call = this._contract(account, params.sponsorshipAddress).populate("set_offer_open", [
11105
- cairo.uint256(params.offerId),
11106
- params.open
11107
- ]);
11108
- const res = await account.execute([call]);
11109
- return { txHash: res.transaction_hash };
11110
- }
11111
- async placeBid(account, params) {
11112
- const sponsorshipAddress = params.sponsorshipAddress ?? this.sponsorshipAddress;
11113
- if (!sponsorshipAddress) {
11114
- throw new Error("IP-Sponsorship address not configured for this chain");
11115
- }
11116
- const amount = cairo.uint256(params.amount);
11117
- const approveCall = {
11118
- contractAddress: params.paymentToken,
11119
- entrypoint: "approve",
11120
- calldata: [normalizeAddress("STARKNET", sponsorshipAddress), amount.low.toString(), amount.high.toString()]
11121
- };
11122
- const bidCall = this._contract(account, sponsorshipAddress).populate("place_bid", [
11123
- cairo.uint256(params.offerId),
11124
- amount
11125
- ]);
11126
- const res = await account.execute([approveCall, bidCall]);
11127
- return { txHash: res.transaction_hash };
11128
- }
11129
- async retractBid(account, params) {
11130
- const call = this._contract(account, params.sponsorshipAddress).populate("retract_bid", [
11131
- cairo.uint256(params.offerId)
11132
- ]);
11133
- const res = await account.execute([call]);
11134
- return { txHash: res.transaction_hash };
11135
- }
11136
- async acceptBid(account, params) {
11137
- const call = this._contract(account, params.sponsorshipAddress).populate("accept_bid", [
11138
- cairo.uint256(params.offerId),
11139
- params.sponsor
11140
- ]);
11141
- const res = await account.execute([call]);
11142
- return { txHash: res.transaction_hash };
11143
- }
11144
- async proposeSponsorship(account, params) {
11145
- const call = this._contract(account, params.sponsorshipAddress).populate("propose_sponsorship", [
11146
- params.nftContract,
11147
- cairo.uint256(params.tokenId),
11148
- cairo.uint256(params.amount),
11149
- params.duration,
11150
- params.validUntil ?? 0,
11151
- params.paymentToken,
11152
- params.licenseTermsUri,
11153
- params.transferable,
11154
- cairo.uint256(params.royaltyBps)
11155
- ]);
11156
- const res = await account.execute([call]);
11157
- return { txHash: res.transaction_hash };
11158
- }
11159
- async withdrawProposal(account, params) {
11160
- const call = this._contract(account, params.sponsorshipAddress).populate("withdraw_proposal", [
11161
- cairo.uint256(params.proposalId)
11162
- ]);
11163
- const res = await account.execute([call]);
11164
- return { txHash: res.transaction_hash };
11165
- }
11166
- async acceptProposal(account, params) {
11167
- const call = this._contract(account, params.sponsorshipAddress).populate("accept_proposal", [
11168
- cairo.uint256(params.proposalId)
11169
- ]);
11170
- const res = await account.execute([call]);
11171
- return { txHash: res.transaction_hash };
11172
- }
11173
- async rejectProposal(account, params) {
11174
- const call = this._contract(account, params.sponsorshipAddress).populate("reject_proposal", [
11175
- cairo.uint256(params.proposalId)
11176
- ]);
11177
- const res = await account.execute([call]);
11178
- return { txHash: res.transaction_hash };
11179
- }
11180
- };
11181
- function createChainProvider(backendUrl, apiKey) {
11182
- return new RpcProvider({
11183
- nodeUrl: `${backendUrl.replace(/\/$/, "")}/v1/rpc`,
11184
- headers: apiKey ? { "x-api-key": apiKey } : {},
11185
- blockIdentifier: "latest"
11186
- });
11187
- }
11188
-
11189
- // src/starknet/client.ts
11190
- var MedialaneClient = class {
11191
- constructor(rawConfig = {}) {
11192
- this.config = resolveConfig(rawConfig);
11193
- this.services = {
11194
- pop: new PopService(this.config),
11195
- drop: new DropService(this.config),
11196
- erc1155Collection: new ERC1155CollectionService(this.config),
11197
- creatorCoin: new CreatorCoinService(this.config),
11198
- ticket: new TicketService(this.config),
11199
- club: new ClubService(this.config),
11200
- sponsorship: new SponsorshipService(this.config)
11201
- };
11202
- if (!this.config.backendUrl) {
11203
- const sentinel = new ApiClient("https://medialane-sdk-no-backend.invalid", this.config.apiKey);
11204
- const apiMethodNames = new Set(
11205
- Object.getOwnPropertyNames(ApiClient.prototype).filter(
11206
- (k) => k !== "constructor" && typeof sentinel[k] === "function"
11207
- )
11208
- );
11209
- this.api = new Proxy(sentinel, {
11210
- get(target, prop, receiver) {
11211
- if (typeof prop === "symbol" || !apiMethodNames.has(prop)) {
11212
- return Reflect.get(target, prop, receiver);
11213
- }
11214
- return () => {
11215
- throw new Error(
11216
- `backendUrl not configured. Pass backendUrl to MedialaneClient to use .api.${String(prop)}()`
11217
- );
11218
- };
11219
- }
11220
- });
11221
- } else {
11222
- this.api = new ApiClient(this.config.backendUrl, this.config.apiKey, this.config.retryOptions, this.config.chain);
11223
- }
11224
- }
11225
- get chain() {
11226
- return this.config.chain;
11227
- }
11228
- get provider() {
11229
- if (!this.config.backendUrl) {
11230
- throw new Error("backendUrl not configured. Pass backendUrl to MedialaneClient to use .provider");
11231
- }
11232
- return this._provider ?? (this._provider = createChainProvider(this.config.backendUrl, this.config.apiKey));
11233
- }
11234
- get marketplaceContract() {
11235
- return this.config.marketplaceContract;
11236
- }
11237
- };
11238
-
11239
- // src/starknet/erc20.ts
11240
- async function erc20Balance(provider, token, holder) {
11241
- const read = (entrypoint) => provider.callContract({ contractAddress: token, entrypoint, calldata: [holder] }, "latest");
11242
- const [low = "0x0", high = "0x0"] = await read("balanceOf").catch(() => read("balance_of"));
11243
- return BigInt(low) + (BigInt(high) << 128n);
11244
- }
11245
- var STARKNET_DOMAIN = [
11246
- { name: "name", type: "shortstring" },
11247
- { name: "version", type: "shortstring" },
11248
- { name: "chainId", type: "shortstring" },
11249
- { name: "revision", type: "shortstring" }
11250
- ];
11251
- var OFFER_ITEM = [
11252
- { name: "item_type", type: "shortstring" },
11253
- { name: "token", type: "ContractAddress" },
11254
- { name: "identifier_or_criteria", type: "felt" },
11255
- { name: "amount", type: "felt" }
11256
- ];
11257
- var CONSIDERATION_ITEM = [
11258
- { name: "item_type", type: "shortstring" },
11259
- { name: "token", type: "ContractAddress" },
11260
- { name: "identifier_or_criteria", type: "felt" },
11261
- { name: "amount", type: "felt" },
11262
- { name: "recipient", type: "ContractAddress" }
11263
- ];
11264
- var ORDER_PARAMETERS = [
11265
- { name: "offerer", type: "ContractAddress" },
11266
- { name: "marketplace", type: "ContractAddress" },
11267
- { name: "offer", type: "OfferItem" },
11268
- { name: "consideration", type: "ConsiderationItem" },
11269
- { name: "royalty_max_bps", type: "felt" },
11270
- { name: "start_time", type: "felt" },
11271
- { name: "end_time", type: "felt" },
11272
- { name: "salt", type: "felt" },
11273
- { name: "counter", type: "felt" }
11274
- ];
11275
- var ORDER_CANCELLATION = [
11276
- { name: "order_hash", type: "felt" },
11277
- { name: "offerer", type: "ContractAddress" }
11278
- ];
11279
- var DOMAIN_VERSION = {
11280
- erc721: "5",
11281
- erc1155: "4"
11282
- };
11283
- function buildDomain(standard, chainId) {
11284
- return {
11285
- name: "Medialane",
11286
- version: DOMAIN_VERSION[standard],
11287
- chainId,
11288
- revision: TypedDataRevision.ACTIVE
11289
- };
11290
- }
11291
- function buildOrderTypedData(message, chainId) {
11292
- return {
11293
- domain: buildDomain("erc721", chainId),
11294
- primaryType: "OrderParameters",
11295
- types: {
11296
- StarknetDomain: STARKNET_DOMAIN,
11297
- OrderParameters: ORDER_PARAMETERS,
11298
- OfferItem: OFFER_ITEM,
11299
- ConsiderationItem: CONSIDERATION_ITEM
11300
- },
11301
- message
11302
- };
11303
- }
11304
- function build1155OrderTypedData(message, chainId) {
11305
- return {
11306
- domain: buildDomain("erc1155", chainId),
11307
- primaryType: "OrderParameters",
11308
- types: {
11309
- StarknetDomain: STARKNET_DOMAIN,
11310
- OrderParameters: ORDER_PARAMETERS,
11311
- OfferItem: OFFER_ITEM,
11312
- ConsiderationItem: CONSIDERATION_ITEM
11313
- },
11314
- message
11315
- };
11316
- }
11317
- function buildCancellationTypedData(message, chainId) {
11318
- return {
11319
- domain: buildDomain("erc721", chainId),
11320
- primaryType: "OrderCancellation",
11321
- types: {
11322
- StarknetDomain: STARKNET_DOMAIN,
11323
- OrderCancellation: ORDER_CANCELLATION
11324
- },
11325
- message
11326
- };
11327
- }
11328
- function build1155CancellationTypedData(message, chainId) {
11329
- return {
11330
- domain: buildDomain("erc1155", chainId),
11331
- primaryType: "OrderCancellation",
11332
- types: {
11333
- StarknetDomain: STARKNET_DOMAIN,
11334
- OrderCancellation: ORDER_CANCELLATION
11335
- },
11336
- message
11337
- };
10502
+ function buildFeeCall(p, cfg) {
10503
+ const fee = feeAmount(p.grossAmount, feeBps(p.surface, cfg));
10504
+ if (fee <= 0n) return null;
10505
+ const u = cairo.uint256(fee.toString());
10506
+ return {
10507
+ contractAddress: p.token,
10508
+ entrypoint: "transfer",
10509
+ calldata: [cfg.fundAddress, u.low.toString(), u.high.toString()]
10510
+ };
11338
10511
  }
11339
10512
 
11340
10513
  // src/starknet/marketplace/build.ts
11341
10514
  function contractFor(cfg) {
11342
- return newContract(IPMarketplaceABI, cfg.marketplaceContract);
10515
+ return newContract(IPMarketplaceABI, cfg.marketplace721Contract);
11343
10516
  }
11344
10517
  function buildListingOrder(i, cfg) {
11345
10518
  const orderParams = {
11346
10519
  offerer: i.offerer,
11347
- marketplace: cfg.marketplaceContract,
10520
+ marketplace: cfg.marketplace721Contract,
11348
10521
  offer: { item_type: "ERC721", token: i.nftContract, identifier_or_criteria: i.tokenId, amount: "1" },
11349
10522
  consideration: {
11350
10523
  item_type: "ERC20",
@@ -11365,7 +10538,7 @@ function buildListingOrder(i, cfg) {
11365
10538
  function buildOfferOrder(i, cfg) {
11366
10539
  const orderParams = {
11367
10540
  offerer: i.offerer,
11368
- marketplace: cfg.marketplaceContract,
10541
+ marketplace: cfg.marketplace721Contract,
11369
10542
  offer: { item_type: "ERC20", token: i.paymentTokenAddress, identifier_or_criteria: "0", amount: i.priceWei },
11370
10543
  consideration: {
11371
10544
  item_type: "ERC721",
@@ -11405,7 +10578,7 @@ function buildFulfillCalls(a, cfg) {
11405
10578
  const approve = {
11406
10579
  contractAddress: a.paymentToken,
11407
10580
  entrypoint: "approve",
11408
- calldata: [cfg.marketplaceContract, u.low.toString(), u.high.toString()]
10581
+ calldata: [cfg.marketplace721Contract, u.low.toString(), u.high.toString()]
11409
10582
  };
11410
10583
  const fulfill = contractFor(cfg).populate("fulfill_order", [a.orderHash]);
11411
10584
  const fee = buildFeeCall(
@@ -11526,15 +10699,15 @@ var StarknetVenue = class {
11526
10699
  }
11527
10700
  async incrementCounter(signer) {
11528
10701
  return signer.execute([
11529
- { contractAddress: this.deps.config.marketplaceContract, entrypoint: "increment_counter", calldata: [] }
10702
+ { contractAddress: this.deps.config.marketplace721Contract, entrypoint: "increment_counter", calldata: [] }
11530
10703
  ]);
11531
10704
  }
11532
10705
  getOrderDetails(orderRef) {
11533
- const marketplace = newContract(IPMarketplaceABI, this.deps.config.marketplaceContract, this.deps.provider);
10706
+ const marketplace = newContract(IPMarketplaceABI, this.deps.config.marketplace721Contract, this.deps.provider);
11534
10707
  return marketplace.get_order_details(orderRef);
11535
10708
  }
11536
10709
  async getCounter(address) {
11537
- return this.readCounter(this.deps.config.marketplaceContract, address);
10710
+ return this.readCounter(this.deps.config.marketplace721Contract, address);
11538
10711
  }
11539
10712
  async fulfillOrder(signer, orderRef, opts) {
11540
10713
  const o = await this.deps.resolveOrder(orderRef);
@@ -11557,7 +10730,7 @@ var StarknetVenue = class {
11557
10730
  const startTime = Math.floor(Date.now() / 1e3) + START_TIME_BUFFER_SECS;
11558
10731
  const endTime = p.endTime && p.endTime > 0 ? p.endTime : startTime + NO_EXPIRY_SECONDS;
11559
10732
  const quantity = p.quantity ?? "1";
11560
- const marketplace = standard === "ERC1155" ? this.deps.config.marketplace1155Contract : this.deps.config.marketplaceContract;
10733
+ const marketplace = standard === "ERC1155" ? this.deps.config.marketplace1155Contract : this.deps.config.marketplace721Contract;
11561
10734
  const counter = String(await this.readCounter(marketplace, signer.address));
11562
10735
  let typedData;
11563
10736
  let buildCalls;
@@ -11619,7 +10792,7 @@ var StarknetVenue = class {
11619
10792
  const approve = {
11620
10793
  contractAddress: nftContract,
11621
10794
  entrypoint: "approve",
11622
- calldata: [this.deps.config.marketplaceContract, id.low.toString(), id.high.toString()]
10795
+ calldata: [this.deps.config.marketplace721Contract, id.low.toString(), id.high.toString()]
11623
10796
  };
11624
10797
  let approved = false;
11625
10798
  try {
@@ -11628,7 +10801,7 @@ var StarknetVenue = class {
11628
10801
  entrypoint: "get_approved",
11629
10802
  calldata: [id.low.toString(), id.high.toString()]
11630
10803
  });
11631
- approved = BigInt(res[0]).toString() === BigInt(this.deps.config.marketplaceContract).toString();
10804
+ approved = BigInt(res[0]).toString() === BigInt(this.deps.config.marketplace721Contract).toString();
11632
10805
  } catch {
11633
10806
  }
11634
10807
  return { approvalNeeded: !approved, approve };
@@ -11817,13 +10990,7 @@ var FundingTransferNotSentError = class extends Error {
11817
10990
  }
11818
10991
  };
11819
10992
  function fundingApiFor(client) {
11820
- return {
11821
- createFunding: (input) => client.createFunding(input),
11822
- getFundingChallenge: (id, payer) => client.getFundingChallenge(id, payer),
11823
- authorizeFunding: (id, input) => client.authorizeFunding(id, input),
11824
- submitFunding: (id, txHash) => client.submitFunding(id, txHash),
11825
- cancelFunding: (id) => client.cancelFunding(id)
11826
- };
10993
+ return client.portal.funding;
11827
10994
  }
11828
10995
  function buildFundingTransferCall(instructions) {
11829
10996
  const amount = BigInt(instructions.amountAtomic);
@@ -11842,32 +11009,32 @@ async function fundWithChainTransfer(api, wallet, options) {
11842
11009
  const maxPolls = options.maxPolls ?? 20;
11843
11010
  step("creating");
11844
11011
  const params = options.amount !== void 0 ? { amount: options.amount } : { amountUsdc: options.amountUsdc };
11845
- const { data: intent } = await api.createFunding({ method: "chain-transfer", params });
11012
+ const intent = await api.create({ method: "chain-transfer", params });
11846
11013
  let txHash;
11847
11014
  let transferStarted = false;
11848
11015
  try {
11849
11016
  step("signing");
11850
- const challenge = await api.getFundingChallenge(intent.id, wallet.address);
11851
- const signature = await wallet.signTypedData(challenge.data.typedData);
11017
+ const challenge = await api.challenge(intent.id, wallet.address);
11018
+ const signature = await wallet.signTypedData(challenge.typedData);
11852
11019
  step("authorizing");
11853
- const authorized = await api.authorizeFunding(intent.id, { payer: wallet.address, signature });
11020
+ const authorized = await api.authorize(intent.id, { payer: wallet.address, signature });
11854
11021
  step("paying");
11855
11022
  transferStarted = true;
11856
- ({ txHash } = await wallet.sendTransfer(buildFundingTransferCall(authorized.data.instructions)));
11023
+ ({ txHash } = await wallet.sendTransfer(buildFundingTransferCall(authorized.instructions)));
11857
11024
  } catch (err) {
11858
11025
  if (!transferStarted || err instanceof FundingTransferNotSentError) {
11859
- await api.cancelFunding(intent.id).catch(() => void 0);
11026
+ await api.cancel(intent.id).catch(() => void 0);
11860
11027
  }
11861
11028
  throw err;
11862
11029
  }
11863
11030
  step("confirming");
11864
11031
  let reason = "waiting for the transfer to confirm";
11865
11032
  for (let attempt = 0; attempt < maxPolls; attempt++) {
11866
- const res = await api.submitFunding(intent.id, txHash);
11867
- if (res.data.status === "SETTLED") {
11868
- return { status: "SETTLED", intentId: intent.id, credited: res.data.credited };
11033
+ const res = await api.submit(intent.id, txHash);
11034
+ if (res.status === "SETTLED") {
11035
+ return { status: "SETTLED", intentId: intent.id, credited: res.credited };
11869
11036
  }
11870
- reason = res.data.reason;
11037
+ reason = res.reason;
11871
11038
  await sleep(pollMs);
11872
11039
  }
11873
11040
  return { status: "PENDING", intentId: intent.id, reason };
@@ -11875,7 +11042,7 @@ async function fundWithChainTransfer(api, wallet, options) {
11875
11042
 
11876
11043
  // src/starknet/services/executeIntent.ts
11877
11044
  async function confirmIntentBestEffort(client, intentId, txHash) {
11878
- await client.api.confirmIntent(intentId, txHash).catch(() => {
11045
+ await client.api.intents.confirm(intentId, txHash).catch(() => {
11879
11046
  });
11880
11047
  }
11881
11048
  var SYNC_TIMEOUT_MS = 2e4;
@@ -11892,8 +11059,8 @@ async function syncTransactionBestEffort(client, txHash, timeoutMs = SYNC_TIMEOU
11892
11059
  });
11893
11060
  const sync = (async () => {
11894
11061
  while (!stopped) {
11895
- const again = await client.api.syncTransaction(txHash).then(
11896
- (res) => res.data?.pending === true,
11062
+ const again = await client.api.intents.syncTransaction(txHash).then(
11063
+ (res) => res?.pending === true,
11897
11064
  readableLater
11898
11065
  );
11899
11066
  if (!again || Date.now() + retryMs >= deadline) return;
@@ -11929,8 +11096,8 @@ async function executeIntent(signer, client, intent, opts = {}) {
11929
11096
  let calls;
11930
11097
  if (intent.requiresSignature) {
11931
11098
  const signature = await signer.signTypedData(intent.typedData);
11932
- const signed = await client.api.submitIntentSignature(intent.id, signature);
11933
- calls = signed.data.calls;
11099
+ const signed = await client.api.intents.submitSignature(intent.id, signature);
11100
+ calls = signed.calls;
11934
11101
  } else {
11935
11102
  calls = intent.calls;
11936
11103
  }
@@ -11965,727 +11132,584 @@ var DEPLOY_EVENTS = {
11965
11132
  var IP_MINTED_SELECTOR = BigInt(hash.getSelectorFromName("IPMinted"));
11966
11133
  var TRANSFER_SELECTOR = BigInt(hash.getSelectorFromName("Transfer"));
11967
11134
  function sameFelt(a, b) {
11968
- if (a === void 0) return false;
11969
- try {
11970
- return BigInt(a) === BigInt(b);
11971
- } catch {
11972
- return false;
11973
- }
11974
- }
11975
- function u2563(low, high) {
11976
- return (BigInt(low ?? 0) + (BigInt(high ?? 0) << 128n)).toString();
11977
- }
11978
- function deployedCollectionFromReceipt(receipt, service) {
11979
- const factory = getService(service)?.onchain?.STARKNET?.factoryAddress;
11980
- const { event, address } = DEPLOY_EVENTS[service];
11981
- const selector = BigInt(hash.getSelectorFromName(event));
11982
- for (const e of receipt.events ?? []) {
11983
- if (factory && !sameFelt(e.from_address, factory)) continue;
11984
- if (!sameFelt(e.keys?.[0], selector)) continue;
11985
- const value = address(e);
11986
- if (value) return normalizeAddress("STARKNET", value);
11987
- }
11988
- return null;
11989
- }
11990
- function mintedTokenIdFromReceipt(receipt, contract) {
11991
- for (const e of receipt.events ?? []) {
11992
- if (!sameFelt(e.from_address, contract)) continue;
11993
- const keys = e.keys ?? [];
11994
- if (sameFelt(keys[0], IP_MINTED_SELECTOR) && keys.length >= 3) return u2563(keys[1], keys[2]);
11995
- if (sameFelt(keys[0], TRANSFER_SELECTOR) && keys.length === 5 && sameFelt(keys[1], 0n)) return u2563(keys[3], keys[4]);
11996
- }
11997
- return null;
11998
- }
11999
-
12000
- // src/starknet/services/sponsoredExecutor.ts
12001
- var SponsoredCallRejectedError = class extends Error {
12002
- };
12003
- var FALLBACK_FUNDING_FAILURES = /* @__PURE__ */ new Set(["sponsor_unavailable", "credits_exhausted"]);
12004
- function allowsFallbackFunding(code, status, stage) {
12005
- if (code) return FALLBACK_FUNDING_FAILURES.has(code);
12006
- return stage === "build" ? status >= 500 : status === 503;
12007
- }
12008
- async function failureOf(res, fallback) {
12009
- const body = await res.json().catch(() => null);
12010
- return { reason: body?.error || fallback, code: typeof body?.code === "string" ? body.code : void 0 };
12011
- }
12012
- async function executeSponsored(config, signer, request) {
12013
- const doFetch = config.fetchImpl ?? fetch;
12014
- const base = config.proxyUrl.replace(/\/$/, "");
12015
- const headers = { "Content-Type": "application/json", ...config.headers };
12016
- const buildRes = await doFetch(`${base}/build`, {
12017
- method: "POST",
12018
- headers,
12019
- body: JSON.stringify(request)
12020
- });
12021
- if (!buildRes.ok) {
12022
- const { reason, code } = await failureOf(buildRes, "We couldn't prepare this transaction.");
12023
- if (allowsFallbackFunding(code, buildRes.status, "build")) return { status: "unavailable", reason };
12024
- throw new SponsoredCallRejectedError(reason);
12025
- }
12026
- const { typedData } = await buildRes.json();
12027
- const signature = await signer.signTypedData(typedData);
12028
- const executeRes = await doFetch(`${base}/execute`, {
12029
- method: "POST",
12030
- headers,
12031
- body: JSON.stringify({ ...request, typedData, signature })
12032
- });
12033
- if (!executeRes.ok) {
12034
- const { reason, code } = await failureOf(executeRes, "We couldn't submit this transaction.");
12035
- if (allowsFallbackFunding(code, executeRes.status, "execute")) {
12036
- return { status: "unavailable", reason };
12037
- }
12038
- throw new SponsoredCallRejectedError(reason);
12039
- }
12040
- const { transactionHash } = await executeRes.json();
12041
- return { status: "sponsored", transactionHash };
12042
- }
12043
- function encodeByteArray(str) {
12044
- const bytes = new TextEncoder().encode(str);
12045
- const fullChunks = [];
12046
- let i = 0;
12047
- while (i + 31 <= bytes.length) {
12048
- let val = 0n;
12049
- for (const b of bytes.slice(i, i + 31)) {
12050
- val = val << 8n | BigInt(b);
12051
- }
12052
- fullChunks.push(num.toHex(val));
12053
- i += 31;
12054
- }
12055
- const remaining = bytes.slice(i);
12056
- let pendingVal = 0n;
12057
- for (const b of remaining) {
12058
- pendingVal = pendingVal << 8n | BigInt(b);
12059
- }
12060
- return [
12061
- fullChunks.length.toString(),
12062
- ...fullChunks,
12063
- num.toHex(pendingVal),
12064
- remaining.length.toString()
12065
- ];
12066
- }
12067
- var STARK_ORDER = 3618502788666131213697322783095070105526743751716087489154079457884512865583n;
12068
- function deriveOwnerKeyPair(secret, recipientId) {
12069
- const prk = extract(sha256, secret);
12070
- const okm = expand(sha256, prk, new TextEncoder().encode(recipientId), 32);
12071
- let scalar = BigInt("0x" + Buffer.from(okm).toString("hex")) % STARK_ORDER;
12072
- if (scalar === 0n) scalar = 1n;
12073
- const privateKey = num.toHex(scalar);
12074
- const publicKey = ec.starkCurve.getStarkKey(privateKey);
12075
- return { privateKey, publicKey };
12076
- }
12077
- var STARKNET_SIGNER_TYPE = "0x537461726b6e6574205369676e6572";
12078
- var OPTION_NONE = "0x1";
12079
- var SIGNER_STARKNET = "0x0";
12080
- function computeOwnerGuid(ownerPubkey) {
12081
- return hash.computePoseidonHash(STARKNET_SIGNER_TYPE, num.toHex(ownerPubkey));
11135
+ if (a === void 0) return false;
11136
+ try {
11137
+ return BigInt(a) === BigInt(b);
11138
+ } catch {
11139
+ return false;
11140
+ }
12082
11141
  }
12083
- function changeOwners(accountAddress, guidsToRemove, pubkeysToAdd) {
12084
- return {
12085
- contractAddress: accountAddress,
12086
- entrypoint: "change_owners",
12087
- calldata: [
12088
- num.toHex(guidsToRemove.length),
12089
- ...guidsToRemove,
12090
- num.toHex(pubkeysToAdd.length),
12091
- ...pubkeysToAdd.flatMap((p) => [SIGNER_STARKNET, num.toHex(p)]),
12092
- OPTION_NONE
12093
- ]
12094
- };
11142
+ function u256(low, high) {
11143
+ return (BigInt(low ?? 0) + (BigInt(high ?? 0) << 128n)).toString();
12095
11144
  }
12096
- function buildAddOwnerCall(accountAddress, addOwnerPubkey) {
12097
- return changeOwners(accountAddress, [], [addOwnerPubkey]);
11145
+ function deployedCollectionFromReceipt(receipt, service) {
11146
+ const factory = getService(service)?.onchain?.STARKNET?.factoryAddress;
11147
+ const { event, address } = DEPLOY_EVENTS[service];
11148
+ const selector = BigInt(hash.getSelectorFromName(event));
11149
+ for (const e of receipt.events ?? []) {
11150
+ if (factory && !sameFelt(e.from_address, factory)) continue;
11151
+ if (!sameFelt(e.keys?.[0], selector)) continue;
11152
+ const value = address(e);
11153
+ if (value) return normalizeAddress("STARKNET", value);
11154
+ }
11155
+ return null;
12098
11156
  }
12099
- function buildRemoveOwnerCall(accountAddress, removeOwnerPubkey) {
12100
- return changeOwners(accountAddress, [computeOwnerGuid(removeOwnerPubkey)], []);
11157
+ function mintedTokenIdFromReceipt(receipt, contract) {
11158
+ for (const e of receipt.events ?? []) {
11159
+ if (!sameFelt(e.from_address, contract)) continue;
11160
+ const keys = e.keys ?? [];
11161
+ if (sameFelt(keys[0], IP_MINTED_SELECTOR) && keys.length >= 3) return u256(keys[1], keys[2]);
11162
+ if (sameFelt(keys[0], TRANSFER_SELECTOR) && keys.length === 5 && sameFelt(keys[1], 0n)) return u256(keys[3], keys[4]);
11163
+ }
11164
+ return null;
12101
11165
  }
12102
- function buildRemoveOwnerByGuidCall(accountAddress, ownerGuid) {
12103
- return changeOwners(accountAddress, [num.toHex(ownerGuid)], []);
11166
+ var FRAGMENT_KEY = "pop-proof";
11167
+ var toHex = (x) => "0x" + x.toString(16).padStart(64, "0");
11168
+ var poseidon = (xs) => BigInt(hash.computePoseidonHashOnElements(xs.map((x) => "0x" + x.toString(16))));
11169
+ var nodeHash = (a, b) => a < b ? poseidon([a, b]) : poseidon([b, a]);
11170
+ function popLeafHash(address) {
11171
+ return poseidon([poseidon([BigInt(address)])]);
12104
11172
  }
12105
- function buildDeployAccountParams(ownerPubkey, salt = 0) {
11173
+ function merkleTree(leafHashes) {
11174
+ const leaves = [...leafHashes].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
11175
+ const tree = new Array(2 * leaves.length - 1);
11176
+ leaves.forEach((leaf, i) => tree[tree.length - 1 - i] = leaf);
11177
+ for (let i = tree.length - 1 - leaves.length; i >= 0; i--) {
11178
+ tree[i] = nodeHash(tree[2 * i + 1], tree[2 * i + 2]);
11179
+ }
12106
11180
  return {
12107
- classHash: STARKNET_MEDIAWALLET_CLASS_HASH,
12108
- constructorCalldata: ownerConstructorCalldata(ownerPubkey),
12109
- addressSalt: num.toHex(salt),
12110
- contractAddress: computeAccountAddress(ownerPubkey, salt)
11181
+ root: tree[0],
11182
+ proof(leaf) {
11183
+ let i = tree.lastIndexOf(leaf);
11184
+ if (i < tree.length - leaves.length) throw new Error("Not a leaf of this tree");
11185
+ const proof = [];
11186
+ while (i > 0) {
11187
+ proof.push(tree[i % 2 === 1 ? i + 1 : i - 1]);
11188
+ i = Math.floor((i - 1) / 2);
11189
+ }
11190
+ return proof;
11191
+ }
12111
11192
  };
12112
11193
  }
12113
- var norm = (address) => normalizeAddress("STARKNET", address);
12114
- var SIGNER_TYPE_NAMES = ["Starknet", "Secp256k1", "Secp256r1"];
12115
- function encodeFeltArray(items) {
12116
- return [num.toHex(items.length), ...items];
12117
- }
12118
- function encodeStarknetSigner(pubkey) {
12119
- return ["0x0", num.toHex(pubkey)];
12120
- }
12121
- function encodeStarknetSignerArray(pubkeys) {
12122
- return [num.toHex(pubkeys.length), ...pubkeys.flatMap(encodeStarknetSigner)];
11194
+ function buildPopAllowlist(addresses) {
11195
+ const unique = [...new Set(addresses.map((a) => normalizeAddress("STARKNET", a)))];
11196
+ if (unique.length === 0) throw new Error("An allowlist needs at least one address");
11197
+ const leaves = unique.map((address) => ({ address, leaf: popLeafHash(address) }));
11198
+ const tree = merkleTree(leaves.map((l) => l.leaf));
11199
+ const proofs = {};
11200
+ for (const { address, leaf } of leaves) proofs[address] = tree.proof(leaf).map(toHex);
11201
+ return { root: toHex(tree.root), proofs };
12123
11202
  }
12124
- function buildSetFirstGuardianCall(address, guardianPubkey) {
12125
- return {
12126
- contractAddress: norm(address),
12127
- entrypoint: "change_guardians",
12128
- calldata: [...encodeFeltArray([]), ...encodeStarknetSignerArray([guardianPubkey])]
12129
- };
11203
+ function verifyPopProof(root, address, proof) {
11204
+ let computed = popLeafHash(address);
11205
+ for (const sibling of proof) computed = nodeHash(computed, BigInt(sibling));
11206
+ return computed === BigInt(root);
12130
11207
  }
12131
- function buildTriggerEscapeOwnerCall(targetAddress, newOwnerPubkey) {
12132
- return {
12133
- contractAddress: norm(targetAddress),
12134
- entrypoint: "trigger_escape_owner",
12135
- calldata: encodeStarknetSigner(newOwnerPubkey)
12136
- };
11208
+ function encodePopClaimFragment(proof) {
11209
+ return `#${FRAGMENT_KEY}=${proof.join(",")}`;
12137
11210
  }
12138
- function buildCompleteEscapeOwnerCall(targetAddress) {
12139
- return { contractAddress: norm(targetAddress), entrypoint: "escape_owner", calldata: [] };
11211
+ function decodePopClaimFragment(fragment) {
11212
+ const raw = new URLSearchParams(fragment.replace(/^#/, "")).get(FRAGMENT_KEY);
11213
+ if (raw === null) return null;
11214
+ if (raw === "") return [];
11215
+ const parts = raw.split(",");
11216
+ return parts.every((p) => /^0x[0-9a-fA-F]{1,64}$/.test(p)) ? parts : null;
12140
11217
  }
12141
- function buildCancelEscapeCall(address) {
12142
- return { contractAddress: norm(address), entrypoint: "cancel_escape", calldata: [] };
11218
+ function popClaimLinks(origin, collection, list) {
11219
+ const base = `${origin}${collectionHref("STARKNET", collection)}`;
11220
+ return Object.entries(list.proofs).map(([address, proof]) => ({
11221
+ address,
11222
+ url: `${base}${encodePopClaimFragment(proof)}`
11223
+ }));
12143
11224
  }
12144
- function decodeGuardiansInfo(res) {
12145
- const len = Number(res[0]);
12146
- const out = [];
12147
- for (let i = 0; i < len; i++) {
12148
- const base = 1 + i * 3;
12149
- out.push({
12150
- type: SIGNER_TYPE_NAMES[Number(res[base])] ?? "Starknet",
12151
- guid: res[base + 1],
12152
- storedValue: res[base + 2]
12153
- });
12154
- }
12155
- return out;
11225
+ function popClaimLinksCsv(links) {
11226
+ return ["address,claim_link", ...links.map((l) => `${l.address},${l.url}`)].join("\n");
12156
11227
  }
12157
- var ESCAPE_TYPE_NAMES = ["None", "Guardian", "Owner"];
12158
- var ESCAPE_STATUS_NAMES = ["None", "NotReady", "Ready", "Expired"];
12159
- function decodeEscapeAndStatus(res) {
12160
- const readyAt = Number(res[0]);
12161
- const escapeType = ESCAPE_TYPE_NAMES[Number(res[1])] ?? "None";
12162
- const optionTag = Number(res[2]);
12163
- const statusIndex = optionTag === 0 ? 5 : 3;
12164
- const status = ESCAPE_STATUS_NAMES[Number(res[statusIndex])] ?? "None";
12165
- return { readyAt, escapeType, status };
11228
+ async function popClaimInfo(provider, collection) {
11229
+ const contractAddress = normalizeAddress("STARKNET", collection);
11230
+ const [root, end] = await Promise.all([
11231
+ provider.callContract({ contractAddress, entrypoint: "allowlist_root", calldata: [] }),
11232
+ provider.callContract({ contractAddress, entrypoint: "claim_end_time", calldata: [] })
11233
+ ]);
11234
+ return { root: root[0] ?? "0x0", claimEndTime: Number(BigInt(end[0] ?? "0x0")) };
12166
11235
  }
12167
- async function getGuardians(provider, address) {
12168
- const res = await provider.callContract({
12169
- contractAddress: norm(address),
12170
- entrypoint: "get_guardians_info",
12171
- calldata: []
12172
- });
12173
- return decodeGuardiansInfo(res);
11236
+ function popClaimState(input) {
11237
+ const { hasClaimed, proof, wallet, info } = input;
11238
+ if (hasClaimed === true) return "claimed";
11239
+ if (hasClaimed === null || info === null) return "loading";
11240
+ if (BigInt(info.root) === 0n) return "closed";
11241
+ if (info.claimEndTime !== 0 && info.now > info.claimEndTime) return "ended";
11242
+ if (proof === null) return "no-link";
11243
+ if (!wallet || !verifyPopProof(info.root, wallet, proof)) return "wrong-wallet";
11244
+ return "ready";
12174
11245
  }
12175
- async function getOwners(provider, address) {
11246
+ var addr = (a) => normalizeAddress("STARKNET", a);
11247
+ var byteArrayFelts = (s) => CallData.compile([byteArray.byteArrayFromString(s)]);
11248
+ var popCalls = {
11249
+ claim(collection, proof) {
11250
+ return { contractAddress: addr(collection), entrypoint: "claim", calldata: [String(proof.length), ...proof] };
11251
+ },
11252
+ /** An empty `tokenUri` uses the collection's URI. */
11253
+ issue(collection, recipient, tokenUri = "") {
11254
+ return { contractAddress: addr(collection), entrypoint: "issue", calldata: [addr(recipient), ...byteArrayFelts(tokenUri)] };
11255
+ },
11256
+ /** Only the token's holder can burn it. */
11257
+ burn(collection, tokenId) {
11258
+ const id = cairo.uint256(BigInt(tokenId));
11259
+ return { contractAddress: addr(collection), entrypoint: "burn", calldata: [String(id.low), String(id.high)] };
11260
+ },
11261
+ setAllowlistRoot(collection, root) {
11262
+ return { contractAddress: addr(collection), entrypoint: "set_allowlist_root", calldata: [root] };
11263
+ }
11264
+ };
11265
+ async function popHasClaimed(provider, collection, address) {
12176
11266
  const res = await provider.callContract({
12177
- contractAddress: norm(address),
12178
- entrypoint: "get_owners_info",
12179
- calldata: []
11267
+ contractAddress: normalizeAddress("STARKNET", collection),
11268
+ entrypoint: "has_claimed",
11269
+ calldata: [normalizeAddress("STARKNET", address)]
12180
11270
  });
12181
- return decodeGuardiansInfo(res);
11271
+ return BigInt(res[0] ?? "0x0") !== 0n;
12182
11272
  }
12183
- async function getEscape(provider, address) {
12184
- const res = await provider.callContract({
12185
- contractAddress: norm(address),
12186
- entrypoint: "get_escape_and_status",
12187
- calldata: []
12188
- });
12189
- return decodeEscapeAndStatus(res);
11273
+ var DROP_MAX_CLAIM_QUANTITY = 50n;
11274
+ var addr2 = (a) => normalizeAddress("STARKNET", a);
11275
+ var factoryData = new CallData(DropFactoryABI);
11276
+ var collectionData = new CallData(DropCollectionABI);
11277
+ function toContractTerms(t) {
11278
+ const price = BigInt(t.price);
11279
+ return {
11280
+ start_time: t.startTime,
11281
+ end_time: t.endTime,
11282
+ price: cairo.uint256(price),
11283
+ payment_token: price === 0n ? "0x0" : addr2(t.paymentToken),
11284
+ max_per_wallet: cairo.uint256(BigInt(t.maxPerWallet))
11285
+ };
12190
11286
  }
12191
- async function getEscapeSecurityPeriod(provider, address) {
12192
- const res = await provider.callContract({
12193
- contractAddress: norm(address),
12194
- entrypoint: "get_escape_security_period",
12195
- calldata: []
12196
- });
12197
- return Number(res[0]);
11287
+ var dropCalls = {
11288
+ create(factory, p) {
11289
+ return {
11290
+ contractAddress: addr2(factory),
11291
+ entrypoint: "create_drop",
11292
+ calldata: factoryData.compile("create_drop", {
11293
+ name: p.name,
11294
+ symbol: p.symbol,
11295
+ base_uri: p.baseUri,
11296
+ max_supply: cairo.uint256(BigInt(p.maxSupply)),
11297
+ terms: toContractTerms(p.terms),
11298
+ allowlist_root: p.allowlistRoot ?? "0x0"
11299
+ })
11300
+ };
11301
+ },
11302
+ /** Approve (paid drops) and claim. The platform fee call is added by the caller. */
11303
+ claim(collection, p) {
11304
+ const quantity = BigInt(p.quantity);
11305
+ if (quantity < 1n || quantity > DROP_MAX_CLAIM_QUANTITY) throw new RangeError(`quantity must be 1 to ${DROP_MAX_CLAIM_QUANTITY}`);
11306
+ const total = BigInt(p.price) * quantity;
11307
+ const calls = [];
11308
+ if (total > 0n) {
11309
+ calls.push({
11310
+ contractAddress: addr2(p.paymentToken),
11311
+ entrypoint: "approve",
11312
+ calldata: CallData.compile([addr2(collection), cairo.uint256(total)])
11313
+ });
11314
+ }
11315
+ calls.push({
11316
+ contractAddress: addr2(collection),
11317
+ entrypoint: "claim",
11318
+ calldata: collectionData.compile("claim", { quantity: cairo.uint256(quantity), proof: p.proof ?? [] })
11319
+ });
11320
+ return calls;
11321
+ },
11322
+ /** Organizer only: free mint within the supply cap. */
11323
+ issue(collection, recipient, quantity) {
11324
+ const q = BigInt(quantity);
11325
+ if (q < 1n) throw new RangeError("quantity must be at least 1");
11326
+ return {
11327
+ contractAddress: addr2(collection),
11328
+ entrypoint: "issue",
11329
+ calldata: collectionData.compile("issue", { recipient: addr2(recipient), quantity: cairo.uint256(q) })
11330
+ };
11331
+ },
11332
+ /** Organizer only. 0 opens the drop to everyone. */
11333
+ setAllowlistRoot(collection, root) {
11334
+ return { contractAddress: addr2(collection), entrypoint: "set_allowlist_root", calldata: collectionData.compile("set_allowlist_root", { root }) };
11335
+ }
11336
+ };
11337
+ function dropMintCost(price, quantity, feeBps2) {
11338
+ const subtotal = BigInt(price) * BigInt(quantity);
11339
+ const fee = feeAmount(subtotal, feeBps2);
11340
+ return { subtotal, fee, total: subtotal + fee };
12198
11341
  }
12199
11342
 
12200
- // src/wallet/store.ts
12201
- function createOwnerStore(config) {
12202
- const { storeKey, changeEvent } = config;
12203
- const announce = () => {
12204
- if (typeof window === "undefined") return;
12205
- window.dispatchEvent(new Event(changeEvent));
12206
- };
11343
+ // src/starknet/drop-state.ts
11344
+ var hex = (v) => normalizeAddress("STARKNET", v ?? "0x0");
11345
+ var u2562 = (low, high) => BigInt(low ?? "0x0") + (BigInt(high ?? "0x0") << 128n);
11346
+ async function readDrop(provider, collection) {
11347
+ const contractAddress = hex(collection);
11348
+ const read = (entrypoint) => provider.callContract({ contractAddress, entrypoint, calldata: [] });
11349
+ const [organizer, terms, root, max, minted] = await Promise.all([
11350
+ read("organizer"),
11351
+ read("terms"),
11352
+ read("allowlist_root"),
11353
+ read("max_supply"),
11354
+ read("total_minted")
11355
+ ]);
12207
11356
  return {
12208
- load() {
12209
- if (typeof window === "undefined") return null;
12210
- try {
12211
- const raw = localStorage.getItem(storeKey);
12212
- return raw ? JSON.parse(raw) : null;
12213
- } catch {
12214
- return null;
12215
- }
12216
- },
12217
- loadAddress() {
12218
- return this.load()?.address ?? null;
12219
- },
12220
- save(sealed) {
12221
- const previous = this.load();
12222
- if (previous && previous.address !== sealed.address) {
12223
- localStorage.setItem(`${storeKey}:${previous.address}`, JSON.stringify(previous));
12224
- }
12225
- localStorage.setItem(storeKey, JSON.stringify(sealed));
12226
- announce();
12227
- },
12228
- clear() {
12229
- localStorage.removeItem(storeKey);
12230
- announce();
12231
- },
12232
- notifyChange: announce,
12233
- onChange(listener) {
12234
- window.addEventListener(changeEvent, listener);
12235
- return () => window.removeEventListener(changeEvent, listener);
12236
- }
11357
+ organizer: hex(organizer[0]),
11358
+ startTime: Number(BigInt(terms[0] ?? "0x0")),
11359
+ endTime: Number(BigInt(terms[1] ?? "0x0")),
11360
+ price: u2562(terms[2], terms[3]),
11361
+ paymentToken: hex(terms[4]),
11362
+ maxPerWallet: u2562(terms[5], terms[6]),
11363
+ allowlistRoot: root[0] ?? "0x0",
11364
+ maxSupply: u2562(max[0], max[1]),
11365
+ totalMinted: u2562(minted[0], minted[1])
12237
11366
  };
12238
11367
  }
12239
-
12240
- // src/wallet/pairing.ts
12241
- var SCHEME = "medialane-device";
12242
- var VERSION = 1;
12243
- var LABEL_MAX = 32;
12244
- var STARK_PRIME = (1n << 251n) + 17n * (1n << 192n) + 1n;
12245
- var InvalidPairingPayloadError = class extends Error {
12246
- constructor(message = "This code is not a Medialane device request.") {
12247
- super(message);
12248
- this.name = "InvalidPairingPayloadError";
12249
- }
12250
- };
12251
- function normalisePublicKey(input) {
12252
- if (typeof input !== "string" || !/^0x[0-9a-fA-F]+$/.test(input)) {
12253
- throw new InvalidPairingPayloadError("That device key is not valid.");
11368
+ async function buildDropClaimCalls(provider, collection, input, feeConfig) {
11369
+ const drop = await readDrop(provider, collection);
11370
+ const calls = dropCalls.claim(collection, {
11371
+ quantity: input.quantity,
11372
+ proof: input.proof,
11373
+ price: drop.price,
11374
+ paymentToken: drop.paymentToken
11375
+ });
11376
+ if (drop.price === 0n) return calls;
11377
+ const fee = buildFeeCall(
11378
+ { surface: "launchpad", token: drop.paymentToken, grossAmount: drop.price * BigInt(input.quantity) },
11379
+ feeConfig
11380
+ );
11381
+ return fee ? [...calls, fee] : calls;
11382
+ }
11383
+ async function dropClaimedBy(provider, collection, wallet) {
11384
+ const res = await provider.callContract({ contractAddress: hex(collection), entrypoint: "claimed_by", calldata: [hex(wallet)] });
11385
+ return u2562(res[0], res[1]);
11386
+ }
11387
+ function dropMintState(input) {
11388
+ const none = (state) => ({ state, maxQuantity: 0n });
11389
+ const { drop, wallet, claimed, proof, balance, now } = input;
11390
+ if (!drop) return none("loading");
11391
+ if (drop.startTime !== 0 && now < drop.startTime) return none("upcoming");
11392
+ if (drop.endTime !== 0 && now > drop.endTime) return none("ended");
11393
+ const supplyLeft = drop.maxSupply === 0n ? null : drop.maxSupply - drop.totalMinted;
11394
+ if (supplyLeft !== null && supplyLeft <= 0n) return none("sold-out");
11395
+ if (!wallet) return none("no-wallet");
11396
+ if (BigInt(drop.allowlistRoot) !== 0n) {
11397
+ if (proof === null) return none("no-link");
11398
+ if (!verifyPopProof(drop.allowlistRoot, wallet, proof)) return none("not-on-list");
12254
11399
  }
12255
- const value = BigInt(input);
12256
- if (value === 0n || value >= STARK_PRIME) {
12257
- throw new InvalidPairingPayloadError("That device key is not valid.");
11400
+ if (claimed === null) return none("loading");
11401
+ const walletLeft = drop.maxPerWallet === 0n ? null : drop.maxPerWallet - claimed;
11402
+ if (walletLeft !== null && walletLeft <= 0n) return none("limit-reached");
11403
+ let max = DROP_MAX_CLAIM_QUANTITY;
11404
+ if (supplyLeft !== null && supplyLeft < max) max = supplyLeft;
11405
+ if (walletLeft !== null && walletLeft < max) max = walletLeft;
11406
+ if (drop.price > 0n) {
11407
+ if (balance === null) return none("loading");
11408
+ while (max > 0n && dropMintCost(drop.price, max, input.feeBps).total > balance) max--;
11409
+ if (max === 0n) return none("insufficient-balance");
12258
11410
  }
12259
- return `0x${value.toString(16)}`;
12260
- }
12261
- function sanitiseLabel(input) {
12262
- const raw = typeof input === "string" ? input : "";
12263
- return raw.replace(/\s+/g, " ").trim().slice(0, LABEL_MAX);
12264
- }
12265
- function encodePairingPayload(payload) {
12266
- return JSON.stringify({
12267
- scheme: SCHEME,
12268
- version: VERSION,
12269
- publicKey: normalisePublicKey(payload.publicKey),
12270
- label: sanitiseLabel(payload.label)
12271
- });
11411
+ return { state: "ready", maxQuantity: max };
12272
11412
  }
12273
- function parsePairingPayload(encoded) {
12274
- let data;
12275
- try {
12276
- data = JSON.parse(encoded);
12277
- } catch {
12278
- throw new InvalidPairingPayloadError();
12279
- }
12280
- if (data === null || typeof data !== "object") throw new InvalidPairingPayloadError();
12281
- if (data.scheme !== SCHEME || data.version !== VERSION) throw new InvalidPairingPayloadError();
12282
- return {
12283
- publicKey: normalisePublicKey(data.publicKey),
12284
- label: sanitiseLabel(data.label)
12285
- };
11413
+ function dropClaimLinks(origin, collection, list) {
11414
+ const base = `${origin}${dropHref(collection)}`;
11415
+ return Object.entries(list.proofs).map(([address, proof]) => ({
11416
+ address,
11417
+ url: `${base}${encodePopClaimFragment(proof)}`
11418
+ }));
12286
11419
  }
12287
- function parseAccountAddress(input) {
12288
- const trimmed = typeof input === "string" ? input.trim() : "";
12289
- if (!/^0x[0-9a-fA-F]{50,64}$/.test(trimmed)) {
12290
- throw new InvalidPairingPayloadError("That does not look like an account address.");
12291
- }
12292
- if (BigInt(trimmed) === 0n) {
12293
- throw new InvalidPairingPayloadError("That does not look like an account address.");
12294
- }
12295
- return trimmed;
11420
+ function populateCall(abi, contractAddress, entrypoint, args) {
11421
+ return { contractAddress, entrypoint, calldata: new CallData(abi).compile(entrypoint, args) };
12296
11422
  }
12297
-
12298
- // src/wallet/recovery-key.ts
12299
- var PREFIX = "medialane-recovery:v1:";
12300
- var ADDRESS = /^0x[0-9a-fA-F]{1,64}$/;
12301
- var InvalidRecoveryKeyError = class extends Error {
12302
- constructor(message = "This is not a valid recovery key.") {
12303
- super(message);
12304
- this.name = "InvalidRecoveryKeyError";
12305
- }
11423
+ var addr3 = (address) => normalizeAddress("STARKNET", address);
11424
+ var optionOf = (value) => value != null ? new CairoOption(CairoOptionVariant.Some, value) : new CairoOption(CairoOptionVariant.None);
11425
+ var deployCollectionCall = (abi, factory, p) => populateCall(abi, addr3(factory), "deploy_collection", [p.name, p.symbol, p.baseUri]);
11426
+ var popFactoryCalls = {
11427
+ createCollection: (factory, p) => populateCall(POPFactoryABI, factory, "create_collection", [p.name, p.symbol, p.baseUri, p.claimEndTime])
12306
11428
  };
12307
- var canonicalAddress = (address) => `0x${BigInt(address).toString(16).padStart(64, "0")}`;
12308
- function keyPair(privateKey) {
12309
- try {
12310
- return starkKeyPairFromPrivateKey(privateKey);
12311
- } catch {
12312
- throw new InvalidRecoveryKeyError();
12313
- }
11429
+ var ticketCalls = {
11430
+ deployCollection: (factory, p) => deployCollectionCall(IPTicketCollectionFactoryABI, factory, p),
11431
+ createTicket: (p) => populateCall(IPTicketCollectionABI, addr3(p.collection), "create_ticket", [
11432
+ cairo.uint256(p.maxSupply),
11433
+ optionOf(p.startTime),
11434
+ optionOf(p.endTime),
11435
+ p.royaltyBps,
11436
+ p.metadataUri
11437
+ ]),
11438
+ mint: (p) => populateCall(IPTicketCollectionABI, addr3(p.collection), "mint", [
11439
+ p.to,
11440
+ cairo.uint256(p.tokenId),
11441
+ cairo.uint256(p.amount)
11442
+ ])
11443
+ };
11444
+ var clubCalls = {
11445
+ deployCollection: (factory, p) => deployCollectionCall(IPClubFactoryABI, factory, p),
11446
+ createMembership: (p) => populateCall(IPClubCollectionABI, addr3(p.collection), "create_membership", [
11447
+ cairo.uint256(p.maxSupply),
11448
+ optionOf(p.startTime),
11449
+ optionOf(p.endTime),
11450
+ p.royaltyBps,
11451
+ p.metadataUri
11452
+ ]),
11453
+ mint: (p) => populateCall(IPClubCollectionABI, addr3(p.collection), "mint", [
11454
+ p.to,
11455
+ cairo.uint256(p.tokenId),
11456
+ cairo.uint256(p.amount)
11457
+ ])
11458
+ };
11459
+ var sponsorship = (contract, entrypoint, args) => populateCall(IPSponsorshipABI, addr3(contract), entrypoint, args);
11460
+ var sponsorshipCalls = {
11461
+ createOffer: (contract, p) => sponsorship(contract, "create_offer", [
11462
+ p.nftContract,
11463
+ cairo.uint256(p.tokenId),
11464
+ cairo.uint256(p.minAmount),
11465
+ p.duration,
11466
+ p.paymentToken,
11467
+ p.licenseTermsUri,
11468
+ p.transferable,
11469
+ cairo.uint256(p.royaltyBps),
11470
+ p.specificSponsor ? new CairoOption(CairoOptionVariant.Some, p.specificSponsor) : new CairoOption(CairoOptionVariant.None)
11471
+ ]),
11472
+ setOfferOpen: (contract, p) => sponsorship(contract, "set_offer_open", [cairo.uint256(p.offerId), p.open]),
11473
+ placeBid: (contract, p) => {
11474
+ const amount = cairo.uint256(p.amount);
11475
+ return [
11476
+ {
11477
+ contractAddress: p.paymentToken,
11478
+ entrypoint: "approve",
11479
+ calldata: [addr3(contract), amount.low.toString(), amount.high.toString()]
11480
+ },
11481
+ sponsorship(contract, "place_bid", [cairo.uint256(p.offerId), amount])
11482
+ ];
11483
+ },
11484
+ retractBid: (contract, p) => sponsorship(contract, "retract_bid", [cairo.uint256(p.offerId)]),
11485
+ acceptBid: (contract, p) => sponsorship(contract, "accept_bid", [cairo.uint256(p.offerId), p.sponsor]),
11486
+ propose: (contract, p) => sponsorship(contract, "propose_sponsorship", [
11487
+ p.nftContract,
11488
+ cairo.uint256(p.tokenId),
11489
+ cairo.uint256(p.amount),
11490
+ p.duration,
11491
+ p.validUntil ?? 0,
11492
+ p.paymentToken,
11493
+ p.licenseTermsUri,
11494
+ p.transferable,
11495
+ cairo.uint256(p.royaltyBps)
11496
+ ]),
11497
+ withdrawProposal: (contract, p) => sponsorship(contract, "withdraw_proposal", [cairo.uint256(p.proposalId)]),
11498
+ acceptProposal: (contract, p) => sponsorship(contract, "accept_proposal", [cairo.uint256(p.proposalId)]),
11499
+ rejectProposal: (contract, p) => sponsorship(contract, "reject_proposal", [cairo.uint256(p.proposalId)])
11500
+ };
11501
+ var edition = (collection, entrypoint, args) => populateCall(IPCollection1155ABI, addr3(collection), entrypoint, args);
11502
+ var editionCalls = {
11503
+ deployCollection: (factory, p) => deployCollectionCall(IPCollection1155FactoryABI, factory, p),
11504
+ mintEdition: (p) => edition(p.collection, "mint_edition", [p.to, BigInt(p.value), p.tokenUri]),
11505
+ batchMintEdition: (p) => edition(p.collection, "batch_mint_edition", [
11506
+ p.to,
11507
+ p.items.map((i) => BigInt(i.value)),
11508
+ p.items.map((i) => i.tokenUri)
11509
+ ]),
11510
+ addSupply: (p) => edition(p.collection, "add_supply", [p.to, BigInt(p.tokenId), BigInt(p.value)]),
11511
+ setDefaultRoyalty: (p) => edition(p.collection, "set_default_royalty", [p.receiver, BigInt(p.feeNumerator)]),
11512
+ setTokenRoyalty: (p) => edition(p.collection, "set_token_royalty", [BigInt(p.tokenId), p.receiver, BigInt(p.feeNumerator)]),
11513
+ setApprovalForAll: (p) => edition(p.collection, "set_approval_for_all", [p.operator, p.approved])
11514
+ };
11515
+
11516
+ // src/starknet/services/coinLaunchMath.ts
11517
+ var COIN_DECIMALS = 18;
11518
+ var SUGGESTED_DEFAULT_PRICE = 0.01;
11519
+ var MIN_SUPPLY = 1000n;
11520
+ var MAX_SUPPLY = 1000000000000n;
11521
+ var MAX_FELT_BYTES = 31;
11522
+ function byteLen(s) {
11523
+ return new TextEncoder().encode(s).length;
12314
11524
  }
12315
- function encodeRecoveryKey(key) {
12316
- if (!ADDRESS.test(key.walletAddress) || BigInt(key.walletAddress) === 0n) throw new InvalidRecoveryKeyError();
12317
- return `${PREFIX}${canonicalAddress(key.walletAddress)}:${keyPair(key.privateKey).privateKeyHex}`;
11525
+ function validateName(s) {
11526
+ if (!s.trim()) return "Name is required";
11527
+ if (byteLen(s) > MAX_FELT_BYTES) return `Name must be at most ${MAX_FELT_BYTES} bytes`;
11528
+ return null;
12318
11529
  }
12319
- function parseRecoveryKey(input) {
12320
- const trimmed = input.trim();
12321
- if (!trimmed.startsWith(PREFIX)) {
12322
- const { privateKeyHex, publicKeyHex } = keyPair(trimmed);
12323
- return { walletAddress: computeAccountAddress(publicKeyHex, 0), privateKey: privateKeyHex };
12324
- }
12325
- const parts = trimmed.slice(PREFIX.length).split(":");
12326
- const [walletAddress, privateKey] = parts;
12327
- if (parts.length !== 2 || !walletAddress || !privateKey || !ADDRESS.test(walletAddress) || BigInt(walletAddress) === 0n) {
12328
- throw new InvalidRecoveryKeyError();
12329
- }
12330
- return { walletAddress: canonicalAddress(walletAddress), privateKey: keyPair(privateKey).privateKeyHex };
11530
+ function validateSymbol(s) {
11531
+ if (!s.trim()) return "Symbol is required";
11532
+ if (byteLen(s) > MAX_FELT_BYTES) return `Symbol must be at most ${MAX_FELT_BYTES} bytes`;
11533
+ return null;
12331
11534
  }
12332
-
12333
- // src/wallet/guardian-status.ts
12334
- function describeGuardianStatus(guardians) {
12335
- if (guardians.length === 0) return { kind: "none" };
12336
- return { kind: "active", guardian: guardians[0] };
11535
+ function validateSupply(human) {
11536
+ if (!/^\d+$/.test(human.trim())) return "Supply must be a whole number";
11537
+ const v = BigInt(human.trim());
11538
+ if (v < MIN_SUPPLY) return `Supply must be at least ${MIN_SUPPLY.toString()}`;
11539
+ if (v > MAX_SUPPLY) return `Supply must be at most ${MAX_SUPPLY.toString()}`;
11540
+ return null;
12337
11541
  }
12338
- function describeRecoveryAction(escape) {
12339
- if (escape.escapeType !== "Owner") return "none";
12340
- if (escape.status === "Ready") return "complete";
12341
- if (escape.status === "Expired") return "start";
12342
- return "none";
11542
+ function toRaw(human, decimals = COIN_DECIMALS) {
11543
+ return human * 10n ** BigInt(decimals);
12343
11544
  }
12344
- function normalizeWalletAddress(address) {
12345
- return normalizeAddress("STARKNET", address);
11545
+ function teamCoinsRaw(supplyRaw, pct) {
11546
+ const bps = BigInt(Math.round(pct * 100));
11547
+ return supplyRaw * bps / 10000n;
12346
11548
  }
12347
- function isValidStarknetAddress(address) {
12348
- try {
12349
- validateAndParseAddress(address.trim());
12350
- return true;
12351
- } catch {
12352
- return false;
12353
- }
11549
+ var PRICE_SCALE = 1000000000000n;
11550
+ function buybackQuoteRaw(teamCoinsRawValue, price, quoteDecimals) {
11551
+ const priceScaled = BigInt(Math.round(price * Number(PRICE_SCALE)));
11552
+ return teamCoinsRawValue * priceScaled * 10n ** BigInt(quoteDecimals) / (PRICE_SCALE * 10n ** BigInt(COIN_DECIMALS));
12354
11553
  }
12355
- var CONTRACT_NOT_FOUND = 20;
12356
- async function isDeployed(provider, address) {
12357
- try {
12358
- await provider.getClassHashAt(normalizeWalletAddress(address));
12359
- return true;
12360
- } catch (err) {
12361
- if (err?.code === CONTRACT_NOT_FOUND) return false;
12362
- throw err;
12363
- }
11554
+ function fdvHuman(supplyHuman, price) {
11555
+ return supplyHuman * price;
12364
11556
  }
12365
11557
 
12366
- // src/wallet/self-fund-consent.ts
12367
- function createSelfFundConsent(estimateFee) {
12368
- let handler = null;
11558
+ // src/starknet/services/creatorCoin.ts
11559
+ var VALIDATED_EKUBO_PARAMS = {
11560
+ fee: "0xc49ba5e353f7d00000000000000000",
11561
+ tickSpacing: 5982n,
11562
+ startingPrice: { mag: 4600158n, sign: true },
11563
+ bound: 88719042n
11564
+ };
11565
+ var TICK_BASE = 1.000001;
11566
+ function priceToEkuboParams(quoteDecimals, price = SUGGESTED_DEFAULT_PRICE) {
11567
+ const decAdj = 10 ** (COIN_DECIMALS - quoteDecimals);
11568
+ const rawRatio = price / decAdj;
11569
+ const tickSpacing = Number(VALIDATED_EKUBO_PARAMS.tickSpacing);
11570
+ const rawTick = Math.log(rawRatio) / Math.log(TICK_BASE);
11571
+ const roundedTick = Math.trunc(rawTick / tickSpacing) * tickSpacing;
12369
11572
  return {
12370
- registerHandler(next) {
12371
- handler = next;
12372
- },
12373
- async request({ address, calls }) {
12374
- if (!handler) return false;
12375
- const feeEstimate = address && calls ? estimateFee(address, calls).catch(() => null) : Promise.resolve(null);
12376
- return handler(feeEstimate);
12377
- }
11573
+ fee: VALIDATED_EKUBO_PARAMS.fee,
11574
+ tickSpacing: VALIDATED_EKUBO_PARAMS.tickSpacing,
11575
+ startingPrice: { mag: BigInt(Math.abs(roundedTick)), sign: roundedTick < 0 },
11576
+ bound: VALIDATED_EKUBO_PARAMS.bound
12378
11577
  };
12379
11578
  }
12380
- function accountFor(provider, address, privateKeyHex) {
12381
- return new Account({ provider, address, signer: privateKeyHex, cairoVersion: "1" });
12382
- }
12383
- async function estimateSelfFundedFee(provider, address, calls) {
12384
- const account = new Account({ provider, address, signer: "0x1", cairoVersion: "1" });
12385
- const estimate = await account.estimateInvokeFee(calls);
12386
- const balanceRaw = await feeTokenBalance(provider, address, estimate.unit).catch(() => null);
12387
- return { feeRaw: estimate.overall_fee, unit: estimate.unit, balanceRaw };
12388
- }
12389
- async function feeTokenBalance(provider, address, unit) {
12390
- const token = getTokenBySymbol(unit === "FRI" ? "STRK" : "ETH");
12391
- if (!token) throw new Error(`No fee token for unit ${unit}`);
12392
- return erc20Balance(provider, token.address, address);
11579
+ function validatePrice(quoteDecimals, price) {
11580
+ if (!isFinite(price) || price <= 0) return "Price must be a positive number";
11581
+ const decAdj = 10 ** (COIN_DECIMALS - quoteDecimals);
11582
+ const rawRatio = price / decAdj;
11583
+ if (!isFinite(rawRatio) || rawRatio <= 0) return "Price must be a positive number";
11584
+ const rawTick = Math.log(rawRatio) / Math.log(TICK_BASE);
11585
+ if (!isFinite(rawTick)) return "Price is outside the supported range";
11586
+ const bound = Number(VALIDATED_EKUBO_PARAMS.bound);
11587
+ if (Math.abs(rawTick) >= bound) return "Price is outside the supported range";
11588
+ return null;
12393
11589
  }
12394
- function selfFundedExecutor(deps) {
12395
- return {
12396
- async execute({ userAddress, privateKeyHex, calls }) {
12397
- const account = accountFor(deps.provider(), userAddress, privateKeyHex);
12398
- const { transaction_hash } = await account.execute(calls);
12399
- return { transactionHash: transaction_hash };
12400
- }
12401
- };
11590
+ var MAX_TEAM_ALLOCATION_PERCENT = 10;
11591
+ var MAX_HOLDERS_AT_LAUNCH = 10;
11592
+ function u2563(parts, offset = 0) {
11593
+ return BigInt(parts[offset] ?? "0x0") + (BigInt(parts[offset + 1] ?? "0x0") << 128n);
12402
11594
  }
12403
- function sponsoredExecutor(deps) {
12404
- const fallback = deps.fallback ?? selfFundedExecutor(deps);
11595
+ async function getCreatorCoinGuarantees(coinAddress, provider) {
11596
+ const call = (entrypoint) => provider.callContract({ contractAddress: coinAddress, entrypoint, calldata: [] });
11597
+ const [launchedRes, allocRes] = await Promise.all([
11598
+ call("is_launched").catch(() => null),
11599
+ call("get_team_allocation").catch(() => null)
11600
+ ]);
11601
+ if (!launchedRes || !allocRes) return null;
11602
+ const [supplyRes, blockRes, liquidityRes] = await Promise.all([
11603
+ call("total_supply"),
11604
+ call("launched_at_block_number").catch(() => null),
11605
+ call("liquidity_type").catch(() => null)
11606
+ ]);
11607
+ const isLaunched = BigInt(launchedRes[0] ?? "0x0") !== 0n;
11608
+ const totalSupply = u2563(supplyRes);
11609
+ const teamAllocation = u2563(allocRes);
11610
+ const teamAllocationPercent = totalSupply > 0n ? Number(teamAllocation * 10000n / totalSupply) / 100 : null;
11611
+ const launchedAtBlock = isLaunched && blockRes?.[0] != null ? Number(BigInt(blockRes[0])) : null;
11612
+ const liquidityPositionId = liquidityRes && BigInt(liquidityRes[0] ?? "0x1") === 0n && liquidityRes[2] != null ? BigInt(liquidityRes[2]).toString() : null;
12405
11613
  return {
12406
- async execute(input) {
12407
- const { userAddress, privateKeyHex, calls, intentIds } = input;
12408
- if (!intentIds?.length) {
12409
- const consented2 = await deps.consent.request({ address: userAddress, calls });
12410
- if (!consented2) throw new SponsoredCallRejectedError("This action can't be sponsored");
12411
- return fallback.execute(input);
12412
- }
12413
- const result = await executeSponsored(
12414
- { proxyUrl: deps.proxyUrl, fetchImpl: deps.fetchImpl },
12415
- {
12416
- address: userAddress,
12417
- signTypedData: async (data) => signWithPrivateKey(privateKeyHex, typedData.getMessageHash(data, userAddress))
12418
- },
12419
- { intentIds }
12420
- );
12421
- if (result.status === "sponsored") return { transactionHash: result.transactionHash };
12422
- const consented = await deps.consent.request({ address: userAddress, calls });
12423
- if (!consented) throw new SponsoredCallRejectedError(result.reason);
12424
- return fallback.execute(input);
12425
- }
11614
+ isLaunched,
11615
+ launchedAtBlock,
11616
+ totalSupplyRaw: totalSupply.toString(),
11617
+ teamAllocationRaw: teamAllocation.toString(),
11618
+ teamAllocationPercent,
11619
+ liquidityPositionId
12426
11620
  };
12427
11621
  }
12428
- async function describeFailure(res, fallback) {
12429
- const body = await res.json().catch(() => null);
12430
- throw new Error(body?.error || fallback);
12431
- }
12432
- async function deploySponsored(input) {
12433
- const doFetch = input.fetchImpl ?? fetch;
12434
- const base = input.proxyUrl.replace(/\/$/, "");
12435
- const buildRes = await doFetch(`${base}/build`, {
12436
- method: "POST",
12437
- headers: { "Content-Type": "application/json" },
12438
- body: JSON.stringify({
12439
- ownerPubkey: input.ownerPubKey,
12440
- ownerAddress: input.ownerAddress,
12441
- salt: input.salt ?? "0x0"
12442
- })
12443
- });
12444
- if (!buildRes.ok) {
12445
- await describeFailure(buildRes, "We couldn't prepare your wallet deployment. Please try again.");
12446
- }
12447
- const { typedData, deployment, calls } = await buildRes.json();
12448
- const account = new Account({
12449
- provider: input.provider,
12450
- address: input.ownerAddress,
12451
- signer: input.privateKeyHex,
12452
- cairoVersion: "1"
12453
- });
12454
- const signature = stark.signatureToHexArray(await account.signMessage(typedData));
12455
- const executeRes = await doFetch(`${base}/execute`, {
12456
- method: "POST",
12457
- headers: { "Content-Type": "application/json" },
12458
- body: JSON.stringify({ ownerAddress: input.ownerAddress, typedData, signature, deployment, calls })
12459
- });
12460
- if (!executeRes.ok) {
12461
- await describeFailure(executeRes, "We couldn't complete your wallet deployment. Please try again.");
12462
- }
12463
- const { transactionHash } = await executeRes.json();
12464
- return { transactionHash };
12465
- }
12466
- async function deploySelfFunded(input) {
12467
- const classHash = getCoordinates("STARKNET").mediaWalletClassHash;
12468
- if (!classHash) throw new Error("Media Wallet class hash is not configured");
12469
- const account = new Account({
12470
- provider: input.provider,
12471
- address: input.ownerAddress,
12472
- signer: input.privateKeyHex,
12473
- cairoVersion: "1"
12474
- });
12475
- const { transaction_hash } = await account.deployAccount({
12476
- classHash,
12477
- constructorCalldata: ownerConstructorCalldata(input.ownerPubKey),
12478
- addressSalt: 0,
12479
- contractAddress: input.ownerAddress
12480
- });
12481
- return { transactionHash: transaction_hash };
11622
+ var factoryAddress = () => getStarknetCoordinates("STARKNET").creatorCoinFactory;
11623
+ function buildCreateCreatorCoinCall(params) {
11624
+ const salt = params.salt ?? BigInt("0x" + Date.now().toString(16));
11625
+ return populateCall(CreatorCoinFactoryABI, factoryAddress(), "create_creator_coin", [
11626
+ params.owner,
11627
+ params.name,
11628
+ params.symbol,
11629
+ BigInt(params.initialSupply),
11630
+ BigInt(salt)
11631
+ ]);
12482
11632
  }
12483
- async function waitUntilDeployed(provider, address, timeoutMs = 9e4, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
12484
- const deadline = Date.now() + timeoutMs;
12485
- let wait = 1e3;
12486
- for (; ; ) {
12487
- if (await isDeployed(provider, address).catch(() => false)) return;
12488
- if (Date.now() >= deadline) {
12489
- throw new Error(
12490
- "Your wallet was submitted but has not appeared on Starknet yet. Please try again in a moment."
12491
- );
12492
- }
12493
- await sleep(wait);
12494
- wait = Math.min(Math.round(wait * 1.5), 5e3);
11633
+ function buildLaunchOnEkuboCalls(params) {
11634
+ const ek = params.ekubo;
11635
+ const launchParameters = {
11636
+ creator_coin_address: params.creatorCoin,
11637
+ transfer_restriction_delay: params.transferRestrictionDelay ?? 0,
11638
+ max_percentage_buy_launch: params.maxPercentageBuyLaunch ?? 200,
11639
+ quote_address: params.quoteToken,
11640
+ initial_holders: params.initialHolders,
11641
+ initial_holders_amounts: params.initialHoldersAmounts.map((a) => BigInt(a))
11642
+ };
11643
+ const ekuboParameters = {
11644
+ fee: BigInt(ek.fee),
11645
+ tick_spacing: BigInt(ek.tickSpacing),
11646
+ starting_price: { mag: BigInt(ek.startingPrice.mag), sign: ek.startingPrice.sign },
11647
+ bound: BigInt(ek.bound)
11648
+ };
11649
+ const calls = [];
11650
+ if (params.quoteFundAmount !== void 0) {
11651
+ const amt = uint256.bnToUint256(BigInt(params.quoteFundAmount));
11652
+ calls.push({
11653
+ contractAddress: params.quoteToken,
11654
+ entrypoint: "transfer",
11655
+ calldata: [factoryAddress(), amt.low, amt.high]
11656
+ });
12495
11657
  }
11658
+ calls.push(populateCall(CreatorCoinFactoryABI, factoryAddress(), "launch_on_ekubo", [launchParameters, ekuboParameters]));
11659
+ return calls;
12496
11660
  }
12497
- async function deployWallet(deps, wallet) {
12498
- const sponsored = deps.deploySponsoredImpl ?? deploySponsored;
12499
- const selfFunded = deps.deploySelfFundedImpl ?? deploySelfFunded;
12500
- if (deps.deployProxyUrl) {
11661
+ var CREATOR_COIN_CREATED_SELECTOR = hash.getSelectorFromName("CreatorCoinCreated");
11662
+ function parseCreatorCoinCreated(receipt) {
11663
+ const factory = normalizeAddress("STARKNET", getStarknetCoordinates("STARKNET").creatorCoinFactory);
11664
+ for (const ev of receipt?.events ?? []) {
11665
+ let from;
12501
11666
  try {
12502
- await sponsored({
12503
- proxyUrl: deps.deployProxyUrl,
12504
- provider: deps.provider(),
12505
- fetchImpl: deps.fetchImpl,
12506
- ...wallet
12507
- });
12508
- } catch (sponsoredErr) {
12509
- try {
12510
- await selfFunded({ provider: deps.provider(), ...wallet });
12511
- } catch (selfFundedErr) {
12512
- const sponsored2 = sponsoredErr instanceof Error ? sponsoredErr.message : String(sponsoredErr);
12513
- const selfFunded2 = selfFundedErr instanceof Error ? selfFundedErr.message : String(selfFundedErr);
12514
- throw new Error(`Sponsored deploy failed: ${sponsored2}. Self-funded fallback failed: ${selfFunded2}`);
12515
- }
11667
+ from = normalizeAddress("STARKNET", ev.from_address ?? "");
11668
+ } catch {
11669
+ continue;
12516
11670
  }
12517
- } else {
12518
- await selfFunded({ provider: deps.provider(), ...wallet });
12519
- }
12520
- await (deps.waitUntilDeployedImpl ?? waitUntilDeployed)(deps.provider(), wallet.ownerAddress);
12521
- }
12522
- async function completeDeployment(deps, onStep, options = {}) {
12523
- let sealed = options.forceNew ? null : deps.store.load();
12524
- if (sealed && await (deps.isDeployedImpl ?? isDeployed)(deps.provider(), sealed.address).catch(() => false)) {
12525
- sealed = null;
12526
- }
12527
- let privateKeyHex;
12528
- if (!sealed) {
12529
- onStep("creating-passkey");
12530
- const created = await deps.passkey.createOwnerKey();
12531
- sealed = created.sealed;
12532
- privateKeyHex = created.privateKeyHex;
12533
- deps.store.save(sealed);
12534
- } else {
12535
- privateKeyHex = await deps.passkey.unlockOwnerKey(sealed);
11671
+ if (from !== factory) continue;
11672
+ const k0 = ev.keys?.[0];
11673
+ if (!k0 || normalizeAddress("STARKNET", k0) !== normalizeAddress("STARKNET", CREATOR_COIN_CREATED_SELECTOR)) continue;
11674
+ const data = ev.data ?? [];
11675
+ if (data.length < 1) continue;
11676
+ return normalizeAddress("STARKNET", data[data.length - 1]);
12536
11677
  }
12537
- onStep("deploying");
12538
- await deployWallet(deps, { ownerAddress: sealed.address, ownerPubKey: sealed.ownerPubKey, privateKeyHex });
12539
- deps.store.notifyChange();
12540
- return { sealed };
12541
- }
12542
- function createDeploymentCoordinator(execute) {
12543
- let inFlight = null;
12544
- let currentStep = null;
12545
- const listeners = /* @__PURE__ */ new Set();
12546
- return {
12547
- run(onStep, options = {}) {
12548
- if (inFlight) {
12549
- if (options.forceNew) {
12550
- return Promise.reject(new Error("A wallet setup is already in progress."));
12551
- }
12552
- if (currentStep) onStep(currentStep);
12553
- listeners.add(onStep);
12554
- return inFlight.finally(() => listeners.delete(onStep));
12555
- }
12556
- listeners.add(onStep);
12557
- let started;
12558
- try {
12559
- started = execute((step) => {
12560
- currentStep = step;
12561
- for (const listener of listeners) listener(step);
12562
- }, options);
12563
- } catch (err) {
12564
- listeners.clear();
12565
- return Promise.reject(err);
12566
- }
12567
- const run = started.finally(() => {
12568
- inFlight = null;
12569
- currentStep = null;
12570
- listeners.clear();
12571
- });
12572
- inFlight = run;
12573
- return run;
12574
- },
12575
- isDeploying: () => inFlight !== null
12576
- };
12577
- }
12578
-
12579
- // src/wallet/client.ts
12580
- function describeDevices(owners, thisDevicePubkey) {
12581
- const mine = computeOwnerGuid(thisDevicePubkey);
12582
- return owners.map((owner) => ({
12583
- guid: owner.guid,
12584
- type: owner.type,
12585
- isThisDevice: BigInt(owner.guid) === BigInt(mine)
12586
- }));
12587
- }
12588
- function canRemoveDevice(devices, guid) {
12589
- if (devices.length <= 1) return false;
12590
- return devices.some((device) => BigInt(device.guid) === BigInt(guid));
11678
+ throw new Error("Coin deployed but the coin address could not be read from the receipt");
12591
11679
  }
12592
- function createMediaWallet(config) {
12593
- const ttl = config.unlockTtlMs ?? 2e4;
12594
- const deployments = createDeploymentCoordinator((onStep, options) => {
12595
- const deps = {
12596
- store: config.store,
12597
- passkey: config.passkey,
12598
- provider: config.provider,
12599
- deployProxyUrl: config.deployProxyUrl,
12600
- fetchImpl: config.fetchImpl
12601
- };
12602
- return completeDeployment(deps, onStep, options);
12603
- });
12604
- const unlockCache = /* @__PURE__ */ new Map();
12605
- const lock = (address) => {
12606
- const entry = unlockCache.get(address);
12607
- if (!entry) return;
12608
- clearTimeout(entry.timer);
12609
- unlockCache.delete(address);
12610
- };
12611
- const unlockOnce = (sealed) => {
12612
- const existing = unlockCache.get(sealed.address);
12613
- if (existing) return existing.promise;
12614
- const promise = config.passkey.unlockOwnerKey(sealed).catch((err) => {
12615
- lock(sealed.address);
12616
- throw err;
12617
- });
12618
- const timer = setTimeout(() => lock(sealed.address), ttl);
12619
- unlockCache.set(sealed.address, { promise, timer });
12620
- return promise;
12621
- };
12622
- const run = async (sealed, calls, userAddress, intentIds) => {
12623
- const privateKeyHex = await unlockOnce(sealed);
12624
- return config.executor.execute({
12625
- userAddress: userAddress ?? sealed.address,
12626
- privateKeyHex,
12627
- calls,
12628
- intentIds
12629
- });
12630
- };
12631
- const walletIntents = config.walletIntents ?? (async (params) => {
12632
- if (!config.backendUrl) throw new Error("This wallet has no backend url configured");
12633
- const created = await new ApiClient(config.backendUrl).createWalletManageIntent(params);
12634
- return created.data;
11680
+ async function isCreatorCoin(provider, address) {
11681
+ const res = await provider.callContract({
11682
+ contractAddress: factoryAddress(),
11683
+ entrypoint: "is_creator_coin",
11684
+ calldata: [address]
12635
11685
  });
12636
- const manage = async (sealed, params) => {
12637
- const intent = await walletIntents(params);
12638
- const { transactionHash } = await run(sealed, intent.calls, params.owner, [intent.id]);
12639
- return transactionHash;
12640
- };
12641
- return {
12642
- store: config.store,
12643
- passkey: config.passkey,
12644
- lock,
12645
- signerFor(sealed) {
12646
- return {
12647
- address: sealed.address,
12648
- signTypedData: async (data) => {
12649
- const privateKeyHex = await unlockOnce(sealed);
12650
- return signWithPrivateKey(privateKeyHex, typedData.getMessageHash(data, sealed.address));
12651
- },
12652
- execute: async (calls, opts) => {
12653
- const { transactionHash } = await run(sealed, calls, void 0, opts?.intentIds);
12654
- return { txHash: transactionHash };
12655
- }
12656
- };
12657
- },
12658
- run,
12659
- getGuardians: (address) => getGuardians(config.provider(), address),
12660
- getEscape: (address) => getEscape(config.provider(), address),
12661
- getEscapeSecurityPeriod: (address) => getEscapeSecurityPeriod(config.provider(), address),
12662
- getOwners: (address) => getOwners(config.provider(), address),
12663
- async isOwnerOf(accountAddress, devicePubkey) {
12664
- const owners = await getOwners(config.provider(), accountAddress);
12665
- const guid = BigInt(computeOwnerGuid(devicePubkey));
12666
- return owners.some((owner) => BigInt(owner.guid) === guid);
12667
- },
12668
- setFirstGuardian: (sealed, guardianPubkey) => manage(sealed, { owner: sealed.address, action: "set_first_guardian", pubkey: guardianPubkey }),
12669
- triggerEscapeOwner: (guardianSealed, targetAddress, newOwnerPubkey) => manage(guardianSealed, { owner: normalizeWalletAddress(targetAddress), action: "trigger_escape", newOwnerPubkey }),
12670
- completeEscapeOwner: (guardianSealed, targetAddress) => manage(guardianSealed, { owner: normalizeWalletAddress(targetAddress), action: "complete_escape" }),
12671
- cancelEscape: (sealed) => manage(sealed, { owner: sealed.address, action: "cancel_escape" }),
12672
- addDevice: (sealed, devicePubkey) => manage(sealed, { owner: sealed.address, action: "add_owner", pubkey: devicePubkey }),
12673
- removeDevice: (sealed, ownerGuid) => manage(sealed, { owner: sealed.address, action: "remove_owner", ownerGuid }),
12674
- completeDeployment: (onStep, options) => deployments.run(onStep, options),
12675
- isDeploying: () => deployments.isDeploying()
12676
- };
11686
+ return BigInt(res[0] ?? "0x0") === 1n;
12677
11687
  }
12678
-
12679
- // src/session/session-wallet.ts
12680
- async function claimSessionWallet(api, walletAddress, deps) {
12681
- const saved = deps.loadOwner();
12682
- const resuming = saved !== null && normalizeWalletAddress(saved.address) === normalizeWalletAddress(walletAddress);
12683
- const sealed = resuming ? saved : { ...(await deps.createOwnerKey()).sealed, address: walletAddress };
12684
- if (!resuming) deps.saveOwner(sealed);
12685
- const { removeOwnerGuid } = await api.setupWalletKey({ newOwnerPubkey: sealed.ownerPubKey });
12686
- if (removeOwnerGuid) await deps.removeOwner(sealed, removeOwnerGuid);
11688
+ function encodeByteArray(str) {
11689
+ const bytes = new TextEncoder().encode(str);
11690
+ const fullChunks = [];
11691
+ let i = 0;
11692
+ while (i + 31 <= bytes.length) {
11693
+ let val = 0n;
11694
+ for (const b of bytes.slice(i, i + 31)) {
11695
+ val = val << 8n | BigInt(b);
11696
+ }
11697
+ fullChunks.push(num.toHex(val));
11698
+ i += 31;
11699
+ }
11700
+ const remaining = bytes.slice(i);
11701
+ let pendingVal = 0n;
11702
+ for (const b of remaining) {
11703
+ pendingVal = pendingVal << 8n | BigInt(b);
11704
+ }
11705
+ return [
11706
+ fullChunks.length.toString(),
11707
+ ...fullChunks,
11708
+ num.toHex(pendingVal),
11709
+ remaining.length.toString()
11710
+ ];
12687
11711
  }
12688
11712
 
12689
- export { MAX_SUPPLY as COIN_MAX_SUPPLY, MIN_SUPPLY as COIN_MIN_SUPPLY, ClubService, CreatorCoinFactoryABI, CreatorCoinService, DROP_MAX_CLAIM_QUANTITY, DropCollectionABI, DropFactoryABI, DropService, ERC1155CollectionService, FundingTransferNotSentError, IPClubCollectionABI, IPClubFactoryABI, IPCollection1155ABI, IPCollection1155FactoryABI, IPCollectionABI, IPGenesisABI, IPMarketplaceABI, IPNftABI, IPSponsorshipABI, IPTicketCollectionABI, IPTicketCollectionFactoryABI, InvalidPairingPayloadError, InvalidRecoveryKeyError, MAX_HOLDERS_AT_LAUNCH, MAX_TEAM_ALLOCATION_PERCENT, Medialane1155ABI, MedialaneClient, MedialaneError, POPCollectionABI, POPFactoryABI, PopService, SUGGESTED_DEFAULT_PRICE, SponsoredCallRejectedError, SponsorshipService, StarknetVenue, TicketService, VALIDATED_EKUBO_PARAMS, accountFor, allowsFallbackFunding, apiKeyConfirmationTypedData, assertTransactionSucceeded, build1155CancellationTypedData, build1155OrderTypedData, buildAddOwnerCall, buildCancelEscapeCall, buildCancellationTypedData, buildCompleteEscapeOwnerCall, buildCreateCreatorCoinCall, buildDeployAccountParams, buildFeeCall, buildFundingTransferCall, buildLaunchOnEkuboCalls, buildOrderTypedData, buildPopAllowlist, buildRemoveOwnerByGuidCall, buildRemoveOwnerCall, buildSetFirstGuardianCall, buildTriggerEscapeOwnerCall, buybackQuoteRaw, canRemoveDevice, claimSessionWallet, toRaw as coinToRaw, completeDeployment, computeOwnerGuid, confirmIntentBestEffort, createChainProvider, createDeploymentCoordinator, createMediaWallet, createOwnerStore, createSelfFundConsent, decodeEscapeAndStatus, decodeGuardiansInfo, decodePopClaimFragment, deploySelfFunded, deploySponsored, deployedCollectionFromReceipt, deriveOwnerKeyPair, describeDevices, describeGuardianStatus, describeRecoveryAction, dropCalls, dropClaimLinks, dropClaimedBy, dropMintCost, dropMintState, encodeByteArray, encodePairingPayload, encodePopClaimFragment, encodeRecoveryKey, erc20Balance, estimateSelfFundedFee, executeIntent, executeIntents, executeSponsored, fdvHuman, feeAmount, feeBps, fundWithChainTransfer, fundingApiFor, getCreatorCoinGuarantees, getEscape, getEscapeSecurityPeriod, getGuardians, getOwners, getSiwsStorageKey, getStoredSiwsToken, isDeployed, isSiwsTokenValid, isValidStarknetAddress, mintedTokenIdFromReceipt, normalizeSiwsSignature, normalizeWalletAddress, parseAccountAddress, parseCreatorCoinCreated, parsePairingPayload, parseRecoveryKey, popCalls, popClaimInfo, popClaimLinks, popClaimLinksCsv, popClaimState, popHasClaimed, priceToEkuboParams, readDrop, requestSiwsToken, selfFundedExecutor, signInWithWallet, sponsoredExecutor, storeSiwsToken, syncTransactionBestEffort, teamCoinsRaw, toContractTerms as toDropContractTerms, validateName as validateCoinName, validateSupply as validateCoinSupply, validateSymbol as validateCoinSymbol, validatePrice, verifyPopProof, waitUntilDeployed };
11713
+ export { MAX_SUPPLY as COIN_MAX_SUPPLY, MIN_SUPPLY as COIN_MIN_SUPPLY, CreatorCoinFactoryABI, DROP_MAX_CLAIM_QUANTITY, DropCollectionABI, DropFactoryABI, FundingTransferNotSentError, IPClubCollectionABI, IPClubFactoryABI, IPCollection1155ABI, IPCollection1155FactoryABI, IPCollectionABI, IPGenesisABI, IPMarketplaceABI, IPNftABI, IPSponsorshipABI, IPTicketCollectionABI, IPTicketCollectionFactoryABI, MAX_HOLDERS_AT_LAUNCH, MAX_TEAM_ALLOCATION_PERCENT, Medialane1155ABI, MedialaneClient, POPCollectionABI, POPFactoryABI, SUGGESTED_DEFAULT_PRICE, StarknetVenue, VALIDATED_EKUBO_PARAMS, apiKeyConfirmationTypedData, assertTransactionSucceeded, build1155CancellationTypedData, build1155OrderTypedData, buildCancellationTypedData, buildCreateCreatorCoinCall, buildDropClaimCalls, buildFeeCall, buildFundingTransferCall, buildLaunchOnEkuboCalls, buildOrderTypedData, buildPopAllowlist, buybackQuoteRaw, clubCalls, toRaw as coinToRaw, confirmIntentBestEffort, createChainProvider, decodePopClaimFragment, deployedCollectionFromReceipt, dropCalls, dropClaimLinks, dropClaimedBy, dropMintCost, dropMintState, editionCalls, encodeByteArray, encodePopClaimFragment, executeIntent, executeIntents, fdvHuman, feeAmount, feeBps, fundWithChainTransfer, fundingApiFor, getCreatorCoinGuarantees, getSiwsStorageKey, getStoredSiwsToken, isCreatorCoin, isSiwsTokenValid, mintedTokenIdFromReceipt, normalizeSiwsSignature, parseCreatorCoinCreated, popCalls, popClaimInfo, popClaimLinks, popClaimLinksCsv, popClaimState, popFactoryCalls, popHasClaimed, populateCall, priceToEkuboParams, readDrop, requestSiwsToken, signInWithWallet, sponsorshipCalls, storeSiwsToken, syncTransactionBestEffort, teamCoinsRaw, ticketCalls, toContractTerms as toDropContractTerms, validateName as validateCoinName, validateSupply as validateCoinSupply, validateSymbol as validateCoinSymbol, validatePrice, verifyPopProof };
12690
11714
  //# sourceMappingURL=index.js.map
12691
11715
  //# sourceMappingURL=index.js.map