@net-protocol/cli 0.1.9 → 0.1.11
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 +105 -0
- package/dist/cli/index.mjs +1043 -2
- package/dist/cli/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import { isNetrSupportedChain, NetrClient } from '@net-protocol/netr';
|
|
|
15
15
|
import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, PROFILE_CANVAS_STORAGE_KEY, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getXUsernameStorageArgs, isValidBio, getProfileMetadataStorageArgs } from '@net-protocol/profiles';
|
|
16
16
|
import { base } from 'viem/chains';
|
|
17
17
|
import * as path from 'path';
|
|
18
|
+
import { BazaarClient } from '@net-protocol/bazaar';
|
|
18
19
|
|
|
19
20
|
function getRequiredChainId(optionValue) {
|
|
20
21
|
const chainId = optionValue || (process.env.NET_CHAIN_ID ? parseInt(process.env.NET_CHAIN_ID, 10) : void 0);
|
|
@@ -1477,8 +1478,8 @@ function registerStorageCommand(program2) {
|
|
|
1477
1478
|
console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
|
|
1478
1479
|
console.log(chalk4.blue(`\u{1F517} Using relay API: ${options.apiUrl}`));
|
|
1479
1480
|
const result = await uploadFileWithRelay(uploadRelayOptions);
|
|
1480
|
-
const { privateKeyToAccount:
|
|
1481
|
-
const userAccount =
|
|
1481
|
+
const { privateKeyToAccount: privateKeyToAccount16 } = await import('viem/accounts');
|
|
1482
|
+
const userAccount = privateKeyToAccount16(commonOptions.privateKey);
|
|
1482
1483
|
const storageUrl = generateStorageUrl(
|
|
1483
1484
|
userAccount.address,
|
|
1484
1485
|
commonOptions.chainId,
|
|
@@ -2935,6 +2936,1045 @@ function registerProfileCommand(program2) {
|
|
|
2935
2936
|
profileCommand.addCommand(getCanvasCommand);
|
|
2936
2937
|
}
|
|
2937
2938
|
|
|
2939
|
+
// src/commands/bazaar/format.ts
|
|
2940
|
+
function formatEthPrice(price) {
|
|
2941
|
+
return price.toFixed(6).replace(/\.?0+$/, "");
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
// src/commands/bazaar/list-listings.ts
|
|
2945
|
+
async function executeListListings(options) {
|
|
2946
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
2947
|
+
chainId: options.chainId,
|
|
2948
|
+
rpcUrl: options.rpcUrl
|
|
2949
|
+
});
|
|
2950
|
+
const bazaarClient = new BazaarClient({
|
|
2951
|
+
chainId: readOnlyOptions.chainId,
|
|
2952
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
2953
|
+
});
|
|
2954
|
+
try {
|
|
2955
|
+
const listings = await bazaarClient.getListings({
|
|
2956
|
+
nftAddress: options.nftAddress
|
|
2957
|
+
});
|
|
2958
|
+
if (options.json) {
|
|
2959
|
+
const output = listings.map((l) => ({
|
|
2960
|
+
orderHash: l.orderHash,
|
|
2961
|
+
maker: l.maker,
|
|
2962
|
+
nftAddress: l.nftAddress,
|
|
2963
|
+
tokenId: l.tokenId,
|
|
2964
|
+
price: l.price,
|
|
2965
|
+
priceWei: l.priceWei.toString(),
|
|
2966
|
+
currency: l.currency,
|
|
2967
|
+
expirationDate: l.expirationDate,
|
|
2968
|
+
orderStatus: l.orderStatus,
|
|
2969
|
+
...l.targetFulfiller ? { targetFulfiller: l.targetFulfiller } : {}
|
|
2970
|
+
}));
|
|
2971
|
+
console.log(JSON.stringify(output, null, 2));
|
|
2972
|
+
return;
|
|
2973
|
+
}
|
|
2974
|
+
if (listings.length === 0) {
|
|
2975
|
+
console.log(chalk4.yellow("No active listings found"));
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
console.log(chalk4.white.bold(`
|
|
2979
|
+
Listings (${listings.length}):
|
|
2980
|
+
`));
|
|
2981
|
+
for (const listing of listings) {
|
|
2982
|
+
const expiry = new Date(listing.expirationDate * 1e3).toLocaleString();
|
|
2983
|
+
console.log(` ${chalk4.cyan("Order Hash:")} ${listing.orderHash}`);
|
|
2984
|
+
console.log(` ${chalk4.cyan("Seller:")} ${listing.maker}`);
|
|
2985
|
+
console.log(` ${chalk4.cyan("NFT:")} ${listing.nftAddress} #${listing.tokenId}`);
|
|
2986
|
+
console.log(` ${chalk4.cyan("Price:")} ${formatEthPrice(listing.price)} ${listing.currency.toUpperCase()}`);
|
|
2987
|
+
console.log(` ${chalk4.cyan("Expires:")} ${expiry}`);
|
|
2988
|
+
if (listing.targetFulfiller) {
|
|
2989
|
+
console.log(` ${chalk4.cyan("Private (for):")} ${listing.targetFulfiller}`);
|
|
2990
|
+
}
|
|
2991
|
+
console.log();
|
|
2992
|
+
}
|
|
2993
|
+
} catch (error) {
|
|
2994
|
+
exitWithError(
|
|
2995
|
+
`Failed to fetch listings: ${error instanceof Error ? error.message : String(error)}`
|
|
2996
|
+
);
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
async function executeListOffers(options) {
|
|
3000
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3001
|
+
chainId: options.chainId,
|
|
3002
|
+
rpcUrl: options.rpcUrl
|
|
3003
|
+
});
|
|
3004
|
+
const bazaarClient = new BazaarClient({
|
|
3005
|
+
chainId: readOnlyOptions.chainId,
|
|
3006
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3007
|
+
});
|
|
3008
|
+
try {
|
|
3009
|
+
const offers = await bazaarClient.getCollectionOffers({
|
|
3010
|
+
nftAddress: options.nftAddress
|
|
3011
|
+
});
|
|
3012
|
+
if (options.json) {
|
|
3013
|
+
const output = offers.map((o) => ({
|
|
3014
|
+
orderHash: o.orderHash,
|
|
3015
|
+
maker: o.maker,
|
|
3016
|
+
nftAddress: o.nftAddress,
|
|
3017
|
+
price: o.price,
|
|
3018
|
+
priceWei: o.priceWei.toString(),
|
|
3019
|
+
currency: o.currency,
|
|
3020
|
+
expirationDate: o.expirationDate,
|
|
3021
|
+
orderStatus: o.orderStatus
|
|
3022
|
+
}));
|
|
3023
|
+
console.log(JSON.stringify(output, null, 2));
|
|
3024
|
+
return;
|
|
3025
|
+
}
|
|
3026
|
+
if (offers.length === 0) {
|
|
3027
|
+
console.log(chalk4.yellow("No active collection offers found"));
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
console.log(chalk4.white.bold(`
|
|
3031
|
+
Collection Offers (${offers.length}):
|
|
3032
|
+
`));
|
|
3033
|
+
for (const offer of offers) {
|
|
3034
|
+
const expiry = new Date(offer.expirationDate * 1e3).toLocaleString();
|
|
3035
|
+
console.log(` ${chalk4.cyan("Order Hash:")} ${offer.orderHash}`);
|
|
3036
|
+
console.log(` ${chalk4.cyan("Buyer:")} ${offer.maker}`);
|
|
3037
|
+
console.log(` ${chalk4.cyan("Collection:")} ${offer.nftAddress}`);
|
|
3038
|
+
console.log(` ${chalk4.cyan("Price:")} ${formatEthPrice(offer.price)} ${offer.currency.toUpperCase()}`);
|
|
3039
|
+
console.log(` ${chalk4.cyan("Expires:")} ${expiry}`);
|
|
3040
|
+
console.log();
|
|
3041
|
+
}
|
|
3042
|
+
} catch (error) {
|
|
3043
|
+
exitWithError(
|
|
3044
|
+
`Failed to fetch offers: ${error instanceof Error ? error.message : String(error)}`
|
|
3045
|
+
);
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
async function executeListSales(options) {
|
|
3049
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3050
|
+
chainId: options.chainId,
|
|
3051
|
+
rpcUrl: options.rpcUrl
|
|
3052
|
+
});
|
|
3053
|
+
const bazaarClient = new BazaarClient({
|
|
3054
|
+
chainId: readOnlyOptions.chainId,
|
|
3055
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3056
|
+
});
|
|
3057
|
+
try {
|
|
3058
|
+
const sales = await bazaarClient.getSales({
|
|
3059
|
+
nftAddress: options.nftAddress
|
|
3060
|
+
});
|
|
3061
|
+
if (options.json) {
|
|
3062
|
+
const output = sales.map((s) => ({
|
|
3063
|
+
orderHash: s.orderHash,
|
|
3064
|
+
seller: s.seller,
|
|
3065
|
+
buyer: s.buyer,
|
|
3066
|
+
tokenAddress: s.tokenAddress,
|
|
3067
|
+
tokenId: s.tokenId,
|
|
3068
|
+
amount: s.amount.toString(),
|
|
3069
|
+
price: s.price,
|
|
3070
|
+
priceWei: s.priceWei.toString(),
|
|
3071
|
+
currency: s.currency,
|
|
3072
|
+
timestamp: s.timestamp
|
|
3073
|
+
}));
|
|
3074
|
+
console.log(JSON.stringify(output, null, 2));
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
if (sales.length === 0) {
|
|
3078
|
+
console.log(chalk4.yellow("No sales found"));
|
|
3079
|
+
return;
|
|
3080
|
+
}
|
|
3081
|
+
console.log(chalk4.white.bold(`
|
|
3082
|
+
Sales (${sales.length}):
|
|
3083
|
+
`));
|
|
3084
|
+
for (const sale of sales) {
|
|
3085
|
+
const date = new Date(sale.timestamp * 1e3).toLocaleString();
|
|
3086
|
+
console.log(` ${chalk4.cyan("Order Hash:")} ${sale.orderHash}`);
|
|
3087
|
+
console.log(` ${chalk4.cyan("Seller:")} ${sale.seller}`);
|
|
3088
|
+
console.log(` ${chalk4.cyan("Buyer:")} ${sale.buyer}`);
|
|
3089
|
+
console.log(` ${chalk4.cyan("Token:")} ${sale.tokenAddress} #${sale.tokenId}`);
|
|
3090
|
+
console.log(` ${chalk4.cyan("Price:")} ${formatEthPrice(sale.price)} ${sale.currency.toUpperCase()}`);
|
|
3091
|
+
console.log(` ${chalk4.cyan("Date:")} ${date}`);
|
|
3092
|
+
console.log();
|
|
3093
|
+
}
|
|
3094
|
+
} catch (error) {
|
|
3095
|
+
exitWithError(
|
|
3096
|
+
`Failed to fetch sales: ${error instanceof Error ? error.message : String(error)}`
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
async function executeCreateListing(options) {
|
|
3101
|
+
const hasPrivateKey = !!(options.privateKey || process.env.NET_PRIVATE_KEY || process.env.PRIVATE_KEY);
|
|
3102
|
+
if (!hasPrivateKey) {
|
|
3103
|
+
await executeKeylessMode(options);
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
const commonOptions = parseCommonOptions({
|
|
3107
|
+
privateKey: options.privateKey,
|
|
3108
|
+
chainId: options.chainId,
|
|
3109
|
+
rpcUrl: options.rpcUrl
|
|
3110
|
+
});
|
|
3111
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
3112
|
+
const bazaarClient = new BazaarClient({
|
|
3113
|
+
chainId: commonOptions.chainId,
|
|
3114
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3115
|
+
});
|
|
3116
|
+
const priceWei = parseEther(options.price);
|
|
3117
|
+
try {
|
|
3118
|
+
console.log(chalk4.blue("Preparing listing..."));
|
|
3119
|
+
const prepared = await bazaarClient.prepareCreateListing({
|
|
3120
|
+
nftAddress: options.nftAddress,
|
|
3121
|
+
tokenId: options.tokenId,
|
|
3122
|
+
priceWei,
|
|
3123
|
+
offerer: account.address,
|
|
3124
|
+
targetFulfiller: options.targetFulfiller
|
|
3125
|
+
});
|
|
3126
|
+
const rpcUrls = getChainRpcUrls({
|
|
3127
|
+
chainId: commonOptions.chainId,
|
|
3128
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3129
|
+
});
|
|
3130
|
+
const walletClient = createWalletClient({
|
|
3131
|
+
account,
|
|
3132
|
+
transport: http(rpcUrls[0])
|
|
3133
|
+
});
|
|
3134
|
+
for (const approval of prepared.approvals) {
|
|
3135
|
+
console.log(chalk4.blue("Sending approval transaction..."));
|
|
3136
|
+
const calldata = encodeFunctionData({
|
|
3137
|
+
abi: approval.abi,
|
|
3138
|
+
functionName: approval.functionName,
|
|
3139
|
+
args: approval.args
|
|
3140
|
+
});
|
|
3141
|
+
const approvalHash = await walletClient.sendTransaction({
|
|
3142
|
+
to: approval.to,
|
|
3143
|
+
data: calldata,
|
|
3144
|
+
chain: null,
|
|
3145
|
+
value: approval.value
|
|
3146
|
+
});
|
|
3147
|
+
console.log(chalk4.green(`Approval tx: ${approvalHash}`));
|
|
3148
|
+
}
|
|
3149
|
+
console.log(chalk4.blue("Signing order..."));
|
|
3150
|
+
const signature = await walletClient.signTypedData({
|
|
3151
|
+
domain: prepared.eip712.domain,
|
|
3152
|
+
types: prepared.eip712.types,
|
|
3153
|
+
primaryType: prepared.eip712.primaryType,
|
|
3154
|
+
message: prepared.eip712.message
|
|
3155
|
+
});
|
|
3156
|
+
console.log(chalk4.blue("Submitting listing..."));
|
|
3157
|
+
const submitTx = bazaarClient.prepareSubmitListing(
|
|
3158
|
+
prepared.eip712.orderParameters,
|
|
3159
|
+
prepared.eip712.counter,
|
|
3160
|
+
signature
|
|
3161
|
+
);
|
|
3162
|
+
const submitCalldata = encodeFunctionData({
|
|
3163
|
+
abi: submitTx.abi,
|
|
3164
|
+
functionName: submitTx.functionName,
|
|
3165
|
+
args: submitTx.args
|
|
3166
|
+
});
|
|
3167
|
+
const hash = await walletClient.sendTransaction({
|
|
3168
|
+
to: submitTx.to,
|
|
3169
|
+
data: submitCalldata,
|
|
3170
|
+
chain: null,
|
|
3171
|
+
value: submitTx.value
|
|
3172
|
+
});
|
|
3173
|
+
console.log(
|
|
3174
|
+
chalk4.green(
|
|
3175
|
+
`Listing created successfully!
|
|
3176
|
+
Transaction: ${hash}
|
|
3177
|
+
NFT: ${options.nftAddress} #${options.tokenId}
|
|
3178
|
+
Price: ${options.price} ETH`
|
|
3179
|
+
)
|
|
3180
|
+
);
|
|
3181
|
+
} catch (error) {
|
|
3182
|
+
exitWithError(
|
|
3183
|
+
`Failed to create listing: ${error instanceof Error ? error.message : String(error)}`
|
|
3184
|
+
);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
async function executeKeylessMode(options) {
|
|
3188
|
+
if (!options.offerer) {
|
|
3189
|
+
exitWithError("--offerer is required when not providing --private-key");
|
|
3190
|
+
}
|
|
3191
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3192
|
+
chainId: options.chainId,
|
|
3193
|
+
rpcUrl: options.rpcUrl
|
|
3194
|
+
});
|
|
3195
|
+
const bazaarClient = new BazaarClient({
|
|
3196
|
+
chainId: readOnlyOptions.chainId,
|
|
3197
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3198
|
+
});
|
|
3199
|
+
const priceWei = parseEther(options.price);
|
|
3200
|
+
try {
|
|
3201
|
+
const prepared = await bazaarClient.prepareCreateListing({
|
|
3202
|
+
nftAddress: options.nftAddress,
|
|
3203
|
+
tokenId: options.tokenId,
|
|
3204
|
+
priceWei,
|
|
3205
|
+
offerer: options.offerer,
|
|
3206
|
+
targetFulfiller: options.targetFulfiller
|
|
3207
|
+
});
|
|
3208
|
+
const output = {
|
|
3209
|
+
eip712: {
|
|
3210
|
+
domain: prepared.eip712.domain,
|
|
3211
|
+
types: prepared.eip712.types,
|
|
3212
|
+
primaryType: prepared.eip712.primaryType,
|
|
3213
|
+
message: prepared.eip712.message
|
|
3214
|
+
},
|
|
3215
|
+
orderParameters: prepared.eip712.orderParameters,
|
|
3216
|
+
counter: prepared.eip712.counter.toString(),
|
|
3217
|
+
approvals: prepared.approvals.map((a) => ({
|
|
3218
|
+
to: a.to,
|
|
3219
|
+
data: encodeFunctionData({
|
|
3220
|
+
abi: a.abi,
|
|
3221
|
+
functionName: a.functionName,
|
|
3222
|
+
args: a.args
|
|
3223
|
+
}),
|
|
3224
|
+
description: `Approve ${a.functionName}`
|
|
3225
|
+
}))
|
|
3226
|
+
};
|
|
3227
|
+
console.log(JSON.stringify(output, bigintReplacer, 2));
|
|
3228
|
+
} catch (error) {
|
|
3229
|
+
exitWithError(
|
|
3230
|
+
`Failed to prepare listing: ${error instanceof Error ? error.message : String(error)}`
|
|
3231
|
+
);
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
function bigintReplacer(_key, value) {
|
|
3235
|
+
if (typeof value === "bigint") {
|
|
3236
|
+
return value.toString();
|
|
3237
|
+
}
|
|
3238
|
+
return value;
|
|
3239
|
+
}
|
|
3240
|
+
async function executeCreateOffer(options) {
|
|
3241
|
+
const hasPrivateKey = !!(options.privateKey || process.env.NET_PRIVATE_KEY || process.env.PRIVATE_KEY);
|
|
3242
|
+
if (!hasPrivateKey) {
|
|
3243
|
+
await executeKeylessMode2(options);
|
|
3244
|
+
return;
|
|
3245
|
+
}
|
|
3246
|
+
const commonOptions = parseCommonOptions({
|
|
3247
|
+
privateKey: options.privateKey,
|
|
3248
|
+
chainId: options.chainId,
|
|
3249
|
+
rpcUrl: options.rpcUrl
|
|
3250
|
+
});
|
|
3251
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
3252
|
+
const bazaarClient = new BazaarClient({
|
|
3253
|
+
chainId: commonOptions.chainId,
|
|
3254
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3255
|
+
});
|
|
3256
|
+
const priceWei = parseEther(options.price);
|
|
3257
|
+
try {
|
|
3258
|
+
console.log(chalk4.blue("Preparing collection offer..."));
|
|
3259
|
+
const prepared = await bazaarClient.prepareCreateCollectionOffer({
|
|
3260
|
+
nftAddress: options.nftAddress,
|
|
3261
|
+
priceWei,
|
|
3262
|
+
offerer: account.address
|
|
3263
|
+
});
|
|
3264
|
+
const rpcUrls = getChainRpcUrls({
|
|
3265
|
+
chainId: commonOptions.chainId,
|
|
3266
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3267
|
+
});
|
|
3268
|
+
const walletClient = createWalletClient({
|
|
3269
|
+
account,
|
|
3270
|
+
transport: http(rpcUrls[0])
|
|
3271
|
+
});
|
|
3272
|
+
for (const approval of prepared.approvals) {
|
|
3273
|
+
console.log(chalk4.blue("Sending approval transaction..."));
|
|
3274
|
+
const calldata = encodeFunctionData({
|
|
3275
|
+
abi: approval.abi,
|
|
3276
|
+
functionName: approval.functionName,
|
|
3277
|
+
args: approval.args
|
|
3278
|
+
});
|
|
3279
|
+
const approvalHash = await walletClient.sendTransaction({
|
|
3280
|
+
to: approval.to,
|
|
3281
|
+
data: calldata,
|
|
3282
|
+
chain: null,
|
|
3283
|
+
value: approval.value
|
|
3284
|
+
});
|
|
3285
|
+
console.log(chalk4.green(`Approval tx: ${approvalHash}`));
|
|
3286
|
+
}
|
|
3287
|
+
console.log(chalk4.blue("Signing offer..."));
|
|
3288
|
+
const signature = await walletClient.signTypedData({
|
|
3289
|
+
domain: prepared.eip712.domain,
|
|
3290
|
+
types: prepared.eip712.types,
|
|
3291
|
+
primaryType: prepared.eip712.primaryType,
|
|
3292
|
+
message: prepared.eip712.message
|
|
3293
|
+
});
|
|
3294
|
+
console.log(chalk4.blue("Submitting offer..."));
|
|
3295
|
+
const submitTx = bazaarClient.prepareSubmitCollectionOffer(
|
|
3296
|
+
prepared.eip712.orderParameters,
|
|
3297
|
+
prepared.eip712.counter,
|
|
3298
|
+
signature
|
|
3299
|
+
);
|
|
3300
|
+
const submitCalldata = encodeFunctionData({
|
|
3301
|
+
abi: submitTx.abi,
|
|
3302
|
+
functionName: submitTx.functionName,
|
|
3303
|
+
args: submitTx.args
|
|
3304
|
+
});
|
|
3305
|
+
const hash = await walletClient.sendTransaction({
|
|
3306
|
+
to: submitTx.to,
|
|
3307
|
+
data: submitCalldata,
|
|
3308
|
+
chain: null,
|
|
3309
|
+
value: submitTx.value
|
|
3310
|
+
});
|
|
3311
|
+
console.log(
|
|
3312
|
+
chalk4.green(
|
|
3313
|
+
`Collection offer created successfully!
|
|
3314
|
+
Transaction: ${hash}
|
|
3315
|
+
Collection: ${options.nftAddress}
|
|
3316
|
+
Price: ${options.price} ETH`
|
|
3317
|
+
)
|
|
3318
|
+
);
|
|
3319
|
+
} catch (error) {
|
|
3320
|
+
exitWithError(
|
|
3321
|
+
`Failed to create offer: ${error instanceof Error ? error.message : String(error)}`
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
async function executeKeylessMode2(options) {
|
|
3326
|
+
if (!options.offerer) {
|
|
3327
|
+
exitWithError("--offerer is required when not providing --private-key");
|
|
3328
|
+
}
|
|
3329
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3330
|
+
chainId: options.chainId,
|
|
3331
|
+
rpcUrl: options.rpcUrl
|
|
3332
|
+
});
|
|
3333
|
+
const bazaarClient = new BazaarClient({
|
|
3334
|
+
chainId: readOnlyOptions.chainId,
|
|
3335
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3336
|
+
});
|
|
3337
|
+
const priceWei = parseEther(options.price);
|
|
3338
|
+
try {
|
|
3339
|
+
const prepared = await bazaarClient.prepareCreateCollectionOffer({
|
|
3340
|
+
nftAddress: options.nftAddress,
|
|
3341
|
+
priceWei,
|
|
3342
|
+
offerer: options.offerer
|
|
3343
|
+
});
|
|
3344
|
+
const output = {
|
|
3345
|
+
eip712: {
|
|
3346
|
+
domain: prepared.eip712.domain,
|
|
3347
|
+
types: prepared.eip712.types,
|
|
3348
|
+
primaryType: prepared.eip712.primaryType,
|
|
3349
|
+
message: prepared.eip712.message
|
|
3350
|
+
},
|
|
3351
|
+
orderParameters: prepared.eip712.orderParameters,
|
|
3352
|
+
counter: prepared.eip712.counter.toString(),
|
|
3353
|
+
approvals: prepared.approvals.map((a) => ({
|
|
3354
|
+
to: a.to,
|
|
3355
|
+
data: encodeFunctionData({
|
|
3356
|
+
abi: a.abi,
|
|
3357
|
+
functionName: a.functionName,
|
|
3358
|
+
args: a.args
|
|
3359
|
+
}),
|
|
3360
|
+
description: `Approve ${a.functionName}`
|
|
3361
|
+
}))
|
|
3362
|
+
};
|
|
3363
|
+
console.log(JSON.stringify(output, bigintReplacer2, 2));
|
|
3364
|
+
} catch (error) {
|
|
3365
|
+
exitWithError(
|
|
3366
|
+
`Failed to prepare offer: ${error instanceof Error ? error.message : String(error)}`
|
|
3367
|
+
);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
function bigintReplacer2(_key, value) {
|
|
3371
|
+
if (typeof value === "bigint") {
|
|
3372
|
+
return value.toString();
|
|
3373
|
+
}
|
|
3374
|
+
return value;
|
|
3375
|
+
}
|
|
3376
|
+
async function executeSubmitListing(options) {
|
|
3377
|
+
let orderData;
|
|
3378
|
+
try {
|
|
3379
|
+
const raw = readFileSync(options.orderData, "utf-8");
|
|
3380
|
+
orderData = JSON.parse(raw);
|
|
3381
|
+
} catch (error) {
|
|
3382
|
+
exitWithError(
|
|
3383
|
+
`Failed to read order data file: ${error instanceof Error ? error.message : String(error)}`
|
|
3384
|
+
);
|
|
3385
|
+
}
|
|
3386
|
+
if (options.encodeOnly) {
|
|
3387
|
+
await executeEncodeOnly3(options, orderData);
|
|
3388
|
+
return;
|
|
3389
|
+
}
|
|
3390
|
+
const commonOptions = parseCommonOptions(
|
|
3391
|
+
{
|
|
3392
|
+
privateKey: options.privateKey,
|
|
3393
|
+
chainId: options.chainId,
|
|
3394
|
+
rpcUrl: options.rpcUrl
|
|
3395
|
+
},
|
|
3396
|
+
true
|
|
3397
|
+
);
|
|
3398
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
3399
|
+
const bazaarClient = new BazaarClient({
|
|
3400
|
+
chainId: commonOptions.chainId,
|
|
3401
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3402
|
+
});
|
|
3403
|
+
try {
|
|
3404
|
+
const submitTx = bazaarClient.prepareSubmitListing(
|
|
3405
|
+
orderData.orderParameters,
|
|
3406
|
+
BigInt(orderData.counter),
|
|
3407
|
+
options.signature
|
|
3408
|
+
);
|
|
3409
|
+
const rpcUrls = getChainRpcUrls({
|
|
3410
|
+
chainId: commonOptions.chainId,
|
|
3411
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3412
|
+
});
|
|
3413
|
+
const walletClient = createWalletClient({
|
|
3414
|
+
account,
|
|
3415
|
+
transport: http(rpcUrls[0])
|
|
3416
|
+
});
|
|
3417
|
+
console.log(chalk4.blue("Submitting listing..."));
|
|
3418
|
+
const calldata = encodeFunctionData({
|
|
3419
|
+
abi: submitTx.abi,
|
|
3420
|
+
functionName: submitTx.functionName,
|
|
3421
|
+
args: submitTx.args
|
|
3422
|
+
});
|
|
3423
|
+
const hash = await walletClient.sendTransaction({
|
|
3424
|
+
to: submitTx.to,
|
|
3425
|
+
data: calldata,
|
|
3426
|
+
chain: null,
|
|
3427
|
+
value: submitTx.value
|
|
3428
|
+
});
|
|
3429
|
+
console.log(chalk4.green(`Listing submitted successfully!
|
|
3430
|
+
Transaction: ${hash}`));
|
|
3431
|
+
} catch (error) {
|
|
3432
|
+
exitWithError(
|
|
3433
|
+
`Failed to submit listing: ${error instanceof Error ? error.message : String(error)}`
|
|
3434
|
+
);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
async function executeEncodeOnly3(options, orderData) {
|
|
3438
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3439
|
+
chainId: options.chainId,
|
|
3440
|
+
rpcUrl: options.rpcUrl
|
|
3441
|
+
});
|
|
3442
|
+
const bazaarClient = new BazaarClient({
|
|
3443
|
+
chainId: readOnlyOptions.chainId,
|
|
3444
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3445
|
+
});
|
|
3446
|
+
const submitTx = bazaarClient.prepareSubmitListing(
|
|
3447
|
+
orderData.orderParameters,
|
|
3448
|
+
BigInt(orderData.counter),
|
|
3449
|
+
options.signature
|
|
3450
|
+
);
|
|
3451
|
+
const encoded = encodeTransaction(
|
|
3452
|
+
{ to: submitTx.to, functionName: submitTx.functionName, args: submitTx.args, abi: submitTx.abi, value: submitTx.value },
|
|
3453
|
+
readOnlyOptions.chainId
|
|
3454
|
+
);
|
|
3455
|
+
console.log(JSON.stringify(encoded, null, 2));
|
|
3456
|
+
}
|
|
3457
|
+
async function executeSubmitOffer(options) {
|
|
3458
|
+
let orderData;
|
|
3459
|
+
try {
|
|
3460
|
+
const raw = readFileSync(options.orderData, "utf-8");
|
|
3461
|
+
orderData = JSON.parse(raw);
|
|
3462
|
+
} catch (error) {
|
|
3463
|
+
exitWithError(
|
|
3464
|
+
`Failed to read order data file: ${error instanceof Error ? error.message : String(error)}`
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
if (options.encodeOnly) {
|
|
3468
|
+
await executeEncodeOnly4(options, orderData);
|
|
3469
|
+
return;
|
|
3470
|
+
}
|
|
3471
|
+
const commonOptions = parseCommonOptions(
|
|
3472
|
+
{
|
|
3473
|
+
privateKey: options.privateKey,
|
|
3474
|
+
chainId: options.chainId,
|
|
3475
|
+
rpcUrl: options.rpcUrl
|
|
3476
|
+
},
|
|
3477
|
+
true
|
|
3478
|
+
);
|
|
3479
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
3480
|
+
const bazaarClient = new BazaarClient({
|
|
3481
|
+
chainId: commonOptions.chainId,
|
|
3482
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3483
|
+
});
|
|
3484
|
+
try {
|
|
3485
|
+
const submitTx = bazaarClient.prepareSubmitCollectionOffer(
|
|
3486
|
+
orderData.orderParameters,
|
|
3487
|
+
BigInt(orderData.counter),
|
|
3488
|
+
options.signature
|
|
3489
|
+
);
|
|
3490
|
+
const rpcUrls = getChainRpcUrls({
|
|
3491
|
+
chainId: commonOptions.chainId,
|
|
3492
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3493
|
+
});
|
|
3494
|
+
const walletClient = createWalletClient({
|
|
3495
|
+
account,
|
|
3496
|
+
transport: http(rpcUrls[0])
|
|
3497
|
+
});
|
|
3498
|
+
console.log(chalk4.blue("Submitting offer..."));
|
|
3499
|
+
const calldata = encodeFunctionData({
|
|
3500
|
+
abi: submitTx.abi,
|
|
3501
|
+
functionName: submitTx.functionName,
|
|
3502
|
+
args: submitTx.args
|
|
3503
|
+
});
|
|
3504
|
+
const hash = await walletClient.sendTransaction({
|
|
3505
|
+
to: submitTx.to,
|
|
3506
|
+
data: calldata,
|
|
3507
|
+
chain: null,
|
|
3508
|
+
value: submitTx.value
|
|
3509
|
+
});
|
|
3510
|
+
console.log(chalk4.green(`Offer submitted successfully!
|
|
3511
|
+
Transaction: ${hash}`));
|
|
3512
|
+
} catch (error) {
|
|
3513
|
+
exitWithError(
|
|
3514
|
+
`Failed to submit offer: ${error instanceof Error ? error.message : String(error)}`
|
|
3515
|
+
);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
async function executeEncodeOnly4(options, orderData) {
|
|
3519
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3520
|
+
chainId: options.chainId,
|
|
3521
|
+
rpcUrl: options.rpcUrl
|
|
3522
|
+
});
|
|
3523
|
+
const bazaarClient = new BazaarClient({
|
|
3524
|
+
chainId: readOnlyOptions.chainId,
|
|
3525
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3526
|
+
});
|
|
3527
|
+
const submitTx = bazaarClient.prepareSubmitCollectionOffer(
|
|
3528
|
+
orderData.orderParameters,
|
|
3529
|
+
BigInt(orderData.counter),
|
|
3530
|
+
options.signature
|
|
3531
|
+
);
|
|
3532
|
+
const encoded = encodeTransaction(
|
|
3533
|
+
{ to: submitTx.to, functionName: submitTx.functionName, args: submitTx.args, abi: submitTx.abi, value: submitTx.value },
|
|
3534
|
+
readOnlyOptions.chainId
|
|
3535
|
+
);
|
|
3536
|
+
console.log(JSON.stringify(encoded, null, 2));
|
|
3537
|
+
}
|
|
3538
|
+
async function executeBuyListing(options) {
|
|
3539
|
+
if (options.encodeOnly) {
|
|
3540
|
+
await executeEncodeOnly5(options);
|
|
3541
|
+
return;
|
|
3542
|
+
}
|
|
3543
|
+
const commonOptions = parseCommonOptions(
|
|
3544
|
+
{
|
|
3545
|
+
privateKey: options.privateKey,
|
|
3546
|
+
chainId: options.chainId,
|
|
3547
|
+
rpcUrl: options.rpcUrl
|
|
3548
|
+
},
|
|
3549
|
+
true
|
|
3550
|
+
);
|
|
3551
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
3552
|
+
const bazaarClient = new BazaarClient({
|
|
3553
|
+
chainId: commonOptions.chainId,
|
|
3554
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3555
|
+
});
|
|
3556
|
+
try {
|
|
3557
|
+
console.log(chalk4.blue("Fetching listing..."));
|
|
3558
|
+
const listings = await bazaarClient.getListings({
|
|
3559
|
+
nftAddress: options.nftAddress
|
|
3560
|
+
});
|
|
3561
|
+
const listing = listings.find(
|
|
3562
|
+
(l) => l.orderHash.toLowerCase() === options.orderHash.toLowerCase()
|
|
3563
|
+
);
|
|
3564
|
+
if (!listing) {
|
|
3565
|
+
exitWithError(`Listing with order hash ${options.orderHash} not found or no longer active`);
|
|
3566
|
+
}
|
|
3567
|
+
console.log(chalk4.blue("Preparing fulfillment..."));
|
|
3568
|
+
const prepared = await bazaarClient.prepareFulfillListing(listing, account.address);
|
|
3569
|
+
const rpcUrls = getChainRpcUrls({
|
|
3570
|
+
chainId: commonOptions.chainId,
|
|
3571
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3572
|
+
});
|
|
3573
|
+
const walletClient = createWalletClient({
|
|
3574
|
+
account,
|
|
3575
|
+
transport: http(rpcUrls[0])
|
|
3576
|
+
});
|
|
3577
|
+
for (const approval of prepared.approvals) {
|
|
3578
|
+
console.log(chalk4.blue("Sending approval transaction..."));
|
|
3579
|
+
const calldata2 = encodeFunctionData({
|
|
3580
|
+
abi: approval.abi,
|
|
3581
|
+
functionName: approval.functionName,
|
|
3582
|
+
args: approval.args
|
|
3583
|
+
});
|
|
3584
|
+
const approvalHash = await walletClient.sendTransaction({
|
|
3585
|
+
to: approval.to,
|
|
3586
|
+
data: calldata2,
|
|
3587
|
+
chain: null,
|
|
3588
|
+
value: approval.value
|
|
3589
|
+
});
|
|
3590
|
+
console.log(chalk4.green(`Approval tx: ${approvalHash}`));
|
|
3591
|
+
}
|
|
3592
|
+
console.log(chalk4.blue("Sending fulfillment transaction..."));
|
|
3593
|
+
const calldata = encodeFunctionData({
|
|
3594
|
+
abi: prepared.fulfillment.abi,
|
|
3595
|
+
functionName: prepared.fulfillment.functionName,
|
|
3596
|
+
args: prepared.fulfillment.args
|
|
3597
|
+
});
|
|
3598
|
+
const hash = await walletClient.sendTransaction({
|
|
3599
|
+
to: prepared.fulfillment.to,
|
|
3600
|
+
data: calldata,
|
|
3601
|
+
chain: null,
|
|
3602
|
+
value: prepared.fulfillment.value
|
|
3603
|
+
});
|
|
3604
|
+
console.log(
|
|
3605
|
+
chalk4.green(
|
|
3606
|
+
`Listing fulfilled successfully!
|
|
3607
|
+
Transaction: ${hash}
|
|
3608
|
+
NFT: ${listing.nftAddress} #${listing.tokenId}
|
|
3609
|
+
Price: ${listing.price} ${listing.currency.toUpperCase()}`
|
|
3610
|
+
)
|
|
3611
|
+
);
|
|
3612
|
+
} catch (error) {
|
|
3613
|
+
exitWithError(
|
|
3614
|
+
`Failed to buy listing: ${error instanceof Error ? error.message : String(error)}`
|
|
3615
|
+
);
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
async function executeEncodeOnly5(options) {
|
|
3619
|
+
if (!options.buyer) {
|
|
3620
|
+
exitWithError("--buyer is required when using --encode-only without --private-key");
|
|
3621
|
+
}
|
|
3622
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3623
|
+
chainId: options.chainId,
|
|
3624
|
+
rpcUrl: options.rpcUrl
|
|
3625
|
+
});
|
|
3626
|
+
const buyerAddress = options.buyer;
|
|
3627
|
+
const bazaarClient = new BazaarClient({
|
|
3628
|
+
chainId: readOnlyOptions.chainId,
|
|
3629
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3630
|
+
});
|
|
3631
|
+
try {
|
|
3632
|
+
const listings = await bazaarClient.getListings({
|
|
3633
|
+
nftAddress: options.nftAddress
|
|
3634
|
+
});
|
|
3635
|
+
const listing = listings.find(
|
|
3636
|
+
(l) => l.orderHash.toLowerCase() === options.orderHash.toLowerCase()
|
|
3637
|
+
);
|
|
3638
|
+
if (!listing) {
|
|
3639
|
+
exitWithError(`Listing with order hash ${options.orderHash} not found or no longer active`);
|
|
3640
|
+
}
|
|
3641
|
+
const prepared = await bazaarClient.prepareFulfillListing(listing, buyerAddress);
|
|
3642
|
+
const result = {
|
|
3643
|
+
approvals: prepared.approvals.map(
|
|
3644
|
+
(a) => encodeTransaction(
|
|
3645
|
+
{ to: a.to, functionName: a.functionName, args: a.args, abi: a.abi, value: a.value },
|
|
3646
|
+
readOnlyOptions.chainId
|
|
3647
|
+
)
|
|
3648
|
+
),
|
|
3649
|
+
fulfillment: encodeTransaction(
|
|
3650
|
+
{
|
|
3651
|
+
to: prepared.fulfillment.to,
|
|
3652
|
+
functionName: prepared.fulfillment.functionName,
|
|
3653
|
+
args: prepared.fulfillment.args,
|
|
3654
|
+
abi: prepared.fulfillment.abi,
|
|
3655
|
+
value: prepared.fulfillment.value
|
|
3656
|
+
},
|
|
3657
|
+
readOnlyOptions.chainId
|
|
3658
|
+
)
|
|
3659
|
+
};
|
|
3660
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3661
|
+
} catch (error) {
|
|
3662
|
+
exitWithError(
|
|
3663
|
+
`Failed to encode buy listing: ${error instanceof Error ? error.message : String(error)}`
|
|
3664
|
+
);
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
async function executeAcceptOffer(options) {
|
|
3668
|
+
if (options.encodeOnly) {
|
|
3669
|
+
await executeEncodeOnly6(options);
|
|
3670
|
+
return;
|
|
3671
|
+
}
|
|
3672
|
+
const commonOptions = parseCommonOptions(
|
|
3673
|
+
{
|
|
3674
|
+
privateKey: options.privateKey,
|
|
3675
|
+
chainId: options.chainId,
|
|
3676
|
+
rpcUrl: options.rpcUrl
|
|
3677
|
+
},
|
|
3678
|
+
true
|
|
3679
|
+
);
|
|
3680
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
3681
|
+
const bazaarClient = new BazaarClient({
|
|
3682
|
+
chainId: commonOptions.chainId,
|
|
3683
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3684
|
+
});
|
|
3685
|
+
try {
|
|
3686
|
+
console.log(chalk4.blue("Fetching offers..."));
|
|
3687
|
+
const offers = await bazaarClient.getCollectionOffers({
|
|
3688
|
+
nftAddress: options.nftAddress
|
|
3689
|
+
});
|
|
3690
|
+
const offer = offers.find(
|
|
3691
|
+
(o) => o.orderHash.toLowerCase() === options.orderHash.toLowerCase()
|
|
3692
|
+
);
|
|
3693
|
+
if (!offer) {
|
|
3694
|
+
exitWithError(`Offer with order hash ${options.orderHash} not found or no longer active`);
|
|
3695
|
+
}
|
|
3696
|
+
console.log(chalk4.blue("Preparing fulfillment..."));
|
|
3697
|
+
const prepared = await bazaarClient.prepareFulfillCollectionOffer(
|
|
3698
|
+
offer,
|
|
3699
|
+
options.tokenId,
|
|
3700
|
+
account.address
|
|
3701
|
+
);
|
|
3702
|
+
const rpcUrls = getChainRpcUrls({
|
|
3703
|
+
chainId: commonOptions.chainId,
|
|
3704
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3705
|
+
});
|
|
3706
|
+
const walletClient = createWalletClient({
|
|
3707
|
+
account,
|
|
3708
|
+
transport: http(rpcUrls[0])
|
|
3709
|
+
});
|
|
3710
|
+
for (const approval of prepared.approvals) {
|
|
3711
|
+
console.log(chalk4.blue("Sending approval transaction..."));
|
|
3712
|
+
const calldata2 = encodeFunctionData({
|
|
3713
|
+
abi: approval.abi,
|
|
3714
|
+
functionName: approval.functionName,
|
|
3715
|
+
args: approval.args
|
|
3716
|
+
});
|
|
3717
|
+
const approvalHash = await walletClient.sendTransaction({
|
|
3718
|
+
to: approval.to,
|
|
3719
|
+
data: calldata2,
|
|
3720
|
+
chain: null,
|
|
3721
|
+
value: approval.value
|
|
3722
|
+
});
|
|
3723
|
+
console.log(chalk4.green(`Approval tx: ${approvalHash}`));
|
|
3724
|
+
}
|
|
3725
|
+
console.log(chalk4.blue("Sending fulfillment transaction..."));
|
|
3726
|
+
const calldata = encodeFunctionData({
|
|
3727
|
+
abi: prepared.fulfillment.abi,
|
|
3728
|
+
functionName: prepared.fulfillment.functionName,
|
|
3729
|
+
args: prepared.fulfillment.args
|
|
3730
|
+
});
|
|
3731
|
+
const hash = await walletClient.sendTransaction({
|
|
3732
|
+
to: prepared.fulfillment.to,
|
|
3733
|
+
data: calldata,
|
|
3734
|
+
chain: null,
|
|
3735
|
+
value: prepared.fulfillment.value
|
|
3736
|
+
});
|
|
3737
|
+
console.log(
|
|
3738
|
+
chalk4.green(
|
|
3739
|
+
`Offer accepted successfully!
|
|
3740
|
+
Transaction: ${hash}
|
|
3741
|
+
NFT: ${options.nftAddress} #${options.tokenId}
|
|
3742
|
+
Price: ${offer.price} ${offer.currency.toUpperCase()}`
|
|
3743
|
+
)
|
|
3744
|
+
);
|
|
3745
|
+
} catch (error) {
|
|
3746
|
+
exitWithError(
|
|
3747
|
+
`Failed to accept offer: ${error instanceof Error ? error.message : String(error)}`
|
|
3748
|
+
);
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
async function executeEncodeOnly6(options) {
|
|
3752
|
+
if (!options.seller) {
|
|
3753
|
+
exitWithError("--seller is required when using --encode-only without --private-key");
|
|
3754
|
+
}
|
|
3755
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3756
|
+
chainId: options.chainId,
|
|
3757
|
+
rpcUrl: options.rpcUrl
|
|
3758
|
+
});
|
|
3759
|
+
const sellerAddress = options.seller;
|
|
3760
|
+
const bazaarClient = new BazaarClient({
|
|
3761
|
+
chainId: readOnlyOptions.chainId,
|
|
3762
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3763
|
+
});
|
|
3764
|
+
try {
|
|
3765
|
+
const offers = await bazaarClient.getCollectionOffers({
|
|
3766
|
+
nftAddress: options.nftAddress
|
|
3767
|
+
});
|
|
3768
|
+
const offer = offers.find(
|
|
3769
|
+
(o) => o.orderHash.toLowerCase() === options.orderHash.toLowerCase()
|
|
3770
|
+
);
|
|
3771
|
+
if (!offer) {
|
|
3772
|
+
exitWithError(`Offer with order hash ${options.orderHash} not found or no longer active`);
|
|
3773
|
+
}
|
|
3774
|
+
const prepared = await bazaarClient.prepareFulfillCollectionOffer(
|
|
3775
|
+
offer,
|
|
3776
|
+
options.tokenId,
|
|
3777
|
+
sellerAddress
|
|
3778
|
+
);
|
|
3779
|
+
const result = {
|
|
3780
|
+
approvals: prepared.approvals.map(
|
|
3781
|
+
(a) => encodeTransaction(
|
|
3782
|
+
{ to: a.to, functionName: a.functionName, args: a.args, abi: a.abi, value: a.value },
|
|
3783
|
+
readOnlyOptions.chainId
|
|
3784
|
+
)
|
|
3785
|
+
),
|
|
3786
|
+
fulfillment: encodeTransaction(
|
|
3787
|
+
{
|
|
3788
|
+
to: prepared.fulfillment.to,
|
|
3789
|
+
functionName: prepared.fulfillment.functionName,
|
|
3790
|
+
args: prepared.fulfillment.args,
|
|
3791
|
+
abi: prepared.fulfillment.abi,
|
|
3792
|
+
value: prepared.fulfillment.value
|
|
3793
|
+
},
|
|
3794
|
+
readOnlyOptions.chainId
|
|
3795
|
+
)
|
|
3796
|
+
};
|
|
3797
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3798
|
+
} catch (error) {
|
|
3799
|
+
exitWithError(
|
|
3800
|
+
`Failed to encode accept offer: ${error instanceof Error ? error.message : String(error)}`
|
|
3801
|
+
);
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
async function executeOwnedNfts(options) {
|
|
3805
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3806
|
+
chainId: options.chainId,
|
|
3807
|
+
rpcUrl: options.rpcUrl
|
|
3808
|
+
});
|
|
3809
|
+
const bazaarClient = new BazaarClient({
|
|
3810
|
+
chainId: readOnlyOptions.chainId,
|
|
3811
|
+
rpcUrl: readOnlyOptions.rpcUrl
|
|
3812
|
+
});
|
|
3813
|
+
const startTokenId = options.startTokenId ? BigInt(options.startTokenId) : void 0;
|
|
3814
|
+
const endTokenId = options.endTokenId ? BigInt(options.endTokenId) : void 0;
|
|
3815
|
+
try {
|
|
3816
|
+
const tokenIds = await bazaarClient.getOwnedTokens({
|
|
3817
|
+
nftAddress: options.nftAddress,
|
|
3818
|
+
ownerAddress: options.owner,
|
|
3819
|
+
startTokenId,
|
|
3820
|
+
endTokenId
|
|
3821
|
+
});
|
|
3822
|
+
if (options.json) {
|
|
3823
|
+
const output = {
|
|
3824
|
+
nftAddress: options.nftAddress,
|
|
3825
|
+
owner: options.owner,
|
|
3826
|
+
tokenIds: tokenIds.map((id) => id.toString()),
|
|
3827
|
+
count: tokenIds.length
|
|
3828
|
+
};
|
|
3829
|
+
console.log(JSON.stringify(output, null, 2));
|
|
3830
|
+
return;
|
|
3831
|
+
}
|
|
3832
|
+
if (tokenIds.length === 0) {
|
|
3833
|
+
console.log(chalk4.yellow("No owned tokens found in the specified range"));
|
|
3834
|
+
return;
|
|
3835
|
+
}
|
|
3836
|
+
console.log(chalk4.white.bold(`
|
|
3837
|
+
Owned Tokens (${tokenIds.length}):
|
|
3838
|
+
`));
|
|
3839
|
+
console.log(` ${chalk4.cyan("Collection:")} ${options.nftAddress}`);
|
|
3840
|
+
console.log(` ${chalk4.cyan("Owner:")} ${options.owner}`);
|
|
3841
|
+
console.log(` ${chalk4.cyan("Token IDs:")} ${tokenIds.map((id) => id.toString()).join(", ")}`);
|
|
3842
|
+
console.log();
|
|
3843
|
+
} catch (error) {
|
|
3844
|
+
exitWithError(
|
|
3845
|
+
`Failed to fetch owned tokens: ${error instanceof Error ? error.message : String(error)}`
|
|
3846
|
+
);
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
|
|
3850
|
+
// src/commands/bazaar/index.ts
|
|
3851
|
+
var chainIdOption = [
|
|
3852
|
+
"--chain-id <id>",
|
|
3853
|
+
"Chain ID. Can also be set via NET_CHAIN_ID env var",
|
|
3854
|
+
(value) => parseInt(value, 10)
|
|
3855
|
+
];
|
|
3856
|
+
var rpcUrlOption = [
|
|
3857
|
+
"--rpc-url <url>",
|
|
3858
|
+
"Custom RPC URL. Can also be set via NET_RPC_URL env var"
|
|
3859
|
+
];
|
|
3860
|
+
var privateKeyOption = [
|
|
3861
|
+
"--private-key <key>",
|
|
3862
|
+
"Private key (0x-prefixed hex). Can also be set via NET_PRIVATE_KEY env var"
|
|
3863
|
+
];
|
|
3864
|
+
function registerBazaarCommand(program2) {
|
|
3865
|
+
const bazaarCommand = program2.command("bazaar").description("Bazaar NFT trading operations");
|
|
3866
|
+
const listListingsCommand = new Command("list-listings").description("List active NFT listings").option("--nft-address <address>", "NFT contract address (optional for cross-collection)").option(...chainIdOption).option(...rpcUrlOption).option("--json", "Output in JSON format").action(async (options) => {
|
|
3867
|
+
await executeListListings({
|
|
3868
|
+
nftAddress: options.nftAddress,
|
|
3869
|
+
chainId: options.chainId,
|
|
3870
|
+
rpcUrl: options.rpcUrl,
|
|
3871
|
+
json: options.json
|
|
3872
|
+
});
|
|
3873
|
+
});
|
|
3874
|
+
const listOffersCommand = new Command("list-offers").description("List active collection offers").requiredOption("--nft-address <address>", "NFT contract address").option(...chainIdOption).option(...rpcUrlOption).option("--json", "Output in JSON format").action(async (options) => {
|
|
3875
|
+
await executeListOffers({
|
|
3876
|
+
nftAddress: options.nftAddress,
|
|
3877
|
+
chainId: options.chainId,
|
|
3878
|
+
rpcUrl: options.rpcUrl,
|
|
3879
|
+
json: options.json
|
|
3880
|
+
});
|
|
3881
|
+
});
|
|
3882
|
+
const listSalesCommand = new Command("list-sales").description("List recent sales").requiredOption("--nft-address <address>", "NFT contract address").option(...chainIdOption).option(...rpcUrlOption).option("--json", "Output in JSON format").action(async (options) => {
|
|
3883
|
+
await executeListSales({
|
|
3884
|
+
nftAddress: options.nftAddress,
|
|
3885
|
+
chainId: options.chainId,
|
|
3886
|
+
rpcUrl: options.rpcUrl,
|
|
3887
|
+
json: options.json
|
|
3888
|
+
});
|
|
3889
|
+
});
|
|
3890
|
+
const createListingCommand = new Command("create-listing").description("Create an NFT listing (with --private-key: full flow; without: output EIP-712 data)").requiredOption("--nft-address <address>", "NFT contract address").requiredOption("--token-id <id>", "Token ID to list").requiredOption("--price <eth>", "Price in ETH (e.g., 0.1)").option("--target-fulfiller <address>", "Make a private listing for this address").option("--offerer <address>", "Offerer address (required without --private-key)").option(...privateKeyOption).option(...chainIdOption).option(...rpcUrlOption).action(async (options) => {
|
|
3891
|
+
await executeCreateListing({
|
|
3892
|
+
nftAddress: options.nftAddress,
|
|
3893
|
+
tokenId: options.tokenId,
|
|
3894
|
+
price: options.price,
|
|
3895
|
+
targetFulfiller: options.targetFulfiller,
|
|
3896
|
+
offerer: options.offerer,
|
|
3897
|
+
privateKey: options.privateKey,
|
|
3898
|
+
chainId: options.chainId,
|
|
3899
|
+
rpcUrl: options.rpcUrl
|
|
3900
|
+
});
|
|
3901
|
+
});
|
|
3902
|
+
const createOfferCommand = new Command("create-offer").description("Create a collection offer (with --private-key: full flow; without: output EIP-712 data)").requiredOption("--nft-address <address>", "NFT contract address").requiredOption("--price <eth>", "Offer price in ETH (e.g., 0.1)").option("--offerer <address>", "Offerer address (required without --private-key)").option(...privateKeyOption).option(...chainIdOption).option(...rpcUrlOption).action(async (options) => {
|
|
3903
|
+
await executeCreateOffer({
|
|
3904
|
+
nftAddress: options.nftAddress,
|
|
3905
|
+
price: options.price,
|
|
3906
|
+
offerer: options.offerer,
|
|
3907
|
+
privateKey: options.privateKey,
|
|
3908
|
+
chainId: options.chainId,
|
|
3909
|
+
rpcUrl: options.rpcUrl
|
|
3910
|
+
});
|
|
3911
|
+
});
|
|
3912
|
+
const submitListingCommand = new Command("submit-listing").description("Submit a signed listing (follow-up to create-listing without --private-key)").requiredOption("--order-data <path>", "Path to order JSON file from create-listing output").requiredOption("--signature <sig>", "EIP-712 signature (0x-prefixed)").option(...privateKeyOption).option(...chainIdOption).option(...rpcUrlOption).option("--encode-only", "Output transaction data as JSON instead of executing").action(async (options) => {
|
|
3913
|
+
await executeSubmitListing({
|
|
3914
|
+
orderData: options.orderData,
|
|
3915
|
+
signature: options.signature,
|
|
3916
|
+
privateKey: options.privateKey,
|
|
3917
|
+
chainId: options.chainId,
|
|
3918
|
+
rpcUrl: options.rpcUrl,
|
|
3919
|
+
encodeOnly: options.encodeOnly
|
|
3920
|
+
});
|
|
3921
|
+
});
|
|
3922
|
+
const submitOfferCommand = new Command("submit-offer").description("Submit a signed offer (follow-up to create-offer without --private-key)").requiredOption("--order-data <path>", "Path to order JSON file from create-offer output").requiredOption("--signature <sig>", "EIP-712 signature (0x-prefixed)").option(...privateKeyOption).option(...chainIdOption).option(...rpcUrlOption).option("--encode-only", "Output transaction data as JSON instead of executing").action(async (options) => {
|
|
3923
|
+
await executeSubmitOffer({
|
|
3924
|
+
orderData: options.orderData,
|
|
3925
|
+
signature: options.signature,
|
|
3926
|
+
privateKey: options.privateKey,
|
|
3927
|
+
chainId: options.chainId,
|
|
3928
|
+
rpcUrl: options.rpcUrl,
|
|
3929
|
+
encodeOnly: options.encodeOnly
|
|
3930
|
+
});
|
|
3931
|
+
});
|
|
3932
|
+
const buyListingCommand = new Command("buy-listing").description("Buy an NFT listing").requiredOption("--order-hash <hash>", "Order hash of the listing to buy").requiredOption("--nft-address <address>", "NFT contract address").option("--buyer <address>", "Buyer address (required with --encode-only)").option(...privateKeyOption).option(...chainIdOption).option(...rpcUrlOption).option("--encode-only", "Output transaction data as JSON instead of executing").action(async (options) => {
|
|
3933
|
+
await executeBuyListing({
|
|
3934
|
+
orderHash: options.orderHash,
|
|
3935
|
+
nftAddress: options.nftAddress,
|
|
3936
|
+
buyer: options.buyer,
|
|
3937
|
+
privateKey: options.privateKey,
|
|
3938
|
+
chainId: options.chainId,
|
|
3939
|
+
rpcUrl: options.rpcUrl,
|
|
3940
|
+
encodeOnly: options.encodeOnly
|
|
3941
|
+
});
|
|
3942
|
+
});
|
|
3943
|
+
const acceptOfferCommand = new Command("accept-offer").description("Accept a collection offer by selling your NFT").requiredOption("--order-hash <hash>", "Order hash of the offer to accept").requiredOption("--nft-address <address>", "NFT contract address").requiredOption("--token-id <id>", "Token ID to sell").option("--seller <address>", "Seller address (required with --encode-only)").option(...privateKeyOption).option(...chainIdOption).option(...rpcUrlOption).option("--encode-only", "Output transaction data as JSON instead of executing").action(async (options) => {
|
|
3944
|
+
await executeAcceptOffer({
|
|
3945
|
+
orderHash: options.orderHash,
|
|
3946
|
+
nftAddress: options.nftAddress,
|
|
3947
|
+
tokenId: options.tokenId,
|
|
3948
|
+
seller: options.seller,
|
|
3949
|
+
privateKey: options.privateKey,
|
|
3950
|
+
chainId: options.chainId,
|
|
3951
|
+
rpcUrl: options.rpcUrl,
|
|
3952
|
+
encodeOnly: options.encodeOnly
|
|
3953
|
+
});
|
|
3954
|
+
});
|
|
3955
|
+
const ownedNftsCommand = new Command("owned-nfts").description("List NFTs owned by an address").requiredOption("--nft-address <address>", "NFT contract address").requiredOption("--owner <address>", "Owner address to check").option(...chainIdOption).option(...rpcUrlOption).option("--json", "Output in JSON format").option("--start-token-id <id>", "Start of token ID range (default: 0)").option("--end-token-id <id>", "End of token ID range (default: 10000)").action(async (options) => {
|
|
3956
|
+
await executeOwnedNfts({
|
|
3957
|
+
nftAddress: options.nftAddress,
|
|
3958
|
+
owner: options.owner,
|
|
3959
|
+
chainId: options.chainId,
|
|
3960
|
+
rpcUrl: options.rpcUrl,
|
|
3961
|
+
json: options.json,
|
|
3962
|
+
startTokenId: options.startTokenId,
|
|
3963
|
+
endTokenId: options.endTokenId
|
|
3964
|
+
});
|
|
3965
|
+
});
|
|
3966
|
+
bazaarCommand.addCommand(listListingsCommand);
|
|
3967
|
+
bazaarCommand.addCommand(listOffersCommand);
|
|
3968
|
+
bazaarCommand.addCommand(listSalesCommand);
|
|
3969
|
+
bazaarCommand.addCommand(createListingCommand);
|
|
3970
|
+
bazaarCommand.addCommand(createOfferCommand);
|
|
3971
|
+
bazaarCommand.addCommand(submitListingCommand);
|
|
3972
|
+
bazaarCommand.addCommand(submitOfferCommand);
|
|
3973
|
+
bazaarCommand.addCommand(buyListingCommand);
|
|
3974
|
+
bazaarCommand.addCommand(acceptOfferCommand);
|
|
3975
|
+
bazaarCommand.addCommand(ownedNftsCommand);
|
|
3976
|
+
}
|
|
3977
|
+
|
|
2938
3978
|
// src/cli/index.ts
|
|
2939
3979
|
var proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY;
|
|
2940
3980
|
if (proxyUrl) {
|
|
@@ -2951,6 +3991,7 @@ registerChainsCommand(program);
|
|
|
2951
3991
|
registerInfoCommand(program);
|
|
2952
3992
|
registerTokenCommand(program);
|
|
2953
3993
|
registerProfileCommand(program);
|
|
3994
|
+
registerBazaarCommand(program);
|
|
2954
3995
|
program.parse();
|
|
2955
3996
|
//# sourceMappingURL=index.mjs.map
|
|
2956
3997
|
//# sourceMappingURL=index.mjs.map
|