feat(instant sale): add the instant sale with copies flow
This commit is contained in:
parent
5c338a156e
commit
4c5f1e7642
|
@ -20,6 +20,7 @@ import {
|
||||||
MAX_METADATA_LEN,
|
MAX_METADATA_LEN,
|
||||||
MAX_EDITION_LEN,
|
MAX_EDITION_LEN,
|
||||||
useWalletModal,
|
useWalletModal,
|
||||||
|
VaultState,
|
||||||
} from '@oyster/common';
|
} from '@oyster/common';
|
||||||
import { useWallet } from '@solana/wallet-adapter-react';
|
import { useWallet } from '@solana/wallet-adapter-react';
|
||||||
import { AuctionView, useBidsForAuction, useUserBalance } from '../../hooks';
|
import { AuctionView, useBidsForAuction, useUserBalance } from '../../hooks';
|
||||||
|
@ -253,8 +254,14 @@ export const AuctionCard = ({
|
||||||
auctionView.auction.info.state === AuctionState.Created;
|
auctionView.auction.info.state === AuctionState.Created;
|
||||||
|
|
||||||
//if instant sale auction bid and claimed hide buttons
|
//if instant sale auction bid and claimed hide buttons
|
||||||
if (auctionView.isInstantSale && auctionView.myBidderPot?.info.emptied) {
|
if (
|
||||||
return <></>
|
(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 (
|
return (
|
||||||
|
@ -387,7 +394,9 @@ export const AuctionCard = ({
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Spin />
|
<Spin />
|
||||||
) : auctionView.isInstantSale ? (
|
) : auctionView.isInstantSale ? (
|
||||||
bids.length ? (
|
!isAuctionManagerAuthorityNotWalletOwner ? (
|
||||||
|
'Claim master'
|
||||||
|
) : auctionView.myBidderPot ? (
|
||||||
'Claim Purchase'
|
'Claim Purchase'
|
||||||
) : (
|
) : (
|
||||||
'Buy Now'
|
'Buy Now'
|
||||||
|
@ -509,7 +518,8 @@ export const AuctionCard = ({
|
||||||
// Placing a "bid" of the full amount results in a purchase to redeem.
|
// Placing a "bid" of the full amount results in a purchase to redeem.
|
||||||
if (
|
if (
|
||||||
myPayingAccount &&
|
myPayingAccount &&
|
||||||
bids.length === 0 &&
|
!auctionView.myBidderPot &&
|
||||||
|
isAuctionManagerAuthorityNotWalletOwner &&
|
||||||
auctionView.auctionDataExtended?.info.instantSalePrice
|
auctionView.auctionDataExtended?.info.instantSalePrice
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
@ -523,15 +533,20 @@ export const AuctionCard = ({
|
||||||
);
|
);
|
||||||
setLastBid(bid);
|
setLastBid(bid);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('sendPlaceBid', e)
|
console.error('sendPlaceBid', e);
|
||||||
setShowBidModal(false);
|
setShowBidModal(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
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
|
// Claim the purchase
|
||||||
try {
|
try {
|
||||||
|
@ -684,7 +699,8 @@ export const AuctionCard = ({
|
||||||
{loading || !accountByMint.get(QUOTE_MINT.toBase58()) ? (
|
{loading || !accountByMint.get(QUOTE_MINT.toBase58()) ? (
|
||||||
<Spin />
|
<Spin />
|
||||||
) : auctionView.isInstantSale ? (
|
) : auctionView.isInstantSale ? (
|
||||||
bids.length ? (
|
auctionView.myBidderPot ||
|
||||||
|
!isAuctionManagerAuthorityNotWalletOwner ? (
|
||||||
'Claim'
|
'Claim'
|
||||||
) : (
|
) : (
|
||||||
'Purchase'
|
'Purchase'
|
||||||
|
|
|
@ -7,6 +7,9 @@ import {
|
||||||
METADATA_PROGRAM_ID,
|
METADATA_PROGRAM_ID,
|
||||||
toPublicKey,
|
toPublicKey,
|
||||||
useQuerySearch,
|
useQuerySearch,
|
||||||
|
AuctionData,
|
||||||
|
BidderPot,
|
||||||
|
BidderMetadata,
|
||||||
} from '@oyster/common';
|
} from '@oyster/common';
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
|
@ -52,9 +55,11 @@ const MetaContext = React.createContext<MetaContextState>({
|
||||||
payoutTickets: {},
|
payoutTickets: {},
|
||||||
prizeTrackingTickets: {},
|
prizeTrackingTickets: {},
|
||||||
stores: {},
|
stores: {},
|
||||||
update: () => {},
|
// @ts-ignore
|
||||||
|
update: () => [AuctionData, BidderPot, BidderMetadata],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/prop-types
|
||||||
export function MetaProvider({ children = null as any }) {
|
export function MetaProvider({ children = null as any }) {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const { isReady, storeAddress } = useStore();
|
const { isReady, storeAddress } = useStore();
|
||||||
|
@ -109,7 +114,7 @@ export function MetaProvider({ children = null as any }) {
|
||||||
[setState],
|
[setState],
|
||||||
);
|
);
|
||||||
|
|
||||||
async function update () {
|
async function update(auctionAddress?, bidderAddress?) {
|
||||||
if (!storeAddress) {
|
if (!storeAddress) {
|
||||||
if (isReady) {
|
if (isReady) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
@ -122,7 +127,7 @@ export function MetaProvider({ children = null as any }) {
|
||||||
console.log('-----> Query started');
|
console.log('-----> Query started');
|
||||||
|
|
||||||
const nextState = await loadAccounts(connection, all);
|
const nextState = await loadAccounts(connection, all);
|
||||||
console.log('loadAccounts',nextState)
|
console.log('loadAccounts', nextState);
|
||||||
console.log('------->Query finished');
|
console.log('------->Query finished');
|
||||||
|
|
||||||
setState(nextState);
|
setState(nextState);
|
||||||
|
@ -130,9 +135,17 @@ export function MetaProvider({ children = null as any }) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
console.log('------->set finished');
|
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(() => {
|
useEffect(() => {
|
||||||
update();
|
update();
|
||||||
|
@ -232,7 +245,8 @@ export function MetaProvider({ children = null as any }) {
|
||||||
value={{
|
value={{
|
||||||
...state,
|
...state,
|
||||||
isLoading,
|
isLoading,
|
||||||
update
|
// @ts-ignore
|
||||||
|
update,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -76,7 +76,14 @@ export interface MetaState {
|
||||||
|
|
||||||
export interface MetaContextState extends MetaState {
|
export interface MetaContextState extends MetaState {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
update: () => void;
|
update: (
|
||||||
|
auctionAddress?: any,
|
||||||
|
bidderAddress?: any,
|
||||||
|
) => [
|
||||||
|
ParsedAccount<AuctionData>,
|
||||||
|
ParsedAccount<BidderPot>,
|
||||||
|
ParsedAccount<BidderMetadata>,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AccountAndPubkey = {
|
export type AccountAndPubkey = {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
programIds,
|
programIds,
|
||||||
StringPublicKey,
|
StringPublicKey,
|
||||||
toPublicKey,
|
toPublicKey,
|
||||||
|
getAuctionExtended,
|
||||||
} from '@oyster/common';
|
} from '@oyster/common';
|
||||||
import {
|
import {
|
||||||
SystemProgram,
|
SystemProgram,
|
||||||
|
@ -69,6 +70,10 @@ export async function redeemPrintingV2Bid(
|
||||||
|
|
||||||
const value = new RedeemPrintingV2BidArgs({ editionOffset, winIndex });
|
const value = new RedeemPrintingV2BidArgs({ editionOffset, winIndex });
|
||||||
const data = Buffer.from(serialize(SCHEMA, value));
|
const data = Buffer.from(serialize(SCHEMA, value));
|
||||||
|
const extended = await getAuctionExtended({
|
||||||
|
auctionProgramId: PROGRAM_IDS.auction,
|
||||||
|
resource: vault,
|
||||||
|
});
|
||||||
const keys = [
|
const keys = [
|
||||||
{
|
{
|
||||||
pubkey: toPublicKey(auctionManagerKey),
|
pubkey: toPublicKey(auctionManagerKey),
|
||||||
|
@ -199,6 +204,11 @@ export async function redeemPrintingV2Bid(
|
||||||
isSigner: false,
|
isSigner: false,
|
||||||
isWritable: false,
|
isWritable: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pubkey: toPublicKey(extended),
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
instructions.push(
|
instructions.push(
|
||||||
|
|
|
@ -172,11 +172,13 @@ export const AuctionCreateView = () => {
|
||||||
if (attributes.category === AuctionCategory.InstantSale) {
|
if (attributes.category === AuctionCategory.InstantSale) {
|
||||||
if (attributes.items.length > 0) {
|
if (attributes.items.length > 0) {
|
||||||
const item = attributes.items[0];
|
const item = attributes.items[0];
|
||||||
|
if (!attributes.editions) {
|
||||||
item.winningConfigType =
|
item.winningConfigType =
|
||||||
item.metadata.info.updateAuthority ===
|
item.metadata.info.updateAuthority ===
|
||||||
(wallet?.publicKey || SystemProgram.programId).toBase58()
|
(wallet?.publicKey || SystemProgram.programId).toBase58()
|
||||||
? WinningConfigType.FullRightsTransfer
|
? WinningConfigType.FullRightsTransfer
|
||||||
: WinningConfigType.TokenOnlyTransfer;
|
: WinningConfigType.TokenOnlyTransfer;
|
||||||
|
}
|
||||||
item.amountRanges = [
|
item.amountRanges = [
|
||||||
new AmountRange({
|
new AmountRange({
|
||||||
amount: new BN(1),
|
amount: new BN(1),
|
||||||
|
@ -770,37 +772,37 @@ const InstantSaleStep = (props: {
|
||||||
Select NFT
|
Select NFT
|
||||||
</ArtSelector>
|
</ArtSelector>
|
||||||
|
|
||||||
{/*<label className="action-field">*/}
|
<label className="action-field">
|
||||||
{/* <Checkbox*/}
|
<Checkbox
|
||||||
{/* defaultChecked={false}*/}
|
defaultChecked={false}
|
||||||
{/* checked={copiesChecked}*/}
|
checked={copiesChecked}
|
||||||
{/* disabled={!copiesEnabled}*/}
|
disabled={!copiesEnabled}
|
||||||
{/* onChange={e => setCopiesChecked(e.target.checked)}*/}
|
onChange={e => setCopiesChecked(e.target.checked)}
|
||||||
{/* >*/}
|
>
|
||||||
{/* <span className="field-title">*/}
|
<span className="field-title">
|
||||||
{/* Create copies of a Master Edition NFT?*/}
|
Create copies of a Master Edition NFT?
|
||||||
{/* </span>*/}
|
</span>
|
||||||
{/* </Checkbox>*/}
|
</Checkbox>
|
||||||
{/* {copiesChecked && copiesEnabled && (*/}
|
{copiesChecked && copiesEnabled && (
|
||||||
{/* <>*/}
|
<>
|
||||||
{/* <span className="field-info">*/}
|
<span className="field-info">
|
||||||
{/* Each copy will be given unique edition number e.g. 1 of 30*/}
|
Each copy will be given unique edition number e.g. 1 of 30
|
||||||
{/* </span>*/}
|
</span>
|
||||||
{/* <Input*/}
|
<Input
|
||||||
{/* autoFocus*/}
|
autoFocus
|
||||||
{/* className="input"*/}
|
className="input"
|
||||||
{/* placeholder="Enter number of copies sold"*/}
|
placeholder="Enter number of copies sold"
|
||||||
{/* allowClear*/}
|
allowClear
|
||||||
{/* onChange={info =>*/}
|
onChange={info =>
|
||||||
{/* props.setAttributes({*/}
|
props.setAttributes({
|
||||||
{/* ...props.attributes,*/}
|
...props.attributes,
|
||||||
{/* editions: parseInt(info.target.value),*/}
|
editions: parseInt(info.target.value),
|
||||||
{/* })*/}
|
})
|
||||||
{/* }*/}
|
}
|
||||||
{/* />*/}
|
/>
|
||||||
{/* </>*/}
|
</>
|
||||||
{/* )}*/}
|
)}
|
||||||
{/*</label>*/}
|
</label>
|
||||||
|
|
||||||
<label className="action-field">
|
<label className="action-field">
|
||||||
<span className="field-title">Price</span>
|
<span className="field-title">Price</span>
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const AuctionListView = () => {
|
||||||
const auctions = useAuctions(AuctionViewState.Live);
|
const auctions = useAuctions(AuctionViewState.Live);
|
||||||
const auctionsEnded = [
|
const auctionsEnded = [
|
||||||
...useAuctions(AuctionViewState.Ended),
|
...useAuctions(AuctionViewState.Ended),
|
||||||
...useAuctions(AuctionViewState.BuyNow).filter((auction) => Number(auction.myBidderPot?.info.emptied) === 0)
|
...useAuctions(AuctionViewState.BuyNow)
|
||||||
];
|
];
|
||||||
const [activeKey, setActiveKey] = useState(LiveAuctionViewState.All);
|
const [activeKey, setActiveKey] = useState(LiveAuctionViewState.All);
|
||||||
const { isLoading } = useMeta();
|
const { isLoading } = useMeta();
|
||||||
|
|
Loading…
Reference in New Issue