Skip to content

Commit

Permalink
Minimum Price Support in UI + Minor contract fix (metaplex-foundation#37
Browse files Browse the repository at this point in the history
)

* Hook up minimum price to the front end with some borsh hacks, and fix a minor bug in the auction contract for minimum price checks

* Remove excess definitions we dont need from the hack.

* feat: no hacks allowed

Co-authored-by: bartosz-lipinski <[email protected]>
  • Loading branch information
bhgames and bartosz-lipinski authored Jun 15, 2021
1 parent 7a7d631 commit 377f6cd
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 85 deletions.
27 changes: 18 additions & 9 deletions js/packages/common/src/actions/auction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,24 @@ export enum PriceFloorType {
}
export class PriceFloor {
type: PriceFloorType;
// It's an array of 32 u8s, when minimum, only first 4 are used (a u64), when blinded price, the entire
// It's an array of 32 u8s, when minimum, only first 8 are used (a u64), when blinded price, the entire
// thing is a hash and not actually a public key, and none is all zeroes
hash: PublicKey;
hash: Uint8Array;

constructor(args: { type: PriceFloorType; hash: PublicKey }) {
minPrice?: BN;

constructor(args: {
type: PriceFloorType;
hash?: Uint8Array;
minPrice?: BN;
}) {
this.type = args.type;
this.hash = args.hash;
this.hash = args.hash || new Uint8Array(32);
if (this.type === PriceFloorType.Minimum) {
if (args.minPrice) {
this.hash.set(args.minPrice.toArrayLike(Buffer, 'le', 8), 0);
}
}
}
}

Expand Down Expand Up @@ -463,7 +474,7 @@ export const AUCTION_SCHEMA = new Map<any, any>([
kind: 'struct',
fields: [
['type', 'u8'],
['hash', 'pubkey'],
['hash', [32]],
],
},
],
Expand Down Expand Up @@ -528,6 +539,7 @@ export async function createAuction(
resource: PublicKey,
endAuctionAt: BN | null,
auctionGap: BN | null,
priceFloor: PriceFloor,
tokenMint: PublicKey,
authority: PublicKey,
creator: PublicKey,
Expand All @@ -545,10 +557,7 @@ export async function createAuction(
auctionGap,
tokenMint,
authority,
priceFloor: new PriceFloor({
type: PriceFloorType.None,
hash: SystemProgram.programId,
}),
priceFloor,
}),
),
);
Expand Down
3 changes: 3 additions & 0 deletions js/packages/web/src/actions/createAuctionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
getSafetyDepositBoxAddress,
createAssociatedTokenAccountInstruction,
sendTransactionWithRetry,
PriceFloor,
} from '@oyster/common';

import { AccountLayout, Token } from '@solana/spl-token';
Expand Down Expand Up @@ -104,6 +105,7 @@ export async function createAuctionManager(
safetyDepositDrafts: SafetyDepositDraft[],
participationSafetyDepositDraft: SafetyDepositDraft | undefined,
paymentMint: PublicKey,
priceFloor: PriceFloor,
): Promise<{
vault: PublicKey;
auction: PublicKey;
Expand Down Expand Up @@ -140,6 +142,7 @@ export async function createAuctionManager(
endAuctionAt,
auctionGap,
paymentMint,
priceFloor,
);

let safetyDepositConfigsWithPotentiallyUnsetTokens =
Expand Down
4 changes: 3 additions & 1 deletion js/packages/web/src/actions/makeAuction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js';
import { utils, actions, WinnerLimit } from '@oyster/common';
import { utils, actions, WinnerLimit, PriceFloor } from '@oyster/common';

import BN from 'bn.js';
import { METAPLEX_PREFIX } from '../models/metaplex';
Expand All @@ -13,6 +13,7 @@ export async function makeAuction(
endAuctionAt: BN,
auctionGap: BN,
paymentMint: PublicKey,
priceFloor: PriceFloor,
): Promise<{
auction: PublicKey;
instructions: TransactionInstruction[];
Expand Down Expand Up @@ -45,6 +46,7 @@ export async function makeAuction(
vault,
endAuctionAt,
auctionGap,
priceFloor,
paymentMint,
auctionManagerKey,
wallet.publicKey,
Expand Down
15 changes: 9 additions & 6 deletions js/packages/web/src/components/AuctionCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import {
MetaplexOverlay,
formatAmount,
formatTokenAmount,
useMint
useMint,
PriceFloorType,
} from '@oyster/common';
import {
AuctionView,
useUserBalance,
} from '../../hooks';
import { AuctionView, useUserBalance } from '../../hooks';
import { sendPlaceBid } from '../../actions/sendPlaceBid';
import { AuctionNumbers } from './../AuctionNumbers';
import {
Expand All @@ -27,6 +25,7 @@ import { sendCancelBid } from '../../actions/cancelBid';
import BN from 'bn.js';
import { Confetti } from '../Confetti';
import { QUOTE_MINT } from '../../constants';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';

const { useWallet } = contexts.Wallet;

Expand Down Expand Up @@ -67,7 +66,10 @@ export const AuctionCard = ({
winnerIndex = auctionView.auction.info.bidState.getWinnerIndex(
auctionView.myBidderPot?.info.bidderAct,
);

const priceFloor =
auctionView.auction.info.priceFloor.type == PriceFloorType.Minimum
? auctionView.auction.info.priceFloor.minPrice?.toNumber() || 0
: 0;
const eligibleForOpenEdition = eligibleForParticipationPrizeGivenWinningIndex(
winnerIndex,
auctionView,
Expand Down Expand Up @@ -331,6 +333,7 @@ export const AuctionCard = ({
disabled={
!myPayingAccount ||
value === undefined ||
value * LAMPORTS_PER_SOL < priceFloor ||
loading ||
!accountByMint.get(QUOTE_MINT.toBase58())
}
Expand Down
98 changes: 55 additions & 43 deletions js/packages/web/src/components/AuctionNumbers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ import {
useMint,
fromLamports,
CountdownState,
PriceFloorType,
} from '@oyster/common';
import {
AuctionView,
AuctionViewState,
useBidsForAuction,
} from '../../hooks';
import { AuctionView, AuctionViewState, useBidsForAuction } from '../../hooks';
import { AmountLabel } from '../AmountLabel';

export const AuctionNumbers = (props: { auctionView: AuctionView }) => {
Expand All @@ -23,6 +20,12 @@ export const AuctionNumbers = (props: { auctionView: AuctionView }) => {
const participationFixedPrice =
auctionView.auctionManager.info.settings.participationConfig?.fixedPrice ||
0;
const participationOnly =
auctionView.auctionManager.info.settings.winningConfigs.length == 0;
const priceFloor =
auctionView.auction.info.priceFloor.type == PriceFloorType.Minimum
? auctionView.auction.info.priceFloor.minPrice?.toNumber() || 0
: 0;
const isUpcoming = auctionView.state === AuctionViewState.Upcoming;
const isStarted = auctionView.state === AuctionViewState.Live;

Expand Down Expand Up @@ -56,7 +59,10 @@ export const AuctionNumbers = (props: { auctionView: AuctionView }) => {
style={{ marginBottom: 10 }}
containerStyle={{ flexDirection: 'column' }}
title="Starting bid"
amount={fromLamports(participationFixedPrice, mintInfo)}
amount={fromLamports(
participationOnly ? participationFixedPrice : priceFloor,
mintInfo,
)}
/>
)}
{isStarted && bids.length > 0 && (
Expand Down Expand Up @@ -98,56 +104,62 @@ const Countdown = ({ state }: { state?: CountdownState }) => {
>
Time left
</div>
{state && (isEnded(state) ? (
<Row style={{ width: '100%' }}>
<div className="cd-number">This auction has ended</div>
</Row>
) : (
<Row style={{ width: '100%', flexWrap: 'nowrap' }}>
{state && state.days > 0 && (
{state &&
(isEnded(state) ? (
<Row style={{ width: '100%' }}>
<div className="cd-number">This auction has ended</div>
</Row>
) : (
<Row style={{ width: '100%', flexWrap: 'nowrap' }}>
{state && state.days > 0 && (
<Col>
<div className="cd-number">
{state.days < 10 && (
<span style={{ opacity: 0.2 }}>0</span>
)}
{state.days}
<span style={{ opacity: 0.2 }}>:</span>
</div>
<div className="cd-label">days</div>
</Col>
)}
<Col>
<div className="cd-number">
{state.days < 10 && <span style={{ opacity: 0.2 }}>0</span>}
{state.days}
{state.hours < 10 && (
<span style={{ opacity: 0.2 }}>0</span>
)}
{state.hours}
<span style={{ opacity: 0.2 }}>:</span>
</div>
<div className="cd-label">days</div>
<div className="cd-label">hour</div>
</Col>
)}
<Col>
<div className="cd-number">
{state.hours < 10 && <span style={{ opacity: 0.2 }}>0</span>}
{state.hours}
<span style={{ opacity: 0.2 }}>:</span>
</div>
<div className="cd-label">hour</div>
</Col>
<Col>
<div className="cd-number">
{state.minutes < 10 && (
<span style={{ opacity: 0.2 }}>0</span>
)}
{state.minutes}
{state.days === 0 && <span style={{ opacity: 0.2 }}>:</span>}
</div>
<div className="cd-label">mins</div>
</Col>
{!state.days && (
<Col>
<div className="cd-number">
{state.seconds < 10 && (
{state.minutes < 10 && (
<span style={{ opacity: 0.2 }}>0</span>
)}
{state.seconds}
{state.minutes}
{state.days === 0 && (
<span style={{ opacity: 0.2 }}>:</span>
)}
</div>
<div className="cd-label">secs</div>
<div className="cd-label">mins</div>
</Col>
)}
</Row>
))}
{!state.days && (
<Col>
<div className="cd-number">
{state.seconds < 10 && (
<span style={{ opacity: 0.2 }}>0</span>
)}
{state.seconds}
</div>
<div className="cd-label">secs</div>
</Col>
)}
</Row>
))}
</>
</div>
</>
);
};

Loading

0 comments on commit 377f6cd

Please sign in to comment.