@rareprotocol/rare-cli 0.3.0 → 0.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # RARE Protocol CLI
2
2
 
3
- Command-line tool for the [RARE Protocol](https://superrare.com) on Ethereum. Deploy NFT contracts, mint tokens, run auctions, and search the network — all from your terminal.
3
+ Command-line tool for the [RARE Protocol](https://superrare.com) on Ethereum. Deploy NFT contracts, mint tokens, run auctions, create offers and listings, and search the network — all from your terminal.
4
4
 
5
5
  ## Install
6
6
 
@@ -149,6 +149,56 @@ rare auction cancel --contract 0x... --token-id 1
149
149
  rare auction status --contract 0x... --token-id 1
150
150
  ```
151
151
 
152
+ ### Offers
153
+
154
+ ```bash
155
+ # Create an offer on a token
156
+ rare offer create --contract 0x... --token-id 1 --amount 0.5
157
+
158
+ # Create an offer with ERC20 currency
159
+ rare offer create --contract 0x... --token-id 1 --amount 100 --currency usdc
160
+
161
+ # Accept an offer on a token you own
162
+ rare offer accept --contract 0x... --token-id 1 --amount 0.5
163
+
164
+ # Cancel your offer
165
+ rare offer cancel --contract 0x... --token-id 1
166
+
167
+ # Check offer status (read-only)
168
+ rare offer status --contract 0x... --token-id 1
169
+ ```
170
+
171
+ ### Listings
172
+
173
+ ```bash
174
+ # List a token for sale at a fixed price
175
+ rare listing create --contract 0x... --token-id 1 --price 1.0
176
+
177
+ # List with ERC20 currency or a targeted buyer
178
+ rare listing create --contract 0x... --token-id 1 --price 100 --currency rare --target 0x...buyer
179
+
180
+ # Buy a listed token
181
+ rare listing buy --contract 0x... --token-id 1 --amount 1.0
182
+
183
+ # Cancel a listing
184
+ rare listing cancel --contract 0x... --token-id 1
185
+
186
+ # Check listing status (read-only)
187
+ rare listing status --contract 0x... --token-id 1
188
+ ```
189
+
190
+ ### Currencies
191
+
192
+ All marketplace commands (`auction`, `offer`, `listing`) accept `--currency` to specify a payment token. Named currencies (`eth`, `usdc`, `rare`) are resolved per-chain automatically. You can also pass any ERC20 address directly.
193
+
194
+ ERC20 allowances are auto-approved when needed for bids, offers, and purchases.
195
+
196
+ ```bash
197
+ # List supported currencies and their addresses
198
+ rare currencies
199
+ rare currencies --chain mainnet
200
+ ```
201
+
152
202
  ### Search
153
203
 
154
204
  ```bash
package/dist/client.d.ts CHANGED
@@ -137,6 +137,72 @@ interface AuctionStatus {
137
137
  endTime: bigint | null;
138
138
  status: 'PENDING' | 'RUNNING' | 'ENDED';
139
139
  }
140
+ interface OfferCreateParams {
141
+ contract: Address;
142
+ tokenId: IntegerInput;
143
+ currency?: Address;
144
+ amount: AmountInput;
145
+ convertible?: boolean;
146
+ }
147
+ interface OfferCancelParams {
148
+ contract: Address;
149
+ tokenId: IntegerInput;
150
+ currency?: Address;
151
+ }
152
+ interface OfferAcceptParams {
153
+ contract: Address;
154
+ tokenId: IntegerInput;
155
+ currency?: Address;
156
+ amount: AmountInput;
157
+ splitAddresses?: Address[];
158
+ splitRatios?: number[];
159
+ }
160
+ interface OfferStatusParams {
161
+ contract: Address;
162
+ tokenId: IntegerInput;
163
+ currency?: Address;
164
+ }
165
+ interface OfferStatus {
166
+ buyer: Address;
167
+ amount: bigint;
168
+ timestamp: bigint;
169
+ marketplaceFee: number;
170
+ convertible: boolean;
171
+ hasOffer: boolean;
172
+ }
173
+ interface ListingCreateParams {
174
+ contract: Address;
175
+ tokenId: IntegerInput;
176
+ currency?: Address;
177
+ price: AmountInput;
178
+ target?: Address;
179
+ splitAddresses?: Address[];
180
+ splitRatios?: number[];
181
+ autoApprove?: boolean;
182
+ }
183
+ interface ListingCancelParams {
184
+ contract: Address;
185
+ tokenId: IntegerInput;
186
+ target?: Address;
187
+ }
188
+ interface ListingBuyParams {
189
+ contract: Address;
190
+ tokenId: IntegerInput;
191
+ currency?: Address;
192
+ amount: AmountInput;
193
+ }
194
+ interface ListingStatusParams {
195
+ contract: Address;
196
+ tokenId: IntegerInput;
197
+ target?: Address;
198
+ }
199
+ interface ListingStatus {
200
+ seller: Address;
201
+ currencyAddress: Address;
202
+ amount: bigint;
203
+ hasListing: boolean;
204
+ isEth: boolean;
205
+ }
140
206
  interface TokenContractInfo {
141
207
  contract: Address;
142
208
  chain: SupportedChain;
@@ -172,6 +238,20 @@ interface RareClient {
172
238
  cancel(params: AuctionCancelParams): Promise<TransactionResult>;
173
239
  getStatus(params: AuctionStatusParams): Promise<AuctionStatus>;
174
240
  };
241
+ offer: {
242
+ create(params: OfferCreateParams): Promise<TransactionResult>;
243
+ cancel(params: OfferCancelParams): Promise<TransactionResult>;
244
+ accept(params: OfferAcceptParams): Promise<TransactionResult>;
245
+ getStatus(params: OfferStatusParams): Promise<OfferStatus>;
246
+ };
247
+ listing: {
248
+ create(params: ListingCreateParams): Promise<TransactionResult & {
249
+ approvalTxHash?: Hash;
250
+ }>;
251
+ cancel(params: ListingCancelParams): Promise<TransactionResult>;
252
+ buy(params: ListingBuyParams): Promise<TransactionResult>;
253
+ getStatus(params: ListingStatusParams): Promise<ListingStatus>;
254
+ };
175
255
  search: {
176
256
  nfts(params?: NftSearchParams): Promise<SearchPageResponse>;
177
257
  collections(params?: CollectionSearchParams): Promise<SearchPageResponse>;
package/dist/client.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // src/sdk/client.ts
2
2
  import {
3
+ erc20Abi,
3
4
  parseEther,
4
- parseEventLogs
5
+ parseEventLogs,
6
+ maxUint256
5
7
  } from "viem";
6
8
 
7
9
  // src/contracts/addresses.ts
@@ -42,6 +44,28 @@ var contractAddresses = {
42
44
  auction: "0x1f0c946f0ee87acb268d50ede6c9b4d010af65d2"
43
45
  }
44
46
  };
47
+ var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
48
+ var currencyAddresses = {
49
+ eth: {
50
+ mainnet: ETH_ADDRESS,
51
+ sepolia: ETH_ADDRESS,
52
+ base: ETH_ADDRESS,
53
+ "base-sepolia": ETH_ADDRESS
54
+ },
55
+ rare: {
56
+ mainnet: "0xba5BDe662c17e2aDFF1075610382B9B691296350",
57
+ sepolia: "0x197FaeF3f59eC80113e773Bb6206a17d183F97CB",
58
+ base: "0x691077c8e8de54ea84efd454630439f99bd8c92f",
59
+ "base-sepolia": "0x8b21bC8571d11F7AdB705ad8F6f6BD1deb79cE01"
60
+ },
61
+ usdc: {
62
+ mainnet: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
63
+ sepolia: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
64
+ base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
65
+ "base-sepolia": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
66
+ }
67
+ };
68
+ var currencyNames = Object.keys(currencyAddresses);
45
69
  function getContractAddresses(chain) {
46
70
  const addresses = contractAddresses[chain];
47
71
  if (!addresses) {
@@ -2720,7 +2744,7 @@ async function searchCollections(params = {}) {
2720
2744
  }
2721
2745
 
2722
2746
  // src/sdk/client.ts
2723
- var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
2747
+ var ETH_ADDRESS2 = "0x0000000000000000000000000000000000000000";
2724
2748
  var approvalAbi = [
2725
2749
  {
2726
2750
  inputs: [{ name: "owner", type: "address" }, { name: "operator", type: "address" }],
@@ -2737,6 +2761,15 @@ var approvalAbi = [
2737
2761
  type: "function"
2738
2762
  }
2739
2763
  ];
2764
+ var marketplaceSettingsAbi = [
2765
+ {
2766
+ inputs: [{ name: "_amount", type: "uint256" }],
2767
+ name: "calculateMarketplaceFee",
2768
+ outputs: [{ name: "", type: "uint256" }],
2769
+ stateMutability: "view",
2770
+ type: "function"
2771
+ }
2772
+ ];
2740
2773
  function resolveChainFromPublicClient(publicClient) {
2741
2774
  const chainId = publicClient.chain?.id;
2742
2775
  if (!chainId) {
@@ -2888,7 +2921,7 @@ function createRareClient(config) {
2888
2921
  async create(params) {
2889
2922
  const { walletClient, account, accountAddress } = requireWallet(config);
2890
2923
  const nftAddress = params.contract;
2891
- const currency = params.currency ?? ETH_ADDRESS;
2924
+ const currency = params.currency ?? ETH_ADDRESS2;
2892
2925
  const tokenId = toInteger(params.tokenId, "tokenId");
2893
2926
  const startingPrice = toWei(params.startingPrice);
2894
2927
  const duration = toInteger(params.duration, "duration");
@@ -2945,10 +2978,55 @@ function createRareClient(config) {
2945
2978
  };
2946
2979
  },
2947
2980
  async bid(params) {
2948
- const { walletClient, account } = requireWallet(config);
2949
- const currency = params.currency ?? ETH_ADDRESS;
2981
+ const { walletClient, account, accountAddress } = requireWallet(config);
2982
+ const currency = params.currency ?? ETH_ADDRESS2;
2950
2983
  const amount = toWei(params.amount);
2951
- const isEth = currency === ETH_ADDRESS;
2984
+ const isEth = currency === ETH_ADDRESS2;
2985
+ let value = 0n;
2986
+ if (isEth) {
2987
+ const settingsAddress = await publicClient.readContract({
2988
+ address: addresses.auction,
2989
+ abi: auctionAbi,
2990
+ functionName: "marketplaceSettings"
2991
+ });
2992
+ const fee = await publicClient.readContract({
2993
+ address: settingsAddress,
2994
+ abi: marketplaceSettingsAbi,
2995
+ functionName: "calculateMarketplaceFee",
2996
+ args: [amount]
2997
+ });
2998
+ value = amount + fee;
2999
+ } else {
3000
+ try {
3001
+ const allowance = await publicClient.readContract({
3002
+ address: currency,
3003
+ abi: erc20Abi,
3004
+ functionName: "allowance",
3005
+ args: [accountAddress, addresses.auction]
3006
+ });
3007
+ if (BigInt(allowance) < amount) {
3008
+ const approveTx = await walletClient.writeContract({
3009
+ address: currency,
3010
+ abi: erc20Abi,
3011
+ functionName: "approve",
3012
+ args: [addresses.auction, maxUint256],
3013
+ account,
3014
+ chain: void 0
3015
+ });
3016
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3017
+ }
3018
+ } catch {
3019
+ const approveTx = await walletClient.writeContract({
3020
+ address: currency,
3021
+ abi: erc20Abi,
3022
+ functionName: "approve",
3023
+ args: [addresses.auction, maxUint256],
3024
+ account,
3025
+ chain: void 0
3026
+ });
3027
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3028
+ }
3029
+ }
2952
3030
  const txHash = await walletClient.writeContract({
2953
3031
  address: addresses.auction,
2954
3032
  abi: auctionAbi,
@@ -2956,7 +3034,7 @@ function createRareClient(config) {
2956
3034
  args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount],
2957
3035
  account,
2958
3036
  chain: void 0,
2959
- value: isEth ? amount : 0n
3037
+ value
2960
3038
  });
2961
3039
  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
2962
3040
  return { txHash, receipt };
@@ -3022,13 +3100,249 @@ function createRareClient(config) {
3022
3100
  auctionType,
3023
3101
  splitAddresses: [...splitAddresses],
3024
3102
  splitRatios: [...splitRatios],
3025
- isEth: currency === ETH_ADDRESS,
3103
+ isEth: currency === ETH_ADDRESS2,
3026
3104
  started,
3027
3105
  endTime,
3028
3106
  status
3029
3107
  };
3030
3108
  }
3031
3109
  },
3110
+ offer: {
3111
+ async create(params) {
3112
+ const { walletClient, account, accountAddress } = requireWallet(config);
3113
+ const currency = params.currency ?? ETH_ADDRESS2;
3114
+ const amount = toWei(params.amount);
3115
+ const isEth = currency === ETH_ADDRESS2;
3116
+ const convertible = params.convertible ?? false;
3117
+ let value = 0n;
3118
+ if (isEth) {
3119
+ const settingsAddress = await publicClient.readContract({
3120
+ address: addresses.auction,
3121
+ abi: auctionAbi,
3122
+ functionName: "marketplaceSettings"
3123
+ });
3124
+ const fee = await publicClient.readContract({
3125
+ address: settingsAddress,
3126
+ abi: marketplaceSettingsAbi,
3127
+ functionName: "calculateMarketplaceFee",
3128
+ args: [amount]
3129
+ });
3130
+ value = amount + fee;
3131
+ } else {
3132
+ try {
3133
+ const allowance = await publicClient.readContract({
3134
+ address: currency,
3135
+ abi: erc20Abi,
3136
+ functionName: "allowance",
3137
+ args: [accountAddress, addresses.auction]
3138
+ });
3139
+ if (BigInt(allowance) < amount) {
3140
+ const approveTx = await walletClient.writeContract({
3141
+ address: currency,
3142
+ abi: erc20Abi,
3143
+ functionName: "approve",
3144
+ args: [addresses.auction, maxUint256],
3145
+ account,
3146
+ chain: void 0
3147
+ });
3148
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3149
+ }
3150
+ } catch {
3151
+ const approveTx = await walletClient.writeContract({
3152
+ address: currency,
3153
+ abi: erc20Abi,
3154
+ functionName: "approve",
3155
+ args: [addresses.auction, maxUint256],
3156
+ account,
3157
+ chain: void 0
3158
+ });
3159
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3160
+ }
3161
+ }
3162
+ const txHash = await walletClient.writeContract({
3163
+ address: addresses.auction,
3164
+ abi: auctionAbi,
3165
+ functionName: "offer",
3166
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount, convertible],
3167
+ account,
3168
+ chain: void 0,
3169
+ value
3170
+ });
3171
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3172
+ return { txHash, receipt };
3173
+ },
3174
+ async cancel(params) {
3175
+ const { walletClient, account } = requireWallet(config);
3176
+ const currency = params.currency ?? ETH_ADDRESS2;
3177
+ const txHash = await walletClient.writeContract({
3178
+ address: addresses.auction,
3179
+ abi: auctionAbi,
3180
+ functionName: "cancelOffer",
3181
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency],
3182
+ account,
3183
+ chain: void 0
3184
+ });
3185
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3186
+ return { txHash, receipt };
3187
+ },
3188
+ async accept(params) {
3189
+ const { walletClient, account, accountAddress } = requireWallet(config);
3190
+ const currency = params.currency ?? ETH_ADDRESS2;
3191
+ const amount = toWei(params.amount);
3192
+ const splitAddresses = params.splitAddresses ?? [accountAddress];
3193
+ const splitRatios = params.splitRatios ?? [100];
3194
+ const txHash = await walletClient.writeContract({
3195
+ address: addresses.auction,
3196
+ abi: auctionAbi,
3197
+ functionName: "acceptOffer",
3198
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount, splitAddresses, splitRatios],
3199
+ account,
3200
+ chain: void 0
3201
+ });
3202
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3203
+ return { txHash, receipt };
3204
+ },
3205
+ async getStatus(params) {
3206
+ const currency = params.currency ?? ETH_ADDRESS2;
3207
+ const [buyer, amount, timestamp, marketplaceFee, convertible] = await publicClient.readContract({
3208
+ address: addresses.auction,
3209
+ abi: auctionAbi,
3210
+ functionName: "tokenCurrentOffers",
3211
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency]
3212
+ });
3213
+ const hasOffer = amount > 0n;
3214
+ return { buyer, amount, timestamp, marketplaceFee, convertible, hasOffer };
3215
+ }
3216
+ },
3217
+ listing: {
3218
+ async create(params) {
3219
+ const { walletClient, account, accountAddress } = requireWallet(config);
3220
+ const currency = params.currency ?? ETH_ADDRESS2;
3221
+ const price = toWei(params.price);
3222
+ const target = params.target ?? ETH_ADDRESS2;
3223
+ const splitAddresses = params.splitAddresses ?? [accountAddress];
3224
+ const splitRatios = params.splitRatios ?? [100];
3225
+ const nftAddress = params.contract;
3226
+ let approvalTxHash;
3227
+ if (params.autoApprove !== false) {
3228
+ const isApproved = await publicClient.readContract({
3229
+ address: nftAddress,
3230
+ abi: approvalAbi,
3231
+ functionName: "isApprovedForAll",
3232
+ args: [accountAddress, addresses.auction]
3233
+ });
3234
+ if (!isApproved) {
3235
+ approvalTxHash = await walletClient.writeContract({
3236
+ address: nftAddress,
3237
+ abi: approvalAbi,
3238
+ functionName: "setApprovalForAll",
3239
+ args: [addresses.auction, true],
3240
+ account,
3241
+ chain: void 0
3242
+ });
3243
+ await publicClient.waitForTransactionReceipt({ hash: approvalTxHash });
3244
+ }
3245
+ }
3246
+ const txHash = await walletClient.writeContract({
3247
+ address: addresses.auction,
3248
+ abi: auctionAbi,
3249
+ functionName: "setSalePrice",
3250
+ args: [nftAddress, toInteger(params.tokenId, "tokenId"), currency, price, target, splitAddresses, splitRatios],
3251
+ account,
3252
+ chain: void 0
3253
+ });
3254
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3255
+ return { txHash, receipt, approvalTxHash };
3256
+ },
3257
+ async cancel(params) {
3258
+ const { walletClient, account } = requireWallet(config);
3259
+ const target = params.target ?? ETH_ADDRESS2;
3260
+ const txHash = await walletClient.writeContract({
3261
+ address: addresses.auction,
3262
+ abi: auctionAbi,
3263
+ functionName: "removeSalePrice",
3264
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), target],
3265
+ account,
3266
+ chain: void 0
3267
+ });
3268
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3269
+ return { txHash, receipt };
3270
+ },
3271
+ async buy(params) {
3272
+ const { walletClient, account, accountAddress } = requireWallet(config);
3273
+ const currency = params.currency ?? ETH_ADDRESS2;
3274
+ const amount = toWei(params.amount);
3275
+ const isEth = currency === ETH_ADDRESS2;
3276
+ let value = 0n;
3277
+ if (isEth) {
3278
+ const settingsAddress = await publicClient.readContract({
3279
+ address: addresses.auction,
3280
+ abi: auctionAbi,
3281
+ functionName: "marketplaceSettings"
3282
+ });
3283
+ const fee = await publicClient.readContract({
3284
+ address: settingsAddress,
3285
+ abi: marketplaceSettingsAbi,
3286
+ functionName: "calculateMarketplaceFee",
3287
+ args: [amount]
3288
+ });
3289
+ value = amount + fee;
3290
+ } else {
3291
+ try {
3292
+ const allowance = await publicClient.readContract({
3293
+ address: currency,
3294
+ abi: erc20Abi,
3295
+ functionName: "allowance",
3296
+ args: [accountAddress, addresses.auction]
3297
+ });
3298
+ if (BigInt(allowance) < amount) {
3299
+ const approveTx = await walletClient.writeContract({
3300
+ address: currency,
3301
+ abi: erc20Abi,
3302
+ functionName: "approve",
3303
+ args: [addresses.auction, maxUint256],
3304
+ account,
3305
+ chain: void 0
3306
+ });
3307
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3308
+ }
3309
+ } catch {
3310
+ const approveTx = await walletClient.writeContract({
3311
+ address: currency,
3312
+ abi: erc20Abi,
3313
+ functionName: "approve",
3314
+ args: [addresses.auction, maxUint256],
3315
+ account,
3316
+ chain: void 0
3317
+ });
3318
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3319
+ }
3320
+ }
3321
+ const txHash = await walletClient.writeContract({
3322
+ address: addresses.auction,
3323
+ abi: auctionAbi,
3324
+ functionName: "buy",
3325
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount],
3326
+ account,
3327
+ chain: void 0,
3328
+ value
3329
+ });
3330
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3331
+ return { txHash, receipt };
3332
+ },
3333
+ async getStatus(params) {
3334
+ const target = params.target ?? ETH_ADDRESS2;
3335
+ const [seller, currencyAddress, amount] = await publicClient.readContract({
3336
+ address: addresses.auction,
3337
+ abi: auctionAbi,
3338
+ functionName: "tokenSalePrices",
3339
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), target]
3340
+ });
3341
+ const hasListing = amount > 0n;
3342
+ const isEth = currencyAddress === ETH_ADDRESS2;
3343
+ return { seller, currencyAddress, amount, hasListing, isEth };
3344
+ }
3345
+ },
3032
3346
  search: {
3033
3347
  async nfts(params = {}) {
3034
3348
  const requestParams = params.chainIds ? params : { ...params, chainIds: [chainId] };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command10 } from "commander";
4
+ import { Command as Command13 } from "commander";
5
5
 
6
6
  // src/commands/configure.ts
7
7
  import { Command } from "commander";
@@ -55,6 +55,42 @@ var contractAddresses = {
55
55
  auction: "0x1f0c946f0ee87acb268d50ede6c9b4d010af65d2"
56
56
  }
57
57
  };
58
+ var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
59
+ var currencyAddresses = {
60
+ eth: {
61
+ mainnet: ETH_ADDRESS,
62
+ sepolia: ETH_ADDRESS,
63
+ base: ETH_ADDRESS,
64
+ "base-sepolia": ETH_ADDRESS
65
+ },
66
+ rare: {
67
+ mainnet: "0xba5BDe662c17e2aDFF1075610382B9B691296350",
68
+ sepolia: "0x197FaeF3f59eC80113e773Bb6206a17d183F97CB",
69
+ base: "0x691077c8e8de54ea84efd454630439f99bd8c92f",
70
+ "base-sepolia": "0x8b21bC8571d11F7AdB705ad8F6f6BD1deb79cE01"
71
+ },
72
+ usdc: {
73
+ mainnet: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
74
+ sepolia: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
75
+ base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
76
+ "base-sepolia": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
77
+ }
78
+ };
79
+ var currencyNames = Object.keys(currencyAddresses);
80
+ function resolveCurrency(input, chain) {
81
+ const lower = input.toLowerCase();
82
+ if (lower in currencyAddresses) {
83
+ const addr = currencyAddresses[lower][chain];
84
+ if (!addr) {
85
+ throw new Error(`Currency "${lower}" is not available on "${chain}".`);
86
+ }
87
+ return addr;
88
+ }
89
+ if (input.startsWith("0x")) {
90
+ return input;
91
+ }
92
+ throw new Error(`Unknown currency "${input}". Supported: ${currencyNames.join(", ")} or a 0x address.`);
93
+ }
58
94
  function getContractAddresses(chain) {
59
95
  const addresses = contractAddresses[chain];
60
96
  if (!addresses) {
@@ -220,8 +256,10 @@ function getWalletClient(chain) {
220
256
 
221
257
  // src/sdk/client.ts
222
258
  import {
259
+ erc20Abi,
223
260
  parseEther,
224
- parseEventLogs
261
+ parseEventLogs,
262
+ maxUint256
225
263
  } from "viem";
226
264
 
227
265
  // src/contracts/abis/factory.ts
@@ -2889,7 +2927,7 @@ async function searchCollections(params = {}) {
2889
2927
  }
2890
2928
 
2891
2929
  // src/sdk/client.ts
2892
- var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
2930
+ var ETH_ADDRESS2 = "0x0000000000000000000000000000000000000000";
2893
2931
  var approvalAbi = [
2894
2932
  {
2895
2933
  inputs: [{ name: "owner", type: "address" }, { name: "operator", type: "address" }],
@@ -2906,6 +2944,15 @@ var approvalAbi = [
2906
2944
  type: "function"
2907
2945
  }
2908
2946
  ];
2947
+ var marketplaceSettingsAbi = [
2948
+ {
2949
+ inputs: [{ name: "_amount", type: "uint256" }],
2950
+ name: "calculateMarketplaceFee",
2951
+ outputs: [{ name: "", type: "uint256" }],
2952
+ stateMutability: "view",
2953
+ type: "function"
2954
+ }
2955
+ ];
2909
2956
  function resolveChainFromPublicClient(publicClient) {
2910
2957
  const chainId = publicClient.chain?.id;
2911
2958
  if (!chainId) {
@@ -3057,7 +3104,7 @@ function createRareClient(config) {
3057
3104
  async create(params) {
3058
3105
  const { walletClient, account, accountAddress } = requireWallet(config);
3059
3106
  const nftAddress = params.contract;
3060
- const currency = params.currency ?? ETH_ADDRESS;
3107
+ const currency = params.currency ?? ETH_ADDRESS2;
3061
3108
  const tokenId = toInteger(params.tokenId, "tokenId");
3062
3109
  const startingPrice = toWei(params.startingPrice);
3063
3110
  const duration = toInteger(params.duration, "duration");
@@ -3114,10 +3161,55 @@ function createRareClient(config) {
3114
3161
  };
3115
3162
  },
3116
3163
  async bid(params) {
3117
- const { walletClient, account } = requireWallet(config);
3118
- const currency = params.currency ?? ETH_ADDRESS;
3164
+ const { walletClient, account, accountAddress } = requireWallet(config);
3165
+ const currency = params.currency ?? ETH_ADDRESS2;
3119
3166
  const amount = toWei(params.amount);
3120
- const isEth = currency === ETH_ADDRESS;
3167
+ const isEth = currency === ETH_ADDRESS2;
3168
+ let value = 0n;
3169
+ if (isEth) {
3170
+ const settingsAddress = await publicClient.readContract({
3171
+ address: addresses.auction,
3172
+ abi: auctionAbi,
3173
+ functionName: "marketplaceSettings"
3174
+ });
3175
+ const fee = await publicClient.readContract({
3176
+ address: settingsAddress,
3177
+ abi: marketplaceSettingsAbi,
3178
+ functionName: "calculateMarketplaceFee",
3179
+ args: [amount]
3180
+ });
3181
+ value = amount + fee;
3182
+ } else {
3183
+ try {
3184
+ const allowance = await publicClient.readContract({
3185
+ address: currency,
3186
+ abi: erc20Abi,
3187
+ functionName: "allowance",
3188
+ args: [accountAddress, addresses.auction]
3189
+ });
3190
+ if (BigInt(allowance) < amount) {
3191
+ const approveTx = await walletClient.writeContract({
3192
+ address: currency,
3193
+ abi: erc20Abi,
3194
+ functionName: "approve",
3195
+ args: [addresses.auction, maxUint256],
3196
+ account,
3197
+ chain: void 0
3198
+ });
3199
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3200
+ }
3201
+ } catch {
3202
+ const approveTx = await walletClient.writeContract({
3203
+ address: currency,
3204
+ abi: erc20Abi,
3205
+ functionName: "approve",
3206
+ args: [addresses.auction, maxUint256],
3207
+ account,
3208
+ chain: void 0
3209
+ });
3210
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3211
+ }
3212
+ }
3121
3213
  const txHash = await walletClient.writeContract({
3122
3214
  address: addresses.auction,
3123
3215
  abi: auctionAbi,
@@ -3125,7 +3217,7 @@ function createRareClient(config) {
3125
3217
  args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount],
3126
3218
  account,
3127
3219
  chain: void 0,
3128
- value: isEth ? amount : 0n
3220
+ value
3129
3221
  });
3130
3222
  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3131
3223
  return { txHash, receipt };
@@ -3191,13 +3283,249 @@ function createRareClient(config) {
3191
3283
  auctionType,
3192
3284
  splitAddresses: [...splitAddresses],
3193
3285
  splitRatios: [...splitRatios],
3194
- isEth: currency === ETH_ADDRESS,
3286
+ isEth: currency === ETH_ADDRESS2,
3195
3287
  started,
3196
3288
  endTime,
3197
3289
  status
3198
3290
  };
3199
3291
  }
3200
3292
  },
3293
+ offer: {
3294
+ async create(params) {
3295
+ const { walletClient, account, accountAddress } = requireWallet(config);
3296
+ const currency = params.currency ?? ETH_ADDRESS2;
3297
+ const amount = toWei(params.amount);
3298
+ const isEth = currency === ETH_ADDRESS2;
3299
+ const convertible = params.convertible ?? false;
3300
+ let value = 0n;
3301
+ if (isEth) {
3302
+ const settingsAddress = await publicClient.readContract({
3303
+ address: addresses.auction,
3304
+ abi: auctionAbi,
3305
+ functionName: "marketplaceSettings"
3306
+ });
3307
+ const fee = await publicClient.readContract({
3308
+ address: settingsAddress,
3309
+ abi: marketplaceSettingsAbi,
3310
+ functionName: "calculateMarketplaceFee",
3311
+ args: [amount]
3312
+ });
3313
+ value = amount + fee;
3314
+ } else {
3315
+ try {
3316
+ const allowance = await publicClient.readContract({
3317
+ address: currency,
3318
+ abi: erc20Abi,
3319
+ functionName: "allowance",
3320
+ args: [accountAddress, addresses.auction]
3321
+ });
3322
+ if (BigInt(allowance) < amount) {
3323
+ const approveTx = await walletClient.writeContract({
3324
+ address: currency,
3325
+ abi: erc20Abi,
3326
+ functionName: "approve",
3327
+ args: [addresses.auction, maxUint256],
3328
+ account,
3329
+ chain: void 0
3330
+ });
3331
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3332
+ }
3333
+ } catch {
3334
+ const approveTx = await walletClient.writeContract({
3335
+ address: currency,
3336
+ abi: erc20Abi,
3337
+ functionName: "approve",
3338
+ args: [addresses.auction, maxUint256],
3339
+ account,
3340
+ chain: void 0
3341
+ });
3342
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3343
+ }
3344
+ }
3345
+ const txHash = await walletClient.writeContract({
3346
+ address: addresses.auction,
3347
+ abi: auctionAbi,
3348
+ functionName: "offer",
3349
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount, convertible],
3350
+ account,
3351
+ chain: void 0,
3352
+ value
3353
+ });
3354
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3355
+ return { txHash, receipt };
3356
+ },
3357
+ async cancel(params) {
3358
+ const { walletClient, account } = requireWallet(config);
3359
+ const currency = params.currency ?? ETH_ADDRESS2;
3360
+ const txHash = await walletClient.writeContract({
3361
+ address: addresses.auction,
3362
+ abi: auctionAbi,
3363
+ functionName: "cancelOffer",
3364
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency],
3365
+ account,
3366
+ chain: void 0
3367
+ });
3368
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3369
+ return { txHash, receipt };
3370
+ },
3371
+ async accept(params) {
3372
+ const { walletClient, account, accountAddress } = requireWallet(config);
3373
+ const currency = params.currency ?? ETH_ADDRESS2;
3374
+ const amount = toWei(params.amount);
3375
+ const splitAddresses = params.splitAddresses ?? [accountAddress];
3376
+ const splitRatios = params.splitRatios ?? [100];
3377
+ const txHash = await walletClient.writeContract({
3378
+ address: addresses.auction,
3379
+ abi: auctionAbi,
3380
+ functionName: "acceptOffer",
3381
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount, splitAddresses, splitRatios],
3382
+ account,
3383
+ chain: void 0
3384
+ });
3385
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3386
+ return { txHash, receipt };
3387
+ },
3388
+ async getStatus(params) {
3389
+ const currency = params.currency ?? ETH_ADDRESS2;
3390
+ const [buyer, amount, timestamp, marketplaceFee, convertible] = await publicClient.readContract({
3391
+ address: addresses.auction,
3392
+ abi: auctionAbi,
3393
+ functionName: "tokenCurrentOffers",
3394
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency]
3395
+ });
3396
+ const hasOffer = amount > 0n;
3397
+ return { buyer, amount, timestamp, marketplaceFee, convertible, hasOffer };
3398
+ }
3399
+ },
3400
+ listing: {
3401
+ async create(params) {
3402
+ const { walletClient, account, accountAddress } = requireWallet(config);
3403
+ const currency = params.currency ?? ETH_ADDRESS2;
3404
+ const price = toWei(params.price);
3405
+ const target = params.target ?? ETH_ADDRESS2;
3406
+ const splitAddresses = params.splitAddresses ?? [accountAddress];
3407
+ const splitRatios = params.splitRatios ?? [100];
3408
+ const nftAddress = params.contract;
3409
+ let approvalTxHash;
3410
+ if (params.autoApprove !== false) {
3411
+ const isApproved = await publicClient.readContract({
3412
+ address: nftAddress,
3413
+ abi: approvalAbi,
3414
+ functionName: "isApprovedForAll",
3415
+ args: [accountAddress, addresses.auction]
3416
+ });
3417
+ if (!isApproved) {
3418
+ approvalTxHash = await walletClient.writeContract({
3419
+ address: nftAddress,
3420
+ abi: approvalAbi,
3421
+ functionName: "setApprovalForAll",
3422
+ args: [addresses.auction, true],
3423
+ account,
3424
+ chain: void 0
3425
+ });
3426
+ await publicClient.waitForTransactionReceipt({ hash: approvalTxHash });
3427
+ }
3428
+ }
3429
+ const txHash = await walletClient.writeContract({
3430
+ address: addresses.auction,
3431
+ abi: auctionAbi,
3432
+ functionName: "setSalePrice",
3433
+ args: [nftAddress, toInteger(params.tokenId, "tokenId"), currency, price, target, splitAddresses, splitRatios],
3434
+ account,
3435
+ chain: void 0
3436
+ });
3437
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3438
+ return { txHash, receipt, approvalTxHash };
3439
+ },
3440
+ async cancel(params) {
3441
+ const { walletClient, account } = requireWallet(config);
3442
+ const target = params.target ?? ETH_ADDRESS2;
3443
+ const txHash = await walletClient.writeContract({
3444
+ address: addresses.auction,
3445
+ abi: auctionAbi,
3446
+ functionName: "removeSalePrice",
3447
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), target],
3448
+ account,
3449
+ chain: void 0
3450
+ });
3451
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3452
+ return { txHash, receipt };
3453
+ },
3454
+ async buy(params) {
3455
+ const { walletClient, account, accountAddress } = requireWallet(config);
3456
+ const currency = params.currency ?? ETH_ADDRESS2;
3457
+ const amount = toWei(params.amount);
3458
+ const isEth = currency === ETH_ADDRESS2;
3459
+ let value = 0n;
3460
+ if (isEth) {
3461
+ const settingsAddress = await publicClient.readContract({
3462
+ address: addresses.auction,
3463
+ abi: auctionAbi,
3464
+ functionName: "marketplaceSettings"
3465
+ });
3466
+ const fee = await publicClient.readContract({
3467
+ address: settingsAddress,
3468
+ abi: marketplaceSettingsAbi,
3469
+ functionName: "calculateMarketplaceFee",
3470
+ args: [amount]
3471
+ });
3472
+ value = amount + fee;
3473
+ } else {
3474
+ try {
3475
+ const allowance = await publicClient.readContract({
3476
+ address: currency,
3477
+ abi: erc20Abi,
3478
+ functionName: "allowance",
3479
+ args: [accountAddress, addresses.auction]
3480
+ });
3481
+ if (BigInt(allowance) < amount) {
3482
+ const approveTx = await walletClient.writeContract({
3483
+ address: currency,
3484
+ abi: erc20Abi,
3485
+ functionName: "approve",
3486
+ args: [addresses.auction, maxUint256],
3487
+ account,
3488
+ chain: void 0
3489
+ });
3490
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3491
+ }
3492
+ } catch {
3493
+ const approveTx = await walletClient.writeContract({
3494
+ address: currency,
3495
+ abi: erc20Abi,
3496
+ functionName: "approve",
3497
+ args: [addresses.auction, maxUint256],
3498
+ account,
3499
+ chain: void 0
3500
+ });
3501
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
3502
+ }
3503
+ }
3504
+ const txHash = await walletClient.writeContract({
3505
+ address: addresses.auction,
3506
+ abi: auctionAbi,
3507
+ functionName: "buy",
3508
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), currency, amount],
3509
+ account,
3510
+ chain: void 0,
3511
+ value
3512
+ });
3513
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
3514
+ return { txHash, receipt };
3515
+ },
3516
+ async getStatus(params) {
3517
+ const target = params.target ?? ETH_ADDRESS2;
3518
+ const [seller, currencyAddress, amount] = await publicClient.readContract({
3519
+ address: addresses.auction,
3520
+ abi: auctionAbi,
3521
+ functionName: "tokenSalePrices",
3522
+ args: [params.contract, toInteger(params.tokenId, "tokenId"), target]
3523
+ });
3524
+ const hasListing = amount > 0n;
3525
+ const isEth = currencyAddress === ETH_ADDRESS2;
3526
+ return { seller, currencyAddress, amount, hasListing, isEth };
3527
+ }
3528
+ },
3201
3529
  search: {
3202
3530
  async nfts(params = {}) {
3203
3531
  const requestParams = params.chainIds ? params : { ...params, chainIds: [chainId] };
@@ -3593,23 +3921,23 @@ function printContractError(error) {
3593
3921
  }
3594
3922
 
3595
3923
  // src/commands/auction.ts
3596
- var ETH_ADDRESS2 = "0x0000000000000000000000000000000000000000";
3924
+ var ETH_ADDRESS3 = "0x0000000000000000000000000000000000000000";
3597
3925
  function auctionCommand() {
3598
3926
  const cmd = new Command4("auction");
3599
3927
  cmd.description("Auction subcommands (create, bid, settle, cancel, status)");
3600
- cmd.command("create").description("Configure and start an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID to auction").requiredOption("--starting-price <amount>", "starting price in ETH (or token units)").requiredOption("--duration <seconds>", "auction duration in seconds").option("--currency <address>", "ERC20 currency address (defaults to ETH)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3928
+ cmd.command("create").description("Configure and start an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID to auction").requiredOption("--starting-price <amount>", "starting price in ETH (or token units)").requiredOption("--duration <seconds>", "auction duration in seconds").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3601
3929
  const chain = getActiveChain(opts.chain);
3602
3930
  const { client } = getWalletClient(chain);
3603
3931
  const publicClient = getPublicClient(chain);
3604
3932
  const rare = createRareClient({ publicClient, walletClient: client });
3605
- const currency = opts.currency ?? ETH_ADDRESS2;
3933
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS3;
3606
3934
  console.log(`Creating auction on ${chain}...`);
3607
3935
  console.log(` Auction contract: ${rare.contracts.auction}`);
3608
3936
  console.log(` NFT contract: ${opts.contract}`);
3609
3937
  console.log(` Token ID: ${opts.tokenId}`);
3610
3938
  console.log(` Starting price: ${opts.startingPrice} ETH`);
3611
3939
  console.log(` Duration: ${opts.duration} seconds`);
3612
- console.log(` Currency: ${currency === ETH_ADDRESS2 ? "ETH" : currency}`);
3940
+ console.log(` Currency: ${currency === ETH_ADDRESS3 ? "ETH" : currency}`);
3613
3941
  try {
3614
3942
  const result = await rare.auction.create({
3615
3943
  contract: opts.contract,
@@ -3628,13 +3956,13 @@ Transaction sent: ${result.txHash}`);
3628
3956
  printContractError(error);
3629
3957
  }
3630
3958
  });
3631
- cmd.command("bid").description("Place a bid on an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "bid amount in ETH (or token units)").option("--currency <address>", "ERC20 currency address (defaults to ETH)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3959
+ cmd.command("bid").description("Place a bid on an auction").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "bid amount in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
3632
3960
  const chain = getActiveChain(opts.chain);
3633
3961
  const { client } = getWalletClient(chain);
3634
3962
  const publicClient = getPublicClient(chain);
3635
3963
  const rare = createRareClient({ publicClient, walletClient: client });
3636
- const currency = opts.currency ?? ETH_ADDRESS2;
3637
- const isEth = currency === ETH_ADDRESS2;
3964
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS3;
3965
+ const isEth = currency === ETH_ADDRESS3;
3638
3966
  console.log(`Placing bid on ${chain}...`);
3639
3967
  console.log(` Auction contract: ${rare.contracts.auction}`);
3640
3968
  console.log(` NFT contract: ${opts.contract}`);
@@ -3981,9 +4309,236 @@ Contract imported successfully.`);
3981
4309
  return cmd;
3982
4310
  }
3983
4311
 
4312
+ // src/commands/offer.ts
4313
+ import { Command as Command10 } from "commander";
4314
+ import { formatEther as formatEther2 } from "viem";
4315
+ var ETH_ADDRESS4 = "0x0000000000000000000000000000000000000000";
4316
+ function offerCommand() {
4317
+ const cmd = new Command10("offer");
4318
+ cmd.description("Offer subcommands (create, cancel, accept, status)");
4319
+ cmd.command("create").description("Create an offer on a token").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "offer amount in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--convertible", "mark offer as convertible").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4320
+ const chain = getActiveChain(opts.chain);
4321
+ const { client } = getWalletClient(chain);
4322
+ const publicClient = getPublicClient(chain);
4323
+ const rare = createRareClient({ publicClient, walletClient: client });
4324
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4325
+ const isEth = currency === ETH_ADDRESS4;
4326
+ console.log(`Creating offer on ${chain}...`);
4327
+ console.log(` Marketplace contract: ${rare.contracts.auction}`);
4328
+ console.log(` NFT contract: ${opts.contract}`);
4329
+ console.log(` Token ID: ${opts.tokenId}`);
4330
+ console.log(` Amount: ${opts.amount} ${isEth ? "ETH" : currency}`);
4331
+ console.log(` Convertible: ${opts.convertible ? "yes" : "no"}`);
4332
+ try {
4333
+ const result = await rare.offer.create({
4334
+ contract: opts.contract,
4335
+ tokenId: opts.tokenId,
4336
+ amount: opts.amount,
4337
+ currency,
4338
+ convertible: opts.convertible ?? false
4339
+ });
4340
+ console.log(`
4341
+ Transaction sent: ${result.txHash}`);
4342
+ console.log(`Offer created! Block: ${result.receipt.blockNumber}`);
4343
+ } catch (error) {
4344
+ printContractError(error);
4345
+ }
4346
+ });
4347
+ cmd.command("cancel").description("Cancel an existing offer").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4348
+ const chain = getActiveChain(opts.chain);
4349
+ const { client } = getWalletClient(chain);
4350
+ const publicClient = getPublicClient(chain);
4351
+ const rare = createRareClient({ publicClient, walletClient: client });
4352
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4353
+ console.log(`Cancelling offer on ${chain}...`);
4354
+ try {
4355
+ const result = await rare.offer.cancel({
4356
+ contract: opts.contract,
4357
+ tokenId: opts.tokenId,
4358
+ currency
4359
+ });
4360
+ console.log(`Transaction sent: ${result.txHash}`);
4361
+ console.log(`Offer cancelled! Block: ${result.receipt.blockNumber}`);
4362
+ } catch (error) {
4363
+ printContractError(error);
4364
+ }
4365
+ });
4366
+ cmd.command("accept").description("Accept an offer on a token you own").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "offer amount to accept in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4367
+ const chain = getActiveChain(opts.chain);
4368
+ const { client } = getWalletClient(chain);
4369
+ const publicClient = getPublicClient(chain);
4370
+ const rare = createRareClient({ publicClient, walletClient: client });
4371
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4372
+ const isEth = currency === ETH_ADDRESS4;
4373
+ console.log(`Accepting offer on ${chain}...`);
4374
+ console.log(` NFT contract: ${opts.contract}`);
4375
+ console.log(` Token ID: ${opts.tokenId}`);
4376
+ console.log(` Amount: ${opts.amount} ${isEth ? "ETH" : currency}`);
4377
+ try {
4378
+ const result = await rare.offer.accept({
4379
+ contract: opts.contract,
4380
+ tokenId: opts.tokenId,
4381
+ amount: opts.amount,
4382
+ currency
4383
+ });
4384
+ console.log(`
4385
+ Transaction sent: ${result.txHash}`);
4386
+ console.log(`Offer accepted! Block: ${result.receipt.blockNumber}`);
4387
+ } catch (error) {
4388
+ printContractError(error);
4389
+ }
4390
+ });
4391
+ cmd.command("status").description("Get current offer details (read-only)").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4392
+ const chain = getActiveChain(opts.chain);
4393
+ const publicClient = getPublicClient(chain);
4394
+ const rare = createRareClient({ publicClient });
4395
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS4;
4396
+ const isEth = currency === ETH_ADDRESS4;
4397
+ const result = await rare.offer.getStatus({
4398
+ contract: opts.contract,
4399
+ tokenId: opts.tokenId,
4400
+ currency
4401
+ });
4402
+ console.log("\nOffer Details:");
4403
+ if (!result.hasOffer) {
4404
+ console.log(" No active offer found.");
4405
+ } else {
4406
+ console.log(` Buyer: ${result.buyer}`);
4407
+ console.log(` Amount: ${formatEther2(result.amount)} ${isEth ? "ETH" : currency}`);
4408
+ console.log(` Timestamp: ${new Date(Number(result.timestamp) * 1e3).toISOString()}`);
4409
+ console.log(` Marketplace fee: ${result.marketplaceFee}%`);
4410
+ console.log(` Convertible: ${result.convertible ? "yes" : "no"}`);
4411
+ }
4412
+ });
4413
+ return cmd;
4414
+ }
4415
+
4416
+ // src/commands/listing.ts
4417
+ import { Command as Command11 } from "commander";
4418
+ import { formatEther as formatEther3 } from "viem";
4419
+ var ETH_ADDRESS5 = "0x0000000000000000000000000000000000000000";
4420
+ function listingCommand() {
4421
+ const cmd = new Command11("listing");
4422
+ cmd.description("Listing subcommands (create, cancel, buy, status)");
4423
+ cmd.command("create").description("Create a listing (set sale price) for a token").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--price <amount>", "listing price in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--target <address>", "target buyer address (defaults to public listing)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4424
+ const chain = getActiveChain(opts.chain);
4425
+ const { client } = getWalletClient(chain);
4426
+ const publicClient = getPublicClient(chain);
4427
+ const rare = createRareClient({ publicClient, walletClient: client });
4428
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS5;
4429
+ const isEth = currency === ETH_ADDRESS5;
4430
+ const target = opts.target ?? ETH_ADDRESS5;
4431
+ console.log(`Creating listing on ${chain}...`);
4432
+ console.log(` Marketplace contract: ${rare.contracts.auction}`);
4433
+ console.log(` NFT contract: ${opts.contract}`);
4434
+ console.log(` Token ID: ${opts.tokenId}`);
4435
+ console.log(` Price: ${opts.price} ${isEth ? "ETH" : currency}`);
4436
+ console.log(` Target: ${target === ETH_ADDRESS5 ? "public" : target}`);
4437
+ try {
4438
+ const result = await rare.listing.create({
4439
+ contract: opts.contract,
4440
+ tokenId: opts.tokenId,
4441
+ price: opts.price,
4442
+ currency,
4443
+ target
4444
+ });
4445
+ if (result.approvalTxHash) {
4446
+ console.log(`Approval tx sent: ${result.approvalTxHash}`);
4447
+ }
4448
+ console.log(`
4449
+ Transaction sent: ${result.txHash}`);
4450
+ console.log(`Listing created! Block: ${result.receipt.blockNumber}`);
4451
+ } catch (error) {
4452
+ printContractError(error);
4453
+ }
4454
+ });
4455
+ cmd.command("cancel").description("Cancel a listing (remove sale price)").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--target <address>", "target buyer address (defaults to public listing)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4456
+ const chain = getActiveChain(opts.chain);
4457
+ const { client } = getWalletClient(chain);
4458
+ const publicClient = getPublicClient(chain);
4459
+ const rare = createRareClient({ publicClient, walletClient: client });
4460
+ const target = opts.target ?? ETH_ADDRESS5;
4461
+ console.log(`Cancelling listing on ${chain}...`);
4462
+ try {
4463
+ const result = await rare.listing.cancel({
4464
+ contract: opts.contract,
4465
+ tokenId: opts.tokenId,
4466
+ target
4467
+ });
4468
+ console.log(`Transaction sent: ${result.txHash}`);
4469
+ console.log(`Listing cancelled! Block: ${result.receipt.blockNumber}`);
4470
+ } catch (error) {
4471
+ printContractError(error);
4472
+ }
4473
+ });
4474
+ cmd.command("buy").description("Buy a listed token").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").requiredOption("--amount <amount>", "purchase amount in ETH (or token units)").option("--currency <currency>", "currency: eth, usdc, rare, or ERC20 address (defaults to eth)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4475
+ const chain = getActiveChain(opts.chain);
4476
+ const { client } = getWalletClient(chain);
4477
+ const publicClient = getPublicClient(chain);
4478
+ const rare = createRareClient({ publicClient, walletClient: client });
4479
+ const currency = opts.currency ? resolveCurrency(opts.currency, chain) : ETH_ADDRESS5;
4480
+ const isEth = currency === ETH_ADDRESS5;
4481
+ console.log(`Buying token on ${chain}...`);
4482
+ console.log(` Marketplace contract: ${rare.contracts.auction}`);
4483
+ console.log(` NFT contract: ${opts.contract}`);
4484
+ console.log(` Token ID: ${opts.tokenId}`);
4485
+ console.log(` Amount: ${opts.amount} ${isEth ? "ETH" : currency}`);
4486
+ try {
4487
+ const result = await rare.listing.buy({
4488
+ contract: opts.contract,
4489
+ tokenId: opts.tokenId,
4490
+ amount: opts.amount,
4491
+ currency
4492
+ });
4493
+ console.log(`
4494
+ Transaction sent: ${result.txHash}`);
4495
+ console.log(`Token purchased! Block: ${result.receipt.blockNumber}`);
4496
+ } catch (error) {
4497
+ printContractError(error);
4498
+ }
4499
+ });
4500
+ cmd.command("status").description("Get listing details (read-only)").requiredOption("--contract <address>", "NFT contract address").requiredOption("--token-id <id>", "token ID").option("--target <address>", "target buyer address (defaults to public listing)").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action(async (opts) => {
4501
+ const chain = getActiveChain(opts.chain);
4502
+ const publicClient = getPublicClient(chain);
4503
+ const rare = createRareClient({ publicClient });
4504
+ const target = opts.target ?? ETH_ADDRESS5;
4505
+ const result = await rare.listing.getStatus({
4506
+ contract: opts.contract,
4507
+ tokenId: opts.tokenId,
4508
+ target
4509
+ });
4510
+ console.log("\nListing Details:");
4511
+ if (!result.hasListing) {
4512
+ console.log(" No active listing found.");
4513
+ } else {
4514
+ console.log(` Seller: ${result.seller}`);
4515
+ console.log(` Amount: ${formatEther3(result.amount)} ${result.isEth ? "ETH" : result.currencyAddress}`);
4516
+ console.log(` Currency: ${result.isEth ? "ETH" : result.currencyAddress}`);
4517
+ }
4518
+ });
4519
+ return cmd;
4520
+ }
4521
+
4522
+ // src/commands/currencies.ts
4523
+ import { Command as Command12 } from "commander";
4524
+ function currenciesCommand() {
4525
+ const cmd = new Command12("currencies");
4526
+ cmd.description("List supported currencies and their addresses").option("--chain <chain>", "chain to use (mainnet, sepolia, base, base-sepolia)").action((opts) => {
4527
+ const chain = getActiveChain(opts.chain);
4528
+ console.log(`
4529
+ Supported currencies on ${chain}:
4530
+ `);
4531
+ for (const name of currencyNames) {
4532
+ const address = resolveCurrency(name, chain);
4533
+ console.log(` ${name.toUpperCase().padEnd(6)} ${address}`);
4534
+ }
4535
+ });
4536
+ return cmd;
4537
+ }
4538
+
3984
4539
  // src/index.ts
3985
- var program = new Command10();
3986
- program.name("rare").description("CLI tool for interacting with the RARE protocol smart contracts").version("0.3.0");
4540
+ var program = new Command13();
4541
+ program.name("rare").description("CLI tool for interacting with the RARE protocol smart contracts").version("0.4.1");
3987
4542
  program.addCommand(configureCommand());
3988
4543
  program.addCommand(deployCommand());
3989
4544
  program.addCommand(mintCommand());
@@ -3993,6 +4548,9 @@ program.addCommand(walletCommand());
3993
4548
  program.addCommand(searchCommand());
3994
4549
  program.addCommand(listCollectionsCommand());
3995
4550
  program.addCommand(importCommand());
4551
+ program.addCommand(offerCommand());
4552
+ program.addCommand(listingCommand());
4553
+ program.addCommand(currenciesCommand());
3996
4554
  program.parseAsync(process.argv).catch((err) => {
3997
4555
  console.error("Error:", err.message ?? err);
3998
4556
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rareprotocol/rare-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "CLI tool for interacting with the RARE protocol smart contracts",
5
5
  "type": "module",
6
6
  "license": "MIT",