@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/README.md +22 -11
- package/dist/{addresses-BE3luaB3.d.ts → addresses-CcGI_7v1.d.ts} +5 -1
- package/dist/{batch-listing-Cu5Hoqxs.d.ts → batch-listing-C1CtPTD5.d.ts} +1 -1
- package/dist/client.d.ts +56 -5
- package/dist/client.js +1407 -654
- package/dist/contracts.d.ts +90 -2
- package/dist/contracts.js +140 -3
- package/dist/index.js +2003 -944
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +11 -5
- package/package.json +1 -1
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
|
|
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("
|
|
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
|
|
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
|
|
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
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
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
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
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
|
|
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
|
|
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
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
params.contract,
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
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
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
plan.nftAddress,
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
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
|
|
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
|
|
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
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
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
|
|
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.
|
|
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:
|
|
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
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
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
|
|
6376
|
-
const
|
|
6377
|
-
|
|
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
|
|
6384
|
-
|
|
6385
|
-
|
|
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
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
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
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
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
|
-
|
|
6397
|
-
return { splitAddresses: splits.addresses, splitRatios: splits.ratios };
|
|
6592
|
+
return a.tokenId.localeCompare(b.tokenId);
|
|
6398
6593
|
}
|
|
6399
|
-
function
|
|
6400
|
-
if (
|
|
6401
|
-
|
|
6594
|
+
function normalizeTokenEntry(token) {
|
|
6595
|
+
if (!isAddress6(token.contract)) {
|
|
6596
|
+
throw new Error(`Invalid token contract address: ${token.contract}`);
|
|
6402
6597
|
}
|
|
6403
|
-
return
|
|
6598
|
+
return {
|
|
6599
|
+
contract: getAddress7(token.contract),
|
|
6600
|
+
tokenId: String(token.tokenId),
|
|
6601
|
+
tokenIdBigInt: toInteger(token.tokenId, "tokenId")
|
|
6602
|
+
};
|
|
6404
6603
|
}
|
|
6405
|
-
function
|
|
6406
|
-
|
|
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:
|
|
6409
|
-
|
|
6410
|
-
|
|
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
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
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
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
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 (!
|
|
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
|
|
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
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
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
|
|
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
|
|
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
|
|
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) ? [...
|
|
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
|
|
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
|
|
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 && !
|
|
7194
|
-
const
|
|
7195
|
-
const
|
|
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 && !
|
|
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 :
|
|
7202
|
-
const reserveAmount = hasAuction ? details.reserveAmount :
|
|
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,
|
|
7214
|
-
splitRatios: resolveStatusSplitRatios(hasAuction, details,
|
|
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:
|
|
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) =>
|
|
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,
|
|
7846
|
+
function resolveStatusSplitAddresses(hasAuction, details, rootConfig) {
|
|
7351
7847
|
if (hasAuction) {
|
|
7352
7848
|
return [...details.splitAddresses];
|
|
7353
7849
|
}
|
|
7354
|
-
if (
|
|
7850
|
+
if (rootConfig === void 0) {
|
|
7355
7851
|
return [];
|
|
7356
7852
|
}
|
|
7357
|
-
return [...
|
|
7853
|
+
return [...rootConfig.splitAddresses];
|
|
7358
7854
|
}
|
|
7359
|
-
function resolveStatusSplitRatios(hasAuction, details,
|
|
7855
|
+
function resolveStatusSplitRatios(hasAuction, details, rootConfig) {
|
|
7360
7856
|
if (hasAuction) {
|
|
7361
7857
|
return [...details.splitRatios];
|
|
7362
7858
|
}
|
|
7363
|
-
if (
|
|
7859
|
+
if (rootConfig === void 0) {
|
|
7364
7860
|
return [];
|
|
7365
7861
|
}
|
|
7366
|
-
return [...
|
|
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
|
|
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
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
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
|
|
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
|
|
7973
|
+
const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
|
|
7466
7974
|
const logs = parseEventLogs3({
|
|
7467
7975
|
abi: batchAuctionHouseAbi,
|
|
7468
|
-
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 =
|
|
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
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
plan.currency,
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
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
|
|
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
|
|
8093
|
+
const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
|
|
7574
8094
|
const logs = parseEventLogs3({
|
|
7575
8095
|
abi: batchAuctionHouseAbi,
|
|
7576
|
-
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
|
|
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 ?
|
|
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
|
|
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
|
|
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 = !
|
|
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:
|
|
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
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
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
|
|
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
|
|
8706
|
+
const targetReceipt = await publicClient.waitForTransactionReceipt({ hash: targetTxHash });
|
|
8175
8707
|
const logs = parseEventLogs4({
|
|
8176
8708
|
abi: batchOfferAbi,
|
|
8177
|
-
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 (!
|
|
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
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
plan.
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
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
|
|
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
|
|
8928
|
-
|
|
8929
|
-
|
|
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
|
|
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
|
|
9082
|
-
const totalPositions =
|
|
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
|
|
9091
|
-
const hasGapOrOverlap =
|
|
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 =
|
|
9100
|
-
if (
|
|
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 (!
|
|
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
|
|
9132
|
-
if (tickLower === null || tickUpper === null || numPositions === 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
|
-
|
|
9150
|
-
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
|
|
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
|
|
10127
|
+
function liquidEditionRevertedReceiptError(message, txHash, receipt) {
|
|
9525
10128
|
return new Error(
|
|
9526
|
-
|
|
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
|
-
|
|
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
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
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
|
|
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:
|
|
9868
|
-
sepolia:
|
|
9869
|
-
base:
|
|
9870
|
-
"base-sepolia":
|
|
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
|
|
10186
|
-
getAddress as
|
|
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:
|
|
10204
|
-
addressThis:
|
|
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:
|
|
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
|
|
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
|
|
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 =
|
|
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" ?
|
|
11265
|
+
const settleParams = executionMode.inputSource === "user" ? encodeAbiParameters2(
|
|
10328
11266
|
parseAbiParameters("address currency, uint128 maxAmount"),
|
|
10329
11267
|
[currencyIn, amountIn]
|
|
10330
|
-
) :
|
|
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" ?
|
|
11273
|
+
const takeParams = executionMode.outputTarget === "user" ? encodeAbiParameters2(
|
|
10336
11274
|
parseAbiParameters("address currency, uint128 minAmount"),
|
|
10337
11275
|
[currencyOut, minAmountOut]
|
|
10338
|
-
) :
|
|
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 =
|
|
11285
|
+
const actions2 = encodePacked3(
|
|
10348
11286
|
["uint8", "uint8", "uint8"],
|
|
10349
11287
|
[settleAction, V4_ACTIONS.SWAP_EXACT_IN_SINGLE, takeAction]
|
|
10350
11288
|
);
|
|
10351
|
-
return
|
|
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 =
|
|
11301
|
+
const actions = encodePacked3(
|
|
10364
11302
|
["uint8", "uint8", "uint8"],
|
|
10365
11303
|
[V4_ACTIONS.SWAP_EXACT_IN, settleAction, takeAction]
|
|
10366
11304
|
);
|
|
10367
|
-
return
|
|
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
|
|
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
|
|
11331
|
+
import { getAddress as getAddress10, isHex as isHex4 } from "viem";
|
|
10394
11332
|
|
|
10395
11333
|
// src/swap/trade-core.ts
|
|
10396
|
-
import { isAddressEqual as
|
|
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) =>
|
|
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 && !
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
params.token,
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
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
|
|
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
|
|
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
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
params.token,
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
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
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
11877
|
-
isAddress as
|
|
11878
|
-
isAddressEqual as
|
|
11879
|
-
isHex as
|
|
11880
|
-
keccak256 as
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 && !
|
|
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 (
|
|
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 :
|
|
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 =
|
|
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(
|
|
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 (!
|
|
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 && !
|
|
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 && !
|
|
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" || !
|
|
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 (!
|
|
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 (!
|
|
13389
|
+
if (!isAddress7(raw)) {
|
|
12398
13390
|
throw new Error(`Invalid allowlist address at ${row.label}: "${raw}".`);
|
|
12399
13391
|
}
|
|
12400
|
-
const address =
|
|
12401
|
-
const duplicate = state.seen.find((seen) =>
|
|
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 (!
|
|
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
|
|
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
|
|
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
|
|
13462
|
+
return isAddressEqual17(a, b);
|
|
12471
13463
|
}
|
|
12472
13464
|
function hexEquals(a, b) {
|
|
12473
13465
|
return a.toLocaleLowerCase() === b.toLocaleLowerCase();
|
|
12474
13466
|
}
|
|
12475
|
-
function
|
|
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
|
|
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) =>
|
|
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
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
12927
|
-
|
|
12928
|
-
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
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
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
12997
|
-
|
|
12998
|
-
mint.
|
|
12999
|
-
|
|
13000
|
-
|
|
13001
|
-
|
|
13002
|
-
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13012
|
-
|
|
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
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
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
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
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
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
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
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
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
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
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
|
-
|
|
14264
|
-
|
|
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 (!
|
|
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
|
|
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("--
|
|
15493
|
-
|
|
15494
|
-
|
|
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
|
|
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 :
|
|
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 (
|
|
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 (!
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|
18913
|
-
import { formatEther as
|
|
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
|
|
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
|
|
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: ${
|
|
18971
|
-
` Min RARE out: ${
|
|
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 ?
|
|
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
|
|
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
|
|
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
|
|
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: ${
|
|
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: ${
|
|
19370
|
-
console.log(`Min ETH out: ${
|
|
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
|
|
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: ${
|
|
19454
|
-
console.log(`Min RARE out: ${
|
|
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
|
|
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
|
|
20515
|
+
import { Command as Command20 } from "commander";
|
|
19472
20516
|
function userCommand() {
|
|
19473
|
-
const cmd = new
|
|
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
|
|
20531
|
+
import { Command as Command21 } from "commander";
|
|
19488
20532
|
function utilsCommand() {
|
|
19489
|
-
const cmd = new
|
|
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
|
|
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
|
|
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 (
|
|
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 (!
|
|
20726
|
+
if (!isRecord12(value)) {
|
|
19674
20727
|
return value;
|
|
19675
20728
|
}
|
|
19676
20729
|
const { receipt, ...shaped } = value;
|
|
19677
|
-
if (
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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());
|