Skip to content

Commit 0c95e80

Browse files
authored
feat(marketplace): add more english auction extensions (#2794)
Signed-off-by: Jonas Daniels <jonas.daniels@outlook.com>
1 parent 31b6a4f commit 0c95e80

File tree

9 files changed

+587
-3
lines changed

9 files changed

+587
-3
lines changed

packages/thirdweb/src/chains/chain-definitions/anvil.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ export const anvil = /* @__PURE__ */ defineChain({
55
name: "Anvil",
66
rpc: "http://localhost:8545",
77
testnet: true,
8+
nativeCurrency: {
9+
name: "Anvil Ether",
10+
symbol: "ETH",
11+
decimals: 18,
12+
},
813
});

packages/thirdweb/src/exports/extensions/marketplace.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,44 @@ export {
108108
getAllValidAuctions,
109109
type GetAllValidAuctionParams,
110110
} from "../../extensions/marketplace/read/english-auction/getAllValidAuctions.js";
111+
export {
112+
getWinningBid,
113+
type GetWinningBidParams,
114+
} from "../../extensions/marketplace/read/english-auction/getWinningBid.js";
115+
export {
116+
isNewWinningBid,
117+
type IsNewWinningBidParams,
118+
} from "../../extensions/marketplace/__generated__/IEnglishAuctions/read/isNewWinningBid.js";
111119

112120
// WRITE
113121
export {
114122
createAuction,
115123
type CreateAuctionParams,
116124
} from "../../extensions/marketplace/write/english-auction/createAuction.js";
125+
export {
126+
bidInAuction,
127+
type BidInAuctionParams,
128+
} from "../../extensions/marketplace/write/english-auction/bidInAuction.js";
129+
export {
130+
cancelAuction,
131+
type CancelAuctionParams,
132+
} from "../../extensions/marketplace/__generated__/IEnglishAuctions/write/cancelAuction.js";
133+
export {
134+
buyoutAuction,
135+
type BuyoutAuctionParams,
136+
} from "../../extensions/marketplace/write/english-auction/buyoutAuction.js";
137+
export {
138+
collectAuctionPayout,
139+
type CollectAuctionPayoutParams,
140+
} from "../../extensions/marketplace/__generated__/IEnglishAuctions/write/collectAuctionPayout.js";
141+
export {
142+
collectAuctionTokens,
143+
type CollectAuctionTokensParams,
144+
} from "../../extensions/marketplace/__generated__/IEnglishAuctions/write/collectAuctionTokens.js";
145+
export {
146+
executeSale,
147+
type ExecuteSaleParams,
148+
} from "../../extensions/marketplace/write/english-auction/executeSale.js";
117149

118150
// EVENTS
119151
export {

packages/thirdweb/src/extensions/marketplace/marketplace.test.ts

Lines changed: 193 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ import { getListing } from "./read/direct/getListing.js";
2525
import { getAllAuctions } from "./read/english-auction/getAllAuctions.js";
2626
import { getAllValidAuctions } from "./read/english-auction/getAllValidAuctions.js";
2727
import { getAuction } from "./read/english-auction/getAuction.js";
28+
import { getWinningBid } from "./read/english-auction/getWinningBid.js";
2829
import { isListingValid } from "./utils.js";
2930
import { buyFromListing } from "./write/direct/buyFromListing.js";
3031
import { createListing } from "./write/direct/createListing.js";
32+
import { bidInAuction } from "./write/english-auction/bidInAuction.js";
33+
import { buyoutAuction } from "./write/english-auction/buyoutAuction.js";
3134
import { createAuction } from "./write/english-auction/createAuction.js";
35+
// import { executeSale } from "./write/english-auction/executeSale.js";
3236

3337
describe.runIf(process.env.TW_SECRET_KEY)(
3438
"Marketplace",
@@ -183,7 +187,7 @@ describe.runIf(process.env.TW_SECRET_KEY)(
183187
{
184188
"decimals": 18,
185189
"displayValue": "1",
186-
"name": "Ether",
190+
"name": "Anvil Ether",
187191
"symbol": "ETH",
188192
"value": 1000000000000000000n,
189193
}
@@ -348,7 +352,7 @@ describe.runIf(process.env.TW_SECRET_KEY)(
348352
{
349353
"decimals": 18,
350354
"displayValue": "1",
351-
"name": "Ether",
355+
"name": "Anvil Ether",
352356
"symbol": "ETH",
353357
"value": 1000000000000000000n,
354358
}
@@ -357,7 +361,7 @@ describe.runIf(process.env.TW_SECRET_KEY)(
357361
{
358362
"decimals": 18,
359363
"displayValue": "10",
360-
"name": "Ether",
364+
"name": "Anvil Ether",
361365
"symbol": "ETH",
362366
"value": 10000000000000000000n,
363367
}
@@ -373,6 +377,192 @@ describe.runIf(process.env.TW_SECRET_KEY)(
373377
"type": "ERC721",
374378
}
375379
`);
380+
381+
// check for a winning bid
382+
await expect(
383+
getWinningBid({
384+
contract: marketplaceContract,
385+
auctionId: listing.id,
386+
}),
387+
).resolves.toBeUndefined();
388+
389+
// invalid bid amount 1: 0 bid (0 is not allowed)
390+
await expect(
391+
sendAndConfirmTransaction({
392+
account: TEST_ACCOUNT_B,
393+
transaction: bidInAuction({
394+
auctionId: listing.id,
395+
contract: marketplaceContract,
396+
bidAmount: "0",
397+
}),
398+
}),
399+
).rejects.toThrowErrorMatchingInlineSnapshot(
400+
"[Error: Bid amount is zero]",
401+
);
402+
// invalid bid amount 2: 11 bid (over buyout)
403+
await expect(
404+
sendAndConfirmTransaction({
405+
account: TEST_ACCOUNT_B,
406+
transaction: bidInAuction({
407+
auctionId: listing.id,
408+
contract: marketplaceContract,
409+
bidAmount: "11",
410+
}),
411+
}),
412+
).rejects.toThrowErrorMatchingInlineSnapshot(
413+
"[Error: Bid amount is above the buyout amount]",
414+
);
415+
// invalid bid amount 3: below minimum bid (but not 0)
416+
await expect(
417+
sendAndConfirmTransaction({
418+
account: TEST_ACCOUNT_B,
419+
transaction: bidInAuction({
420+
auctionId: listing.id,
421+
contract: marketplaceContract,
422+
bidAmount: "0.5",
423+
}),
424+
}),
425+
).rejects.toThrowErrorMatchingInlineSnapshot(
426+
"[Error: Bid amount is below the minimum bid amount]",
427+
);
428+
429+
// valid bid amount: "2"
430+
await expect(
431+
sendAndConfirmTransaction({
432+
account: TEST_ACCOUNT_B,
433+
transaction: bidInAuction({
434+
auctionId: listing.id,
435+
contract: marketplaceContract,
436+
bidAmount: "2",
437+
}),
438+
}),
439+
).resolves.toBeDefined();
440+
441+
// check for a new winning bid
442+
await expect(
443+
getWinningBid({
444+
contract: marketplaceContract,
445+
auctionId: listing.id,
446+
}),
447+
).resolves.toMatchInlineSnapshot(`
448+
{
449+
"bidAmountWei": 2000000000000000000n,
450+
"bidderAddress": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
451+
"currencyAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
452+
"currencyValue": {
453+
"decimals": 18,
454+
"displayValue": "2",
455+
"name": "Anvil Ether",
456+
"symbol": "ETH",
457+
"value": 2000000000000000000n,
458+
},
459+
}
460+
`);
461+
462+
// invalid bid amount, above minimum but below existing winning bid
463+
await expect(
464+
sendAndConfirmTransaction({
465+
account: TEST_ACCOUNT_B,
466+
transaction: bidInAuction({
467+
auctionId: listing.id,
468+
contract: marketplaceContract,
469+
bidAmount: "1.5",
470+
}),
471+
}),
472+
).rejects.toThrowErrorMatchingInlineSnapshot(
473+
"[Error: Bid amount is too low to outbid the existing winning bid]",
474+
);
475+
476+
// invalid bid amount, above winning bit but below bid + bidBuffer (default 500bps)
477+
await expect(
478+
sendAndConfirmTransaction({
479+
account: TEST_ACCOUNT_B,
480+
transaction: bidInAuction({
481+
auctionId: listing.id,
482+
contract: marketplaceContract,
483+
// 2 * 1.05 = 2.1, so 2.05 is invalid
484+
bidAmount: "2.05",
485+
}),
486+
}),
487+
).rejects.toThrowErrorMatchingInlineSnapshot(
488+
"[Error: Bid amount is too low to outbid the existing winning bid]",
489+
);
490+
491+
// actually outbid the winning bid
492+
await expect(
493+
sendAndConfirmTransaction({
494+
account: TEST_ACCOUNT_B,
495+
transaction: bidInAuction({
496+
auctionId: listing.id,
497+
contract: marketplaceContract,
498+
bidAmount: "3",
499+
}),
500+
}),
501+
).resolves.toBeDefined();
502+
503+
// check for a new winning bid
504+
await expect(
505+
getWinningBid({
506+
contract: marketplaceContract,
507+
auctionId: listing.id,
508+
}),
509+
).resolves.toMatchInlineSnapshot(`
510+
{
511+
"bidAmountWei": 3000000000000000000n,
512+
"bidderAddress": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
513+
"currencyAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
514+
"currencyValue": {
515+
"decimals": 18,
516+
"displayValue": "3",
517+
"name": "Anvil Ether",
518+
"symbol": "ETH",
519+
"value": 3000000000000000000n,
520+
},
521+
}
522+
`);
523+
524+
// buyout auction
525+
await expect(
526+
sendAndConfirmTransaction({
527+
account: TEST_ACCOUNT_B,
528+
transaction: buyoutAuction({
529+
contract: marketplaceContract,
530+
auctionId: listing.id,
531+
}),
532+
}),
533+
).resolves.toBeDefined();
534+
535+
// check for a new winning bid
536+
await expect(
537+
getWinningBid({
538+
contract: marketplaceContract,
539+
auctionId: listing.id,
540+
}),
541+
).resolves.toMatchInlineSnapshot(`
542+
{
543+
"bidAmountWei": 10000000000000000000n,
544+
"bidderAddress": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
545+
"currencyAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
546+
"currencyValue": {
547+
"decimals": 18,
548+
"displayValue": "10",
549+
"name": "Anvil Ether",
550+
"symbol": "ETH",
551+
"value": 10000000000000000000n,
552+
},
553+
}
554+
`);
555+
556+
// // execute the sale
557+
// await expect(
558+
// sendAndConfirmTransaction({
559+
// account: TEST_ACCOUNT_A,
560+
// transaction: executeSale({
561+
// contract: marketplaceContract,
562+
// auctionId: listing.id,
563+
// }),
564+
// }),
565+
// ).resolves.toBeDefined();
376566
});
377567
});
378568
},
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ADDRESS_ZERO } from "../../../../constants/addresses.js";
2+
import type { BaseTransactionOptions } from "../../../../transaction/types.js";
3+
import { resolveCurrencyValue } from "../../../../utils/extensions/resolve-currency-value.js";
4+
import {
5+
type GetWinningBidParams as GeneratedWinningBidParams,
6+
getWinningBid as getWinningBidGenerated,
7+
} from "../../__generated__/IEnglishAuctions/read/getWinningBid.js";
8+
9+
export type GetWinningBidParams = GeneratedWinningBidParams;
10+
11+
/**
12+
* Retrieves the winning bid information for a given auction.
13+
*
14+
* @param options - The options for retrieving the winning bid.
15+
* @returns The winning bid information, or undefined if there is no winning bid.
16+
* @extension MARKETPLACE
17+
* @example
18+
* ```ts
19+
* import { getWinningBid } from "thirdweb/extensions/marketplace";
20+
*
21+
* const winningBid = await getWinningBid({
22+
* contract,
23+
* auctionId: 0n,
24+
* });
25+
* ```
26+
*/
27+
export async function getWinningBid(
28+
options: BaseTransactionOptions<GetWinningBidParams>,
29+
) {
30+
const [bidderAddress, currencyAddress, bidAmountWei] =
31+
await getWinningBidGenerated(options);
32+
33+
if (bidderAddress === ADDRESS_ZERO) {
34+
return undefined;
35+
}
36+
37+
return {
38+
bidderAddress,
39+
currencyAddress,
40+
bidAmountWei,
41+
currencyValue: await resolveCurrencyValue({
42+
chain: options.contract.chain,
43+
client: options.contract.client,
44+
currencyAddress,
45+
wei: bidAmountWei,
46+
}),
47+
};
48+
}

0 commit comments

Comments
 (0)