feat(instant sale): add the instant sale with copies flow

This commit is contained in:
shotgunofdeath 2021-09-12 20:17:45 +03:00
parent 5c338a156e
commit 4c5f1e7642
6 changed files with 102 additions and 53 deletions

View File

@ -20,6 +20,7 @@ import {
MAX_METADATA_LEN,
MAX_EDITION_LEN,
useWalletModal,
VaultState,
} from '@oyster/common';
import { useWallet } from '@solana/wallet-adapter-react';
import { AuctionView, useBidsForAuction, useUserBalance } from '../../hooks';
@ -183,7 +184,7 @@ export const AuctionCard = ({
action?: JSX.Element;
}) => {
const connection = useConnection();
const {update} = useMeta();
const { update } = useMeta();
const wallet = useWallet();
const { setVisible } = useWalletModal();
@ -253,8 +254,14 @@ export const AuctionCard = ({
auctionView.auction.info.state === AuctionState.Created;
//if instant sale auction bid and claimed hide buttons
if (auctionView.isInstantSale && auctionView.myBidderPot?.info.emptied) {
return <></>
if (
(auctionView.isInstantSale &&
Number(auctionView.myBidderPot?.info.emptied) !== 0 &&
isAuctionManagerAuthorityNotWalletOwner &&
auctionView.auction.info.bidState.max.toNumber() === bids.length) ||
auctionView.vault.info.state === VaultState.Deactivated
) {
return <></>;
}
return (
@ -387,7 +394,9 @@ export const AuctionCard = ({
{loading ? (
<Spin />
) : auctionView.isInstantSale ? (
bids.length ? (
!isAuctionManagerAuthorityNotWalletOwner ? (
'Claim master'
) : auctionView.myBidderPot ? (
'Claim Purchase'
) : (
'Buy Now'
@ -509,7 +518,8 @@ export const AuctionCard = ({
// Placing a "bid" of the full amount results in a purchase to redeem.
if (
myPayingAccount &&
bids.length === 0 &&
!auctionView.myBidderPot &&
isAuctionManagerAuthorityNotWalletOwner &&
auctionView.auctionDataExtended?.info.instantSalePrice
) {
try {
@ -523,15 +533,20 @@ export const AuctionCard = ({
);
setLastBid(bid);
} catch (e) {
console.error('sendPlaceBid', e)
console.error('sendPlaceBid', e);
setShowBidModal(false);
setLoading(false);
return;
}
}
await update();
const newAuctionState = await update(
auctionView.auction.pubkey,
wallet.publicKey,
);
auctionView.auction = newAuctionState[0];
auctionView.myBidderPot = newAuctionState[1];
auctionView.myBidderMetadata = newAuctionState[2];
// Claim the purchase
try {
@ -684,7 +699,8 @@ export const AuctionCard = ({
{loading || !accountByMint.get(QUOTE_MINT.toBase58()) ? (
<Spin />
) : auctionView.isInstantSale ? (
bids.length ? (
auctionView.myBidderPot ||
!isAuctionManagerAuthorityNotWalletOwner ? (
'Claim'
) : (
'Purchase'

View File

@ -7,6 +7,9 @@ import {
METADATA_PROGRAM_ID,
toPublicKey,
useQuerySearch,
AuctionData,
BidderPot,
BidderMetadata,
} from '@oyster/common';
import React, {
useCallback,
@ -52,9 +55,11 @@ const MetaContext = React.createContext<MetaContextState>({
payoutTickets: {},
prizeTrackingTickets: {},
stores: {},
update: () => {},
// @ts-ignore
update: () => [AuctionData, BidderPot, BidderMetadata],
});
// eslint-disable-next-line react/prop-types
export function MetaProvider({ children = null as any }) {
const connection = useConnection();
const { isReady, storeAddress } = useStore();
@ -109,7 +114,7 @@ export function MetaProvider({ children = null as any }) {
[setState],
);
async function update () {
async function update(auctionAddress?, bidderAddress?) {
if (!storeAddress) {
if (isReady) {
setIsLoading(false);
@ -122,7 +127,7 @@ export function MetaProvider({ children = null as any }) {
console.log('-----> Query started');
const nextState = await loadAccounts(connection, all);
console.log('loadAccounts',nextState)
console.log('loadAccounts', nextState);
console.log('------->Query finished');
setState(nextState);
@ -130,9 +135,17 @@ export function MetaProvider({ children = null as any }) {
setIsLoading(false);
console.log('------->set finished');
updateMints(nextState.metadataByMint);
}
await updateMints(nextState.metadataByMint);
if (auctionAddress && bidderAddress) {
const auctionBidderKey = auctionAddress + '-' + bidderAddress;
return [
nextState.auctions[auctionAddress],
nextState.bidderPotsByAuctionAndBidder[auctionBidderKey],
nextState.bidderMetadataByAuctionAndBidder[auctionBidderKey],
];
}
}
useEffect(() => {
update();
@ -232,7 +245,8 @@ export function MetaProvider({ children = null as any }) {
value={{
...state,
isLoading,
update
// @ts-ignore
update,
}}
>
{children}

View File

@ -76,7 +76,14 @@ export interface MetaState {
export interface MetaContextState extends MetaState {
isLoading: boolean;
update: () => void;
update: (
auctionAddress?: any,
bidderAddress?: any,
) => [
ParsedAccount<AuctionData>,
ParsedAccount<BidderPot>,
ParsedAccount<BidderMetadata>,
];
}
export type AccountAndPubkey = {

View File

@ -5,6 +5,7 @@ import {
programIds,
StringPublicKey,
toPublicKey,
getAuctionExtended,
} from '@oyster/common';
import {
SystemProgram,
@ -69,6 +70,10 @@ export async function redeemPrintingV2Bid(
const value = new RedeemPrintingV2BidArgs({ editionOffset, winIndex });
const data = Buffer.from(serialize(SCHEMA, value));
const extended = await getAuctionExtended({
auctionProgramId: PROGRAM_IDS.auction,
resource: vault,
});
const keys = [
{
pubkey: toPublicKey(auctionManagerKey),
@ -199,6 +204,11 @@ export async function redeemPrintingV2Bid(
isSigner: false,
isWritable: false,
},
{
pubkey: toPublicKey(extended),
isSigner: false,
isWritable: false,
},
];
instructions.push(

View File

@ -172,11 +172,13 @@ export const AuctionCreateView = () => {
if (attributes.category === AuctionCategory.InstantSale) {
if (attributes.items.length > 0) {
const item = attributes.items[0];
item.winningConfigType =
item.metadata.info.updateAuthority ===
(wallet?.publicKey || SystemProgram.programId).toBase58()
? WinningConfigType.FullRightsTransfer
: WinningConfigType.TokenOnlyTransfer;
if (!attributes.editions) {
item.winningConfigType =
item.metadata.info.updateAuthority ===
(wallet?.publicKey || SystemProgram.programId).toBase58()
? WinningConfigType.FullRightsTransfer
: WinningConfigType.TokenOnlyTransfer;
}
item.amountRanges = [
new AmountRange({
amount: new BN(1),
@ -770,37 +772,37 @@ const InstantSaleStep = (props: {
Select NFT
</ArtSelector>
{/*<label className="action-field">*/}
{/* <Checkbox*/}
{/* defaultChecked={false}*/}
{/* checked={copiesChecked}*/}
{/* disabled={!copiesEnabled}*/}
{/* onChange={e => setCopiesChecked(e.target.checked)}*/}
{/* >*/}
{/* <span className="field-title">*/}
{/* Create copies of a Master Edition NFT?*/}
{/* </span>*/}
{/* </Checkbox>*/}
{/* {copiesChecked && copiesEnabled && (*/}
{/* <>*/}
{/* <span className="field-info">*/}
{/* Each copy will be given unique edition number e.g. 1 of 30*/}
{/* </span>*/}
{/* <Input*/}
{/* autoFocus*/}
{/* className="input"*/}
{/* placeholder="Enter number of copies sold"*/}
{/* allowClear*/}
{/* onChange={info =>*/}
{/* props.setAttributes({*/}
{/* ...props.attributes,*/}
{/* editions: parseInt(info.target.value),*/}
{/* })*/}
{/* }*/}
{/* />*/}
{/* </>*/}
{/* )}*/}
{/*</label>*/}
<label className="action-field">
<Checkbox
defaultChecked={false}
checked={copiesChecked}
disabled={!copiesEnabled}
onChange={e => setCopiesChecked(e.target.checked)}
>
<span className="field-title">
Create copies of a Master Edition NFT?
</span>
</Checkbox>
{copiesChecked && copiesEnabled && (
<>
<span className="field-info">
Each copy will be given unique edition number e.g. 1 of 30
</span>
<Input
autoFocus
className="input"
placeholder="Enter number of copies sold"
allowClear
onChange={info =>
props.setAttributes({
...props.attributes,
editions: parseInt(info.target.value),
})
}
/>
</>
)}
</label>
<label className="action-field">
<span className="field-title">Price</span>

View File

@ -25,7 +25,7 @@ export const AuctionListView = () => {
const auctions = useAuctions(AuctionViewState.Live);
const auctionsEnded = [
...useAuctions(AuctionViewState.Ended),
...useAuctions(AuctionViewState.BuyNow).filter((auction) => Number(auction.myBidderPot?.info.emptied) === 0)
...useAuctions(AuctionViewState.BuyNow)
];
const [activeKey, setActiveKey] = useState(LiveAuctionViewState.All);
const { isLoading } = useMeta();