@rareprotocol/rare-cli 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -292,7 +292,7 @@ Error: ${message}`);
292
292
 
293
293
  // src/program.ts
294
294
  import { createInterface as createInterface7 } from "readline/promises";
295
- import { Command as Command22 } from "commander";
295
+ import { Command as Command23 } from "commander";
296
296
 
297
297
  // src/commands/configure.ts
298
298
  import { text } from "stream/consumers";
@@ -338,6 +338,7 @@ var contractAddresses = {
338
338
  sepolia: {
339
339
  factory: getAddress("0x3c7526a0975156299ceef369b8ff3c01cc670523"),
340
340
  auction: getAddress("0xC8Edc7049b233641ad3723D6C60019D1c8771612"),
341
+ rareBridge: getAddress("0xdC168291658f6C5F1D0b33E573c4d289DCA9dD08"),
341
342
  sovereignFactory: getAddress("0x46B2850ba7787734F648A6848b5eDE0815C1F8Bf"),
342
343
  lazySovereignFactory: getAddress("0xc5B8Ad9003673a23d005A6448C74d8955a1a38fA"),
343
344
  rareMinter: getAddress("0xd28Dc0B89104d7BBd902F338a0193fF063617ccE"),
@@ -355,6 +356,7 @@ var contractAddresses = {
355
356
  mainnet: {
356
357
  factory: getAddress("0xAe8E375a268Ed6442bEaC66C6254d6De5AeD4aB1"),
357
358
  auction: getAddress("0x6D7c44773C52D396F43c2D511B81aa168E9a7a42"),
359
+ rareBridge: getAddress("0x88135dd0e7a8a2e42272dda89849a997ce2e83f7"),
358
360
  sovereignFactory: getAddress("0xe980ec62378529d95ba446433f4deb6324129c59"),
359
361
  lazySovereignFactory: getAddress("0xba798BD606d86D207ca2751510173532899117a1"),
360
362
  rareMinter: getAddress("0x5fa112EFeD8297bec0010b312208d223E0cE891E"),
@@ -365,19 +367,27 @@ var contractAddresses = {
365
367
  marketplaceSettings: getAddress("0x61DBF87164d33FD3695256DC8Ba74D3B1d304170"),
366
368
  erc20ApprovalManager: getAddress("0xa837a7eAff154Ab837617Cf7250648D3Ec0A4436"),
367
369
  erc721ApprovalManager: getAddress("0x4bb0Deea6d1A30C601338aAB776d394C2AE5c0F8"),
368
- liquidFactory: getAddress("0xbb4341CFd588a098e9aCE1D224178836426c4a8E"),
370
+ liquidFactory: getAddress("0x25f993C222fE5e891128a782A5168f1C78629540"),
369
371
  swapRouter: getAddress("0xEBd58EdA8408d9EA409f2c2bE8898BD9738f3583"),
370
372
  v4Quoter: getAddress("0x52F0E24D1c21C8A0cB1e5a5dD6198556BD9E1203")
371
373
  },
372
374
  base: {
373
375
  factory: getAddress("0xf776204233bfb52ba0ddff24810cbdbf3dbf94dd"),
374
- auction: getAddress("0x51c36ffb05e17ed80ee5c02fa83d7677c5613de2")
376
+ auction: getAddress("0x51c36ffb05e17ed80ee5c02fa83d7677c5613de2"),
377
+ rareBridge: getAddress("0x3b41e21094611d152a08d3691a70837f1a077dae")
375
378
  },
376
379
  "base-sepolia": {
377
380
  factory: getAddress("0x2b181ae0f1aea6fed75591b04991b1a3f9868d51"),
378
- auction: getAddress("0x1f0c946f0ee87acb268d50ede6c9b4d010af65d2")
381
+ auction: getAddress("0x1f0c946f0ee87acb268d50ede6c9b4d010af65d2"),
382
+ rareBridge: getAddress("0xca491bb62A7730E97F500510132C47633DDD0229")
379
383
  }
380
384
  };
385
+ var ccipChainSelectors = {
386
+ mainnet: 5009297550715157269n,
387
+ sepolia: 16015286601757825753n,
388
+ base: 15971525489660198786n,
389
+ "base-sepolia": 10344971235874465080n
390
+ };
381
391
  var canonicalV4Pools = {
382
392
  sepolia: {
383
393
  rareEthPool: {
@@ -527,6 +537,16 @@ function getCanonicalV4Pools(chain) {
527
537
  }
528
538
  return pools;
529
539
  }
540
+ function getRareBridgeAddress(chain) {
541
+ const address = getContractAddresses(chain).rareBridge;
542
+ if (!address) {
543
+ throw new Error(`RareBridge is not configured on "${chain}". Supported RareBridge chains: mainnet, sepolia, base, base-sepolia.`);
544
+ }
545
+ return address;
546
+ }
547
+ function getCcipChainSelector(chain) {
548
+ return ccipChainSelectors[chain];
549
+ }
530
550
  function isSupportedChain(value) {
531
551
  return supportedChains.some((chain) => chain === value);
532
552
  }
@@ -1176,8 +1196,12 @@ import createClient from "openapi-fetch";
1176
1196
 
1177
1197
  // src/data-access/base-url.ts
1178
1198
  var DEFAULT_RARE_API_BASE_URL = "https://api.superrare.com";
1199
+ function normalizeRareApiBaseUrlCandidate(baseUrl) {
1200
+ const trimmedBaseUrl = baseUrl?.trim();
1201
+ return trimmedBaseUrl === "" ? void 0 : trimmedBaseUrl;
1202
+ }
1179
1203
  function resolveRareApiBaseUrl(baseUrl) {
1180
- return process.env.RARE_API_BASE_URL ?? baseUrl ?? DEFAULT_RARE_API_BASE_URL;
1204
+ return normalizeRareApiBaseUrlCandidate(process.env.RARE_API_BASE_URL) ?? normalizeRareApiBaseUrlCandidate(baseUrl) ?? DEFAULT_RARE_API_BASE_URL;
1181
1205
  }
1182
1206
 
1183
1207
  // src/data-access/client.ts
@@ -4418,6 +4442,50 @@ var auctionAbi = [
4418
4442
  ];
4419
4443
 
4420
4444
  // src/sdk/approvals-shell.ts
4445
+ var ApprovalSideEffectError = class extends Error {
4446
+ operation;
4447
+ approvals;
4448
+ constructor(params) {
4449
+ super(
4450
+ `${approvalSummary(params.approvals)} before ${params.operation}, but ${params.operation} did not complete. The approval remains valid; retry the operation or revoke approval if it should not remain active.`,
4451
+ { cause: params.cause }
4452
+ );
4453
+ this.name = "ApprovalSideEffectError";
4454
+ this.operation = params.operation;
4455
+ this.approvals = params.approvals;
4456
+ }
4457
+ };
4458
+ async function runWithApprovalSideEffectAlert(params) {
4459
+ try {
4460
+ return await params.run();
4461
+ } catch (error) {
4462
+ const approvals = params.approvals.filter(hasApprovalTxHash);
4463
+ if (approvals.length === 0) {
4464
+ throw error;
4465
+ }
4466
+ throw new ApprovalSideEffectError({
4467
+ operation: params.operation,
4468
+ approvals,
4469
+ cause: error
4470
+ });
4471
+ }
4472
+ }
4473
+ function hasApprovalTxHash(approval) {
4474
+ return approval.approvalTxHash !== void 0;
4475
+ }
4476
+ function approvalSummary(approvals) {
4477
+ const [approval] = approvals;
4478
+ return approvals.length === 1 && approval !== void 0 ? `Approval transaction ${approval.approvalTxHash} was mined (${approvalDetails(approval)})` : `Approval transactions were mined: ${approvals.map((sideEffect) => `${sideEffect.approvalTxHash} (${approvalDetails(sideEffect)})`).join(", ")}`;
4479
+ }
4480
+ function approvalDetails(approval) {
4481
+ if (approval.type === "erc20" || approval.type === "erc20-reset") {
4482
+ return `${approval.type}; token ${approval.target}; spender ${approval.spender ?? "unknown"}`;
4483
+ }
4484
+ if (approval.type === "minter") {
4485
+ return `minter; collection ${approval.target}; minter ${approval.minter ?? "unknown"}`;
4486
+ }
4487
+ return `nft; contract ${approval.target}; operator ${approval.operator ?? "unknown"}`;
4488
+ }
4421
4489
  var approvalAbi = [
4422
4490
  {
4423
4491
  inputs: [{ name: "owner", type: "address" }, { name: "operator", type: "address" }],
@@ -4570,7 +4638,7 @@ async function toTokenAmount(publicClient, token, value, field) {
4570
4638
  }
4571
4639
  async function ensureTokenAllowance(publicClient, walletClient, account, owner, token, spender, amount) {
4572
4640
  if (isAddressEqual5(token, ETH_ADDRESS) || amount === 0n) {
4573
- return;
4641
+ return void 0;
4574
4642
  }
4575
4643
  const allowance = await publicClient.readContract({
4576
4644
  address: token,
@@ -4579,7 +4647,7 @@ async function ensureTokenAllowance(publicClient, walletClient, account, owner,
4579
4647
  args: [owner, spender]
4580
4648
  });
4581
4649
  if (allowance >= amount) {
4582
- return;
4650
+ return void 0;
4583
4651
  }
4584
4652
  const approveTx = await walletClient.writeContract({
4585
4653
  address: token,
@@ -4589,7 +4657,14 @@ async function ensureTokenAllowance(publicClient, walletClient, account, owner,
4589
4657
  account,
4590
4658
  chain: void 0
4591
4659
  });
4592
- await publicClient.waitForTransactionReceipt({ hash: approveTx });
4660
+ await confirmErc20Approval(publicClient, {
4661
+ approvalTxHash: approveTx,
4662
+ currency: token,
4663
+ accountAddress: owner,
4664
+ spenderAddress: spender,
4665
+ requiredAmount: amount
4666
+ });
4667
+ return approveTx;
4593
4668
  }
4594
4669
  var PaymentApprovalRequiredError = class extends Error {
4595
4670
  requiredAmount;
@@ -4662,7 +4737,13 @@ async function preparePaymentAmountForSpender(opts) {
4662
4737
  account,
4663
4738
  chain: void 0
4664
4739
  });
4665
- await publicClient.waitForTransactionReceipt({ hash: approvalTxHash });
4740
+ await confirmErc20Approval(publicClient, {
4741
+ approvalTxHash,
4742
+ currency,
4743
+ accountAddress,
4744
+ spenderAddress,
4745
+ requiredAmount
4746
+ });
4666
4747
  return {
4667
4748
  value: 0n,
4668
4749
  requiredAmount,
@@ -4700,6 +4781,23 @@ async function readAllowance(publicClient, currency, accountAddress, spenderAddr
4700
4781
  args: [accountAddress, spenderAddress]
4701
4782
  });
4702
4783
  }
4784
+ async function confirmErc20Approval(publicClient, params) {
4785
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: params.approvalTxHash });
4786
+ if (receipt.status !== "success") {
4787
+ throw new Error(`ERC20 approval transaction ${params.approvalTxHash} did not succeed.`);
4788
+ }
4789
+ const allowance = await readAllowance(
4790
+ publicClient,
4791
+ params.currency,
4792
+ params.accountAddress,
4793
+ params.spenderAddress
4794
+ );
4795
+ if (allowance < params.requiredAmount) {
4796
+ throw new Error(
4797
+ `ERC20 approval transaction ${params.approvalTxHash} was mined but allowance for spender ${params.spenderAddress} is ${allowance.toString()} raw units, below the required ${params.requiredAmount.toString()} raw units.`
4798
+ );
4799
+ }
4800
+ }
4703
4801
 
4704
4802
  // src/sdk/validation-core.ts
4705
4803
  import { isHex } from "viem";
@@ -5133,6 +5231,11 @@ function createAuctionNamespace(publicClient, config, chain, addresses) {
5133
5231
  accountAddress,
5134
5232
  currentUnixTimestamp()
5135
5233
  );
5234
+ const auctionType = await publicClient.readContract({
5235
+ address: addresses.auction,
5236
+ abi: auctionAbi,
5237
+ functionName: plan.auctionType === "scheduled" ? "SCHEDULED_AUCTION" : "COLDIE_AUCTION"
5238
+ });
5136
5239
  const approvalTxHash = await approveNftContractIfNeeded({
5137
5240
  publicClient,
5138
5241
  walletClient,
@@ -5142,30 +5245,37 @@ function createAuctionNamespace(publicClient, config, chain, addresses) {
5142
5245
  operator: addresses.auction,
5143
5246
  autoApprove: params.autoApprove
5144
5247
  });
5145
- const auctionType = await publicClient.readContract({
5146
- address: addresses.auction,
5147
- abi: auctionAbi,
5148
- functionName: plan.auctionType === "scheduled" ? "SCHEDULED_AUCTION" : "COLDIE_AUCTION"
5149
- });
5150
- const txHash = await walletClient.writeContract({
5151
- address: addresses.auction,
5152
- abi: auctionAbi,
5153
- functionName: "configureAuction",
5154
- args: [
5155
- auctionType,
5156
- plan.nftAddress,
5157
- plan.tokenId,
5158
- plan.startingPrice,
5159
- plan.currency,
5160
- plan.duration,
5161
- plan.startTime,
5162
- plan.splitAddresses,
5163
- plan.splitRatios
5164
- ],
5165
- account,
5166
- chain: void 0
5248
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
5249
+ operation: "auction create",
5250
+ approvals: [{
5251
+ type: "nft",
5252
+ approvalTxHash,
5253
+ target: plan.nftAddress,
5254
+ operator: addresses.auction
5255
+ }],
5256
+ run: async () => {
5257
+ const targetTxHash = await walletClient.writeContract({
5258
+ address: addresses.auction,
5259
+ abi: auctionAbi,
5260
+ functionName: "configureAuction",
5261
+ args: [
5262
+ auctionType,
5263
+ plan.nftAddress,
5264
+ plan.tokenId,
5265
+ plan.startingPrice,
5266
+ plan.currency,
5267
+ plan.duration,
5268
+ plan.startTime,
5269
+ plan.splitAddresses,
5270
+ plan.splitRatios
5271
+ ],
5272
+ account,
5273
+ chain: void 0
5274
+ });
5275
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5276
+ return { txHash: targetTxHash, receipt: targetReceipt };
5277
+ }
5167
5278
  });
5168
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5169
5279
  return {
5170
5280
  txHash,
5171
5281
  receipt,
@@ -5191,22 +5301,34 @@ function createAuctionNamespace(publicClient, config, chain, addresses) {
5191
5301
  amount: plan.amount,
5192
5302
  autoApprove: params.autoApprove
5193
5303
  });
5194
- const txHash = await walletClient.writeContract({
5195
- address: addresses.auction,
5196
- abi: auctionAbi,
5197
- functionName: "bid",
5198
- args: [params.contract, plan.tokenId, plan.currency, plan.amount],
5199
- account,
5200
- chain: void 0,
5201
- value: payment.value
5304
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
5305
+ operation: "auction bid",
5306
+ approvals: [{
5307
+ type: "erc20",
5308
+ approvalTxHash: payment.approvalTxHash,
5309
+ target: plan.currency,
5310
+ spender: addresses.auction
5311
+ }],
5312
+ run: async () => {
5313
+ const targetTxHash = await walletClient.writeContract({
5314
+ address: addresses.auction,
5315
+ abi: auctionAbi,
5316
+ functionName: "bid",
5317
+ args: [params.contract, plan.tokenId, plan.currency, plan.amount],
5318
+ account,
5319
+ chain: void 0,
5320
+ value: payment.value
5321
+ });
5322
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5323
+ return { txHash: targetTxHash, receipt: targetReceipt };
5324
+ }
5202
5325
  });
5203
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5204
5326
  return { txHash, receipt, approvalTxHash: payment.approvalTxHash };
5205
5327
  },
5206
5328
  async settle(params) {
5207
5329
  const { walletClient, account } = requireWallet(config);
5208
5330
  const plan = planAuctionTokenAction(params);
5209
- const txHash = await walletClient.writeContract({
5331
+ const targetTxHash = await walletClient.writeContract({
5210
5332
  address: addresses.auction,
5211
5333
  abi: auctionAbi,
5212
5334
  functionName: "settleAuction",
@@ -5214,13 +5336,13 @@ function createAuctionNamespace(publicClient, config, chain, addresses) {
5214
5336
  account,
5215
5337
  chain: void 0
5216
5338
  });
5217
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5218
- return { txHash, receipt };
5339
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5340
+ return { txHash: targetTxHash, receipt: targetReceipt };
5219
5341
  },
5220
5342
  async cancel(params) {
5221
5343
  const { walletClient, account } = requireWallet(config);
5222
5344
  const plan = planAuctionTokenAction(params);
5223
- const txHash = await walletClient.writeContract({
5345
+ const targetTxHash = await walletClient.writeContract({
5224
5346
  address: addresses.auction,
5225
5347
  abi: auctionAbi,
5226
5348
  functionName: "cancelAuction",
@@ -5228,8 +5350,8 @@ function createAuctionNamespace(publicClient, config, chain, addresses) {
5228
5350
  account,
5229
5351
  chain: void 0
5230
5352
  });
5231
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5232
- return { txHash, receipt };
5353
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5354
+ return { txHash: targetTxHash, receipt: targetReceipt };
5233
5355
  },
5234
5356
  async status(params) {
5235
5357
  const plan = planAuctionTokenAction(params);
@@ -5306,23 +5428,35 @@ function createOfferNamespace(publicClient, config, chain, addresses) {
5306
5428
  amount: plan.amount,
5307
5429
  autoApprove: params.autoApprove
5308
5430
  });
5309
- const txHash = await walletClient.writeContract({
5310
- address: addresses.auction,
5311
- abi: auctionAbi,
5312
- functionName: "offer",
5313
- args: [params.contract, plan.tokenId, plan.currency, plan.amount, false],
5314
- account,
5315
- chain: void 0,
5316
- value: payment.value
5431
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
5432
+ operation: "offer create",
5433
+ approvals: [{
5434
+ type: "erc20",
5435
+ approvalTxHash: payment.approvalTxHash,
5436
+ target: plan.currency,
5437
+ spender: addresses.auction
5438
+ }],
5439
+ run: async () => {
5440
+ const targetTxHash = await walletClient.writeContract({
5441
+ address: addresses.auction,
5442
+ abi: auctionAbi,
5443
+ functionName: "offer",
5444
+ args: [params.contract, plan.tokenId, plan.currency, plan.amount, false],
5445
+ account,
5446
+ chain: void 0,
5447
+ value: payment.value
5448
+ });
5449
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5450
+ return { txHash: targetTxHash, receipt: targetReceipt };
5451
+ }
5317
5452
  });
5318
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5319
5453
  return { txHash, receipt, approvalTxHash: payment.approvalTxHash };
5320
5454
  },
5321
5455
  async cancel(params) {
5322
5456
  const { walletClient, account } = requireWallet(config);
5323
5457
  const currency = params.currency === void 0 ? ETH_ADDRESS : resolveCurrencyForSdk(params.currency, chain).address;
5324
5458
  const plan = planOfferCancel({ ...params, currency });
5325
- const txHash = await walletClient.writeContract({
5459
+ const targetTxHash = await walletClient.writeContract({
5326
5460
  address: addresses.auction,
5327
5461
  abi: auctionAbi,
5328
5462
  functionName: "cancelOffer",
@@ -5330,8 +5464,8 @@ function createOfferNamespace(publicClient, config, chain, addresses) {
5330
5464
  account,
5331
5465
  chain: void 0
5332
5466
  });
5333
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5334
- return { txHash, receipt };
5467
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5468
+ return { txHash: targetTxHash, receipt: targetReceipt };
5335
5469
  },
5336
5470
  async accept(params) {
5337
5471
  const { walletClient, account, accountAddress } = requireWallet(config);
@@ -5348,22 +5482,34 @@ function createOfferNamespace(publicClient, config, chain, addresses) {
5348
5482
  operator: addresses.auction,
5349
5483
  autoApprove: params.autoApprove
5350
5484
  });
5351
- const txHash = await walletClient.writeContract({
5352
- address: addresses.auction,
5353
- abi: auctionAbi,
5354
- functionName: "acceptOffer",
5355
- args: [
5356
- params.contract,
5357
- plan.tokenId,
5358
- plan.currency,
5359
- plan.amount,
5360
- plan.splitAddresses,
5361
- plan.splitRatios
5362
- ],
5363
- account,
5364
- chain: void 0
5485
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
5486
+ operation: "offer accept",
5487
+ approvals: [{
5488
+ type: "nft",
5489
+ approvalTxHash,
5490
+ target: params.contract,
5491
+ operator: addresses.auction
5492
+ }],
5493
+ run: async () => {
5494
+ const targetTxHash = await walletClient.writeContract({
5495
+ address: addresses.auction,
5496
+ abi: auctionAbi,
5497
+ functionName: "acceptOffer",
5498
+ args: [
5499
+ params.contract,
5500
+ plan.tokenId,
5501
+ plan.currency,
5502
+ plan.amount,
5503
+ plan.splitAddresses,
5504
+ plan.splitRatios
5505
+ ],
5506
+ account,
5507
+ chain: void 0
5508
+ });
5509
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5510
+ return { txHash: targetTxHash, receipt: targetReceipt };
5511
+ }
5365
5512
  });
5366
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5367
5513
  return { txHash, receipt, approvalTxHash };
5368
5514
  },
5369
5515
  async status(params) {
@@ -5428,29 +5574,41 @@ function createListingNamespace(publicClient, config, chain, addresses) {
5428
5574
  operator: addresses.auction,
5429
5575
  autoApprove: params.autoApprove
5430
5576
  });
5431
- const txHash = await walletClient.writeContract({
5432
- address: addresses.auction,
5433
- abi: auctionAbi,
5434
- functionName: "setSalePrice",
5435
- args: [
5436
- plan.nftAddress,
5437
- plan.tokenId,
5438
- plan.currency,
5439
- plan.price,
5440
- plan.target,
5441
- plan.splitAddresses,
5442
- plan.splitRatios
5443
- ],
5444
- account,
5445
- chain: void 0
5577
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
5578
+ operation: "listing create",
5579
+ approvals: [{
5580
+ type: "nft",
5581
+ approvalTxHash,
5582
+ target: plan.nftAddress,
5583
+ operator: addresses.auction
5584
+ }],
5585
+ run: async () => {
5586
+ const targetTxHash = await walletClient.writeContract({
5587
+ address: addresses.auction,
5588
+ abi: auctionAbi,
5589
+ functionName: "setSalePrice",
5590
+ args: [
5591
+ plan.nftAddress,
5592
+ plan.tokenId,
5593
+ plan.currency,
5594
+ plan.price,
5595
+ plan.target,
5596
+ plan.splitAddresses,
5597
+ plan.splitRatios
5598
+ ],
5599
+ account,
5600
+ chain: void 0
5601
+ });
5602
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5603
+ return { txHash: targetTxHash, receipt: targetReceipt };
5604
+ }
5446
5605
  });
5447
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5448
5606
  return { txHash, receipt, approvalTxHash };
5449
5607
  },
5450
5608
  async cancel(params) {
5451
5609
  const { walletClient, account } = requireWallet(config);
5452
5610
  const plan = planListingCancel(params);
5453
- const txHash = await walletClient.writeContract({
5611
+ const targetTxHash = await walletClient.writeContract({
5454
5612
  address: addresses.auction,
5455
5613
  abi: auctionAbi,
5456
5614
  functionName: "removeSalePrice",
@@ -5458,8 +5616,8 @@ function createListingNamespace(publicClient, config, chain, addresses) {
5458
5616
  account,
5459
5617
  chain: void 0
5460
5618
  });
5461
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5462
- return { txHash, receipt };
5619
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5620
+ return { txHash: targetTxHash, receipt: targetReceipt };
5463
5621
  },
5464
5622
  async buy(params) {
5465
5623
  const { walletClient, account, accountAddress } = requireWallet(config);
@@ -5478,16 +5636,28 @@ function createListingNamespace(publicClient, config, chain, addresses) {
5478
5636
  amount: plan.amount,
5479
5637
  autoApprove: params.autoApprove
5480
5638
  });
5481
- const txHash = await walletClient.writeContract({
5482
- address: addresses.auction,
5483
- abi: auctionAbi,
5484
- functionName: "buy",
5485
- args: [params.contract, plan.tokenId, plan.currency, plan.amount],
5486
- account,
5487
- chain: void 0,
5488
- value: payment.value
5639
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
5640
+ operation: "listing buy",
5641
+ approvals: [{
5642
+ type: "erc20",
5643
+ approvalTxHash: payment.approvalTxHash,
5644
+ target: plan.currency,
5645
+ spender: addresses.auction
5646
+ }],
5647
+ run: async () => {
5648
+ const targetTxHash = await walletClient.writeContract({
5649
+ address: addresses.auction,
5650
+ abi: auctionAbi,
5651
+ functionName: "buy",
5652
+ args: [params.contract, plan.tokenId, plan.currency, plan.amount],
5653
+ account,
5654
+ chain: void 0,
5655
+ value: payment.value
5656
+ });
5657
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
5658
+ return { txHash: targetTxHash, receipt: targetReceipt };
5659
+ }
5489
5660
  });
5490
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5491
5661
  return { txHash, receipt, approvalTxHash: payment.approvalTxHash };
5492
5662
  },
5493
5663
  async status(params) {
@@ -5505,7 +5675,7 @@ function createListingNamespace(publicClient, config, chain, addresses) {
5505
5675
  }
5506
5676
 
5507
5677
  // src/sdk/batch-listing.ts
5508
- import { isAddressEqual as isAddressEqual10 } from "viem";
5678
+ import { isAddressEqual as isAddressEqual11 } from "viem";
5509
5679
 
5510
5680
  // src/contracts/abis/batch-listing.ts
5511
5681
  var batchListingAbi = [
@@ -5763,15 +5933,18 @@ function parseBatchTokenList(params) {
5763
5933
  const rawTokens = format === "json" ? parseJsonBatchTokens(params.content) : parseCsvBatchTokens(params.content);
5764
5934
  return normalizeBatchTokens(rawTokens, params.chainId);
5765
5935
  }
5766
- function parseBatchTokenListArtifact(content) {
5936
+ function parseBatchTokenListArtifact(content, chainIdInput) {
5767
5937
  const parsed = parseJson(content, "batch token artifact");
5768
5938
  if (!isRecord2(parsed)) {
5769
5939
  throw new Error("Batch token artifact must be a JSON object.");
5770
5940
  }
5771
- if (parsed.type !== "rare-batch-token-list") {
5941
+ if (parsed.type !== void 0 && parsed.type !== "rare-batch-token-list") {
5772
5942
  throw new Error('Batch token artifact type must be "rare-batch-token-list".');
5773
5943
  }
5774
- if (parsed.version !== 1) {
5944
+ if (parsed.type === void 0 && !isUntypedBatchTokenListArtifactLike(parsed)) {
5945
+ throw new Error('Batch token artifact type must be "rare-batch-token-list".');
5946
+ }
5947
+ if (parsed.version !== void 0 && parsed.version !== 1) {
5775
5948
  throw new Error("Batch token artifact version must be 1.");
5776
5949
  }
5777
5950
  if (typeof parsed.root !== "string") {
@@ -5780,11 +5953,19 @@ function parseBatchTokenListArtifact(content) {
5780
5953
  if (!Array.isArray(parsed.tokens)) {
5781
5954
  throw new Error("Batch token artifact tokens must be an array.");
5782
5955
  }
5956
+ const parsedChainId = parsed.chainId === void 0 ? void 0 : parseUnknownInteger(parsed.chainId, "artifact chainId");
5957
+ const expectedChainId = chainIdInput === void 0 ? void 0 : normalizeChainId(chainIdInput, "chainId");
5958
+ const artifactChainId = parsedChainId ?? expectedChainId;
5959
+ if (parsedChainId !== void 0 && expectedChainId !== void 0 && normalizeChainId(parsedChainId, "artifact chainId") !== expectedChainId) {
5960
+ throw new Error(
5961
+ `Input chainId ${normalizeChainId(parsedChainId, "artifact chainId")} does not match --chain-id ${expectedChainId}.`
5962
+ );
5963
+ }
5783
5964
  const artifact = buildBatchTokenTreeArtifact({
5784
5965
  content: JSON.stringify(parsed.tokens),
5785
5966
  format: "json",
5786
5967
  sourceName: "batch token artifact tokens",
5787
- chainId: parsed.chainId === void 0 ? void 0 : parseUnknownInteger(parsed.chainId, "artifact chainId")
5968
+ chainId: artifactChainId
5788
5969
  });
5789
5970
  const root = normalizeBytes32(parsed.root, "artifact root");
5790
5971
  if (typeof parsed.count === "number" && parsed.count !== artifact.count) {
@@ -5798,12 +5979,15 @@ function parseBatchTokenListArtifact(content) {
5798
5979
  function parseBatchTokenListArtifactOrBuild(params) {
5799
5980
  if (params.content.trimStart().startsWith("{")) {
5800
5981
  const parsed = parseJson(params.content, "batch token JSON");
5801
- if (isRecord2(parsed) && parsed.type === "rare-batch-token-list") {
5802
- return parseBatchTokenListArtifact(params.content);
5982
+ if (isRecord2(parsed) && (parsed.type === "rare-batch-token-list" || isUntypedBatchTokenListArtifactLike(parsed))) {
5983
+ return parseBatchTokenListArtifact(params.content, params.chainId);
5803
5984
  }
5804
5985
  }
5805
5986
  return buildBatchTokenTreeArtifact(params);
5806
5987
  }
5988
+ function isUntypedBatchTokenListArtifactLike(value) {
5989
+ return typeof value.root === "string" && Array.isArray(value.tokens) && !("currency" in value) && !("amount" in value) && !("splitAddresses" in value) && !("splitRatios" in value);
5990
+ }
5807
5991
  function getBatchTokenProof(params) {
5808
5992
  const contractAddress = normalizeAddressValue(params.contractAddress, "contractAddress");
5809
5993
  const tokenId = normalizeTokenId(params.tokenId, "tokenId");
@@ -6365,91 +6549,377 @@ function uniqueRoots(roots) {
6365
6549
  }
6366
6550
 
6367
6551
  // src/sdk/batch-listing-core.ts
6368
- import { isAddressEqual as isAddressEqual9 } from "viem";
6369
- function uniqueAddresses(addresses) {
6370
- return addresses.reduce(
6371
- (unique, address) => unique.some((existing) => isAddressEqual9(existing, address)) ? unique : [...unique, address],
6372
- []
6373
- );
6552
+ import { isAddressEqual as isAddressEqual10 } from "viem";
6553
+
6554
+ // src/sdk/merkle-core.ts
6555
+ import { Buffer } from "buffer";
6556
+ import { MerkleTree } from "merkletreejs";
6557
+ import {
6558
+ encodePacked as encodePacked2,
6559
+ getAddress as getAddress7,
6560
+ isAddress as isAddress6,
6561
+ isAddressEqual as isAddressEqual9,
6562
+ isHex as isHex3,
6563
+ keccak256 as keccak2562
6564
+ } from "viem";
6565
+ function hexBuffer(hex) {
6566
+ return Buffer.from(hex.startsWith("0x") ? hex.slice(2) : hex, "hex");
6374
6567
  }
6375
- function planBatchListingRootRegistration(artifact, accountAddress) {
6376
- const local = planBatchListingRootRegistrationLocalInputs(artifact);
6377
- if (local !== void 0) {
6378
- return local;
6379
- }
6380
- const splits = planPayoutSplits(void 0, void 0, accountAddress);
6381
- return { splitAddresses: splits.addresses, splitRatios: splits.ratios };
6568
+ function tokenLeaf(contract, tokenId) {
6569
+ const packed = encodePacked2(["address", "uint256"], [contract, tokenId]);
6570
+ return hexBuffer(keccak2562(packed));
6382
6571
  }
6383
- function planBatchListingRootRegistrationLocalInputs(artifact) {
6384
- if (artifact.tokens.length < 2) {
6385
- throw new Error("Root artifact must contain at least two tokens; the batch listing contract rejects empty proofs");
6572
+ function addressLeaf(address) {
6573
+ return hexBuffer(keccak2562(address));
6574
+ }
6575
+ function parseBytes32(value, field) {
6576
+ if (!isHex3(value, { strict: true }) || value.length !== 66) {
6577
+ throw new Error(`${field} must be a 0x-prefixed bytes32 hex string`);
6386
6578
  }
6387
- if (artifact.allowList !== void 0 && artifact.allowList.addresses.length < 2) {
6388
- throw new Error(
6389
- "Allowlist must contain at least two addresses; the batch listing contract rejects empty allowlist proofs"
6390
- );
6579
+ const normalized = value.toLowerCase();
6580
+ if (!isHex3(normalized, { strict: true }) || normalized.length !== 66) {
6581
+ throw new Error(`${field} must be a 0x-prefixed bytes32 hex string`);
6391
6582
  }
6392
- const { splitAddresses, splitRatios } = artifact;
6393
- if (splitAddresses.length === 0 && splitRatios.length === 0) {
6394
- return void 0;
6583
+ return normalized;
6584
+ }
6585
+ function parseBytes32Array(values, field) {
6586
+ return values.map((value, index) => parseBytes32(value, `${field}[${index}]`));
6587
+ }
6588
+ function compareTokenEntries(a, b) {
6589
+ if (!isAddressEqual9(a.contract, b.contract)) {
6590
+ return a.contract.localeCompare(b.contract);
6395
6591
  }
6396
- const splits = planProvidedPayoutSplits(splitAddresses, splitRatios);
6397
- return { splitAddresses: splits.addresses, splitRatios: splits.ratios };
6592
+ return a.tokenId.localeCompare(b.tokenId);
6398
6593
  }
6399
- function shouldResolveBatchListingAllowListProof(params) {
6400
- if (params.allowList === void 0 || params.tokenProof.allowListProof !== void 0) {
6401
- return false;
6594
+ function normalizeTokenEntry(token) {
6595
+ if (!isAddress6(token.contract)) {
6596
+ throw new Error(`Invalid token contract address: ${token.contract}`);
6402
6597
  }
6403
- return params.nowTimestamp === void 0 || params.allowList.endTimestamp > params.nowTimestamp;
6598
+ return {
6599
+ contract: getAddress7(token.contract),
6600
+ tokenId: String(token.tokenId),
6601
+ tokenIdBigInt: toInteger(token.tokenId, "tokenId")
6602
+ };
6404
6603
  }
6405
- function shapeBatchListingStatus(params) {
6406
- const hasListing = params.listingConfig.amount > 0n && params.cancellationNonce === params.listingConfig.nonce;
6604
+ function buildBatchListingTree(tokens) {
6605
+ if (tokens.length < 2) {
6606
+ throw new Error("buildBatchListingTree requires at least two tokens");
6607
+ }
6608
+ const sorted = tokens.map(normalizeTokenEntry).sort(compareTokenEntries);
6609
+ const leaves = sorted.map((token) => tokenLeaf(token.contract, token.tokenIdBigInt));
6610
+ const tree = new MerkleTree(leaves, (data) => hexBuffer(keccak2562(data)), {
6611
+ sortPairs: true
6612
+ });
6407
6613
  return {
6408
- root: params.root,
6409
- seller: params.creator,
6410
- currencyAddress: params.listingConfig.currency,
6411
- amount: params.listingConfig.amount,
6412
- splitRecipients: [...params.listingConfig.splitRecipients],
6413
- splitRatios: [...params.listingConfig.splitRatios],
6414
- nonce: params.listingConfig.nonce,
6415
- isEth: isAddressEqual9(params.listingConfig.currency, ETH_ADDRESS),
6416
- hasListing,
6417
- allowList: params.allowList,
6418
- ...params.tokenStatus
6614
+ root: parseBytes32(tree.getHexRoot(), "root"),
6615
+ tree,
6616
+ sortedTokens: sorted.map(({ contract, tokenId }) => ({ contract, tokenId }))
6419
6617
  };
6420
6618
  }
6421
-
6422
- // src/sdk/batch-listing.ts
6423
- var ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
6424
- function createBatchListingNamespace(publicClient, config, addresses) {
6619
+ function buildAllowListTree(addresses) {
6620
+ if (addresses.length < 2) {
6621
+ throw new Error("buildAllowListTree requires at least two addresses");
6622
+ }
6623
+ const sorted = addresses.map((address) => {
6624
+ if (!isAddress6(address)) throw new Error(`Invalid allowlist address: ${address}`);
6625
+ return getAddress7(address);
6626
+ }).sort((a, b) => a.localeCompare(b));
6627
+ const leaves = sorted.map(addressLeaf);
6628
+ const tree = new MerkleTree(leaves, (data) => hexBuffer(keccak2562(data)), {
6629
+ sortPairs: true
6630
+ });
6425
6631
  return {
6426
- async create(params) {
6427
- const { walletClient, account, accountAddress } = requireWallet(config);
6428
- const artifact = await resolveApiBatchListingRootArtifact(config, params.artifact);
6429
- const splitConfig = planBatchListingRootRegistration(artifact, accountAddress);
6430
- const uniqueContracts = uniqueAddresses(artifact.tokens.map((token) => token.contract));
6431
- for (const token of artifact.tokens.slice(0, 3)) {
6432
- const owner = await publicClient.readContract({
6433
- address: token.contract,
6434
- abi: [
6435
- {
6436
- type: "function",
6437
- name: "ownerOf",
6438
- inputs: [{ name: "tokenId", type: "uint256" }],
6439
- outputs: [{ name: "", type: "address" }],
6440
- stateMutability: "view"
6441
- }
6442
- ],
6443
- functionName: "ownerOf",
6444
- args: [BigInt(token.tokenId)]
6632
+ root: parseBytes32(tree.getHexRoot(), "root"),
6633
+ tree,
6634
+ sortedAddresses: sorted
6635
+ };
6636
+ }
6637
+ function getTokenProof(tree, contract, tokenId) {
6638
+ const leaf = tokenLeaf(getAddress7(contract), tokenId);
6639
+ return parseBytes32Array(tree.getHexProof(leaf), "proof");
6640
+ }
6641
+ function getAddressProof(tree, address) {
6642
+ const leaf = addressLeaf(getAddress7(address));
6643
+ return parseBytes32Array(tree.getHexProof(leaf), "proof");
6644
+ }
6645
+ function buildMerkleProofArtifact(artifact, contract, tokenId, buyer) {
6646
+ const tokenIdBig = toInteger(tokenId, "tokenId");
6647
+ const contractChecksum = getAddress7(contract);
6648
+ const found = artifact.tokens.find(
6649
+ (token) => isAddressEqual9(token.contract, contractChecksum) && BigInt(token.tokenId) === tokenIdBig
6650
+ );
6651
+ if (found === void 0) {
6652
+ throw new Error(
6653
+ `Token ${contractChecksum}/${tokenIdBig.toString()} is not in this root artifact's token set`
6654
+ );
6655
+ }
6656
+ const { tree, root } = buildBatchListingTree(
6657
+ artifact.tokens.map((token) => ({ contract: token.contract, tokenId: token.tokenId }))
6658
+ );
6659
+ const artifactRoot = parseBytes32(artifact.root, "artifact.root");
6660
+ if (root !== artifactRoot) {
6661
+ throw new Error(
6662
+ `Recomputed NFT tree root (${root}) does not match artifact root (${artifact.root}). Artifact is corrupt or tree encoding has drifted.`
6663
+ );
6664
+ }
6665
+ const allowListProofFields = buildAllowListProofFields(artifact, buyer);
6666
+ return {
6667
+ root: artifactRoot,
6668
+ contract: contractChecksum,
6669
+ tokenId: tokenIdBig.toString(),
6670
+ proof: getTokenProof(tree, contractChecksum, tokenIdBig),
6671
+ ...allowListProofFields ?? {}
6672
+ };
6673
+ }
6674
+ function buildAllowListProofFields(artifact, buyer) {
6675
+ if (artifact.allowList === void 0) return void 0;
6676
+ if (buyer === void 0) {
6677
+ throw new Error(
6678
+ "This root has an allowlist; pass buyer address to buildMerkleProofArtifact to include allowListProof"
6679
+ );
6680
+ }
6681
+ if (!isAddress6(buyer)) throw new Error(`Invalid buyer address: ${buyer}`);
6682
+ const buyerChecksum = getAddress7(buyer);
6683
+ const inAllowList = artifact.allowList.addresses.some((address) => isAddressEqual9(address, buyerChecksum));
6684
+ if (!inAllowList) {
6685
+ throw new Error(`Buyer ${buyerChecksum} is not in the allowlist`);
6686
+ }
6687
+ const { tree, root } = buildAllowListTree(artifact.allowList.addresses);
6688
+ const artifactAllowListRoot = parseBytes32(artifact.allowList.root, "allowList.root");
6689
+ if (root !== artifactAllowListRoot) {
6690
+ throw new Error(
6691
+ `Recomputed allowlist root (${root}) does not match artifact (${artifact.allowList.root})`
6692
+ );
6693
+ }
6694
+ return {
6695
+ allowListProof: getAddressProof(tree, buyerChecksum),
6696
+ allowListAddress: buyerChecksum
6697
+ };
6698
+ }
6699
+ function assertRecord(value, field) {
6700
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
6701
+ throw new Error(`${field} must be a JSON object`);
6702
+ }
6703
+ }
6704
+ function assertHexRoot(value, field) {
6705
+ if (typeof value !== "string" || !isHex3(value, { strict: true }) || value.length !== 66) {
6706
+ throw new Error(`${field} must be a 0x-prefixed bytes32 hex string`);
6707
+ }
6708
+ }
6709
+ function assertAddress(value, field) {
6710
+ if (typeof value !== "string" || !isAddress6(value)) {
6711
+ throw new Error(`${field} must be a valid 0x address`);
6712
+ }
6713
+ }
6714
+ function validateRootArtifact(value) {
6715
+ assertRecord(value, "Root artifact");
6716
+ if (isBatchTokenTreeArtifactLike(value)) {
6717
+ throw new Error(
6718
+ "Input looks like a token tree artifact from rare utils tree build, not a batch listing root artifact. For rare listing batch create, pass --price and optionally --currency/--split with the token tree artifact."
6719
+ );
6720
+ }
6721
+ assertHexRoot(value.root, "root");
6722
+ assertAddress(value.currency, "currency");
6723
+ if (typeof value.amount !== "string") throw new Error("amount must be a string (base units)");
6724
+ if (!Array.isArray(value.splitAddresses)) throw new Error("splitAddresses must be an array");
6725
+ if (!Array.isArray(value.splitRatios)) throw new Error("splitRatios must be an array");
6726
+ if (!Array.isArray(value.tokens) || value.tokens.length < 2) {
6727
+ throw new Error("tokens must contain at least two entries");
6728
+ }
6729
+ value.tokens.forEach((token) => {
6730
+ assertRecord(token, "tokens[]");
6731
+ assertAddress(token.contract, "tokens[].contract");
6732
+ if (typeof token.tokenId !== "string") throw new Error("tokens[].tokenId must be a string");
6733
+ });
6734
+ if (value.allowList !== void 0 && value.allowList !== null) {
6735
+ assertRecord(value.allowList, "allowList");
6736
+ assertHexRoot(value.allowList.root, "allowList.root");
6737
+ if (!Array.isArray(value.allowList.addresses)) throw new Error("allowList.addresses must be an array");
6738
+ if (value.allowList.addresses.length < 2) {
6739
+ throw new Error("allowList.addresses must contain at least two entries");
6740
+ }
6741
+ value.allowList.addresses.forEach((address) => {
6742
+ assertAddress(address, "allowList.addresses entry");
6743
+ });
6744
+ }
6745
+ }
6746
+ function isBatchTokenTreeArtifactLike(value) {
6747
+ if (value.type === "rare-batch-token-list") {
6748
+ return true;
6749
+ }
6750
+ return Array.isArray(value.tokens) && !("currency" in value) && !("amount" in value) && !("splitAddresses" in value) && !("splitRatios" in value);
6751
+ }
6752
+ function validateProofArtifact(value) {
6753
+ assertRecord(value, "Proof artifact");
6754
+ assertHexRoot(value.root, "root");
6755
+ assertAddress(value.contract, "contract");
6756
+ if (typeof value.tokenId !== "string") throw new Error("tokenId must be a string");
6757
+ if (!Array.isArray(value.proof)) throw new Error("proof must be an array of bytes32 hex");
6758
+ if (value.proof.length === 0) throw new Error("proof must not be empty");
6759
+ value.proof.forEach((proof) => {
6760
+ assertHexRoot(proof, "proof entry");
6761
+ });
6762
+ if (value.allowListProof !== void 0 && value.allowListProof !== null) {
6763
+ if (!Array.isArray(value.allowListProof)) throw new Error("allowListProof must be an array");
6764
+ value.allowListProof.forEach((proof) => {
6765
+ assertHexRoot(proof, "allowListProof entry");
6766
+ });
6767
+ }
6768
+ if (value.allowListAddress !== void 0 && value.allowListAddress !== null) {
6769
+ assertAddress(value.allowListAddress, "allowListAddress");
6770
+ }
6771
+ }
6772
+
6773
+ // src/sdk/batch-listing-core.ts
6774
+ function uniqueAddresses(addresses) {
6775
+ return addresses.reduce(
6776
+ (unique, address) => unique.some((existing) => isAddressEqual10(existing, address)) ? unique : [...unique, address],
6777
+ []
6778
+ );
6779
+ }
6780
+ function parseBatchListingCreateRootArtifactInput(value) {
6781
+ if (!isRecord3(value)) {
6782
+ validateRootArtifact(value);
6783
+ throw new Error("unreachable: non-object root artifact validation did not throw");
6784
+ }
6785
+ if (isBatchTokenTreeInputObject(value)) {
6786
+ return void 0;
6787
+ }
6788
+ validateRootArtifact(value);
6789
+ return value;
6790
+ }
6791
+ function planBatchListingCreateArtifact(plan) {
6792
+ const splitOverride = planOptionalSplitOverride(plan.splitAddresses, plan.splitRatios);
6793
+ const artifact = plan.kind === "root-artifact" ? planBatchListingCreateRootArtifact(plan, splitOverride) : planBatchListingCreateTokenTreeArtifact(plan, splitOverride);
6794
+ planBatchListingRootRegistrationLocalInputs(artifact);
6795
+ return artifact;
6796
+ }
6797
+ function planBatchListingRootRegistration(artifact, accountAddress) {
6798
+ const local = planBatchListingRootRegistrationLocalInputs(artifact);
6799
+ if (local !== void 0) {
6800
+ return local;
6801
+ }
6802
+ const splits = planPayoutSplits(void 0, void 0, accountAddress);
6803
+ return { splitAddresses: splits.addresses, splitRatios: splits.ratios };
6804
+ }
6805
+ function planBatchListingCreateRootArtifact(plan, splitOverride) {
6806
+ if (plan.currencyOverride !== void 0 && plan.amountOverride === void 0) {
6807
+ throw new Error("--currency requires --price when overriding a batch listing root artifact.");
6808
+ }
6809
+ return {
6810
+ ...plan.artifact,
6811
+ currency: plan.currencyOverride ?? plan.artifact.currency,
6812
+ amount: plan.amountOverride ?? plan.artifact.amount,
6813
+ ...splitOverride === void 0 ? {} : {
6814
+ splitAddresses: splitOverride.addresses,
6815
+ splitRatios: splitOverride.ratios
6816
+ }
6817
+ };
6818
+ }
6819
+ function planBatchListingCreateTokenTreeArtifact(plan, splitOverride) {
6820
+ return {
6821
+ root: plan.artifact.root,
6822
+ currency: plan.currency,
6823
+ amount: plan.amount,
6824
+ splitAddresses: splitOverride?.addresses ?? [],
6825
+ splitRatios: splitOverride?.ratios ?? [],
6826
+ tokens: plan.artifact.tokens.map((token) => ({
6827
+ contract: token.contractAddress,
6828
+ tokenId: token.tokenId
6829
+ }))
6830
+ };
6831
+ }
6832
+ function planOptionalSplitOverride(splitAddresses, splitRatios) {
6833
+ if (splitAddresses === void 0 && splitRatios === void 0) {
6834
+ return void 0;
6835
+ }
6836
+ if (splitAddresses === void 0 || splitRatios === void 0) {
6837
+ throw new Error("splitAddresses and splitRatios must both be provided.");
6838
+ }
6839
+ return planProvidedPayoutSplits(splitAddresses, splitRatios);
6840
+ }
6841
+ function isBatchTokenTreeInputObject(value) {
6842
+ if (value.type === "rare-batch-token-list") {
6843
+ return true;
6844
+ }
6845
+ if ("currency" in value || "amount" in value || "splitAddresses" in value || "splitRatios" in value || !Array.isArray(value.tokens)) {
6846
+ return false;
6847
+ }
6848
+ return true;
6849
+ }
6850
+ function isRecord3(value) {
6851
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6852
+ }
6853
+ function planBatchListingRootRegistrationLocalInputs(artifact) {
6854
+ if (artifact.tokens.length < 2) {
6855
+ throw new Error("Root artifact must contain at least two tokens; the batch listing contract rejects empty proofs");
6856
+ }
6857
+ if (artifact.allowList !== void 0 && artifact.allowList.addresses.length < 2) {
6858
+ throw new Error(
6859
+ "Allowlist must contain at least two addresses; the batch listing contract rejects empty allowlist proofs"
6860
+ );
6861
+ }
6862
+ const { splitAddresses, splitRatios } = artifact;
6863
+ if (splitAddresses.length === 0 && splitRatios.length === 0) {
6864
+ return void 0;
6865
+ }
6866
+ const splits = planProvidedPayoutSplits(splitAddresses, splitRatios);
6867
+ return { splitAddresses: splits.addresses, splitRatios: splits.ratios };
6868
+ }
6869
+ function shouldResolveBatchListingAllowListProof(params) {
6870
+ if (params.allowList === void 0 || params.tokenProof.allowListProof !== void 0) {
6871
+ return false;
6872
+ }
6873
+ return params.nowTimestamp === void 0 || params.allowList.endTimestamp > params.nowTimestamp;
6874
+ }
6875
+ function shapeBatchListingStatus(params) {
6876
+ const hasListing = params.listingConfig.amount > 0n && params.cancellationNonce === params.listingConfig.nonce;
6877
+ return {
6878
+ root: params.root,
6879
+ seller: params.creator,
6880
+ currencyAddress: params.listingConfig.currency,
6881
+ amount: params.listingConfig.amount,
6882
+ splitRecipients: [...params.listingConfig.splitRecipients],
6883
+ splitRatios: [...params.listingConfig.splitRatios],
6884
+ nonce: params.listingConfig.nonce,
6885
+ isEth: isAddressEqual10(params.listingConfig.currency, ETH_ADDRESS),
6886
+ hasListing,
6887
+ allowList: params.allowList,
6888
+ ...params.tokenStatus
6889
+ };
6890
+ }
6891
+
6892
+ // src/sdk/batch-listing.ts
6893
+ var ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
6894
+ function createBatchListingNamespace(publicClient, config, addresses) {
6895
+ return {
6896
+ async create(params) {
6897
+ const { walletClient, account, accountAddress } = requireWallet(config);
6898
+ const artifact = await resolveApiBatchListingRootArtifact(config, params.artifact);
6899
+ const splitConfig = planBatchListingRootRegistration(artifact, accountAddress);
6900
+ const uniqueContracts = uniqueAddresses(artifact.tokens.map((token) => token.contract));
6901
+ for (const token of artifact.tokens.slice(0, 3)) {
6902
+ const owner = await publicClient.readContract({
6903
+ address: token.contract,
6904
+ abi: [
6905
+ {
6906
+ type: "function",
6907
+ name: "ownerOf",
6908
+ inputs: [{ name: "tokenId", type: "uint256" }],
6909
+ outputs: [{ name: "", type: "address" }],
6910
+ stateMutability: "view"
6911
+ }
6912
+ ],
6913
+ functionName: "ownerOf",
6914
+ args: [BigInt(token.tokenId)]
6445
6915
  });
6446
- if (!isAddressEqual10(owner, accountAddress)) {
6916
+ if (!isAddressEqual11(owner, accountAddress)) {
6447
6917
  throw new Error(
6448
6918
  `Token ${token.contract}/${token.tokenId} is owned by ${owner}, not the configured account ${accountAddress}. Re-check the token set before registering this batch listing.`
6449
6919
  );
6450
6920
  }
6451
6921
  }
6452
- const approvalTxHashes = await approveNftContracts({
6922
+ const nftApprovals = await approveNftContracts({
6453
6923
  publicClient,
6454
6924
  walletClient,
6455
6925
  account,
@@ -6458,26 +6928,38 @@ function createBatchListingNamespace(publicClient, config, addresses) {
6458
6928
  nftAddresses: uniqueContracts,
6459
6929
  autoApprove: params.autoApprove
6460
6930
  });
6461
- const txHash = await walletClient.writeContract({
6462
- address: addresses.batchListing,
6463
- abi: batchListingAbi,
6464
- functionName: "registerSalePriceMerkleRoot",
6465
- args: [
6466
- artifact.root,
6467
- artifact.currency,
6468
- BigInt(artifact.amount),
6469
- splitConfig.splitAddresses,
6470
- splitConfig.splitRatios
6471
- ],
6472
- account,
6473
- chain: void 0
6931
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
6932
+ operation: "batch listing create",
6933
+ approvals: nftApprovals.map((approval) => ({
6934
+ type: "nft",
6935
+ approvalTxHash: approval.txHash,
6936
+ target: approval.nftAddress,
6937
+ operator: addresses.erc721ApprovalManager
6938
+ })),
6939
+ run: async () => {
6940
+ const targetTxHash = await walletClient.writeContract({
6941
+ address: addresses.batchListing,
6942
+ abi: batchListingAbi,
6943
+ functionName: "registerSalePriceMerkleRoot",
6944
+ args: [
6945
+ artifact.root,
6946
+ artifact.currency,
6947
+ BigInt(artifact.amount),
6948
+ splitConfig.splitAddresses,
6949
+ splitConfig.splitRatios
6950
+ ],
6951
+ account,
6952
+ chain: void 0
6953
+ });
6954
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
6955
+ return { txHash: targetTxHash, receipt: targetReceipt };
6956
+ }
6474
6957
  });
6475
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
6476
6958
  return {
6477
6959
  txHash,
6478
6960
  receipt,
6479
6961
  root: artifact.root,
6480
- approvalTxHashes: approvalTxHashes.length > 0 ? approvalTxHashes : void 0
6962
+ approvalTxHashes: nftApprovals.length > 0 ? nftApprovals.map((approval) => approval.txHash) : void 0
6481
6963
  };
6482
6964
  },
6483
6965
  async cancel(params) {
@@ -6490,7 +6972,7 @@ function createBatchListingNamespace(publicClient, config, addresses) {
6490
6972
  creator: accountAddress,
6491
6973
  params
6492
6974
  });
6493
- const txHash = await walletClient.writeContract({
6975
+ const targetTxHash = await walletClient.writeContract({
6494
6976
  address: addresses.batchListing,
6495
6977
  abi: batchListingAbi,
6496
6978
  functionName: "cancelSalePriceMerkleRoot",
@@ -6498,8 +6980,8 @@ function createBatchListingNamespace(publicClient, config, addresses) {
6498
6980
  account,
6499
6981
  chain: void 0
6500
6982
  });
6501
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
6502
- return { txHash, receipt, root };
6983
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
6984
+ return { txHash: targetTxHash, receipt: targetReceipt, root };
6503
6985
  },
6504
6986
  async buy(params) {
6505
6987
  const { walletClient, account, accountAddress } = requireWallet(config);
@@ -6530,25 +7012,37 @@ function createBatchListingNamespace(publicClient, config, addresses) {
6530
7012
  amount,
6531
7013
  autoApprove: params.autoApprove
6532
7014
  });
6533
- const txHash = await walletClient.writeContract({
6534
- address: addresses.batchListing,
6535
- abi: batchListingAbi,
6536
- functionName: "buyWithMerkleProof",
6537
- args: [
6538
- proofArtifact.contract,
6539
- tokenIdBig,
6540
- currency,
6541
- amount,
6542
- params.creator,
6543
- proofArtifact.root,
6544
- proofArtifact.proof,
6545
- allowListProof
6546
- ],
6547
- account,
6548
- chain: void 0,
6549
- value: payment.value
7015
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
7016
+ operation: "batch listing buy",
7017
+ approvals: [{
7018
+ type: "erc20",
7019
+ approvalTxHash: payment.approvalTxHash,
7020
+ target: currency,
7021
+ spender: addresses.erc20ApprovalManager
7022
+ }],
7023
+ run: async () => {
7024
+ const targetTxHash = await walletClient.writeContract({
7025
+ address: addresses.batchListing,
7026
+ abi: batchListingAbi,
7027
+ functionName: "buyWithMerkleProof",
7028
+ args: [
7029
+ proofArtifact.contract,
7030
+ tokenIdBig,
7031
+ currency,
7032
+ amount,
7033
+ params.creator,
7034
+ proofArtifact.root,
7035
+ proofArtifact.proof,
7036
+ allowListProof
7037
+ ],
7038
+ account,
7039
+ chain: void 0,
7040
+ value: payment.value
7041
+ });
7042
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
7043
+ return { txHash: targetTxHash, receipt: targetReceipt };
7044
+ }
6550
7045
  });
6551
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
6552
7046
  return { txHash, receipt, approvalTxHash: payment.approvalTxHash };
6553
7047
  },
6554
7048
  async setAllowlist(params) {
@@ -6566,7 +7060,7 @@ function createBatchListingNamespace(publicClient, config, addresses) {
6566
7060
  requireInput(params.endTime ?? params.artifact?.allowList?.endTimestamp, "endTime"),
6567
7061
  "endTime"
6568
7062
  );
6569
- const txHash = await walletClient.writeContract({
7063
+ const targetTxHash = await walletClient.writeContract({
6570
7064
  address: addresses.batchListing,
6571
7065
  abi: batchListingAbi,
6572
7066
  functionName: "setAllowListConfig",
@@ -6574,8 +7068,8 @@ function createBatchListingNamespace(publicClient, config, addresses) {
6574
7068
  account,
6575
7069
  chain: void 0
6576
7070
  });
6577
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
6578
- return { txHash, receipt, root, allowListRoot, endTime };
7071
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
7072
+ return { txHash: targetTxHash, receipt: targetReceipt, root, allowListRoot, endTime };
6579
7073
  },
6580
7074
  async status(params) {
6581
7075
  const resolvedParams = await resolveBatchListingStatusParams({
@@ -6804,7 +7298,7 @@ function isHash(value) {
6804
7298
  }
6805
7299
  async function approveNftContracts(opts) {
6806
7300
  return opts.nftAddresses.reduce(async (previous, nftAddress) => {
6807
- const hashes = await previous;
7301
+ const approvals = await previous;
6808
7302
  const txHash = await approveNftContractIfNeeded({
6809
7303
  publicClient: opts.publicClient,
6810
7304
  walletClient: opts.walletClient,
@@ -6814,7 +7308,7 @@ async function approveNftContracts(opts) {
6814
7308
  operator: opts.operator,
6815
7309
  autoApprove: opts.autoApprove
6816
7310
  });
6817
- return isHash(txHash) ? [...hashes, txHash] : hashes;
7311
+ return isHash(txHash) ? [...approvals, { nftAddress, txHash }] : approvals;
6818
7312
  }, Promise.resolve([]));
6819
7313
  }
6820
7314
  async function prepareBatchListingPayment(opts) {
@@ -6867,7 +7361,7 @@ async function readTokenStatus(publicClient, batchListingAddress, params) {
6867
7361
 
6868
7362
  // src/sdk/batch-auction.ts
6869
7363
  import {
6870
- isAddressEqual as isAddressEqual12,
7364
+ isAddressEqual as isAddressEqual13,
6871
7365
  parseUnits as parseUnits3,
6872
7366
  parseEventLogs as parseEventLogs3
6873
7367
  } from "viem";
@@ -7099,7 +7593,7 @@ var batchAuctionHouseAbi = [
7099
7593
  ];
7100
7594
 
7101
7595
  // src/sdk/batch-auction-core.ts
7102
- import { isAddressEqual as isAddressEqual11 } from "viem";
7596
+ import { isAddressEqual as isAddressEqual12 } from "viem";
7103
7597
  var zeroAddress3 = ETH_ADDRESS;
7104
7598
  var marketplaceFeePercentage = 3n;
7105
7599
  function planBatchAuctionCreateLocalInputs(params, nowSeconds) {
@@ -7190,17 +7684,19 @@ function planBatchAuctionStatus(params) {
7190
7684
  };
7191
7685
  }
7192
7686
  function shapeBatchAuctionStatus(details, currentBid, rootContext, nowSeconds) {
7193
- const hasAuction = details.startingTime > 0n && !isAddressEqual11(details.seller, zeroAddress3);
7194
- const hasRootConfig = rootContext !== void 0 && rootContext.config.duration > 0n;
7195
- const duration = hasAuction ? details.duration : rootContext?.config.duration ?? 0n;
7687
+ const hasAuction = details.startingTime > 0n && !isAddressEqual12(details.seller, zeroAddress3);
7688
+ const hasCurrentRootConfig = rootContext !== void 0 && rootContext.config.duration > 0n && rootContext.rootNonce === rootContext.config.nonce;
7689
+ const currentRootConfig = hasCurrentRootConfig ? rootContext.config : void 0;
7690
+ const hasRootConfig = currentRootConfig !== void 0;
7691
+ const duration = hasAuction ? details.duration : currentRootConfig?.duration ?? 0n;
7196
7692
  const startingTime = hasAuction ? details.startingTime : 0n;
7197
7693
  const endTime = hasAuction ? startingTime + duration : null;
7198
7694
  const ended = endTime !== null && nowSeconds >= endTime;
7199
- const currentBidder = currentBid.amount > 0n && !isAddressEqual11(currentBid.bidder, zeroAddress3) ? currentBid.bidder : null;
7695
+ const currentBidder = currentBid.amount > 0n && !isAddressEqual12(currentBid.bidder, zeroAddress3) ? currentBid.bidder : null;
7200
7696
  const seller = hasAuction ? details.seller : rootContext?.creator ?? zeroAddress3;
7201
- const currency = hasAuction ? details.currency : rootContext?.config.currency ?? ETH_ADDRESS;
7202
- const reserveAmount = hasAuction ? details.reserveAmount : rootContext?.config.reserveAmount ?? 0n;
7203
- const tokenNonceConsumed = rootContext === void 0 ? null : rootContext.tokenNonce >= rootContext.config.nonce;
7697
+ const currency = hasAuction ? details.currency : currentRootConfig?.currency ?? ETH_ADDRESS;
7698
+ const reserveAmount = hasAuction ? details.reserveAmount : currentRootConfig?.reserveAmount ?? 0n;
7699
+ const tokenNonceConsumed = rootContext === void 0 ? null : !hasCurrentRootConfig || rootContext.tokenNonce >= rootContext.config.nonce;
7204
7700
  return {
7205
7701
  seller,
7206
7702
  root: rootContext?.root ?? null,
@@ -7210,8 +7706,8 @@ function shapeBatchAuctionStatus(details, currentBid, rootContext, nowSeconds) {
7210
7706
  creationBlock: details.creationBlock,
7211
7707
  startingTime,
7212
7708
  endTime,
7213
- splitAddresses: resolveStatusSplitAddresses(hasAuction, details, rootContext),
7214
- splitRatios: resolveStatusSplitRatios(hasAuction, details, rootContext),
7709
+ splitAddresses: resolveStatusSplitAddresses(hasAuction, details, currentRootConfig),
7710
+ splitRatios: resolveStatusSplitRatios(hasAuction, details, currentRootConfig),
7215
7711
  hasRootConfig,
7216
7712
  rootNonce: rootContext?.rootNonce ?? null,
7217
7713
  tokenNonce: rootContext?.tokenNonce ?? null,
@@ -7231,7 +7727,7 @@ function shapeBatchAuctionStatus(details, currentBid, rootContext, nowSeconds) {
7231
7727
  hasRootConfig,
7232
7728
  tokenNonceConsumed
7233
7729
  }),
7234
- isEth: isAddressEqual11(currency, ETH_ADDRESS)
7730
+ isEth: isAddressEqual12(currency, ETH_ADDRESS)
7235
7731
  };
7236
7732
  }
7237
7733
  function shapeBatchAuctionDetailsRead(details) {
@@ -7342,28 +7838,28 @@ function planSplitRecipients(splitAddresses, splitRatios, accountAddress) {
7342
7838
  };
7343
7839
  }
7344
7840
  function uniqueAddresses2(addresses) {
7345
- return addresses.reduce((unique, address) => unique.some((candidate) => isAddressEqual11(candidate, address)) ? unique : [...unique, address], []);
7841
+ return addresses.reduce((unique, address) => unique.some((candidate) => isAddressEqual12(candidate, address)) ? unique : [...unique, address], []);
7346
7842
  }
7347
7843
  function addMinimumBidIncrease(amount) {
7348
7844
  return amount + amount * marketplaceFeePercentage / 100n;
7349
7845
  }
7350
- function resolveStatusSplitAddresses(hasAuction, details, rootContext) {
7846
+ function resolveStatusSplitAddresses(hasAuction, details, rootConfig) {
7351
7847
  if (hasAuction) {
7352
7848
  return [...details.splitAddresses];
7353
7849
  }
7354
- if (rootContext === void 0) {
7850
+ if (rootConfig === void 0) {
7355
7851
  return [];
7356
7852
  }
7357
- return [...rootContext.config.splitAddresses];
7853
+ return [...rootConfig.splitAddresses];
7358
7854
  }
7359
- function resolveStatusSplitRatios(hasAuction, details, rootContext) {
7855
+ function resolveStatusSplitRatios(hasAuction, details, rootConfig) {
7360
7856
  if (hasAuction) {
7361
7857
  return [...details.splitRatios];
7362
7858
  }
7363
- if (rootContext === void 0) {
7859
+ if (rootConfig === void 0) {
7364
7860
  return [];
7365
7861
  }
7366
- return [...rootContext.config.splitRatios];
7862
+ return [...rootConfig.splitRatios];
7367
7863
  }
7368
7864
  function resolveBatchAuctionState(params) {
7369
7865
  if (params.hasAuction) {
@@ -7397,7 +7893,7 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7397
7893
  currentUnixTimestamp2()
7398
7894
  );
7399
7895
  const erc721ApprovalManager = plan.approvalContracts.length === 0 ? void 0 : requireContractAddress(chain, "erc721ApprovalManager");
7400
- const approvalTxHashes = await approveNftContracts2({
7896
+ const nftApprovals = await approveNftContracts2({
7401
7897
  publicClient,
7402
7898
  account,
7403
7899
  accountAddress,
@@ -7406,31 +7902,43 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7406
7902
  nftAddresses: plan.approvalContracts,
7407
7903
  autoApprove: params.autoApprove
7408
7904
  });
7409
- const txHash = await walletClient.writeContract({
7410
- address: batchAuctionHouse,
7411
- abi: batchAuctionHouseAbi,
7412
- functionName: "registerAuctionMerkleRoot",
7413
- args: [
7414
- plan.root,
7415
- plan.currency,
7416
- plan.reserveAmount,
7417
- plan.duration,
7418
- plan.splitAddresses,
7419
- plan.splitRatios
7420
- ],
7421
- account,
7422
- chain: void 0
7423
- });
7424
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
7425
- const logs = parseEventLogs3({
7426
- abi: batchAuctionHouseAbi,
7427
- logs: receipt.logs,
7428
- eventName: "AuctionMerkleRootRegistered"
7905
+ const { txHash, receipt, registered } = await runWithApprovalSideEffectAlert({
7906
+ operation: "batch auction create",
7907
+ approvals: nftApprovals.map((approval) => ({
7908
+ type: "nft",
7909
+ approvalTxHash: approval.txHash,
7910
+ target: approval.nftAddress,
7911
+ operator: erc721ApprovalManager
7912
+ })),
7913
+ run: async () => {
7914
+ const targetTxHash = await walletClient.writeContract({
7915
+ address: batchAuctionHouse,
7916
+ abi: batchAuctionHouseAbi,
7917
+ functionName: "registerAuctionMerkleRoot",
7918
+ args: [
7919
+ plan.root,
7920
+ plan.currency,
7921
+ plan.reserveAmount,
7922
+ plan.duration,
7923
+ plan.splitAddresses,
7924
+ plan.splitRatios
7925
+ ],
7926
+ account,
7927
+ chain: void 0
7928
+ });
7929
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
7930
+ const logs = parseEventLogs3({
7931
+ abi: batchAuctionHouseAbi,
7932
+ logs: targetReceipt.logs,
7933
+ eventName: "AuctionMerkleRootRegistered"
7934
+ });
7935
+ const [registeredLog] = logs;
7936
+ if (!registeredLog) {
7937
+ throw new Error("Batch auction create transaction succeeded but AuctionMerkleRootRegistered was not found in logs.");
7938
+ }
7939
+ return { txHash: targetTxHash, receipt: targetReceipt, registered: registeredLog };
7940
+ }
7429
7941
  });
7430
- const [registered] = logs;
7431
- if (!registered) {
7432
- throw new Error("Batch auction create transaction succeeded but AuctionMerkleRootRegistered was not found in logs.");
7433
- }
7434
7942
  return {
7435
7943
  txHash,
7436
7944
  receipt,
@@ -7441,7 +7949,7 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7441
7949
  reserveAmount: registered.args.startingAmount,
7442
7950
  duration: registered.args.duration,
7443
7951
  nonce: registered.args.nonce,
7444
- approvalTxHashes
7952
+ approvalTxHashes: nftApprovals.map((approval) => approval.txHash)
7445
7953
  };
7446
7954
  },
7447
7955
  async cancel(params) {
@@ -7454,7 +7962,7 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7454
7962
  params
7455
7963
  );
7456
7964
  const plan = planBatchAuctionRoot(resolvedParams);
7457
- const txHash = await walletClient.writeContract({
7965
+ const targetTxHash = await walletClient.writeContract({
7458
7966
  address: batchAuctionHouse,
7459
7967
  abi: batchAuctionHouseAbi,
7460
7968
  functionName: "cancelAuctionMerkleRoot",
@@ -7462,10 +7970,10 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7462
7970
  account,
7463
7971
  chain: void 0
7464
7972
  });
7465
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
7973
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
7466
7974
  const logs = parseEventLogs3({
7467
7975
  abi: batchAuctionHouseAbi,
7468
- logs: receipt.logs,
7976
+ logs: targetReceipt.logs,
7469
7977
  eventName: "AuctionMerkleRootCancelled"
7470
7978
  });
7471
7979
  const [cancelled] = logs;
@@ -7473,8 +7981,8 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7473
7981
  throw new Error("Batch auction cancel transaction succeeded but AuctionMerkleRootCancelled was not found in logs.");
7474
7982
  }
7475
7983
  return {
7476
- txHash,
7477
- receipt,
7984
+ txHash: targetTxHash,
7985
+ receipt: targetReceipt,
7478
7986
  batchAuctionHouse,
7479
7987
  creator: cancelled.args.creator,
7480
7988
  root: cancelled.args.merkleRoot
@@ -7504,7 +8012,7 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7504
8012
  const price = requireInput(resolvedParams.price, "price");
7505
8013
  const amount = typeof price === "bigint" ? price : parseUnits3(stringifyAmountInput(price, "price"), await resolveCurrencyDecimals(publicClient, chain, currency));
7506
8014
  const plan = planBatchAuctionBid({ ...resolvedParams, currency, price: amount });
7507
- const erc20ApprovalManager = isAddressEqual12(plan.currency, ETH_ADDRESS) ? batchAuctionHouse : requireContractAddress(chain, "erc20ApprovalManager");
8015
+ const erc20ApprovalManager = isAddressEqual13(plan.currency, ETH_ADDRESS) ? batchAuctionHouse : requireContractAddress(chain, "erc20ApprovalManager");
7508
8016
  const payment = await preparePaymentAmountForSpender({
7509
8017
  publicClient,
7510
8018
  walletClient,
@@ -7515,33 +8023,45 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7515
8023
  requiredAmount: plan.requiredPayment,
7516
8024
  autoApprove: params.autoApprove
7517
8025
  });
7518
- const txHash = await walletClient.writeContract({
7519
- address: batchAuctionHouse,
7520
- abi: batchAuctionHouseAbi,
7521
- functionName: "bidWithAuctionMerkleProof",
7522
- args: [
7523
- plan.currency,
7524
- plan.contract,
7525
- plan.tokenId,
7526
- plan.creator,
7527
- plan.root,
7528
- plan.amount,
7529
- plan.proof
7530
- ],
7531
- account,
7532
- chain: void 0,
7533
- value: payment.value
7534
- });
7535
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
7536
- const logs = parseEventLogs3({
7537
- abi: batchAuctionHouseAbi,
7538
- logs: receipt.logs,
7539
- eventName: "AuctionMerkleBid"
8026
+ const { txHash, receipt, bid } = await runWithApprovalSideEffectAlert({
8027
+ operation: "batch auction bid",
8028
+ approvals: [{
8029
+ type: "erc20",
8030
+ approvalTxHash: payment.approvalTxHash,
8031
+ target: plan.currency,
8032
+ spender: erc20ApprovalManager
8033
+ }],
8034
+ run: async () => {
8035
+ const targetTxHash = await walletClient.writeContract({
8036
+ address: batchAuctionHouse,
8037
+ abi: batchAuctionHouseAbi,
8038
+ functionName: "bidWithAuctionMerkleProof",
8039
+ args: [
8040
+ plan.currency,
8041
+ plan.contract,
8042
+ plan.tokenId,
8043
+ plan.creator,
8044
+ plan.root,
8045
+ plan.amount,
8046
+ plan.proof
8047
+ ],
8048
+ account,
8049
+ chain: void 0,
8050
+ value: payment.value
8051
+ });
8052
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
8053
+ const logs = parseEventLogs3({
8054
+ abi: batchAuctionHouseAbi,
8055
+ logs: targetReceipt.logs,
8056
+ eventName: "AuctionMerkleBid"
8057
+ });
8058
+ const [bidLog] = logs;
8059
+ if (!bidLog) {
8060
+ throw new Error("Batch auction bid transaction succeeded but AuctionMerkleBid was not found in logs.");
8061
+ }
8062
+ return { txHash: targetTxHash, receipt: targetReceipt, bid: bidLog };
8063
+ }
7540
8064
  });
7541
- const [bid] = logs;
7542
- if (!bid) {
7543
- throw new Error("Batch auction bid transaction succeeded but AuctionMerkleBid was not found in logs.");
7544
- }
7545
8065
  return {
7546
8066
  txHash,
7547
8067
  receipt,
@@ -7562,7 +8082,7 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7562
8082
  const batchAuctionHouse = requireContractAddress(chain, "batchAuctionHouse");
7563
8083
  const { walletClient, account } = requireWallet(config);
7564
8084
  const plan = planBatchAuctionStatus(params);
7565
- const txHash = await walletClient.writeContract({
8085
+ const targetTxHash = await walletClient.writeContract({
7566
8086
  address: batchAuctionHouse,
7567
8087
  abi: batchAuctionHouseAbi,
7568
8088
  functionName: "settleAuction",
@@ -7570,10 +8090,10 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7570
8090
  account,
7571
8091
  chain: void 0
7572
8092
  });
7573
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
8093
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
7574
8094
  const logs = parseEventLogs3({
7575
8095
  abi: batchAuctionHouseAbi,
7576
- logs: receipt.logs,
8096
+ logs: targetReceipt.logs,
7577
8097
  eventName: "AuctionSettled"
7578
8098
  });
7579
8099
  const [settled] = logs;
@@ -7581,8 +8101,8 @@ function createBatchAuctionNamespace(publicClient, config, chain) {
7581
8101
  throw new Error("Batch auction settle transaction succeeded but AuctionSettled was not found in logs.");
7582
8102
  }
7583
8103
  return {
7584
- txHash,
7585
- receipt,
8104
+ txHash: targetTxHash,
8105
+ receipt: targetReceipt,
7586
8106
  batchAuctionHouse,
7587
8107
  seller: settled.args.seller,
7588
8108
  bidder: settled.args.bidder,
@@ -7769,7 +8289,7 @@ async function approveNftContracts2(opts) {
7769
8289
  }
7770
8290
  const { walletClient, operator } = opts;
7771
8291
  return opts.nftAddresses.reduce(async (previous, nftAddress) => {
7772
- const hashes = await previous;
8292
+ const approvals = await previous;
7773
8293
  const txHash = await approveNftContract({
7774
8294
  publicClient: opts.publicClient,
7775
8295
  walletClient,
@@ -7779,7 +8299,7 @@ async function approveNftContracts2(opts) {
7779
8299
  nftAddress,
7780
8300
  autoApprove: opts.autoApprove
7781
8301
  });
7782
- return txHash === void 0 ? hashes : [...hashes, txHash];
8302
+ return txHash === void 0 ? approvals : [...approvals, { nftAddress, txHash }];
7783
8303
  }, Promise.resolve([]));
7784
8304
  }
7785
8305
  async function approveNftContract(opts) {
@@ -7851,7 +8371,7 @@ async function resolveRootContext(opts) {
7851
8371
 
7852
8372
  // src/sdk/batch-offer.ts
7853
8373
  import {
7854
- isAddressEqual as isAddressEqual14,
8374
+ isAddressEqual as isAddressEqual15,
7855
8375
  parseUnits as parseUnits4,
7856
8376
  parseEventLogs as parseEventLogs4
7857
8377
  } from "viem";
@@ -7958,7 +8478,7 @@ var batchOfferAbi = [
7958
8478
  ];
7959
8479
 
7960
8480
  // src/sdk/batch-offer-core.ts
7961
- import { isAddressEqual as isAddressEqual13 } from "viem";
8481
+ import { isAddressEqual as isAddressEqual14 } from "viem";
7962
8482
  var zeroAddress4 = ETH_ADDRESS;
7963
8483
  var zeroBytes322 = "0x0000000000000000000000000000000000000000000000000000000000000000";
7964
8484
  function planBatchOfferCreateLocalInputs(params, nowSeconds) {
@@ -8015,7 +8535,7 @@ function planBatchOfferAccept(params, accountAddress) {
8015
8535
  };
8016
8536
  }
8017
8537
  function shapeBatchOfferStatus(offer, expected, nowSeconds) {
8018
- const hasOffer = !isAddressEqual13(offer.creator, zeroAddress4) && offer.rootHash !== zeroBytes322 && offer.amount > 0n;
8538
+ const hasOffer = !isAddressEqual14(offer.creator, zeroAddress4) && offer.rootHash !== zeroBytes322 && offer.amount > 0n;
8019
8539
  const expired = hasOffer && offer.expiry <= nowSeconds;
8020
8540
  const state = !hasOffer ? "NONE" : expired ? "EXPIRED" : "ACTIVE";
8021
8541
  return {
@@ -8030,7 +8550,7 @@ function shapeBatchOfferStatus(offer, expected, nowSeconds) {
8030
8550
  revoked: hasOffer ? false : null,
8031
8551
  fillable: hasOffer && !expired,
8032
8552
  state,
8033
- isEth: isAddressEqual13(offer.currency, ETH_ADDRESS)
8553
+ isEth: isAddressEqual14(offer.currency, ETH_ADDRESS)
8034
8554
  };
8035
8555
  }
8036
8556
  function shapeBatchOfferRead(value) {
@@ -8119,25 +8639,37 @@ function createBatchOfferNamespace(publicClient, config, chain) {
8119
8639
  amount: plan.amount,
8120
8640
  autoApprove: params.autoApprove
8121
8641
  });
8122
- const txHash = await walletClient.writeContract({
8123
- address: batchOfferCreator,
8124
- abi: batchOfferAbi,
8125
- functionName: "createBatchOffer",
8126
- args: [plan.root, plan.amount, plan.currency, plan.expiry],
8127
- account,
8128
- chain: void 0,
8129
- value: payment.value
8130
- });
8131
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
8132
- const logs = parseEventLogs4({
8133
- abi: batchOfferAbi,
8134
- logs: receipt.logs,
8135
- eventName: "BatchOfferCreated"
8642
+ const { txHash, receipt, created } = await runWithApprovalSideEffectAlert({
8643
+ operation: "batch offer create",
8644
+ approvals: [{
8645
+ type: "erc20",
8646
+ approvalTxHash: payment.approvalTxHash,
8647
+ target: plan.currency,
8648
+ spender: batchOfferCreator
8649
+ }],
8650
+ run: async () => {
8651
+ const targetTxHash = await walletClient.writeContract({
8652
+ address: batchOfferCreator,
8653
+ abi: batchOfferAbi,
8654
+ functionName: "createBatchOffer",
8655
+ args: [plan.root, plan.amount, plan.currency, plan.expiry],
8656
+ account,
8657
+ chain: void 0,
8658
+ value: payment.value
8659
+ });
8660
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
8661
+ const logs = parseEventLogs4({
8662
+ abi: batchOfferAbi,
8663
+ logs: targetReceipt.logs,
8664
+ eventName: "BatchOfferCreated"
8665
+ });
8666
+ const [createdLog] = logs;
8667
+ if (!createdLog) {
8668
+ throw new Error("Batch offer create transaction succeeded but BatchOfferCreated was not found in logs.");
8669
+ }
8670
+ return { txHash: targetTxHash, receipt: targetReceipt, created: createdLog };
8671
+ }
8136
8672
  });
8137
- const [created] = logs;
8138
- if (!created) {
8139
- throw new Error("Batch offer create transaction succeeded but BatchOfferCreated was not found in logs.");
8140
- }
8141
8673
  return {
8142
8674
  txHash,
8143
8675
  receipt,
@@ -8163,7 +8695,7 @@ function createBatchOfferNamespace(publicClient, config, chain) {
8163
8695
  params
8164
8696
  });
8165
8697
  const plan = planBatchOfferRoot(resolvedParams);
8166
- const txHash = await walletClient.writeContract({
8698
+ const targetTxHash = await walletClient.writeContract({
8167
8699
  address: batchOfferCreator,
8168
8700
  abi: batchOfferAbi,
8169
8701
  functionName: "revokeBatchOffer",
@@ -8171,10 +8703,10 @@ function createBatchOfferNamespace(publicClient, config, chain) {
8171
8703
  account,
8172
8704
  chain: void 0
8173
8705
  });
8174
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
8706
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
8175
8707
  const logs = parseEventLogs4({
8176
8708
  abi: batchOfferAbi,
8177
- logs: receipt.logs,
8709
+ logs: targetReceipt.logs,
8178
8710
  eventName: "BatchOfferRevoked"
8179
8711
  });
8180
8712
  const [revoked] = logs;
@@ -8182,8 +8714,8 @@ function createBatchOfferNamespace(publicClient, config, chain) {
8182
8714
  throw new Error("Batch offer revoke transaction succeeded but BatchOfferRevoked was not found in logs.");
8183
8715
  }
8184
8716
  return {
8185
- txHash,
8186
- receipt,
8717
+ txHash: targetTxHash,
8718
+ receipt: targetReceipt,
8187
8719
  batchOfferCreator,
8188
8720
  creator: revoked.args.creator,
8189
8721
  root: revoked.args.rootHash,
@@ -8208,7 +8740,7 @@ function createBatchOfferNamespace(publicClient, config, chain) {
8208
8740
  functionName: "ownerOf",
8209
8741
  args: [plan.tokenId]
8210
8742
  });
8211
- if (!isAddressEqual14(owner, accountAddress)) {
8743
+ if (!isAddressEqual15(owner, accountAddress)) {
8212
8744
  throw new Error(`Connected wallet ${accountAddress} does not own token ${plan.contract} #${plan.tokenId.toString()}.`);
8213
8745
  }
8214
8746
  const approvalTxHash = await approveNftContractIfNeeded({
@@ -8220,32 +8752,44 @@ function createBatchOfferNamespace(publicClient, config, chain) {
8220
8752
  operator: batchOfferCreator,
8221
8753
  autoApprove: plan.autoApprove
8222
8754
  });
8223
- const txHash = await walletClient.writeContract({
8224
- address: batchOfferCreator,
8225
- abi: batchOfferAbi,
8226
- functionName: "acceptBatchOffer",
8227
- args: [
8228
- plan.creator,
8229
- plan.proof,
8230
- plan.root,
8231
- plan.contract,
8232
- plan.tokenId,
8233
- plan.splitAddresses,
8234
- plan.splitRatios
8235
- ],
8236
- account,
8237
- chain: void 0
8238
- });
8239
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
8240
- const logs = parseEventLogs4({
8241
- abi: batchOfferAbi,
8242
- logs: receipt.logs,
8243
- eventName: "BatchOfferAccepted"
8755
+ const { txHash, receipt, accepted } = await runWithApprovalSideEffectAlert({
8756
+ operation: "batch offer accept",
8757
+ approvals: [{
8758
+ type: "nft",
8759
+ approvalTxHash,
8760
+ target: plan.contract,
8761
+ operator: batchOfferCreator
8762
+ }],
8763
+ run: async () => {
8764
+ const targetTxHash = await walletClient.writeContract({
8765
+ address: batchOfferCreator,
8766
+ abi: batchOfferAbi,
8767
+ functionName: "acceptBatchOffer",
8768
+ args: [
8769
+ plan.creator,
8770
+ plan.proof,
8771
+ plan.root,
8772
+ plan.contract,
8773
+ plan.tokenId,
8774
+ plan.splitAddresses,
8775
+ plan.splitRatios
8776
+ ],
8777
+ account,
8778
+ chain: void 0
8779
+ });
8780
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
8781
+ const logs = parseEventLogs4({
8782
+ abi: batchOfferAbi,
8783
+ logs: targetReceipt.logs,
8784
+ eventName: "BatchOfferAccepted"
8785
+ });
8786
+ const [acceptedLog] = logs;
8787
+ if (!acceptedLog) {
8788
+ throw new Error("Batch offer accept transaction succeeded but BatchOfferAccepted was not found in logs.");
8789
+ }
8790
+ return { txHash: targetTxHash, receipt: targetReceipt, accepted: acceptedLog };
8791
+ }
8244
8792
  });
8245
- const [accepted] = logs;
8246
- if (!accepted) {
8247
- throw new Error("Batch offer accept transaction succeeded but BatchOfferAccepted was not found in logs.");
8248
- }
8249
8793
  return {
8250
8794
  txHash,
8251
8795
  receipt,
@@ -8866,6 +9410,7 @@ var liquidFactoryAbi = [
8866
9410
  var TICK_BASE = 1.0001;
8867
9411
  var TICK_LOG_BASE = Math.log(TICK_BASE);
8868
9412
  var TOKEN_BASE_UNITS = 1e18;
9413
+ var SHARE_SCALE_UNITS = 10n ** 18n;
8869
9414
  var RESERVE_TAIL_SHARES_PERCENT = 2;
8870
9415
  var RESERVE_TAIL_END_PRICE_MULTIPLE = 100;
8871
9416
  var SHARES_SUM_TOLERANCE = 1e-6;
@@ -8914,7 +9459,7 @@ var CURVE_PRESET_DEFINITIONS = {
8914
9459
  reserveTailStartTokenPriceUsd: 50
8915
9460
  }
8916
9461
  };
8917
- function isRecord3(value) {
9462
+ function isRecord4(value) {
8918
9463
  return typeof value === "object" && value !== null;
8919
9464
  }
8920
9465
  function isPositiveFiniteNumber(value) {
@@ -8924,12 +9469,66 @@ function toValidNumber(value) {
8924
9469
  if (typeof value !== "number" || !Number.isFinite(value)) return null;
8925
9470
  return value;
8926
9471
  }
8927
- function toValidShareNumber(value) {
8928
- const numeric = typeof value === "string" ? Number(value) : toValidNumber(value);
8929
- if (numeric === null || numeric <= 0 || numeric > 1) {
9472
+ function toNormalizedShare(value) {
9473
+ if (typeof value === "number") {
9474
+ if (!Number.isFinite(value) || value <= 0 || value > 1) {
9475
+ return null;
9476
+ }
9477
+ return parseShareDecimalString(expandFiniteNumber(value));
9478
+ }
9479
+ if (typeof value !== "string") {
8930
9480
  return null;
8931
9481
  }
8932
- return numeric;
9482
+ return parseShareDecimalString(value);
9483
+ }
9484
+ function expandFiniteNumber(value) {
9485
+ const rawValue = value.toString();
9486
+ const [coefficient = "", exponentValue] = rawValue.toLowerCase().split("e");
9487
+ if (exponentValue === void 0) {
9488
+ return rawValue;
9489
+ }
9490
+ const exponent = Number(exponentValue);
9491
+ const [integerPart = "", fractionalPart = ""] = coefficient.split(".");
9492
+ const digits = `${integerPart}${fractionalPart}`;
9493
+ const decimalIndex = integerPart.length + exponent;
9494
+ if (decimalIndex <= 0) {
9495
+ return `0.${"0".repeat(Math.abs(decimalIndex))}${digits}`;
9496
+ }
9497
+ if (decimalIndex >= digits.length) {
9498
+ return `${digits}${"0".repeat(decimalIndex - digits.length)}`;
9499
+ }
9500
+ return `${digits.slice(0, decimalIndex)}.${digits.slice(decimalIndex)}`;
9501
+ }
9502
+ function parseShareDecimalString(value) {
9503
+ const normalized = value.trim();
9504
+ if (!/^(?:\d+\.?\d*|\.\d+)$/.test(normalized)) {
9505
+ return null;
9506
+ }
9507
+ const shareParts = normalized.startsWith(".") ? ["0", normalized.slice(1)] : normalized.split(".");
9508
+ const integerPart = shareParts[0] ?? "";
9509
+ const fractionalDigits = shareParts[1] ?? "";
9510
+ const excessFractionalDigits = fractionalDigits.slice(18);
9511
+ if (/[1-9]/.test(excessFractionalDigits)) {
9512
+ return null;
9513
+ }
9514
+ const integerUnits = BigInt(integerPart === "" ? "0" : integerPart);
9515
+ const fractionalUnits = BigInt(fractionalDigits.slice(0, 18).padEnd(18, "0"));
9516
+ const scaledUnits = integerUnits * SHARE_SCALE_UNITS + fractionalUnits;
9517
+ if (scaledUnits <= 0n || scaledUnits > SHARE_SCALE_UNITS) {
9518
+ return null;
9519
+ }
9520
+ return {
9521
+ decimal: formatScaledShareDecimal(scaledUnits),
9522
+ scaledUnits
9523
+ };
9524
+ }
9525
+ function formatScaledShareDecimal(scaledUnits) {
9526
+ const integerUnits = scaledUnits / SHARE_SCALE_UNITS;
9527
+ const fractionalUnits = scaledUnits % SHARE_SCALE_UNITS;
9528
+ if (fractionalUnits === 0n) {
9529
+ return integerUnits.toString();
9530
+ }
9531
+ return `${integerUnits}.${fractionalUnits.toString().padStart(18, "0").replace(/0+$/, "")}`;
8933
9532
  }
8934
9533
  function toApproxTokenAmount(value, label) {
8935
9534
  const numeric = typeof value === "number" ? value : Number(value);
@@ -9078,8 +9677,8 @@ function validateAndNormalizeSegments(rawSegments, totalCurveSupplyTokens, tickS
9078
9677
  if (invalidResult !== void 0) {
9079
9678
  return invalidResult.result;
9080
9679
  }
9081
- const parsedSegments = normalizedResults.filter((result) => result.isValid).map((result) => result.segment);
9082
- const totalPositions = parsedSegments.reduce((sum, segment) => sum + segment.numPositions, 0);
9680
+ const parsedEntries = normalizedResults.filter((result) => result.isValid).map((result) => result.entry);
9681
+ const totalPositions = parsedEntries.reduce((sum, entry) => sum + entry.segment.numPositions, 0);
9083
9682
  if (totalPositions > MAX_TOTAL_POSITIONS) {
9084
9683
  return {
9085
9684
  isValid: false,
@@ -9087,8 +9686,8 @@ function validateAndNormalizeSegments(rawSegments, totalCurveSupplyTokens, tickS
9087
9686
  errorMessage: `Total positions across all curves must not exceed ${MAX_TOTAL_POSITIONS}`
9088
9687
  };
9089
9688
  }
9090
- const sortedSegments = [...parsedSegments].sort((a, b) => a.tickLower - b.tickLower);
9091
- const hasGapOrOverlap = sortedSegments.slice(1).some((current, index) => current.tickLower !== sortedSegments[index]?.tickUpper);
9689
+ const sortedEntries = [...parsedEntries].sort((a, b) => a.segment.tickLower - b.segment.tickLower);
9690
+ const hasGapOrOverlap = sortedEntries.slice(1).some((current, index) => current.segment.tickLower !== sortedEntries[index]?.segment.tickUpper);
9092
9691
  if (hasGapOrOverlap) {
9093
9692
  return {
9094
9693
  isValid: false,
@@ -9096,10 +9695,11 @@ function validateAndNormalizeSegments(rawSegments, totalCurveSupplyTokens, tickS
9096
9695
  errorMessage: "Curve segments must be contiguous (no overlap or gaps)"
9097
9696
  };
9098
9697
  }
9099
- const shareSum = sortedSegments.reduce((sum, segment) => sum + Number(segment.shares), 0);
9100
- if (Math.abs(shareSum - 1) > SHARES_SUM_TOLERANCE) {
9698
+ const shareSum = sortedEntries.reduce((sum, entry) => sum + entry.shareScaledUnits, 0n);
9699
+ if (shareSum !== SHARE_SCALE_UNITS) {
9101
9700
  return { isValid: false, error: "share-sum-invalid", errorMessage: "Curve share values must add up to 1" };
9102
9701
  }
9702
+ const sortedSegments = sortedEntries.map((entry) => entry.segment);
9103
9703
  const narrowSegment = sortedSegments.find((segment) => {
9104
9704
  const minSpan = segment.numPositions * tickSpacing;
9105
9705
  return segment.tickUpper - segment.tickLower < minSpan || computeGrossLiquidityAtFarTick(segment.tickLower, segment.tickUpper - segment.tickLower, segment.numPositions, Number(segment.shares), totalCurveSupplyTokens) > MAX_LIQUIDITY_PER_TICK;
@@ -9122,14 +9722,14 @@ function validateAndNormalizeSegments(rawSegments, totalCurveSupplyTokens, tickS
9122
9722
  return { isValid: true, curves: sortedSegments };
9123
9723
  }
9124
9724
  function normalizeSegment(segment, tickSpacing) {
9125
- if (!isRecord3(segment)) {
9725
+ if (!isRecord4(segment)) {
9126
9726
  return invalidSegmentResult();
9127
9727
  }
9128
9728
  const tickLower = toValidNumber(segment.tickLower);
9129
9729
  const tickUpper = toValidNumber(segment.tickUpper);
9130
9730
  const numPositions = toValidNumber(segment.numPositions);
9131
- const shares = toValidShareNumber(segment.shares);
9132
- if (tickLower === null || tickUpper === null || numPositions === null || shares === null) {
9731
+ const share = toNormalizedShare(segment.shares);
9732
+ if (tickLower === null || tickUpper === null || numPositions === null || share === null) {
9133
9733
  return invalidSegmentResult();
9134
9734
  }
9135
9735
  if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper) || !Number.isInteger(numPositions) || numPositions <= 0) {
@@ -9146,11 +9746,14 @@ function normalizeSegment(segment, tickSpacing) {
9146
9746
  }
9147
9747
  return {
9148
9748
  isValid: true,
9149
- segment: {
9150
- tickLower,
9151
- tickUpper,
9152
- numPositions,
9153
- shares: `${shares}`
9749
+ entry: {
9750
+ segment: {
9751
+ tickLower,
9752
+ tickUpper,
9753
+ numPositions,
9754
+ shares: share.decimal
9755
+ },
9756
+ shareScaledUnits: share.scaledUnits
9154
9757
  }
9155
9758
  };
9156
9759
  }
@@ -9521,9 +10124,23 @@ function missingLiquidEditionAddressError(txHash, receipt, cause) {
9521
10124
  const message = `Liquid Edition deploy transaction succeeded, but the deployed contract address could not be read from the LiquidTokenCreated event logs after ${LIQUID_EDITION_ADDRESS_LOG_RETRY_ATTEMPTS + 1} attempts. Transaction hash: ${txHash}. Block: ${receipt.blockNumber}. The connected RPC may be delayed or returning incomplete receipt logs; retry with a synced RPC or inspect the transaction hash.`;
9522
10125
  return cause instanceof Error ? new Error(message, { cause }) : new Error(message);
9523
10126
  }
9524
- function liquidEditionDeployRevertedError(txHash, receipt) {
10127
+ function liquidEditionRevertedReceiptError(message, txHash, receipt) {
9525
10128
  return new Error(
9526
- `Liquid Edition deploy transaction reverted before emitting LiquidTokenCreated. Transaction hash: ${txHash}. Block: ${receipt.blockNumber}.`
10129
+ `${message} Transaction hash: ${txHash}. Block: ${receipt.blockNumber}.`
10130
+ );
10131
+ }
10132
+ function liquidEditionDeployRevertedError(txHash, receipt) {
10133
+ return liquidEditionRevertedReceiptError(
10134
+ "Liquid Edition deploy transaction reverted before emitting LiquidTokenCreated.",
10135
+ txHash,
10136
+ receipt
10137
+ );
10138
+ }
10139
+ function liquidEditionSetRenderContractRevertedError(txHash, receipt) {
10140
+ return liquidEditionRevertedReceiptError(
10141
+ 'Liquid Edition setRenderContract transaction was confirmed with status "reverted".',
10142
+ txHash,
10143
+ receipt
9527
10144
  );
9528
10145
  }
9529
10146
  async function waitForLiquidEditionAddress(publicClient, txHash) {
@@ -9609,7 +10226,13 @@ function createLiquidNamespace(config, chain, addresses) {
9609
10226
  throw new Error(validation.errorMessage ?? "Invalid curve configuration");
9610
10227
  }
9611
10228
  const initialRareLiquidity = params.initialRareLiquidity !== void 0 ? await toTokenAmount(publicClient, factoryConfig.baseToken, params.initialRareLiquidity, "initialRareLiquidity") : 0n;
9612
- await ensureTokenAllowance(
10229
+ const curves = validation.curves.map((curve) => ({
10230
+ tickLower: curve.tickLower,
10231
+ tickUpper: curve.tickUpper,
10232
+ numPositions: curve.numPositions,
10233
+ shares: parseUnits6(curve.shares, 18)
10234
+ }));
10235
+ const approvalTxHash = await ensureTokenAllowance(
9613
10236
  publicClient,
9614
10237
  walletClient,
9615
10238
  account,
@@ -9618,43 +10241,49 @@ function createLiquidNamespace(config, chain, addresses) {
9618
10241
  liquidFactory,
9619
10242
  initialRareLiquidity
9620
10243
  );
9621
- const curves = validation.curves.map((curve) => ({
9622
- tickLower: curve.tickLower,
9623
- tickUpper: curve.tickUpper,
9624
- numPositions: curve.numPositions,
9625
- shares: parseUnits6(curve.shares, 18)
9626
- }));
9627
- const txHash = customMaxTotalSupply === void 0 ? await walletClient.writeContract({
9628
- address: liquidFactory,
9629
- abi: liquidFactoryAbi,
9630
- functionName: "createLiquidTokenMultiCurve",
9631
- args: [
9632
- accountAddress,
9633
- params.tokenUri,
9634
- params.name,
9635
- params.symbol,
9636
- initialRareLiquidity,
9637
- curves
9638
- ],
9639
- account,
9640
- chain: void 0
9641
- }) : await walletClient.writeContract({
9642
- address: liquidFactory,
9643
- abi: liquidFactoryAbi,
9644
- functionName: "createLiquidTokenMultiCurveWithSupply",
9645
- args: [
9646
- accountAddress,
9647
- params.tokenUri,
9648
- params.name,
9649
- params.symbol,
9650
- initialRareLiquidity,
9651
- curves,
9652
- customMaxTotalSupply
9653
- ],
9654
- account,
9655
- chain: void 0
10244
+ const { txHash, receipt, contract } = await runWithApprovalSideEffectAlert({
10245
+ operation: "liquid edition deploy",
10246
+ approvals: [{
10247
+ type: "erc20",
10248
+ approvalTxHash,
10249
+ target: factoryConfig.baseToken,
10250
+ spender: liquidFactory
10251
+ }],
10252
+ run: async () => {
10253
+ const targetTxHash = customMaxTotalSupply === void 0 ? await walletClient.writeContract({
10254
+ address: liquidFactory,
10255
+ abi: liquidFactoryAbi,
10256
+ functionName: "createLiquidTokenMultiCurve",
10257
+ args: [
10258
+ accountAddress,
10259
+ params.tokenUri,
10260
+ params.name,
10261
+ params.symbol,
10262
+ initialRareLiquidity,
10263
+ curves
10264
+ ],
10265
+ account,
10266
+ chain: void 0
10267
+ }) : await walletClient.writeContract({
10268
+ address: liquidFactory,
10269
+ abi: liquidFactoryAbi,
10270
+ functionName: "createLiquidTokenMultiCurveWithSupply",
10271
+ args: [
10272
+ accountAddress,
10273
+ params.tokenUri,
10274
+ params.name,
10275
+ params.symbol,
10276
+ initialRareLiquidity,
10277
+ curves,
10278
+ customMaxTotalSupply
10279
+ ],
10280
+ account,
10281
+ chain: void 0
10282
+ });
10283
+ const deployed = await waitForLiquidEditionAddress(publicClient, targetTxHash);
10284
+ return { txHash: targetTxHash, receipt: deployed.receipt, contract: deployed.contract };
10285
+ }
9656
10286
  });
9657
- const { receipt, contract } = await waitForLiquidEditionAddress(publicClient, txHash);
9658
10287
  return {
9659
10288
  txHash,
9660
10289
  receipt,
@@ -9689,6 +10318,9 @@ function createLiquidNamespace(config, chain, addresses) {
9689
10318
  chain: void 0
9690
10319
  });
9691
10320
  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
10321
+ if (receipt.status === "reverted") {
10322
+ throw liquidEditionSetRenderContractRevertedError(txHash, receipt);
10323
+ }
9692
10324
  return {
9693
10325
  txHash,
9694
10326
  receipt,
@@ -9795,6 +10427,312 @@ function createLiquidNamespace(config, chain, addresses) {
9795
10427
  };
9796
10428
  }
9797
10429
 
10430
+ // src/sdk/bridge.ts
10431
+ import { encodeFunctionData } from "viem";
10432
+
10433
+ // src/contracts/abis/rare-bridge.ts
10434
+ var rareBridgeAbi = [
10435
+ {
10436
+ type: "function",
10437
+ name: "getFee",
10438
+ inputs: [
10439
+ {
10440
+ name: "_destinationChainSelector",
10441
+ type: "uint64",
10442
+ internalType: "uint64"
10443
+ },
10444
+ {
10445
+ name: "_destinationChainRecipient",
10446
+ type: "address",
10447
+ internalType: "address"
10448
+ },
10449
+ {
10450
+ name: "_distributionData",
10451
+ type: "bytes",
10452
+ internalType: "bytes"
10453
+ },
10454
+ {
10455
+ name: "_extraArgs",
10456
+ type: "bytes",
10457
+ internalType: "bytes"
10458
+ },
10459
+ {
10460
+ name: "_payFeesInLink",
10461
+ type: "bool",
10462
+ internalType: "bool"
10463
+ }
10464
+ ],
10465
+ outputs: [
10466
+ {
10467
+ name: "fee",
10468
+ type: "uint256",
10469
+ internalType: "uint256"
10470
+ }
10471
+ ],
10472
+ stateMutability: "view"
10473
+ },
10474
+ {
10475
+ type: "function",
10476
+ name: "send",
10477
+ inputs: [
10478
+ {
10479
+ name: "_destinationChainSelector",
10480
+ type: "uint64",
10481
+ internalType: "uint64"
10482
+ },
10483
+ {
10484
+ name: "_destinationChainRecipient",
10485
+ type: "address",
10486
+ internalType: "address"
10487
+ },
10488
+ {
10489
+ name: "_distributionData",
10490
+ type: "bytes",
10491
+ internalType: "bytes"
10492
+ },
10493
+ {
10494
+ name: "_extraArgs",
10495
+ type: "bytes",
10496
+ internalType: "bytes"
10497
+ },
10498
+ {
10499
+ name: "_payFeesInLink",
10500
+ type: "bool",
10501
+ internalType: "bool"
10502
+ }
10503
+ ],
10504
+ outputs: [],
10505
+ stateMutability: "payable"
10506
+ },
10507
+ {
10508
+ type: "event",
10509
+ name: "MessageSent",
10510
+ inputs: [
10511
+ {
10512
+ name: "messageId",
10513
+ type: "bytes32",
10514
+ indexed: true,
10515
+ internalType: "bytes32"
10516
+ },
10517
+ {
10518
+ name: "destinationChainSelector",
10519
+ type: "uint64",
10520
+ indexed: true,
10521
+ internalType: "uint64"
10522
+ },
10523
+ {
10524
+ name: "destinationChainRecipient",
10525
+ type: "address",
10526
+ indexed: true,
10527
+ internalType: "address"
10528
+ },
10529
+ {
10530
+ name: "fee",
10531
+ type: "uint256",
10532
+ indexed: false,
10533
+ internalType: "uint256"
10534
+ },
10535
+ {
10536
+ name: "payFeesInLink",
10537
+ type: "bool",
10538
+ indexed: false,
10539
+ internalType: "bool"
10540
+ }
10541
+ ],
10542
+ anonymous: false
10543
+ }
10544
+ ];
10545
+
10546
+ // src/sdk/bridge-core.ts
10547
+ import { encodeAbiParameters } from "viem";
10548
+ var allowedBridgePairs = [
10549
+ { sourceChain: "mainnet", destinationChain: "base" },
10550
+ { sourceChain: "base", destinationChain: "mainnet" },
10551
+ { sourceChain: "sepolia", destinationChain: "base-sepolia" },
10552
+ { sourceChain: "base-sepolia", destinationChain: "sepolia" }
10553
+ ];
10554
+ function validateBridgeRoute(route) {
10555
+ const supported = allowedBridgePairs.some(
10556
+ (pair) => pair.sourceChain === route.sourceChain && pair.destinationChain === route.destinationChain
10557
+ );
10558
+ if (supported) {
10559
+ return { isValid: true };
10560
+ }
10561
+ return {
10562
+ isValid: false,
10563
+ error: "unsupported_bridge_route",
10564
+ errorMessage: `Unsupported RARE bridge route "${route.sourceChain}" -> "${route.destinationChain}". Supported routes: mainnet <-> base, sepolia <-> base-sepolia.`
10565
+ };
10566
+ }
10567
+ function getBridgeInfo(chain) {
10568
+ return {
10569
+ chain,
10570
+ chainId: chainIds[chain],
10571
+ rareBridgeAddress: getRareBridgeAddress(chain),
10572
+ rareTokenAddress: resolveCurrency("rare", chain),
10573
+ ccipChainSelector: getCcipChainSelector(chain)
10574
+ };
10575
+ }
10576
+ function encodeBridgeDistribution(params) {
10577
+ return encodeAbiParameters(
10578
+ [
10579
+ { name: "recipients", type: "address[]" },
10580
+ { name: "amounts", type: "uint256[]" }
10581
+ ],
10582
+ [[params.recipient], [params.amount]]
10583
+ );
10584
+ }
10585
+ function buildBridgeSendArgs(params) {
10586
+ return [
10587
+ params.destinationBridgeInfo.ccipChainSelector,
10588
+ params.destinationBridgeInfo.rareBridgeAddress,
10589
+ params.distributionData,
10590
+ "0x",
10591
+ false
10592
+ ];
10593
+ }
10594
+ function buildCcipExplorerUrl(txHash) {
10595
+ return `https://ccip.chain.link/tx/${txHash}`;
10596
+ }
10597
+
10598
+ // src/sdk/bridge.ts
10599
+ function createBridgeNamespace(publicClient, config, sourceChain) {
10600
+ return {
10601
+ async quote(params) {
10602
+ return buildBridgeQuote(publicClient, config, sourceChain, params);
10603
+ },
10604
+ async send(params) {
10605
+ return executeBridge(publicClient, config, sourceChain, params);
10606
+ }
10607
+ };
10608
+ }
10609
+ async function executeBridge(publicClient, config, sourceChain, params) {
10610
+ const { walletClient, account, accountAddress } = requireWallet(config);
10611
+ const quote = await buildBridgeQuote(publicClient, config, sourceChain, {
10612
+ ...params,
10613
+ recipient: params.recipient ?? accountAddress
10614
+ }, {
10615
+ estimateGas: false
10616
+ });
10617
+ const approval = await preparePaymentAmountForSpender({
10618
+ publicClient,
10619
+ walletClient,
10620
+ account,
10621
+ accountAddress,
10622
+ spenderAddress: quote.sourceBridgeAddress,
10623
+ currency: quote.rareTokenAddress,
10624
+ requiredAmount: quote.amount,
10625
+ autoApprove: params.autoApprove
10626
+ });
10627
+ const sendArgs = buildBridgeSendArgs({
10628
+ destinationBridgeInfo: getBridgeInfo(quote.destinationChain),
10629
+ distributionData: quote.distributionData
10630
+ });
10631
+ const { txHash, receipt, estimatedGas } = await runWithApprovalSideEffectAlert({
10632
+ operation: "bridge send",
10633
+ approvals: [{
10634
+ type: "erc20",
10635
+ approvalTxHash: approval.approvalTxHash,
10636
+ target: quote.rareTokenAddress,
10637
+ spender: quote.sourceBridgeAddress
10638
+ }],
10639
+ run: async () => {
10640
+ const gas = await estimateBridgeGas(publicClient, {
10641
+ account: accountAddress,
10642
+ sourceBridgeAddress: quote.sourceBridgeAddress,
10643
+ args: sendArgs,
10644
+ nativeFee: quote.nativeFee
10645
+ });
10646
+ const targetTxHash = await walletClient.writeContract({
10647
+ address: quote.sourceBridgeAddress,
10648
+ abi: rareBridgeAbi,
10649
+ functionName: "send",
10650
+ args: sendArgs,
10651
+ value: quote.nativeFee,
10652
+ account,
10653
+ chain: void 0
10654
+ });
10655
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
10656
+ return { txHash: targetTxHash, receipt: targetReceipt, estimatedGas: gas };
10657
+ }
10658
+ });
10659
+ return {
10660
+ ...quote,
10661
+ estimatedGas,
10662
+ txHash,
10663
+ receipt,
10664
+ approvalTxHash: approval.approvalTxHash,
10665
+ ccipExplorerUrl: buildCcipExplorerUrl(txHash)
10666
+ };
10667
+ }
10668
+ async function buildBridgeQuote(publicClient, config, sourceChain, params, options = {}) {
10669
+ const routeValidation = validateBridgeRoute({
10670
+ sourceChain,
10671
+ destinationChain: params.destinationChain
10672
+ });
10673
+ if (!routeValidation.isValid) {
10674
+ throw new Error(routeValidation.errorMessage);
10675
+ }
10676
+ const sourceBridgeInfo = getBridgeInfo(sourceChain);
10677
+ const destinationBridgeInfo = getBridgeInfo(params.destinationChain);
10678
+ const recipient = resolveRecipient(params.recipient, config);
10679
+ const amount = toPositiveWei(params.amount, "amount");
10680
+ const distributionData = encodeBridgeDistribution({ recipient, amount });
10681
+ const args = buildBridgeSendArgs({
10682
+ destinationBridgeInfo,
10683
+ distributionData
10684
+ });
10685
+ const nativeFee = await publicClient.readContract({
10686
+ address: sourceBridgeInfo.rareBridgeAddress,
10687
+ abi: rareBridgeAbi,
10688
+ functionName: "getFee",
10689
+ args
10690
+ });
10691
+ const estimatedGas = options.estimateGas === false ? void 0 : await estimateBridgeGas(publicClient, {
10692
+ account: getConfiguredAccountAddress2(config),
10693
+ sourceBridgeAddress: sourceBridgeInfo.rareBridgeAddress,
10694
+ args,
10695
+ nativeFee
10696
+ });
10697
+ return {
10698
+ sourceChain,
10699
+ sourceChainId: sourceBridgeInfo.chainId,
10700
+ destinationChain: params.destinationChain,
10701
+ destinationChainId: destinationBridgeInfo.chainId,
10702
+ sourceBridgeAddress: sourceBridgeInfo.rareBridgeAddress,
10703
+ destinationBridgeAddress: destinationBridgeInfo.rareBridgeAddress,
10704
+ rareTokenAddress: sourceBridgeInfo.rareTokenAddress,
10705
+ destinationCcipChainSelector: destinationBridgeInfo.ccipChainSelector,
10706
+ amount,
10707
+ recipient,
10708
+ distributionData,
10709
+ nativeFee,
10710
+ estimatedGas
10711
+ };
10712
+ }
10713
+ function resolveRecipient(recipient, config) {
10714
+ const resolved = recipient ?? getConfiguredAccountAddress2(config);
10715
+ if (resolved === void 0) {
10716
+ throw new Error("No recipient available for bridge quote. Pass params.recipient or provide config.account/walletClient with an account.");
10717
+ }
10718
+ return resolved;
10719
+ }
10720
+ async function estimateBridgeGas(publicClient, params) {
10721
+ if (params.account === void 0) {
10722
+ return void 0;
10723
+ }
10724
+ return publicClient.estimateGas({
10725
+ account: params.account,
10726
+ to: params.sourceBridgeAddress,
10727
+ data: encodeFunctionData({
10728
+ abi: rareBridgeAbi,
10729
+ functionName: "send",
10730
+ args: params.args
10731
+ }),
10732
+ value: params.nativeFee
10733
+ });
10734
+ }
10735
+
9798
10736
  // src/contracts/abis/liquid-router.ts
9799
10737
  var liquidRouterAbi = [
9800
10738
  {
@@ -9845,7 +10783,7 @@ var liquidRouterAbi = [
9845
10783
  ];
9846
10784
 
9847
10785
  // src/swap/known-pools.ts
9848
- import { getAddress as getAddress7 } from "viem";
10786
+ import { getAddress as getAddress8 } from "viem";
9849
10787
 
9850
10788
  // src/swap/pool-core.ts
9851
10789
  function normalizeAddress(value) {
@@ -9864,10 +10802,10 @@ function inferBaseCurrencyAddress(poolKey, token) {
9864
10802
 
9865
10803
  // src/swap/known-pools.ts
9866
10804
  var wrappedEthAddresses = {
9867
- mainnet: getAddress7("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
9868
- sepolia: getAddress7("0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"),
9869
- base: getAddress7("0x4200000000000000000000000000000000000006"),
9870
- "base-sepolia": getAddress7("0x4200000000000000000000000000000000000006")
10805
+ mainnet: getAddress8("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
10806
+ sepolia: getAddress8("0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"),
10807
+ base: getAddress8("0x4200000000000000000000000000000000000006"),
10808
+ "base-sepolia": getAddress8("0x4200000000000000000000000000000000000006")
9871
10809
  };
9872
10810
  function poolToKey(pool) {
9873
10811
  return {
@@ -10181,9 +11119,9 @@ async function quoteRouteSteps(publicClient, quoterAddress, routeSteps, currentA
10181
11119
 
10182
11120
  // src/swap/route-encoding.ts
10183
11121
  import {
10184
- encodeAbiParameters,
10185
- encodePacked as encodePacked2,
10186
- getAddress as getAddress8,
11122
+ encodeAbiParameters as encodeAbiParameters2,
11123
+ encodePacked as encodePacked3,
11124
+ getAddress as getAddress9,
10187
11125
  parseAbiParameters
10188
11126
  } from "viem";
10189
11127
  var ROUTER_COMMANDS = {
@@ -10200,8 +11138,8 @@ var V4_ACTIONS = {
10200
11138
  TAKE_ALL: 15
10201
11139
  };
10202
11140
  var ROUTER_RECIPIENTS = {
10203
- msgSender: getAddress8("0x0000000000000000000000000000000000000001"),
10204
- addressThis: getAddress8("0x0000000000000000000000000000000000000002")
11141
+ msgSender: getAddress9("0x0000000000000000000000000000000000000001"),
11142
+ addressThis: getAddress9("0x0000000000000000000000000000000000000002")
10205
11143
  };
10206
11144
  var ROUTER_AMOUNT_CONSTANTS = {
10207
11145
  openDelta: 0n,
@@ -10213,7 +11151,7 @@ function encodeRoute(quote, amountIn, currencyIn, currencyOut) {
10213
11151
  }
10214
11152
  const { commandBytes, inputs } = encodeRouteParts(quote, amountIn, currencyIn, currencyOut, 0);
10215
11153
  return {
10216
- commands: encodePacked2(commandBytes.map(() => "uint8"), [...commandBytes]),
11154
+ commands: encodePacked3(commandBytes.map(() => "uint8"), [...commandBytes]),
10217
11155
  inputs
10218
11156
  };
10219
11157
  }
@@ -10293,13 +11231,13 @@ function getV4ExecutionMode(v4BlockStartIndex, nextIndex, routeLength) {
10293
11231
  };
10294
11232
  }
10295
11233
  function encodeWrapEth(recipient, amount) {
10296
- return encodeAbiParameters(
11234
+ return encodeAbiParameters2(
10297
11235
  parseAbiParameters("address recipient, uint256 amount"),
10298
11236
  [recipient, amount]
10299
11237
  );
10300
11238
  }
10301
11239
  function encodeUnwrapWeth(recipient, amountMinimum) {
10302
- return encodeAbiParameters(
11240
+ return encodeAbiParameters2(
10303
11241
  parseAbiParameters("address recipient, uint256 amountMinimum"),
10304
11242
  [recipient, amountMinimum]
10305
11243
  );
@@ -10319,23 +11257,23 @@ function encodeV4ExactIn({
10319
11257
  step.poolKey.hooks,
10320
11258
  "0x"
10321
11259
  ]);
10322
- const swapParams = encodeAbiParameters(
11260
+ const swapParams = encodeAbiParameters2(
10323
11261
  parseAbiParameters("(address,(address,uint24,int24,address,bytes)[],uint128,uint128)"),
10324
11262
  [[currencyIn, pathKeysArray, amountIn, minAmountOut]]
10325
11263
  );
10326
11264
  const settleAction = executionMode.inputSource === "user" ? V4_ACTIONS.SETTLE_ALL : V4_ACTIONS.SETTLE;
10327
- const settleParams = executionMode.inputSource === "user" ? encodeAbiParameters(
11265
+ const settleParams = executionMode.inputSource === "user" ? encodeAbiParameters2(
10328
11266
  parseAbiParameters("address currency, uint128 maxAmount"),
10329
11267
  [currencyIn, amountIn]
10330
- ) : encodeAbiParameters(
11268
+ ) : encodeAbiParameters2(
10331
11269
  parseAbiParameters("address currency, uint256 amount, bool payerIsUser"),
10332
11270
  [currencyIn, ROUTER_AMOUNT_CONSTANTS.contractBalance, false]
10333
11271
  );
10334
11272
  const takeAction = executionMode.outputTarget === "user" ? V4_ACTIONS.TAKE_ALL : V4_ACTIONS.TAKE;
10335
- const takeParams = executionMode.outputTarget === "user" ? encodeAbiParameters(
11273
+ const takeParams = executionMode.outputTarget === "user" ? encodeAbiParameters2(
10336
11274
  parseAbiParameters("address currency, uint128 minAmount"),
10337
11275
  [currencyOut, minAmountOut]
10338
- ) : encodeAbiParameters(
11276
+ ) : encodeAbiParameters2(
10339
11277
  parseAbiParameters("address currency, address recipient, uint256 amount"),
10340
11278
  [currencyOut, ROUTER_RECIPIENTS.addressThis, ROUTER_AMOUNT_CONSTANTS.openDelta]
10341
11279
  );
@@ -10344,11 +11282,11 @@ function encodeV4ExactIn({
10344
11282
  if (singleStep === void 0) {
10345
11283
  throw new Error("Missing V4 exact input single step.");
10346
11284
  }
10347
- const actions2 = encodePacked2(
11285
+ const actions2 = encodePacked3(
10348
11286
  ["uint8", "uint8", "uint8"],
10349
11287
  [settleAction, V4_ACTIONS.SWAP_EXACT_IN_SINGLE, takeAction]
10350
11288
  );
10351
- return encodeAbiParameters(
11289
+ return encodeAbiParameters2(
10352
11290
  parseAbiParameters("bytes actions, bytes[] params"),
10353
11291
  [
10354
11292
  actions2,
@@ -10360,11 +11298,11 @@ function encodeV4ExactIn({
10360
11298
  ]
10361
11299
  );
10362
11300
  }
10363
- const actions = encodePacked2(
11301
+ const actions = encodePacked3(
10364
11302
  ["uint8", "uint8", "uint8"],
10365
11303
  [V4_ACTIONS.SWAP_EXACT_IN, settleAction, takeAction]
10366
11304
  );
10367
- return encodeAbiParameters(
11305
+ return encodeAbiParameters2(
10368
11306
  parseAbiParameters("bytes actions, bytes[] params"),
10369
11307
  [actions, [swapParams, settleParams, takeParams]]
10370
11308
  );
@@ -10383,17 +11321,17 @@ function encodeV4ExactInSingle(step, amountIn, minAmountOut) {
10383
11321
  minAmountOut,
10384
11322
  "0x"
10385
11323
  ];
10386
- return encodeAbiParameters(
11324
+ return encodeAbiParameters2(
10387
11325
  parseAbiParameters("((address,address,uint24,int24,address),bool,uint128,uint128,bytes)"),
10388
11326
  [swapExactInSingleTuple]
10389
11327
  );
10390
11328
  }
10391
11329
 
10392
11330
  // src/swap/uniswap-api.ts
10393
- import { getAddress as getAddress9, isHex as isHex3 } from "viem";
11331
+ import { getAddress as getAddress10, isHex as isHex4 } from "viem";
10394
11332
 
10395
11333
  // src/swap/trade-core.ts
10396
- import { isAddressEqual as isAddressEqual15 } from "viem";
11334
+ import { isAddressEqual as isAddressEqual16 } from "viem";
10397
11335
  function toTradeInteger(value, field) {
10398
11336
  if (typeof value === "bigint") return value;
10399
11337
  if (typeof value === "number") {
@@ -10461,7 +11399,7 @@ function buildLiquidRouterTradeQuote(params) {
10461
11399
  }
10462
11400
  function getQuotedRecipientAmount(quote, recipient) {
10463
11401
  const recipientOutput = quote.aggregatedOutputs?.find(
10464
- (output2) => isAddressEqual15(output2.recipient, recipient)
11402
+ (output2) => isAddressEqual16(output2.recipient, recipient)
10465
11403
  );
10466
11404
  if (recipientOutput) {
10467
11405
  return {
@@ -10480,7 +11418,7 @@ function assertSupportedUniswapRouting(routing) {
10480
11418
  }
10481
11419
  }
10482
11420
  function assertRecipientSupportedForUniswapFallback(recipient, accountAddress) {
10483
- if (recipient !== void 0 && !isAddressEqual15(recipient, accountAddress)) {
11421
+ if (recipient !== void 0 && !isAddressEqual16(recipient, accountAddress)) {
10484
11422
  throw new Error("recipient override is not supported for Uniswap API fallback routes.");
10485
11423
  }
10486
11424
  }
@@ -10539,7 +11477,7 @@ function requireApiKey(options) {
10539
11477
  }
10540
11478
  return apiKey;
10541
11479
  }
10542
- function isRecord4(value) {
11480
+ function isRecord5(value) {
10543
11481
  return typeof value === "object" && value !== null;
10544
11482
  }
10545
11483
  function parseString(value, field) {
@@ -10560,7 +11498,7 @@ function parseNumber(value, field) {
10560
11498
  function parseAddress2(value, field) {
10561
11499
  const raw = parseString(value, field);
10562
11500
  try {
10563
- return getAddress9(raw);
11501
+ return getAddress10(raw);
10564
11502
  } catch {
10565
11503
  throw new Error(`Uniswap API response field "${field}" must be a valid EVM address.`);
10566
11504
  }
@@ -10570,13 +11508,13 @@ function parseOptionalAddress2(value, field) {
10570
11508
  }
10571
11509
  function parseHex(value, field) {
10572
11510
  const raw = parseString(value, field);
10573
- if (!isHex3(raw)) {
11511
+ if (!isHex4(raw)) {
10574
11512
  throw new Error(`Uniswap API response field "${field}" must be a hex string.`);
10575
11513
  }
10576
11514
  return raw;
10577
11515
  }
10578
11516
  function parseRecord(value, field) {
10579
- if (!isRecord4(value)) {
11517
+ if (!isRecord5(value)) {
10580
11518
  throw new Error(`Uniswap API response field "${field}" must be an object.`);
10581
11519
  }
10582
11520
  return value;
@@ -10743,7 +11681,7 @@ function parseUniswapSwapResponse(value) {
10743
11681
  };
10744
11682
  }
10745
11683
  function getErrorMessage2(parsed) {
10746
- if (isRecord4(parsed) && typeof parsed.message === "string") {
11684
+ if (isRecord5(parsed) && typeof parsed.message === "string") {
10747
11685
  return parsed.message;
10748
11686
  }
10749
11687
  return void 0;
@@ -10990,7 +11928,7 @@ async function executeRawRouterBuy(params) {
10990
11928
  const minAmountOutInput = requireInput(params.minAmountOut, "minAmountOut");
10991
11929
  const ethAmount = toWei(amountIn);
10992
11930
  const minTokensOut = await toTokenAmount(params.publicClient, params.token, minAmountOutInput, "minAmountOut");
10993
- const txHash = await walletClient.writeContract({
11931
+ const targetTxHash = await walletClient.writeContract({
10994
11932
  address: router,
10995
11933
  abi: liquidRouterAbi,
10996
11934
  functionName: "buy",
@@ -10999,8 +11937,8 @@ async function executeRawRouterBuy(params) {
10999
11937
  chain: void 0,
11000
11938
  value: ethAmount
11001
11939
  });
11002
- const receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });
11003
- return { txHash, receipt, minAmountOut: minTokensOut };
11940
+ const targetReceipt = await params.publicClient.waitForTransactionReceipt({ hash: targetTxHash });
11941
+ return { txHash: targetTxHash, receipt: targetReceipt, minAmountOut: minTokensOut };
11004
11942
  }
11005
11943
  async function executeRawRouterSell(params) {
11006
11944
  const { walletClient, account, accountAddress } = requireWallet(params.config);
@@ -11010,25 +11948,37 @@ async function executeRawRouterSell(params) {
11010
11948
  const minAmountOutInput = requireInput(params.minAmountOut, "minAmountOut");
11011
11949
  const tokenAmount = await toTokenAmount(params.publicClient, params.token, amountIn, "amountIn");
11012
11950
  const minEthOut = toWei(minAmountOutInput);
11013
- await ensureTokenAllowance(params.publicClient, walletClient, account, accountAddress, params.token, router, tokenAmount);
11014
- const txHash = await walletClient.writeContract({
11015
- address: router,
11016
- abi: liquidRouterAbi,
11017
- functionName: "sell",
11018
- args: [
11019
- params.token,
11020
- tokenAmount,
11021
- params.recipient ?? accountAddress,
11022
- minEthOut,
11023
- params.commands,
11024
- [...params.inputs],
11025
- resolveDeadline(params.deadline)
11026
- ],
11027
- account,
11028
- chain: void 0
11951
+ const approvalTxHash = await ensureTokenAllowance(params.publicClient, walletClient, account, accountAddress, params.token, router, tokenAmount);
11952
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
11953
+ operation: "swap sell",
11954
+ approvals: [{
11955
+ type: "erc20",
11956
+ approvalTxHash,
11957
+ target: params.token,
11958
+ spender: router
11959
+ }],
11960
+ run: async () => {
11961
+ const targetTxHash = await walletClient.writeContract({
11962
+ address: router,
11963
+ abi: liquidRouterAbi,
11964
+ functionName: "sell",
11965
+ args: [
11966
+ params.token,
11967
+ tokenAmount,
11968
+ params.recipient ?? accountAddress,
11969
+ minEthOut,
11970
+ params.commands,
11971
+ [...params.inputs],
11972
+ resolveDeadline(params.deadline)
11973
+ ],
11974
+ account,
11975
+ chain: void 0
11976
+ });
11977
+ const targetReceipt = await params.publicClient.waitForTransactionReceipt({ hash: targetTxHash });
11978
+ return { txHash: targetTxHash, receipt: targetReceipt };
11979
+ }
11029
11980
  });
11030
- const receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });
11031
- return { txHash, receipt, minAmountOut: minEthOut, tokenAmount };
11981
+ return { txHash, receipt, minAmountOut: minEthOut, tokenAmount, approvalTxHash };
11032
11982
  }
11033
11983
  function isRawTokenTradeParams(params) {
11034
11984
  return params.route === "raw";
@@ -11072,28 +12022,38 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11072
12022
  validateRouterPayload(params.commands, params.inputs);
11073
12023
  const amountIn = await toTokenAmount(publicClient, params.tokenIn, params.amountIn, "amountIn");
11074
12024
  const minAmountOut = await toTokenAmount(publicClient, params.tokenOut, params.minAmountOut, "minAmountOut");
11075
- if (params.tokenIn !== ETH_ADDRESS) {
11076
- await ensureTokenAllowance(publicClient, walletClient, account, accountAddress, params.tokenIn, router, amountIn);
11077
- }
11078
- const txHash = await walletClient.writeContract({
11079
- address: router,
11080
- abi: liquidRouterAbi,
11081
- functionName: "swap",
11082
- args: [
11083
- params.tokenIn,
11084
- amountIn,
11085
- params.tokenOut,
11086
- params.recipient ?? accountAddress,
11087
- minAmountOut,
11088
- params.commands,
11089
- [...params.inputs],
11090
- resolveDeadline(params.deadline)
11091
- ],
11092
- account,
11093
- chain: void 0,
11094
- value: params.tokenIn === ETH_ADDRESS ? amountIn : void 0
12025
+ const approvalTxHash = params.tokenIn === ETH_ADDRESS ? void 0 : await ensureTokenAllowance(publicClient, walletClient, account, accountAddress, params.tokenIn, router, amountIn);
12026
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
12027
+ operation: "swap tokens",
12028
+ approvals: [{
12029
+ type: "erc20",
12030
+ approvalTxHash,
12031
+ target: params.tokenIn,
12032
+ spender: router
12033
+ }],
12034
+ run: async () => {
12035
+ const targetTxHash = await walletClient.writeContract({
12036
+ address: router,
12037
+ abi: liquidRouterAbi,
12038
+ functionName: "swap",
12039
+ args: [
12040
+ params.tokenIn,
12041
+ amountIn,
12042
+ params.tokenOut,
12043
+ params.recipient ?? accountAddress,
12044
+ minAmountOut,
12045
+ params.commands,
12046
+ [...params.inputs],
12047
+ resolveDeadline(params.deadline)
12048
+ ],
12049
+ account,
12050
+ chain: void 0,
12051
+ value: params.tokenIn === ETH_ADDRESS ? amountIn : void 0
12052
+ });
12053
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
12054
+ return { txHash: targetTxHash, receipt: targetReceipt };
12055
+ }
11095
12056
  });
11096
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
11097
12057
  return { txHash, receipt };
11098
12058
  },
11099
12059
  async quoteBuyToken(params) {
@@ -11160,7 +12120,7 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11160
12120
  });
11161
12121
  if (quoteDetails.kind === "local") {
11162
12122
  const router = requireConfiguredAddress(addresses.swapRouter, "Liquid router", chain);
11163
- const txHash = await walletClient.writeContract({
12123
+ const targetTxHash = await walletClient.writeContract({
11164
12124
  address: router,
11165
12125
  abi: liquidRouterAbi,
11166
12126
  functionName: "buy",
@@ -11176,10 +12136,10 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11176
12136
  chain: void 0,
11177
12137
  value: quoteDetails.quote.amountIn
11178
12138
  });
11179
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
12139
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
11180
12140
  return {
11181
- txHash,
11182
- receipt,
12141
+ txHash: targetTxHash,
12142
+ receipt: targetReceipt,
11183
12143
  estimatedAmountOut: quoteDetails.quote.estimatedAmountOut,
11184
12144
  minAmountOut: quoteDetails.quote.minAmountOut,
11185
12145
  routeSource: quoteDetails.quote.routeSource,
@@ -11271,24 +12231,36 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11271
12231
  const router = requireConfiguredAddress(addresses.swapRouter, "Liquid router", chain);
11272
12232
  const amountIn = requireInput(params.amountIn, "amountIn");
11273
12233
  const tokenAmount = await toTokenAmount(publicClient, params.token, amountIn, "amountIn");
11274
- await ensureTokenAllowance(publicClient, walletClient, account, accountAddress, params.token, router, tokenAmount);
11275
- const txHash = await walletClient.writeContract({
11276
- address: router,
11277
- abi: liquidRouterAbi,
11278
- functionName: "sell",
11279
- args: [
11280
- params.token,
11281
- tokenAmount,
11282
- params.recipient ?? accountAddress,
11283
- quoteDetails.quote.minAmountOut,
11284
- quoteDetails.quote.commands,
11285
- [...quoteDetails.quote.inputs],
11286
- resolveDeadline(params.deadline)
11287
- ],
11288
- account,
11289
- chain: void 0
12234
+ const approvalTxHash2 = await ensureTokenAllowance(publicClient, walletClient, account, accountAddress, params.token, router, tokenAmount);
12235
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
12236
+ operation: "sell token",
12237
+ approvals: [{
12238
+ type: "erc20",
12239
+ approvalTxHash: approvalTxHash2,
12240
+ target: params.token,
12241
+ spender: router
12242
+ }],
12243
+ run: async () => {
12244
+ const targetTxHash = await walletClient.writeContract({
12245
+ address: router,
12246
+ abi: liquidRouterAbi,
12247
+ functionName: "sell",
12248
+ args: [
12249
+ params.token,
12250
+ tokenAmount,
12251
+ params.recipient ?? accountAddress,
12252
+ quoteDetails.quote.minAmountOut,
12253
+ quoteDetails.quote.commands,
12254
+ [...quoteDetails.quote.inputs],
12255
+ resolveDeadline(params.deadline)
12256
+ ],
12257
+ account,
12258
+ chain: void 0
12259
+ });
12260
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
12261
+ return { txHash: targetTxHash, receipt: targetReceipt };
12262
+ }
11290
12263
  });
11291
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
11292
12264
  return {
11293
12265
  txHash,
11294
12266
  receipt,
@@ -11297,7 +12269,8 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11297
12269
  routeSource: quoteDetails.quote.routeSource,
11298
12270
  execution: quoteDetails.quote.execution,
11299
12271
  commands: quoteDetails.quote.commands,
11300
- inputs: quoteDetails.quote.inputs
12272
+ inputs: quoteDetails.quote.inputs,
12273
+ approvalTxHash: approvalTxHash2
11301
12274
  };
11302
12275
  }
11303
12276
  const approval = await requestUniswapApproval({
@@ -11316,14 +12289,33 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11316
12289
  accountAddress,
11317
12290
  chainId
11318
12291
  })).txHash : void 0;
11319
- const swapResponse = await requestUniswapSwap({
11320
- apiKey: quoteDetails.apiKey,
11321
- quote: quoteDetails.rawQuote,
11322
- deadline: uniswapDeadline
11323
- });
11324
- const sent = await sendPreparedTransaction(publicClient, walletClient, account, swapResponse.swap, {
11325
- accountAddress,
11326
- chainId
12292
+ const sent = await runWithApprovalSideEffectAlert({
12293
+ operation: "sell token",
12294
+ approvals: [
12295
+ {
12296
+ type: "erc20-reset",
12297
+ approvalTxHash: approvalResetTxHash,
12298
+ target: params.token,
12299
+ spender: approval.cancel?.to
12300
+ },
12301
+ {
12302
+ type: "erc20",
12303
+ approvalTxHash,
12304
+ target: params.token,
12305
+ spender: approval.approval?.to
12306
+ }
12307
+ ],
12308
+ run: async () => {
12309
+ const swapResponse = await requestUniswapSwap({
12310
+ apiKey: quoteDetails.apiKey,
12311
+ quote: quoteDetails.rawQuote,
12312
+ deadline: uniswapDeadline
12313
+ });
12314
+ return sendPreparedTransaction(publicClient, walletClient, account, swapResponse.swap, {
12315
+ accountAddress,
12316
+ chainId
12317
+ });
12318
+ }
11327
12319
  });
11328
12320
  return {
11329
12321
  ...sent,
@@ -11342,7 +12334,7 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11342
12334
  const { walletClient, account, accountAddress } = requireWallet(config);
11343
12335
  const router = requireConfiguredAddress(addresses.swapRouter, "Liquid router", chain);
11344
12336
  const quote = await buildBuyRareQuote(publicClient, chain, addresses, params);
11345
- const txHash = await walletClient.writeContract({
12337
+ const targetTxHash = await walletClient.writeContract({
11346
12338
  address: router,
11347
12339
  abi: liquidRouterAbi,
11348
12340
  functionName: "buy",
@@ -11351,10 +12343,10 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11351
12343
  chain: void 0,
11352
12344
  value: quote.ethAmount
11353
12345
  });
11354
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
12346
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
11355
12347
  return {
11356
- txHash,
11357
- receipt,
12348
+ txHash: targetTxHash,
12349
+ receipt: targetReceipt,
11358
12350
  estimatedRareOut: quote.estimatedRareOut,
11359
12351
  minRareOut: quote.minRareOut,
11360
12352
  commands: quote.commands,
@@ -11368,7 +12360,7 @@ function createSwapNamespace(config, chain, chainId, addresses) {
11368
12360
  import {
11369
12361
  erc20Abi as erc20Abi2,
11370
12362
  hexToBigInt as hexToBigInt2,
11371
- isAddressEqual as isAddressEqual17,
12363
+ isAddressEqual as isAddressEqual18,
11372
12364
  parseEventLogs as parseEventLogs6
11373
12365
  } from "viem";
11374
12366
 
@@ -11715,7 +12707,7 @@ function normalizeLazySovereignCollectionContractType(input) {
11715
12707
  );
11716
12708
  }
11717
12709
  function planCreateLazySovereignCollection(params) {
11718
- const contractType = params.contractType ?? "lazy";
12710
+ const contractType = normalizeLazySovereignCollectionContractType(params.contractType) ?? "lazy";
11719
12711
  return {
11720
12712
  name: params.name,
11721
12713
  symbol: params.symbol,
@@ -11873,11 +12865,11 @@ function toRoyaltyPercentage(value) {
11873
12865
 
11874
12866
  // src/sdk/release-core.ts
11875
12867
  import {
11876
- getAddress as getAddress10,
11877
- isAddress as isAddress6,
11878
- isAddressEqual as isAddressEqual16,
11879
- isHex as isHex4,
11880
- keccak256 as keccak2562,
12868
+ getAddress as getAddress11,
12869
+ isAddress as isAddress7,
12870
+ isAddressEqual as isAddressEqual17,
12871
+ isHex as isHex5,
12872
+ keccak256 as keccak2563,
11881
12873
  parseEther as parseEther2,
11882
12874
  parseUnits as parseUnits7
11883
12875
  } from "viem";
@@ -11894,7 +12886,7 @@ function requireRareMinterAddress(address) {
11894
12886
  }
11895
12887
  function assertReleaseContractOwner(opts) {
11896
12888
  const { contract, accountAddress, owner } = opts;
11897
- if (!isAddressEqual16(owner, accountAddress)) {
12889
+ if (!isAddressEqual17(owner, accountAddress)) {
11898
12890
  throw new Error(
11899
12891
  `Connected wallet ${accountAddress} is not the owner of collection ${contract}. Contract owner is ${owner}.`
11900
12892
  );
@@ -12042,7 +13034,7 @@ function parseReleaseAllowlistArtifactJson(input) {
12042
13034
  return parseReleaseAllowlistArtifact(parsed);
12043
13035
  }
12044
13036
  function parseReleaseAllowlistArtifact(input) {
12045
- if (!isRecord5(input)) {
13037
+ if (!isRecord6(input)) {
12046
13038
  throw new Error("Allowlist artifact must be a JSON object.");
12047
13039
  }
12048
13040
  if (input.kind !== RELEASE_ALLOWLIST_ARTIFACT_KIND || input.version !== 1) {
@@ -12054,7 +13046,7 @@ function parseReleaseAllowlistArtifact(input) {
12054
13046
  }
12055
13047
  const wallets = normalizeAllowlistRows(
12056
13048
  input.wallets.map((entry, index) => {
12057
- if (!isRecord5(entry)) {
13049
+ if (!isRecord6(entry)) {
12058
13050
  throw new Error(`Invalid allowlist artifact wallet at index ${index}: expected an object.`);
12059
13051
  }
12060
13052
  return {
@@ -12083,7 +13075,7 @@ function parseReleaseAllowlistCsv(input) {
12083
13075
  throw new Error("CSV allowlist is empty.");
12084
13076
  }
12085
13077
  const headerColumn = findAllowlistAddressColumn(firstRow.fields);
12086
- if (headerColumn === -1 && !isAddress6(firstRow.fields[0]?.trim() ?? "")) {
13078
+ if (headerColumn === -1 && !isAddress7(firstRow.fields[0]?.trim() ?? "")) {
12087
13079
  throw new Error("CSV allowlist must put wallet addresses in the first column or include an address/wallet header.");
12088
13080
  }
12089
13081
  const addressColumn = headerColumn === -1 ? 0 : headerColumn;
@@ -12098,10 +13090,10 @@ function parseReleaseAllowlistCsv(input) {
12098
13090
  }
12099
13091
  function parseReleaseAllowlistJson(input) {
12100
13092
  const parsed = parseJsonUnknown(input, "Malformed JSON allowlist");
12101
- if (isRecord5(parsed) && parsed.kind === RELEASE_ALLOWLIST_ARTIFACT_KIND) {
13093
+ if (isRecord6(parsed) && parsed.kind === RELEASE_ALLOWLIST_ARTIFACT_KIND) {
12102
13094
  return parseReleaseAllowlistArtifact(parsed).wallets.map((wallet) => wallet.address);
12103
13095
  }
12104
- const entries = Array.isArray(parsed) ? parsed : isRecord5(parsed) && Array.isArray(parsed.wallets) ? parsed.wallets : isRecord5(parsed) && Array.isArray(parsed.addresses) ? parsed.addresses : null;
13096
+ const entries = Array.isArray(parsed) ? parsed : isRecord6(parsed) && Array.isArray(parsed.wallets) ? parsed.wallets : isRecord6(parsed) && Array.isArray(parsed.addresses) ? parsed.addresses : null;
12105
13097
  if (!entries) {
12106
13098
  throw new Error(
12107
13099
  "JSON allowlist must be an array of wallet addresses, an array of objects with address/wallet, or an object with wallets/addresses."
@@ -12142,27 +13134,27 @@ function buildReleaseAllowlistArtifact(wallets) {
12142
13134
  };
12143
13135
  }
12144
13136
  function getReleaseAllowlistProof(opts) {
12145
- const address = getAddress10(opts.address);
13137
+ const address = getAddress11(opts.address);
12146
13138
  return opts.artifact.wallets.find((entry) => addressesEqual(entry.address, address)) ?? null;
12147
13139
  }
12148
13140
  function verifyReleaseAllowlistProof(opts) {
12149
13141
  const root = normalizeBytes322(opts.root, "allowlist root");
12150
13142
  const hash = opts.proof.reduce(
12151
13143
  (current, sibling) => hashMerklePair(current, normalizeBytes322(sibling, "allowlist proof item")),
12152
- hashAllowlistAddress(getAddress10(opts.address))
13144
+ hashAllowlistAddress(getAddress11(opts.address))
12153
13145
  );
12154
13146
  return hexEquals(hash, root);
12155
13147
  }
12156
13148
  function preflightReleaseDirectSaleMint(params) {
12157
13149
  const { status, plan, buyer, nowSeconds } = params;
12158
13150
  const quantity = BigInt(plan.quantity);
12159
- if (!isAddressEqual16(status.contract, plan.contract)) {
13151
+ if (!isAddressEqual17(status.contract, plan.contract)) {
12160
13152
  throw new Error(`Release status is for ${status.contract}, but mint plan is for ${plan.contract}.`);
12161
13153
  }
12162
13154
  if (!status.configured) {
12163
13155
  throw new Error("RareMinter direct sale is not configured for this contract.");
12164
13156
  }
12165
- if (plan.recipient !== void 0 && !isAddressEqual16(plan.recipient, buyer)) {
13157
+ if (plan.recipient !== void 0 && !isAddressEqual17(plan.recipient, buyer)) {
12166
13158
  throw new Error("RareMinter direct sale mint does not support a separate recipient; it mints to the connected wallet.");
12167
13159
  }
12168
13160
  if (status.startTime > nowSeconds) {
@@ -12186,7 +13178,7 @@ function preflightReleaseDirectSaleMint(params) {
12186
13178
  throw new Error("buyer has reached the per-wallet transaction limit.");
12187
13179
  }
12188
13180
  }
12189
- if (plan.currency !== void 0 && !isAddressEqual16(plan.currency, status.currencyAddress)) {
13181
+ if (plan.currency !== void 0 && !isAddressEqual17(plan.currency, status.currencyAddress)) {
12190
13182
  throw new Error(`expected currency ${plan.currency} does not match configured currency ${status.currencyAddress}.`);
12191
13183
  }
12192
13184
  const price = plan.price === void 0 ? status.price : normalizeReleasePrice({
@@ -12320,11 +13312,11 @@ function requireReleaseAccountCounter(value, label) {
12320
13312
  return value;
12321
13313
  }
12322
13314
  function normalizeBytes322(value, field) {
12323
- if (typeof value !== "string" || !isHex4(value) || value.length !== 66) {
13315
+ if (typeof value !== "string" || !isHex5(value) || value.length !== 66) {
12324
13316
  throw new Error(`${field} must be a 32-byte hex string.`);
12325
13317
  }
12326
13318
  const normalized = value.toLocaleLowerCase();
12327
- if (!isHex4(normalized) || normalized.length !== 66) {
13319
+ if (!isHex5(normalized) || normalized.length !== 66) {
12328
13320
  throw new Error(`${field} must be a 32-byte hex string.`);
12329
13321
  }
12330
13322
  return normalized;
@@ -12394,11 +13386,11 @@ function normalizeAllowlistRows(rows) {
12394
13386
  throw new Error(`Invalid allowlist address at ${row.label}: expected a string.`);
12395
13387
  }
12396
13388
  const raw = row.value.trim();
12397
- if (!isAddress6(raw)) {
13389
+ if (!isAddress7(raw)) {
12398
13390
  throw new Error(`Invalid allowlist address at ${row.label}: "${raw}".`);
12399
13391
  }
12400
- const address = getAddress10(raw);
12401
- const duplicate = state.seen.find((seen) => isAddressEqual16(seen.address, address));
13392
+ const address = getAddress11(raw);
13393
+ const duplicate = state.seen.find((seen) => isAddressEqual17(seen.address, address));
12402
13394
  if (duplicate !== void 0) {
12403
13395
  throw new Error(`Duplicate allowlist address at ${row.label}: "${address}" duplicates ${duplicate.label}.`);
12404
13396
  }
@@ -12412,7 +13404,7 @@ function getAddressFromJsonAllowlistEntry(entry, label) {
12412
13404
  if (typeof entry === "string") {
12413
13405
  return entry;
12414
13406
  }
12415
- if (!isRecord5(entry)) {
13407
+ if (!isRecord6(entry)) {
12416
13408
  throw new Error(`Invalid allowlist ${label}: expected a string or object.`);
12417
13409
  }
12418
13410
  if ("address" in entry) return entry.address;
@@ -12454,11 +13446,11 @@ function getMerkleRoot(layers) {
12454
13446
  return root;
12455
13447
  }
12456
13448
  function hashAllowlistAddress(address) {
12457
- return keccak2562(address);
13449
+ return keccak2563(address);
12458
13450
  }
12459
13451
  function hashMerklePair(a, b) {
12460
13452
  const [left, right] = compareHex(a, b) <= 0 ? [a, b] : [b, a];
12461
- return keccak2562(`0x${left.slice(2)}${right.slice(2)}`);
13453
+ return keccak2563(`0x${left.slice(2)}${right.slice(2)}`);
12462
13454
  }
12463
13455
  function compareAddress(a, b) {
12464
13456
  return a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase());
@@ -12467,12 +13459,12 @@ function compareHex(a, b) {
12467
13459
  return a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase());
12468
13460
  }
12469
13461
  function addressesEqual(a, b) {
12470
- return isAddressEqual16(a, b);
13462
+ return isAddressEqual17(a, b);
12471
13463
  }
12472
13464
  function hexEquals(a, b) {
12473
13465
  return a.toLocaleLowerCase() === b.toLocaleLowerCase();
12474
13466
  }
12475
- function isRecord5(value) {
13467
+ function isRecord6(value) {
12476
13468
  return typeof value === "object" && value !== null && !Array.isArray(value);
12477
13469
  }
12478
13470
  function parseJsonUnknown(input, label) {
@@ -12542,10 +13534,8 @@ async function readReleaseCollectionOwner(publicClient, contract) {
12542
13534
  );
12543
13535
  }
12544
13536
  }
12545
- async function assertConfigurableReleaseContract(opts) {
13537
+ async function assertReleaseMinterCanMint(opts) {
12546
13538
  const { publicClient, contract, accountAddress, rareMinter } = opts;
12547
- const owner = await readReleaseCollectionOwner(publicClient, contract);
12548
- assertReleaseContractOwner({ contract, accountAddress, owner });
12549
13539
  try {
12550
13540
  await publicClient.simulateContract({
12551
13541
  address: contract,
@@ -12724,7 +13714,7 @@ function readMintDirectSaleTokenRange(opts) {
12724
13714
  eventName: "MintDirectSale",
12725
13715
  logs: opts.receipt.logs
12726
13716
  }).filter(
12727
- (log2) => isAddressEqual17(log2.args._contractAddress, opts.contract) && isAddressEqual17(log2.args._buyer, opts.buyer)
13717
+ (log2) => isAddressEqual18(log2.args._contractAddress, opts.contract) && isAddressEqual18(log2.args._buyer, opts.buyer)
12728
13718
  );
12729
13719
  if (event === void 0) {
12730
13720
  throw new Error(`MintDirectSale event was not found for ${opts.contract} and buyer ${opts.buyer}.`);
@@ -12911,6 +13901,11 @@ function createReleaseNamespace(publicClient, config, chain, addresses) {
12911
13901
  currencyDecimals: currencyDecimals2,
12912
13902
  nowSeconds: currentUnixTimestamp3()
12913
13903
  });
13904
+ await assertCollectionOwnerForReleaseWrite({
13905
+ publicClient,
13906
+ contract: plan.contract,
13907
+ accountAddress
13908
+ });
12914
13909
  const approvalTxHash = await approveReleaseMinterIfNeeded({
12915
13910
  publicClient,
12916
13911
  walletClient,
@@ -12919,29 +13914,41 @@ function createReleaseNamespace(publicClient, config, chain, addresses) {
12919
13914
  minter: rareMinter,
12920
13915
  autoApprove: params.autoApprove
12921
13916
  });
12922
- await assertConfigurableReleaseContract({
12923
- publicClient,
12924
- contract: plan.contract,
12925
- accountAddress,
12926
- rareMinter
12927
- });
12928
- const txHash = await walletClient.writeContract({
12929
- address: rareMinter,
12930
- abi: rareMinterAbi,
12931
- functionName: "prepareMintDirectSale",
12932
- args: [
12933
- plan.contract,
12934
- plan.currencyAddress,
12935
- plan.price,
12936
- plan.startTime,
12937
- plan.maxMints,
12938
- plan.splitRecipients,
12939
- plan.splitRatios
12940
- ],
12941
- account,
12942
- chain: void 0
13917
+ const { txHash, receipt } = await runWithApprovalSideEffectAlert({
13918
+ operation: "release configure",
13919
+ approvals: [{
13920
+ type: "minter",
13921
+ approvalTxHash,
13922
+ target: plan.contract,
13923
+ minter: rareMinter
13924
+ }],
13925
+ run: async () => {
13926
+ await assertReleaseMinterCanMint({
13927
+ publicClient,
13928
+ contract: plan.contract,
13929
+ accountAddress,
13930
+ rareMinter
13931
+ });
13932
+ const configureTxHash = await walletClient.writeContract({
13933
+ address: rareMinter,
13934
+ abi: rareMinterAbi,
13935
+ functionName: "prepareMintDirectSale",
13936
+ args: [
13937
+ plan.contract,
13938
+ plan.currencyAddress,
13939
+ plan.price,
13940
+ plan.startTime,
13941
+ plan.maxMints,
13942
+ plan.splitRecipients,
13943
+ plan.splitRatios
13944
+ ],
13945
+ account,
13946
+ chain: void 0
13947
+ });
13948
+ const configureReceipt = await publicClient.waitForTransactionReceipt({ hash: configureTxHash });
13949
+ return { txHash: configureTxHash, receipt: configureReceipt };
13950
+ }
12943
13951
  });
12944
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
12945
13952
  return {
12946
13953
  txHash,
12947
13954
  receipt,
@@ -12990,26 +13997,38 @@ function createReleaseNamespace(publicClient, config, chain, addresses) {
12990
13997
  amount: mint.totalPrice,
12991
13998
  autoApprove: plan.autoApprove
12992
13999
  });
12993
- const txHash = await walletClient.writeContract({
12994
- address: rareMinter,
12995
- abi: rareMinterAbi,
12996
- functionName: "mintDirectSale",
12997
- args: [
12998
- mint.contract,
12999
- mint.currency,
13000
- mint.price,
13001
- mint.quantity,
13002
- mint.proof
13003
- ],
13004
- account,
13005
- chain: void 0,
13006
- value: payment.value
13007
- });
13008
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
13009
- const tokenRange = readMintDirectSaleTokenRange({
13010
- receipt,
13011
- contract: mint.contract,
13012
- buyer: accountAddress
14000
+ const { txHash, receipt, tokenRange } = await runWithApprovalSideEffectAlert({
14001
+ operation: "release mint",
14002
+ approvals: [{
14003
+ type: "erc20",
14004
+ approvalTxHash: payment.approvalTxHash,
14005
+ target: mint.currency,
14006
+ spender: rareMinter
14007
+ }],
14008
+ run: async () => {
14009
+ const targetTxHash = await walletClient.writeContract({
14010
+ address: rareMinter,
14011
+ abi: rareMinterAbi,
14012
+ functionName: "mintDirectSale",
14013
+ args: [
14014
+ mint.contract,
14015
+ mint.currency,
14016
+ mint.price,
14017
+ mint.quantity,
14018
+ mint.proof
14019
+ ],
14020
+ account,
14021
+ chain: void 0,
14022
+ value: payment.value
14023
+ });
14024
+ const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
14025
+ const mintedTokenRange = readMintDirectSaleTokenRange({
14026
+ receipt: targetReceipt,
14027
+ contract: mint.contract,
14028
+ buyer: accountAddress
14029
+ });
14030
+ return { txHash: targetTxHash, receipt: targetReceipt, tokenRange: mintedTokenRange };
14031
+ }
13013
14032
  });
13014
14033
  return {
13015
14034
  txHash,
@@ -13952,317 +14971,115 @@ async function writeSetDefaultRoyaltyReceiver(opts) {
13952
14971
  chain: void 0
13953
14972
  });
13954
14973
  }
13955
- async function writeSetDefaultRoyaltyPercentage(opts) {
13956
- const write = buildCollectionRoyaltyPercentageWrite(opts.plan);
13957
- try {
13958
- await opts.publicClient.simulateContract({
13959
- address: opts.plan.contract,
13960
- abi: collectionOwnerAbi,
13961
- functionName: write.functionName,
13962
- args: write.args,
13963
- account: opts.account
13964
- });
13965
- } catch (error) {
13966
- throw contractSupportError(write.functionName, opts.plan.contract, error);
13967
- }
13968
- return opts.walletClient.writeContract({
13969
- address: opts.plan.contract,
13970
- abi: collectionOwnerAbi,
13971
- functionName: write.functionName,
13972
- args: write.args,
13973
- account: opts.account,
13974
- chain: void 0
13975
- });
13976
- }
13977
- async function writeSetTokenRoyaltyReceiver(opts) {
13978
- try {
13979
- await opts.publicClient.simulateContract({
13980
- address: opts.plan.contract,
13981
- abi: collectionOwnerAbi,
13982
- functionName: "setRoyaltyReceiverForToken",
13983
- args: [opts.plan.receiver, opts.plan.tokenId],
13984
- account: opts.account
13985
- });
13986
- } catch (error) {
13987
- throw contractSupportError("setRoyaltyReceiverForToken", opts.plan.contract, error);
13988
- }
13989
- return opts.walletClient.writeContract({
13990
- address: opts.plan.contract,
13991
- abi: collectionOwnerAbi,
13992
- functionName: "setRoyaltyReceiverForToken",
13993
- args: [opts.plan.receiver, opts.plan.tokenId],
13994
- account: opts.account,
13995
- chain: void 0
13996
- });
13997
- }
13998
- async function writeUpdateBaseUri(opts) {
13999
- try {
14000
- await opts.publicClient.simulateContract({
14001
- address: opts.plan.contract,
14002
- abi: collectionOwnerAbi,
14003
- functionName: "updateBaseURI",
14004
- args: [opts.plan.baseUri],
14005
- account: opts.account
14006
- });
14007
- } catch (error) {
14008
- throw contractSupportError("updateBaseURI", opts.plan.contract, error);
14009
- }
14010
- return opts.walletClient.writeContract({
14011
- address: opts.plan.contract,
14012
- abi: collectionOwnerAbi,
14013
- functionName: "updateBaseURI",
14014
- args: [opts.plan.baseUri],
14015
- account: opts.account,
14016
- chain: void 0
14017
- });
14018
- }
14019
- async function writeUpdateTokenUri(opts) {
14020
- try {
14021
- await opts.publicClient.simulateContract({
14022
- address: opts.plan.contract,
14023
- abi: collectionOwnerAbi,
14024
- functionName: "updateTokenURI",
14025
- args: [opts.plan.tokenId, opts.plan.tokenUri],
14026
- account: opts.account
14027
- });
14028
- } catch (error) {
14029
- throw contractSupportError("updateTokenURI", opts.plan.contract, error);
14030
- }
14031
- return opts.walletClient.writeContract({
14032
- address: opts.plan.contract,
14033
- abi: collectionOwnerAbi,
14034
- functionName: "updateTokenURI",
14035
- args: [opts.plan.tokenId, opts.plan.tokenUri],
14036
- account: opts.account,
14037
- chain: void 0
14038
- });
14039
- }
14040
- async function writeLockBaseUri(opts) {
14041
- try {
14042
- await opts.publicClient.simulateContract({
14043
- address: opts.plan.contract,
14044
- abi: collectionOwnerAbi,
14045
- functionName: "lockBaseURI",
14046
- account: opts.account
14047
- });
14048
- } catch (error) {
14049
- throw contractSupportError("lockBaseURI", opts.plan.contract, error);
14050
- }
14051
- return opts.walletClient.writeContract({
14052
- address: opts.plan.contract,
14053
- abi: collectionOwnerAbi,
14054
- functionName: "lockBaseURI",
14055
- account: opts.account,
14056
- chain: void 0
14057
- });
14058
- }
14059
- function contractSupportError(operation, contract, cause) {
14060
- return new Error(
14061
- `Collection ${contract} does not support ${operation}, or the ${operation} preflight failed.`,
14062
- { cause }
14063
- );
14064
- }
14065
-
14066
- // src/sdk/merkle-core.ts
14067
- import { Buffer } from "buffer";
14068
- import { MerkleTree } from "merkletreejs";
14069
- import {
14070
- encodePacked as encodePacked3,
14071
- getAddress as getAddress11,
14072
- isAddress as isAddress7,
14073
- isAddressEqual as isAddressEqual18,
14074
- isHex as isHex5,
14075
- keccak256 as keccak2563
14076
- } from "viem";
14077
- function hexBuffer(hex) {
14078
- return Buffer.from(hex.startsWith("0x") ? hex.slice(2) : hex, "hex");
14079
- }
14080
- function tokenLeaf(contract, tokenId) {
14081
- const packed = encodePacked3(["address", "uint256"], [contract, tokenId]);
14082
- return hexBuffer(keccak2563(packed));
14083
- }
14084
- function addressLeaf(address) {
14085
- return hexBuffer(keccak2563(address));
14086
- }
14087
- function parseBytes32(value, field) {
14088
- if (!isHex5(value) || value.length !== 66) {
14089
- throw new Error(`${field} must be a 0x-prefixed bytes32 hex string`);
14090
- }
14091
- return value;
14092
- }
14093
- function parseBytes32Array(values, field) {
14094
- return values.map((value, index) => parseBytes32(value, `${field}[${index}]`));
14095
- }
14096
- function compareTokenEntries(a, b) {
14097
- if (!isAddressEqual18(a.contract, b.contract)) {
14098
- return a.contract.localeCompare(b.contract);
14099
- }
14100
- return a.tokenId.localeCompare(b.tokenId);
14101
- }
14102
- function normalizeTokenEntry(token) {
14103
- if (!isAddress7(token.contract)) {
14104
- throw new Error(`Invalid token contract address: ${token.contract}`);
14105
- }
14106
- return {
14107
- contract: getAddress11(token.contract),
14108
- tokenId: String(token.tokenId),
14109
- tokenIdBigInt: toInteger(token.tokenId, "tokenId")
14110
- };
14111
- }
14112
- function buildBatchListingTree(tokens) {
14113
- if (tokens.length < 2) {
14114
- throw new Error("buildBatchListingTree requires at least two tokens");
14115
- }
14116
- const sorted = tokens.map(normalizeTokenEntry).sort(compareTokenEntries);
14117
- const leaves = sorted.map((token) => tokenLeaf(token.contract, token.tokenIdBigInt));
14118
- const tree = new MerkleTree(leaves, (data) => hexBuffer(keccak2563(data)), {
14119
- sortPairs: true
14120
- });
14121
- return {
14122
- root: parseBytes32(tree.getHexRoot(), "root"),
14123
- tree,
14124
- sortedTokens: sorted.map(({ contract, tokenId }) => ({ contract, tokenId }))
14125
- };
14126
- }
14127
- function buildAllowListTree(addresses) {
14128
- if (addresses.length < 2) {
14129
- throw new Error("buildAllowListTree requires at least two addresses");
14130
- }
14131
- const sorted = addresses.map((address) => {
14132
- if (!isAddress7(address)) throw new Error(`Invalid allowlist address: ${address}`);
14133
- return getAddress11(address);
14134
- }).sort((a, b) => a.localeCompare(b));
14135
- const leaves = sorted.map(addressLeaf);
14136
- const tree = new MerkleTree(leaves, (data) => hexBuffer(keccak2563(data)), {
14137
- sortPairs: true
14138
- });
14139
- return {
14140
- root: parseBytes32(tree.getHexRoot(), "root"),
14141
- tree,
14142
- sortedAddresses: sorted
14143
- };
14144
- }
14145
- function getTokenProof(tree, contract, tokenId) {
14146
- const leaf = tokenLeaf(getAddress11(contract), tokenId);
14147
- return parseBytes32Array(tree.getHexProof(leaf), "proof");
14148
- }
14149
- function getAddressProof(tree, address) {
14150
- const leaf = addressLeaf(getAddress11(address));
14151
- return parseBytes32Array(tree.getHexProof(leaf), "proof");
14152
- }
14153
- function buildMerkleProofArtifact(artifact, contract, tokenId, buyer) {
14154
- const tokenIdBig = toInteger(tokenId, "tokenId");
14155
- const contractChecksum = getAddress11(contract);
14156
- const found = artifact.tokens.find(
14157
- (token) => isAddressEqual18(token.contract, contractChecksum) && BigInt(token.tokenId) === tokenIdBig
14158
- );
14159
- if (found === void 0) {
14160
- throw new Error(
14161
- `Token ${contractChecksum}/${tokenIdBig.toString()} is not in this root artifact's token set`
14162
- );
14163
- }
14164
- const { tree, root } = buildBatchListingTree(
14165
- artifact.tokens.map((token) => ({ contract: token.contract, tokenId: token.tokenId }))
14166
- );
14167
- if (root !== artifact.root) {
14168
- throw new Error(
14169
- `Recomputed NFT tree root (${root}) does not match artifact root (${artifact.root}). Artifact is corrupt or tree encoding has drifted.`
14170
- );
14171
- }
14172
- const allowListProofFields = buildAllowListProofFields(artifact, buyer);
14173
- return {
14174
- root: artifact.root,
14175
- contract: contractChecksum,
14176
- tokenId: tokenIdBig.toString(),
14177
- proof: getTokenProof(tree, contractChecksum, tokenIdBig),
14178
- ...allowListProofFields ?? {}
14179
- };
14180
- }
14181
- function buildAllowListProofFields(artifact, buyer) {
14182
- if (artifact.allowList === void 0) return void 0;
14183
- if (buyer === void 0) {
14184
- throw new Error(
14185
- "This root has an allowlist; pass buyer address to buildMerkleProofArtifact to include allowListProof"
14186
- );
14187
- }
14188
- if (!isAddress7(buyer)) throw new Error(`Invalid buyer address: ${buyer}`);
14189
- const buyerChecksum = getAddress11(buyer);
14190
- const inAllowList = artifact.allowList.addresses.some((address) => isAddressEqual18(address, buyerChecksum));
14191
- if (!inAllowList) {
14192
- throw new Error(`Buyer ${buyerChecksum} is not in the allowlist`);
14193
- }
14194
- const { tree, root } = buildAllowListTree(artifact.allowList.addresses);
14195
- if (root !== artifact.allowList.root) {
14196
- throw new Error(
14197
- `Recomputed allowlist root (${root}) does not match artifact (${artifact.allowList.root})`
14198
- );
14199
- }
14200
- return {
14201
- allowListProof: getAddressProof(tree, buyerChecksum),
14202
- allowListAddress: buyerChecksum
14203
- };
14204
- }
14205
- function assertRecord(value, field) {
14206
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
14207
- throw new Error(`${field} must be a JSON object`);
14208
- }
14209
- }
14210
- function assertHexRoot(value, field) {
14211
- if (typeof value !== "string" || !isHex5(value) || value.length !== 66) {
14212
- throw new Error(`${field} must be a 0x-prefixed bytes32 hex string`);
14213
- }
14214
- }
14215
- function assertAddress(value, field) {
14216
- if (typeof value !== "string" || !isAddress7(value)) {
14217
- throw new Error(`${field} must be a valid 0x address`);
14974
+ async function writeSetDefaultRoyaltyPercentage(opts) {
14975
+ const write = buildCollectionRoyaltyPercentageWrite(opts.plan);
14976
+ try {
14977
+ await opts.publicClient.simulateContract({
14978
+ address: opts.plan.contract,
14979
+ abi: collectionOwnerAbi,
14980
+ functionName: write.functionName,
14981
+ args: write.args,
14982
+ account: opts.account
14983
+ });
14984
+ } catch (error) {
14985
+ throw contractSupportError(write.functionName, opts.plan.contract, error);
14218
14986
  }
14987
+ return opts.walletClient.writeContract({
14988
+ address: opts.plan.contract,
14989
+ abi: collectionOwnerAbi,
14990
+ functionName: write.functionName,
14991
+ args: write.args,
14992
+ account: opts.account,
14993
+ chain: void 0
14994
+ });
14219
14995
  }
14220
- function validateRootArtifact(value) {
14221
- assertRecord(value, "Root artifact");
14222
- assertHexRoot(value.root, "root");
14223
- assertAddress(value.currency, "currency");
14224
- if (typeof value.amount !== "string") throw new Error("amount must be a string (base units)");
14225
- if (!Array.isArray(value.splitAddresses)) throw new Error("splitAddresses must be an array");
14226
- if (!Array.isArray(value.splitRatios)) throw new Error("splitRatios must be an array");
14227
- if (!Array.isArray(value.tokens) || value.tokens.length < 2) {
14228
- throw new Error("tokens must contain at least two entries");
14996
+ async function writeSetTokenRoyaltyReceiver(opts) {
14997
+ try {
14998
+ await opts.publicClient.simulateContract({
14999
+ address: opts.plan.contract,
15000
+ abi: collectionOwnerAbi,
15001
+ functionName: "setRoyaltyReceiverForToken",
15002
+ args: [opts.plan.receiver, opts.plan.tokenId],
15003
+ account: opts.account
15004
+ });
15005
+ } catch (error) {
15006
+ throw contractSupportError("setRoyaltyReceiverForToken", opts.plan.contract, error);
14229
15007
  }
14230
- value.tokens.forEach((token) => {
14231
- assertRecord(token, "tokens[]");
14232
- assertAddress(token.contract, "tokens[].contract");
14233
- if (typeof token.tokenId !== "string") throw new Error("tokens[].tokenId must be a string");
15008
+ return opts.walletClient.writeContract({
15009
+ address: opts.plan.contract,
15010
+ abi: collectionOwnerAbi,
15011
+ functionName: "setRoyaltyReceiverForToken",
15012
+ args: [opts.plan.receiver, opts.plan.tokenId],
15013
+ account: opts.account,
15014
+ chain: void 0
14234
15015
  });
14235
- if (value.allowList !== void 0 && value.allowList !== null) {
14236
- assertRecord(value.allowList, "allowList");
14237
- assertHexRoot(value.allowList.root, "allowList.root");
14238
- if (!Array.isArray(value.allowList.addresses)) throw new Error("allowList.addresses must be an array");
14239
- if (value.allowList.addresses.length < 2) {
14240
- throw new Error("allowList.addresses must contain at least two entries");
14241
- }
14242
- value.allowList.addresses.forEach((address) => {
14243
- assertAddress(address, "allowList.addresses entry");
15016
+ }
15017
+ async function writeUpdateBaseUri(opts) {
15018
+ try {
15019
+ await opts.publicClient.simulateContract({
15020
+ address: opts.plan.contract,
15021
+ abi: collectionOwnerAbi,
15022
+ functionName: "updateBaseURI",
15023
+ args: [opts.plan.baseUri],
15024
+ account: opts.account
14244
15025
  });
15026
+ } catch (error) {
15027
+ throw contractSupportError("updateBaseURI", opts.plan.contract, error);
14245
15028
  }
14246
- }
14247
- function validateProofArtifact(value) {
14248
- assertRecord(value, "Proof artifact");
14249
- assertHexRoot(value.root, "root");
14250
- assertAddress(value.contract, "contract");
14251
- if (typeof value.tokenId !== "string") throw new Error("tokenId must be a string");
14252
- if (!Array.isArray(value.proof)) throw new Error("proof must be an array of bytes32 hex");
14253
- if (value.proof.length === 0) throw new Error("proof must not be empty");
14254
- value.proof.forEach((proof) => {
14255
- assertHexRoot(proof, "proof entry");
15029
+ return opts.walletClient.writeContract({
15030
+ address: opts.plan.contract,
15031
+ abi: collectionOwnerAbi,
15032
+ functionName: "updateBaseURI",
15033
+ args: [opts.plan.baseUri],
15034
+ account: opts.account,
15035
+ chain: void 0
14256
15036
  });
14257
- if (value.allowListProof !== void 0 && value.allowListProof !== null) {
14258
- if (!Array.isArray(value.allowListProof)) throw new Error("allowListProof must be an array");
14259
- value.allowListProof.forEach((proof) => {
14260
- assertHexRoot(proof, "allowListProof entry");
15037
+ }
15038
+ async function writeUpdateTokenUri(opts) {
15039
+ try {
15040
+ await opts.publicClient.simulateContract({
15041
+ address: opts.plan.contract,
15042
+ abi: collectionOwnerAbi,
15043
+ functionName: "updateTokenURI",
15044
+ args: [opts.plan.tokenId, opts.plan.tokenUri],
15045
+ account: opts.account
14261
15046
  });
15047
+ } catch (error) {
15048
+ throw contractSupportError("updateTokenURI", opts.plan.contract, error);
14262
15049
  }
14263
- if (value.allowListAddress !== void 0 && value.allowListAddress !== null) {
14264
- assertAddress(value.allowListAddress, "allowListAddress");
15050
+ return opts.walletClient.writeContract({
15051
+ address: opts.plan.contract,
15052
+ abi: collectionOwnerAbi,
15053
+ functionName: "updateTokenURI",
15054
+ args: [opts.plan.tokenId, opts.plan.tokenUri],
15055
+ account: opts.account,
15056
+ chain: void 0
15057
+ });
15058
+ }
15059
+ async function writeLockBaseUri(opts) {
15060
+ try {
15061
+ await opts.publicClient.simulateContract({
15062
+ address: opts.plan.contract,
15063
+ abi: collectionOwnerAbi,
15064
+ functionName: "lockBaseURI",
15065
+ account: opts.account
15066
+ });
15067
+ } catch (error) {
15068
+ throw contractSupportError("lockBaseURI", opts.plan.contract, error);
14265
15069
  }
15070
+ return opts.walletClient.writeContract({
15071
+ address: opts.plan.contract,
15072
+ abi: collectionOwnerAbi,
15073
+ functionName: "lockBaseURI",
15074
+ account: opts.account,
15075
+ chain: void 0
15076
+ });
15077
+ }
15078
+ function contractSupportError(operation, contract, cause) {
15079
+ return new Error(
15080
+ `Collection ${contract} does not support ${operation}, or the ${operation} preflight failed.`,
15081
+ { cause }
15082
+ );
14266
15083
  }
14267
15084
 
14268
15085
  // src/sdk/utils.ts
@@ -14355,6 +15172,7 @@ function createRareClient(config) {
14355
15172
  contracts: {
14356
15173
  factory: addresses.factory,
14357
15174
  auction: addresses.auction,
15175
+ rareBridge: addresses.rareBridge,
14358
15176
  sovereignFactory: addresses.sovereignFactory,
14359
15177
  lazySovereignFactory: addresses.lazySovereignFactory,
14360
15178
  rareMinter: addresses.rareMinter,
@@ -14370,6 +15188,7 @@ function createRareClient(config) {
14370
15188
  v4Quoter: addresses.v4Quoter
14371
15189
  },
14372
15190
  liquidEdition: createLiquidNamespace(config, chain, addresses),
15191
+ bridge: createBridgeNamespace(publicClient, config, chain),
14373
15192
  swap: createSwapNamespace(config, chain, chainId, addresses),
14374
15193
  auction,
14375
15194
  offer,
@@ -14441,7 +15260,7 @@ function createRareClient(config) {
14441
15260
  };
14442
15261
  }
14443
15262
  function assertNoClientChainOverride(params, method, chain) {
14444
- if (!isRecord6(params)) return;
15263
+ if (!isRecord7(params)) return;
14445
15264
  if (!Object.prototype.hasOwnProperty.call(params, "chain") && !Object.prototype.hasOwnProperty.call(params, "chainId")) {
14446
15265
  return;
14447
15266
  }
@@ -14449,7 +15268,7 @@ function assertNoClientChainOverride(params, method, chain) {
14449
15268
  `${method} uses the RareClient chain (${chain}). Create another RareClient with a different publicClient to use another chain.`
14450
15269
  );
14451
15270
  }
14452
- function isRecord6(value) {
15271
+ function isRecord7(value) {
14453
15272
  return typeof value === "object" && value !== null;
14454
15273
  }
14455
15274
 
@@ -15489,12 +16308,15 @@ function createUtilsMerkleCommand() {
15489
16308
  }
15490
16309
  function addBatchListingCommands(cmd) {
15491
16310
  cmd.addCommand(createBatchListingListCommand());
15492
- cmd.command("create").description("Register a sale-price Merkle root from a root artifact").requiredOption("--input <path>", "path to a root artifact JSON file").option("--yes", "yes to all prompts and required approvals").option("--chain <chain>", "chain to use (mainnet, sepolia)").option("--chain-id <id>", "chain ID (1, 11155111)").action(async (opts) => {
15493
- const artifact = await loadMerkleRootArtifact(opts.input);
15494
- planBatchListingRootRegistrationLocalInputs(artifact);
16311
+ cmd.command("create").description("Register a sale-price Merkle root from a root artifact or token tree artifact").requiredOption("--input <path>", "path to a root artifact JSON file, token tree artifact, CSV, or JSON token list").option("--format <format>", "input format for --input (csv, json)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth for token tree inputs)").option("--price <amount>", "listing price in ETH or token units (required for token tree inputs)").option(
16312
+ "--split <addr=ratio>",
16313
+ "seller payout split recipient (repeatable). Format: 0xADDR=RATIO. Ratios must sum to 100. If omitted, 100% goes to the connected wallet.",
16314
+ collectSplit
16315
+ ).option("--yes", "yes to all prompts and required approvals").option("--chain <chain>", "chain to use (mainnet, sepolia)").option("--chain-id <id>", "chain ID (1, 11155111)").action(async (opts) => {
15495
16316
  const chain = getActiveChain(opts.chain, opts.chainId);
15496
- const { client } = getWalletClient(chain);
15497
16317
  const publicClient = getPublicClient(chain);
16318
+ const artifact = await resolveBatchListingCreateArtifact(opts, { chain, publicClient });
16319
+ const { client } = getWalletClient(chain);
15498
16320
  const rare = createRareClient({ publicClient, walletClient: client });
15499
16321
  log(`Registering batch listing on ${chain}...`);
15500
16322
  log(` Marketplace contract: ${rare.contracts.batchListing}`);
@@ -15503,6 +16325,15 @@ function addBatchListingCommands(cmd) {
15503
16325
  log(
15504
16326
  ` Amount: ${await formatBatchAmount(publicClient, chain, artifact.currency, BigInt(artifact.amount))} ${isAddressEqual19(artifact.currency, ETH_ADDRESS) ? "ETH" : artifact.currency}`
15505
16327
  );
16328
+ if (artifact.splitAddresses.length > 0) {
16329
+ log(" Splits:");
16330
+ formatSplitLines({
16331
+ addresses: artifact.splitAddresses,
16332
+ ratios: artifact.splitRatios
16333
+ }).forEach((line) => {
16334
+ log(line);
16335
+ });
16336
+ }
15506
16337
  log(` Auto-approve NFTs: ${opts.yes === true ? "yes" : "no"}`);
15507
16338
  const result = await runWithNftApprovalConsent({
15508
16339
  commandName: "rare listing batch create",
@@ -15711,6 +16542,61 @@ async function readBatchTreeArtifact(opts) {
15711
16542
  chainId: resolveTreeChainId(opts)
15712
16543
  });
15713
16544
  }
16545
+ async function resolveBatchListingCreateArtifact(opts, context) {
16546
+ const content = await readFile2(opts.input, "utf8");
16547
+ const parsedObject = parseJsonObjectInput(content);
16548
+ const splits = finalizeSplits(opts.split);
16549
+ const rootArtifact = parsedObject === void 0 ? void 0 : parseBatchListingCreateRootArtifactInput(parsedObject);
16550
+ if (rootArtifact !== void 0) {
16551
+ const currencyOverride = opts.currency === void 0 ? void 0 : resolveCurrency(opts.currency, context.chain);
16552
+ const amountOverride = opts.price === void 0 ? void 0 : (await parseBatchAmount(
16553
+ context.publicClient,
16554
+ context.chain,
16555
+ currencyOverride ?? rootArtifact.currency,
16556
+ opts.price
16557
+ )).toString();
16558
+ return planBatchListingCreateArtifact({
16559
+ kind: "root-artifact",
16560
+ artifact: rootArtifact,
16561
+ currencyOverride,
16562
+ amountOverride,
16563
+ splitAddresses: splits?.addresses,
16564
+ splitRatios: splits?.ratios
16565
+ });
16566
+ }
16567
+ if (opts.price === void 0) {
16568
+ throw new Error(
16569
+ "rare listing batch create requires --price when --input is a token tree artifact from rare utils tree build."
16570
+ );
16571
+ }
16572
+ const currency = opts.currency === void 0 ? ETH_ADDRESS : resolveCurrency(opts.currency, context.chain);
16573
+ const amount = await parseBatchAmount(context.publicClient, context.chain, currency, opts.price);
16574
+ const tokenTreeArtifact = parseBatchTokenListArtifactOrBuild({
16575
+ content,
16576
+ format: parseFormatOption(opts.format),
16577
+ sourceName: opts.input,
16578
+ chainId: resolveTreeChainId(opts)
16579
+ });
16580
+ return planBatchListingCreateArtifact({
16581
+ kind: "token-tree",
16582
+ artifact: tokenTreeArtifact,
16583
+ currency,
16584
+ amount: amount.toString(),
16585
+ splitAddresses: splits?.addresses,
16586
+ splitRatios: splits?.ratios
16587
+ });
16588
+ }
16589
+ function parseJsonObjectInput(content) {
16590
+ const trimmed = content.trimStart();
16591
+ if (!trimmed.startsWith("{")) {
16592
+ return void 0;
16593
+ }
16594
+ const parsed = JSON.parse(content);
16595
+ return isRecord8(parsed) ? parsed : void 0;
16596
+ }
16597
+ function isRecord8(value) {
16598
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16599
+ }
15714
16600
  function resolveTreeChainId(opts) {
15715
16601
  if (opts.chain === void 0) {
15716
16602
  return opts.chainId;
@@ -16745,7 +17631,7 @@ function writeJsonFile(filePath, data) {
16745
17631
  function errorMessage3(error) {
16746
17632
  return error instanceof Error ? error.message : String(error);
16747
17633
  }
16748
- function isRecord7(value) {
17634
+ function isRecord9(value) {
16749
17635
  return typeof value === "object" && value !== null && !Array.isArray(value);
16750
17636
  }
16751
17637
  function detectAllowlistFormat(filePath, format) {
@@ -16776,7 +17662,7 @@ function loadAllowlistArtifact(filePath) {
16776
17662
  function readProofFile(filePath) {
16777
17663
  const content = readTextFile(filePath, "allowlist proof");
16778
17664
  const parsed = parseProofJson(content);
16779
- const proof = Array.isArray(parsed) ? parsed : isRecord7(parsed) && Array.isArray(parsed.proof) ? parsed.proof : void 0;
17665
+ const proof = Array.isArray(parsed) ? parsed : isRecord9(parsed) && Array.isArray(parsed.proof) ? parsed.proof : void 0;
16780
17666
  if (proof === void 0) {
16781
17667
  throw new Error("--proof must be a JSON array or an object with a proof array.");
16782
17668
  }
@@ -17469,7 +18355,7 @@ var MintMetadataOptionsError = class extends Error {
17469
18355
  function parseMintAttribute(raw) {
17470
18356
  if (raw.startsWith("{")) {
17471
18357
  const parsed = JSON.parse(raw);
17472
- if (isRecord8(parsed)) {
18358
+ if (isRecord10(parsed)) {
17473
18359
  assertFiniteAttributeNumber(parsed.value, "value", raw);
17474
18360
  assertFiniteAttributeNumber(parsed.max_value, "max_value", raw);
17475
18361
  }
@@ -17497,7 +18383,7 @@ function assertFiniteAttributeNumber(value, field, raw) {
17497
18383
  }
17498
18384
  }
17499
18385
  function isMintAttribute(value) {
17500
- if (!isRecord8(value) || !isAttributeValue(value.value)) {
18386
+ if (!isRecord10(value) || !isAttributeValue(value.value)) {
17501
18387
  return false;
17502
18388
  }
17503
18389
  return typeof value.trait_type === "string" && (value.display_type === void 0 || isDisplayType(value.display_type)) && (value.max_value === void 0 || typeof value.max_value === "number" && Number.isFinite(value.max_value));
@@ -17508,7 +18394,7 @@ function isAttributeValue(value) {
17508
18394
  function isDisplayType(value) {
17509
18395
  return value === "number" || value === "boost_number" || value === "boost_percentage" || value === "date";
17510
18396
  }
17511
- function isRecord8(value) {
18397
+ function isRecord10(value) {
17512
18398
  return typeof value === "object" && value !== null && !Array.isArray(value);
17513
18399
  }
17514
18400
  function planMintTokenUri(params) {
@@ -17743,7 +18629,7 @@ var DISPLAY_TYPES = [
17743
18629
  function isDisplayType2(value) {
17744
18630
  return DISPLAY_TYPES.some((displayType) => displayType === value);
17745
18631
  }
17746
- function isRecord9(value) {
18632
+ function isRecord11(value) {
17747
18633
  return typeof value === "object" && value !== null;
17748
18634
  }
17749
18635
  function parseAttributeValue(value, raw) {
@@ -17787,7 +18673,7 @@ function parseDisplayType(value, raw) {
17787
18673
  }
17788
18674
  function parseAttributeJson(raw) {
17789
18675
  const parsed = parseJson3(raw);
17790
- if (!isRecord9(parsed) || parsed.value === void 0) {
18676
+ if (!isRecord11(parsed) || parsed.value === void 0) {
17791
18677
  throw new Error(`Attribute JSON must include "value": ${raw}`);
17792
18678
  }
17793
18679
  const trait_type = parseOptionalString2(parsed.trait_type, "trait_type", raw) ?? "value";
@@ -18906,14 +19792,172 @@ function formatLongValue(value, maxLength = 160) {
18906
19792
  return value.length <= maxLength ? value : `${value.slice(0, maxLength - 3)}...`;
18907
19793
  }
18908
19794
 
19795
+ // src/commands/bridge.ts
19796
+ import { Command as Command18 } from "commander";
19797
+ import { formatEther as formatEther2 } from "viem";
19798
+
19799
+ // src/commands/options.ts
19800
+ import { getAddress as getAddress14, isAddress as isAddress11 } from "viem";
19801
+ var chainOptionDescription = "chain name (mainnet, sepolia, base, base-sepolia)";
19802
+ var chainIdOptionDescription = "chain ID (1, 11155111, 8453, 84532)";
19803
+ function addChainOptions(cmd) {
19804
+ return cmd.option("--chain <chain>", chainOptionDescription).option("--chain-id <id>", chainIdOptionDescription);
19805
+ }
19806
+
19807
+ // src/commands/bridge.ts
19808
+ function bridgeCommand() {
19809
+ const cmd = new Command18("bridge");
19810
+ cmd.description("Bridge RARE across supported CCIP routes");
19811
+ cmd.addCommand(bridgeQuoteCommand());
19812
+ cmd.addCommand(bridgeSendCommand());
19813
+ return cmd;
19814
+ }
19815
+ function bridgeQuoteCommand() {
19816
+ const cmd = new Command18("quote");
19817
+ cmd.description("Quote the native fee for bridging RARE");
19818
+ addBridgeRouteOptions(cmd).action(async (opts) => {
19819
+ const plan = parseBridgeRouteOptions(opts, "rare bridge quote");
19820
+ const publicClient = getPublicClient(plan.sourceChain);
19821
+ const rare = createRareClient({
19822
+ publicClient,
19823
+ account: getConfiguredAccountAddress(plan.sourceChain)
19824
+ });
19825
+ const quote = await rare.bridge.quote({
19826
+ amount: plan.amount,
19827
+ destinationChain: plan.destinationChain,
19828
+ recipient: plan.recipient
19829
+ });
19830
+ output(
19831
+ {
19832
+ sourceChain: quote.sourceChain,
19833
+ sourceChainId: quote.sourceChainId,
19834
+ destinationChain: quote.destinationChain,
19835
+ destinationChainId: quote.destinationChainId,
19836
+ sourceBridgeAddress: quote.sourceBridgeAddress,
19837
+ destinationBridgeAddress: quote.destinationBridgeAddress,
19838
+ rareTokenAddress: quote.rareTokenAddress,
19839
+ destinationCcipChainSelector: quote.destinationCcipChainSelector,
19840
+ amount: quote.amount,
19841
+ recipient: quote.recipient,
19842
+ nativeFee: quote.nativeFee,
19843
+ estimatedGas: quote.estimatedGas ?? null,
19844
+ distributionData: quote.distributionData
19845
+ },
19846
+ () => {
19847
+ printBridgeQuote(quote);
19848
+ }
19849
+ );
19850
+ });
19851
+ return cmd;
19852
+ }
19853
+ function bridgeSendCommand() {
19854
+ const cmd = new Command18("send");
19855
+ cmd.description("Bridge RARE to another supported chain");
19856
+ addBridgeRouteOptions(cmd).option("--yes", "yes to all prompts, including approval and transaction submission").action(async (opts) => {
19857
+ const plan = parseBridgeRouteOptions(opts, "rare bridge send");
19858
+ const publicClient = getPublicClient(plan.sourceChain);
19859
+ const { client } = getWalletClient(plan.sourceChain);
19860
+ const rare = createRareClient({ publicClient, walletClient: client });
19861
+ log(`Bridging RARE from ${plan.sourceChain} to ${plan.destinationChain}...`);
19862
+ log(` Source bridge: ${rare.contracts.rareBridge ?? "unavailable"}`);
19863
+ log(` Amount: ${plan.amount} RARE`);
19864
+ if (plan.recipient !== void 0) {
19865
+ log(` Recipient: ${plan.recipient}`);
19866
+ }
19867
+ const sendParams = {
19868
+ amount: plan.amount,
19869
+ destinationChain: plan.destinationChain,
19870
+ recipient: plan.recipient
19871
+ };
19872
+ const result = await runWithPaymentApprovalConsent({
19873
+ commandName: "rare bridge send",
19874
+ approvalMessage: "RARE approval is required before bridging.",
19875
+ runWithoutApproval: async () => rare.bridge.send({
19876
+ ...sendParams,
19877
+ autoApprove: opts.yes === true
19878
+ }),
19879
+ runWithApproval: async () => rare.bridge.send({
19880
+ ...sendParams,
19881
+ autoApprove: true
19882
+ })
19883
+ });
19884
+ if (result === void 0) {
19885
+ return;
19886
+ }
19887
+ output(
19888
+ {
19889
+ txHash: result.txHash,
19890
+ blockNumber: result.receipt.blockNumber.toString(),
19891
+ approvalTxHash: result.approvalTxHash ?? null,
19892
+ ccipExplorerUrl: result.ccipExplorerUrl,
19893
+ sourceChain: result.sourceChain,
19894
+ sourceChainId: result.sourceChainId,
19895
+ destinationChain: result.destinationChain,
19896
+ destinationChainId: result.destinationChainId,
19897
+ sourceBridgeAddress: result.sourceBridgeAddress,
19898
+ destinationBridgeAddress: result.destinationBridgeAddress,
19899
+ rareTokenAddress: result.rareTokenAddress,
19900
+ destinationCcipChainSelector: result.destinationCcipChainSelector,
19901
+ amount: result.amount,
19902
+ recipient: result.recipient,
19903
+ nativeFee: result.nativeFee,
19904
+ estimatedGas: result.estimatedGas ?? null,
19905
+ distributionData: result.distributionData
19906
+ },
19907
+ () => {
19908
+ if (result.approvalTxHash !== void 0) {
19909
+ console.log(`Approval tx sent: ${result.approvalTxHash}`);
19910
+ }
19911
+ console.log(`Transaction sent: ${result.txHash}`);
19912
+ console.log(`Confirmed in block ${result.receipt.blockNumber}`);
19913
+ console.log(`CCIP explorer: ${result.ccipExplorerUrl}`);
19914
+ }
19915
+ );
19916
+ });
19917
+ return cmd;
19918
+ }
19919
+ function addBridgeRouteOptions(cmd) {
19920
+ return addChainOptions(cmd).requiredOption("--amount <amount>", "RARE amount to bridge").requiredOption("--destination-chain <chain>", "destination chain (mainnet, base, sepolia, base-sepolia)").option("--recipient <address>", "destination recipient address");
19921
+ }
19922
+ function parseBridgeRouteOptions(opts, commandName) {
19923
+ if (opts.amount === void 0) {
19924
+ throw new Error(`${commandName} requires --amount.`);
19925
+ }
19926
+ if (opts.destinationChain === void 0) {
19927
+ throw new Error(`${commandName} requires --destination-chain.`);
19928
+ }
19929
+ return {
19930
+ sourceChain: getActiveChain(opts.chain, opts.chainId),
19931
+ destinationChain: parseDestinationChain(opts.destinationChain),
19932
+ amount: opts.amount,
19933
+ recipient: parseOptionalAddress(opts.recipient, "--recipient")
19934
+ };
19935
+ }
19936
+ function parseDestinationChain(value) {
19937
+ if (!isSupportedChain(value)) {
19938
+ throw new Error(`--destination-chain must be one of: ${supportedChains.join(", ")}`);
19939
+ }
19940
+ return value;
19941
+ }
19942
+ function printBridgeQuote(quote) {
19943
+ console.log(`
19944
+ RARE bridge quote: ${quote.sourceChain} -> ${quote.destinationChain}`);
19945
+ console.log(` Amount: ${formatEther2(quote.amount)} RARE`);
19946
+ console.log(` Recipient: ${quote.recipient}`);
19947
+ console.log(` Native fee: ${formatEther2(quote.nativeFee)} ETH`);
19948
+ console.log(` Estimated gas: ${quote.estimatedGas?.toString() ?? "unavailable"}`);
19949
+ console.log(` Source bridge: ${quote.sourceBridgeAddress}`);
19950
+ console.log(` Destination bridge: ${quote.destinationBridgeAddress}`);
19951
+ }
19952
+
18909
19953
  // src/commands/swap.ts
18910
19954
  import { readFile as readFile5 } from "fs/promises";
18911
19955
  import { createInterface as createInterface6 } from "readline/promises";
18912
- import { Command as Command18 } from "commander";
18913
- import { formatEther as formatEther3 } from "viem";
19956
+ import { Command as Command19 } from "commander";
19957
+ import { formatEther as formatEther4 } from "viem";
18914
19958
 
18915
19959
  // src/commands/swap-core.ts
18916
- import { formatEther as formatEther2, formatUnits as formatUnits9, getAddress as getAddress14, isHex as isHex7 } from "viem";
19960
+ import { formatEther as formatEther3, formatUnits as formatUnits9, getAddress as getAddress15, isHex as isHex7 } from "viem";
18917
19961
  function parseInputsJson(raw, label) {
18918
19962
  const parsed = parseJson4(raw, label);
18919
19963
  if (!Array.isArray(parsed)) {
@@ -18941,7 +19985,7 @@ function ensureHex(value, label) {
18941
19985
  }
18942
19986
  function parseAddress3(value, label) {
18943
19987
  try {
18944
- return getAddress14(value);
19988
+ return getAddress15(value);
18945
19989
  } catch {
18946
19990
  throw new Error(`${label} must be a valid EVM address.`);
18947
19991
  }
@@ -18967,15 +20011,15 @@ function formatBuyRareQuoteLines(params) {
18967
20011
  `Quote for buying RARE on ${params.chain}:`,
18968
20012
  ...params.router ? [` Router: ${params.router}`] : [],
18969
20013
  ` ETH in: ${params.eth}`,
18970
- ` Estimated RARE out: ${formatEther2(params.quote.estimatedRareOut)}`,
18971
- ` Min RARE out: ${formatEther2(params.quote.minRareOut)}`,
20014
+ ` Estimated RARE out: ${formatEther3(params.quote.estimatedRareOut)}`,
20015
+ ` Min RARE out: ${formatEther3(params.quote.minRareOut)}`,
18972
20016
  params.usedMinRareOutOverride ? " Min out source: manual override" : ` Slippage: ${params.quote.slippageBps} bps`,
18973
20017
  ...params.recipient ? [` Recipient: ${params.recipient}`] : []
18974
20018
  ];
18975
20019
  return lines;
18976
20020
  }
18977
20021
  function formatQuotedAmount(amount, decimals) {
18978
- return decimals === 18 ? formatEther2(amount) : formatUnits9(amount, decimals);
20022
+ return decimals === 18 ? formatEther3(amount) : formatUnits9(amount, decimals);
18979
20023
  }
18980
20024
  function formatTokenTradeQuoteLines(params) {
18981
20025
  const outputLabel = params.direction === "buy" ? "Estimated token out" : "Estimated ETH out";
@@ -19022,7 +20066,7 @@ async function confirmProceed() {
19022
20066
  }
19023
20067
  }
19024
20068
  function swapTokensCommand() {
19025
- const cmd = new Command18("tokens");
20069
+ const cmd = new Command19("tokens");
19026
20070
  cmd.alias("swap");
19027
20071
  cmd.description("Execute a raw router token swap");
19028
20072
  cmd.requiredOption("--token-in <address>", "input token address").requiredOption("--amount-in <amount>", "amount of the input token").requiredOption("--token-out <address>", "output token address").requiredOption("--min-amount-out <amount>", "minimum output token amount").requiredOption("--commands <hex>", "raw router commands hex").requiredOption("--inputs-file <path>", "JSON file containing router input calldata array").option("--recipient <address>", "recipient address").option("--deadline <seconds>", "deadline as a unix timestamp in seconds").option("--yes", "skip the interactive transaction confirmation").option("--chain <chain>", "chain to use (mainnet, sepolia)").option("--chain-id <id>", "chain ID (1, 11155111)").action(async (opts) => {
@@ -19068,7 +20112,7 @@ function swapTokensCommand() {
19068
20112
  return cmd;
19069
20113
  }
19070
20114
  function swapBuyTokenCommand() {
19071
- const cmd = new Command18("buy-token");
20115
+ const cmd = new Command19("buy-token");
19072
20116
  cmd.description("Buy a token with ETH using a canonical liquid route or Uniswap fallback");
19073
20117
  cmd.requiredOption("--token <address>", "token address to buy").requiredOption("--amount-in <amount>", "ETH amount to spend").option("--route <mode>", "route mode: auto, local, uniswap, raw (default: auto)").option("--slippage-bps <bps>", "slippage in basis points (default: 50)").option("--min-amount-out <amount>", "override minimum token amount out").option("--commands <hex>", "raw router commands hex when --route raw").option("--inputs-file <path>", "JSON file containing router input calldata array when --route raw").option("--quote-only", "show the quote without submitting a transaction").option("--yes", "submit the quoted swap and any required approvals without an interactive confirmation").option("--recipient <address>", "recipient address").option("--deadline <seconds>", "deadline as a unix timestamp in seconds").option("--chain <chain>", "chain to use").option("--chain-id <id>", "chain ID (1, 11155111, 8453, 84532)").action(async (opts) => {
19074
20118
  const quoteOnly = opts.quoteOnly === true;
@@ -19220,7 +20264,7 @@ function swapBuyTokenCommand() {
19220
20264
  return cmd;
19221
20265
  }
19222
20266
  function swapSellTokenCommand() {
19223
- const cmd = new Command18("sell-token");
20267
+ const cmd = new Command19("sell-token");
19224
20268
  cmd.description("Sell a token for ETH using a canonical liquid route or Uniswap fallback");
19225
20269
  cmd.requiredOption("--token <address>", "token address to sell").requiredOption("--amount-in <amount>", "token amount to sell").option("--route <mode>", "route mode: auto, local, uniswap, raw (default: auto)").option("--slippage-bps <bps>", "slippage in basis points (default: 50)").option("--min-amount-out <amount>", "override minimum ETH amount out").option("--commands <hex>", "raw router commands hex when --route raw").option("--inputs-file <path>", "JSON file containing router input calldata array when --route raw").option("--quote-only", "show the quote without submitting a transaction").option("--yes", "submit the quoted swap and any required approvals without an interactive confirmation").option("--recipient <address>", "recipient address").option("--deadline <seconds>", "deadline as a unix timestamp in seconds").option("--chain <chain>", "chain to use").option("--chain-id <id>", "chain ID (1, 11155111, 8453, 84532)").action(async (opts) => {
19226
20270
  const quoteOnly = opts.quoteOnly === true;
@@ -19278,7 +20322,7 @@ function swapSellTokenCommand() {
19278
20322
  },
19279
20323
  () => {
19280
20324
  console.log(`Transaction sent: ${result2.txHash}`);
19281
- console.log(`Min ETH out: ${formatEther3(result2.minAmountOut)}`);
20325
+ console.log(`Min ETH out: ${formatEther4(result2.minAmountOut)}`);
19282
20326
  }
19283
20327
  );
19284
20328
  return;
@@ -19366,15 +20410,15 @@ function swapSellTokenCommand() {
19366
20410
  },
19367
20411
  () => {
19368
20412
  console.log(`Transaction sent: ${result.txHash}`);
19369
- console.log(`Estimated ETH out: ${formatEther3(result.estimatedAmountOut)}`);
19370
- console.log(`Min ETH out: ${formatEther3(result.minAmountOut)}`);
20413
+ console.log(`Estimated ETH out: ${formatEther4(result.estimatedAmountOut)}`);
20414
+ console.log(`Min ETH out: ${formatEther4(result.minAmountOut)}`);
19371
20415
  }
19372
20416
  );
19373
20417
  });
19374
20418
  return cmd;
19375
20419
  }
19376
20420
  function swapBuyRareCommand() {
19377
- const cmd = new Command18("buy-rare");
20421
+ const cmd = new Command19("buy-rare");
19378
20422
  cmd.description("Buy RARE with ETH using the curated canonical route");
19379
20423
  cmd.requiredOption("--amount-in <amount>", "ETH amount to spend").option("--slippage-bps <bps>", "slippage in basis points (default: 50)").option("--min-amount-out <amount>", "override minimum RARE out").option("--quote-only", "show the quote without submitting a transaction").option("--yes", "submit the quoted swap without an interactive confirmation").option("--recipient <address>", "recipient address").option("--deadline <seconds>", "deadline as a unix timestamp in seconds").option("--chain <chain>", "chain to use (mainnet, sepolia)").option("--chain-id <id>", "chain ID (1, 11155111)").action(async (opts) => {
19380
20424
  const quoteOnly = opts.quoteOnly === true;
@@ -19450,15 +20494,15 @@ function swapBuyRareCommand() {
19450
20494
  },
19451
20495
  () => {
19452
20496
  console.log(`Transaction sent: ${result.txHash}`);
19453
- console.log(`Estimated RARE out: ${formatEther3(result.estimatedRareOut)}`);
19454
- console.log(`Min RARE out: ${formatEther3(result.minRareOut)}`);
20497
+ console.log(`Estimated RARE out: ${formatEther4(result.estimatedRareOut)}`);
20498
+ console.log(`Min RARE out: ${formatEther4(result.minRareOut)}`);
19455
20499
  }
19456
20500
  );
19457
20501
  });
19458
20502
  return cmd;
19459
20503
  }
19460
20504
  function swapCommand() {
19461
- const cmd = new Command18("swap");
20505
+ const cmd = new Command19("swap");
19462
20506
  cmd.description("Interact with token swap routes");
19463
20507
  cmd.addCommand(swapTokensCommand());
19464
20508
  cmd.addCommand(swapBuyTokenCommand());
@@ -19468,9 +20512,9 @@ function swapCommand() {
19468
20512
  }
19469
20513
 
19470
20514
  // src/commands/user.ts
19471
- import { Command as Command19 } from "commander";
20515
+ import { Command as Command20 } from "commander";
19472
20516
  function userCommand() {
19473
- const cmd = new Command19("user");
20517
+ const cmd = new Command20("user");
19474
20518
  cmd.description("Get RARE Protocol users");
19475
20519
  cmd.command("get").description("Get a user by wallet address").argument("<address>", "wallet address").action(async (address) => {
19476
20520
  const userAddress = parseAddress(address, "<address>");
@@ -19484,9 +20528,9 @@ function userCommand() {
19484
20528
  }
19485
20529
 
19486
20530
  // src/commands/utils.ts
19487
- import { Command as Command20 } from "commander";
20531
+ import { Command as Command21 } from "commander";
19488
20532
  function utilsCommand() {
19489
- const cmd = new Command20("utils");
20533
+ const cmd = new Command21("utils");
19490
20534
  cmd.description("Offline Merkle tree and proof utilities");
19491
20535
  cmd.addCommand(createUtilsTreeCommand());
19492
20536
  cmd.addCommand(createUtilsMerkleCommand());
@@ -19494,14 +20538,14 @@ function utilsCommand() {
19494
20538
  }
19495
20539
 
19496
20540
  // src/commands/mcp.ts
19497
- import { Command as Command21 } from "commander";
20541
+ import { Command as Command22 } from "commander";
19498
20542
 
19499
20543
  // src/mcp/server.ts
19500
20544
  import { readFile as readFile6 } from "fs/promises";
19501
20545
  import { basename as basename3 } from "path";
19502
20546
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
19503
20547
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19504
- import { isAddress as isAddress11, isHex as isHex8 } from "viem";
20548
+ import { isAddress as isAddress12, isHex as isHex8 } from "viem";
19505
20549
  import { z } from "zod";
19506
20550
 
19507
20551
  // src/mcp/core.ts
@@ -19536,6 +20580,8 @@ var mcpToolSpecs = [
19536
20580
  sdkTool("write", "rare.swap.buy", "Execute a raw liquid-router token buy."),
19537
20581
  sdkTool("write", "rare.swap.sell", "Execute a raw liquid-router token sell."),
19538
20582
  sdkTool("write", "rare.swap.swapTokens", "Execute a raw liquid-router token swap."),
20583
+ sdkTool("read", "rare.bridge.quote", "Quote the native fee for bridging RARE."),
20584
+ sdkTool("write", "rare.bridge.send", "Bridge RARE to another supported chain."),
19539
20585
  sdkTool("read", "rare.swap.quoteBuyToken", "Quote buying a token with ETH."),
19540
20586
  sdkTool("write", "rare.swap.buyToken", "Buy a token with ETH."),
19541
20587
  sdkTool("read", "rare.swap.quoteSellToken", "Quote selling a token for ETH."),
@@ -19624,6 +20670,13 @@ var mcpToolNames = mcpToolSpecs.map((tool) => tool.name);
19624
20670
  function selectMcpToolNames(opts) {
19625
20671
  return opts.allowWrites ? [...mcpReadToolNames, ...mcpWriteToolNames] : [...mcpReadToolNames];
19626
20672
  }
20673
+ function shapeMcpToolAnnotations(access) {
20674
+ return {
20675
+ readOnlyHint: access === "read",
20676
+ destructiveHint: access === "write" ? true : void 0,
20677
+ openWorldHint: true
20678
+ };
20679
+ }
19627
20680
  function sdkPathToMcpToolName(sdkPath) {
19628
20681
  const path2 = sdkPath.startsWith("rare.") ? sdkPath.slice("rare.".length) : sdkPath;
19629
20682
  return path2.split(".").map(camelToSnake).join("_");
@@ -19662,7 +20715,7 @@ function serializeForMcp(value) {
19662
20715
  if (Array.isArray(value)) {
19663
20716
  return value.map(serializeForMcp);
19664
20717
  }
19665
- if (isRecord10(value)) {
20718
+ if (isRecord12(value)) {
19666
20719
  return Object.fromEntries(
19667
20720
  Object.entries(value).map(([key, nested]) => [key, serializeForMcp(nested)]).filter(([, nested]) => nested !== void 0)
19668
20721
  );
@@ -19670,11 +20723,11 @@ function serializeForMcp(value) {
19670
20723
  return value;
19671
20724
  }
19672
20725
  function shapeMcpTransactionResult(value, extra = {}) {
19673
- if (!isRecord10(value)) {
20726
+ if (!isRecord12(value)) {
19674
20727
  return value;
19675
20728
  }
19676
20729
  const { receipt, ...shaped } = value;
19677
- if (isRecord10(receipt) && Object.prototype.hasOwnProperty.call(receipt, "blockNumber")) {
20730
+ if (isRecord12(receipt) && Object.prototype.hasOwnProperty.call(receipt, "blockNumber")) {
19678
20731
  return { ...shaped, blockNumber: receipt.blockNumber, ...extra };
19679
20732
  }
19680
20733
  return { ...shaped, ...extra };
@@ -19685,14 +20738,14 @@ function maskSecret2(value) {
19685
20738
  function camelToSnake(value) {
19686
20739
  return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
19687
20740
  }
19688
- function isRecord10(value) {
20741
+ function isRecord12(value) {
19689
20742
  return typeof value === "object" && value !== null && !Array.isArray(value);
19690
20743
  }
19691
20744
 
19692
20745
  // src/mcp/server.ts
19693
20746
  var chainSchema = z.enum(supportedChains);
19694
20747
  var optionalChain = { chain: chainSchema.optional() };
19695
- var addressSchema = z.string().refine(isAddress11, "must be a valid 0x address");
20748
+ var addressSchema = z.string().refine(isAddress12, "must be a valid 0x address");
19696
20749
  var hexSchema = z.string().refine(isHex8, "must be a hex string");
19697
20750
  var integerSchema = z.union([z.string(), z.number()]);
19698
20751
  var amountSchema = z.union([z.string(), z.number()]);
@@ -19762,11 +20815,7 @@ function registerTool(server, spec) {
19762
20815
  server.registerTool(spec.name, {
19763
20816
  description: spec.description,
19764
20817
  inputSchema: tool.inputSchema,
19765
- annotations: {
19766
- readOnlyHint: spec.access === "read",
19767
- destructiveHint: spec.access === "write" ? false : void 0,
19768
- openWorldHint: true
19769
- }
20818
+ annotations: shapeMcpToolAnnotations(spec.access)
19770
20819
  }, async (args) => withToolErrors(async () => tool.handler(args)));
19771
20820
  }
19772
20821
  var toolHandlers = {
@@ -19863,6 +20912,14 @@ var toolHandlers = {
19863
20912
  inputSchema: { ...optionalChain, tokenIn: addressSchema, tokenOut: addressSchema, amountIn: amountSchema, ...rawRouteSchema, recipient: addressSchema.optional(), deadline: integerSchema.optional() },
19864
20913
  handler: ({ chain, ...args }) => callWrite(chain, async (rare) => txResult(await rare.swap.swapTokens(args)))
19865
20914
  },
20915
+ bridge_quote: {
20916
+ inputSchema: { ...optionalChain, amount: amountSchema, destinationChain: chainSchema, recipient: addressSchema.optional() },
20917
+ handler: ({ chain, ...args }) => callRead(chain, (rare) => rare.bridge.quote(args))
20918
+ },
20919
+ bridge_send: {
20920
+ inputSchema: { ...optionalChain, amount: amountSchema, destinationChain: chainSchema, recipient: addressSchema.optional(), ...autoApproveSchema },
20921
+ handler: ({ chain, ...args }) => callWrite(chain, async (rare) => txResult(await rare.bridge.send(args)))
20922
+ },
19866
20923
  swap_quote_buy_token: {
19867
20924
  inputSchema: { ...optionalChain, token: addressSchema, amountIn: amountSchema, minAmountOut: amountSchema.optional(), slippageBps: integerSchema.optional(), recipient: addressSchema.optional(), deadline: integerSchema.optional() },
19868
20925
  handler: ({ chain, ...args }) => callRead(chain, (rare) => rare.swap.quoteBuyToken(args))
@@ -20220,6 +21277,7 @@ function readRare(chain) {
20220
21277
  const selected = resolveChain(chain);
20221
21278
  return createRareClient({
20222
21279
  publicClient: getPublicClient(selected),
21280
+ account: getConfiguredAccountAddress(selected),
20223
21281
  resolveUniswapApiKey: () => getConfiguredUniswapApiKey(selected)
20224
21282
  });
20225
21283
  }
@@ -20301,7 +21359,7 @@ var McpToolError = class extends Error {
20301
21359
 
20302
21360
  // src/commands/mcp.ts
20303
21361
  function mcpCommand() {
20304
- const cmd = new Command21("mcp");
21362
+ const cmd = new Command22("mcp");
20305
21363
  cmd.description("Run MCP server integrations");
20306
21364
  cmd.command("serve").description("Start a stdio MCP server for agent-friendly RARE SDK access").option("--allow-writes", "register write-capable tools").action(async (opts) => {
20307
21365
  await serveMcp({ allowWrites: Boolean(opts.allowWrites) });
@@ -20339,7 +21397,7 @@ function requiresExplicitConfirmation(commandPath2) {
20339
21397
  // package.json
20340
21398
  var package_default = {
20341
21399
  name: "@rareprotocol/rare-cli",
20342
- version: "1.1.0",
21400
+ version: "1.2.1",
20343
21401
  description: "CLI tool for interacting with the RARE protocol smart contracts",
20344
21402
  type: "module",
20345
21403
  license: "MIT",
@@ -20453,7 +21511,7 @@ var package_default = {
20453
21511
 
20454
21512
  // src/program.ts
20455
21513
  function createRareProgram() {
20456
- const program2 = new Command22();
21514
+ const program2 = new Command23();
20457
21515
  program2.name("rare").description("CLI tool for interacting with the RARE protocol smart contracts").version(package_default.version).option("--json", "output results as JSON");
20458
21516
  program2.hook("preAction", async (_thisCommand, actionCommand) => {
20459
21517
  const decision = confirmationDecision(program2, actionCommand);
@@ -20482,6 +21540,7 @@ function createRareProgram() {
20482
21540
  program2.addCommand(collectionCommand());
20483
21541
  program2.addCommand(currenciesCommand());
20484
21542
  program2.addCommand(liquidEditionCommand());
21543
+ program2.addCommand(bridgeCommand());
20485
21544
  program2.addCommand(swapCommand());
20486
21545
  program2.addCommand(userCommand());
20487
21546
  program2.addCommand(utilsCommand());