Working on instant sale
This commit is contained in:
parent
b4f5b4b29b
commit
bf22676c2c
|
@ -373,10 +373,14 @@ export interface IPartialCreateAuctionArgs {
|
||||||
tickSize: BN | null;
|
tickSize: BN | null;
|
||||||
|
|
||||||
gapTickSizePercentage: number | null;
|
gapTickSizePercentage: number | null;
|
||||||
|
|
||||||
|
instantSalePrice: BN | null;
|
||||||
|
|
||||||
|
name: number[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreateAuctionArgs implements IPartialCreateAuctionArgs {
|
export class CreateAuctionArgs implements IPartialCreateAuctionArgs {
|
||||||
instruction: number = 1;
|
instruction: number = 7;
|
||||||
/// How many winners are allowed for this auction. See AuctionData.
|
/// How many winners are allowed for this auction. See AuctionData.
|
||||||
winners: WinnerLimit;
|
winners: WinnerLimit;
|
||||||
/// End time is the cut-off point that the auction is forced to end by. See AuctionData.
|
/// End time is the cut-off point that the auction is forced to end by. See AuctionData.
|
||||||
|
@ -396,6 +400,10 @@ export class CreateAuctionArgs implements IPartialCreateAuctionArgs {
|
||||||
|
|
||||||
gapTickSizePercentage: number | null;
|
gapTickSizePercentage: number | null;
|
||||||
|
|
||||||
|
instantSalePrice: BN | null;
|
||||||
|
|
||||||
|
name: number[] | null;
|
||||||
|
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
winners: WinnerLimit;
|
winners: WinnerLimit;
|
||||||
endAuctionAt: BN | null;
|
endAuctionAt: BN | null;
|
||||||
|
@ -406,6 +414,8 @@ export class CreateAuctionArgs implements IPartialCreateAuctionArgs {
|
||||||
priceFloor: PriceFloor;
|
priceFloor: PriceFloor;
|
||||||
tickSize: BN | null;
|
tickSize: BN | null;
|
||||||
gapTickSizePercentage: number | null;
|
gapTickSizePercentage: number | null;
|
||||||
|
name: number[] | null;
|
||||||
|
instantSalePrice: BN | null;
|
||||||
}) {
|
}) {
|
||||||
this.winners = args.winners;
|
this.winners = args.winners;
|
||||||
this.endAuctionAt = args.endAuctionAt;
|
this.endAuctionAt = args.endAuctionAt;
|
||||||
|
@ -416,6 +426,8 @@ export class CreateAuctionArgs implements IPartialCreateAuctionArgs {
|
||||||
this.priceFloor = args.priceFloor;
|
this.priceFloor = args.priceFloor;
|
||||||
this.tickSize = args.tickSize;
|
this.tickSize = args.tickSize;
|
||||||
this.gapTickSizePercentage = args.gapTickSizePercentage;
|
this.gapTickSizePercentage = args.gapTickSizePercentage;
|
||||||
|
this.name = args.name;
|
||||||
|
this.instantSalePrice = args.instantSalePrice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,6 +480,8 @@ export const AUCTION_SCHEMA = new Map<any, any>([
|
||||||
['priceFloor', PriceFloor],
|
['priceFloor', PriceFloor],
|
||||||
['tickSize', { kind: 'option', type: 'u64' }],
|
['tickSize', { kind: 'option', type: 'u64' }],
|
||||||
['gapTickSizePercentage', { kind: 'option', type: 'u8' }],
|
['gapTickSizePercentage', { kind: 'option', type: 'u8' }],
|
||||||
|
['instantSalePrice', { kind: 'option', type: 'u64' }],
|
||||||
|
['name', { kind: 'option', type: [32] }],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -545,6 +559,8 @@ export const AUCTION_SCHEMA = new Map<any, any>([
|
||||||
['totalUncancelledBids', 'u64'],
|
['totalUncancelledBids', 'u64'],
|
||||||
['tickSize', { kind: 'option', type: 'u64' }],
|
['tickSize', { kind: 'option', type: 'u64' }],
|
||||||
['gapTickSizePercentage', { kind: 'option', type: 'u8' }],
|
['gapTickSizePercentage', { kind: 'option', type: 'u8' }],
|
||||||
|
['instantSalePrice', { kind: 'option', type: 'u64' }],
|
||||||
|
['name', { kind: 'option', type: [32] }],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -237,7 +237,20 @@ export class Metadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async init() {
|
public async init() {
|
||||||
const edition = await getEdition(this.mint);
|
const edition: PublicKey;
|
||||||
|
if (this.info.editionNonce != null) {
|
||||||
|
edition = await PublicKey.createProgramAddress(
|
||||||
|
[
|
||||||
|
Buffer.from(METADATA_PREFIX),
|
||||||
|
METADATA_PROGRAM_ID.toBuffer(),
|
||||||
|
tempCache.metadata[i].info.mint.toBuffer(),
|
||||||
|
new Uint8Array([tempCache.metadata[i].info.editionNonce || 0]),
|
||||||
|
],
|
||||||
|
METADATA_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
edition = await getEdition(tempCache.metadata[i].info.mint);
|
||||||
|
}
|
||||||
this.edition = edition;
|
this.edition = edition;
|
||||||
this.masterEdition = edition;
|
this.masterEdition = edition;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { getAuctionExtended, programIds } from '@oyster/common';
|
||||||
|
import {
|
||||||
|
PublicKey,
|
||||||
|
SYSVAR_CLOCK_PUBKEY,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from '@solana/web3.js';
|
||||||
|
import { serialize } from 'borsh';
|
||||||
|
|
||||||
|
import { EndAuctionArgs, getAuctionKeys, SCHEMA } from '.';
|
||||||
|
|
||||||
|
export async function endAuction(
|
||||||
|
vault: PublicKey,
|
||||||
|
auctionManagerAuthority: PublicKey,
|
||||||
|
instructions: TransactionInstruction[],
|
||||||
|
) {
|
||||||
|
const PROGRAM_IDS = programIds();
|
||||||
|
const store = PROGRAM_IDS.store;
|
||||||
|
if (!store) {
|
||||||
|
throw new Error('Store not initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { auctionKey, auctionManagerKey } = await getAuctionKeys(vault);
|
||||||
|
const auctionExtended = await getAuctionExtended({
|
||||||
|
auctionProgramId: PROGRAM_IDS.auction,
|
||||||
|
resource: vault,
|
||||||
|
});
|
||||||
|
const value = new EndAuctionArgs({ reveal: null });
|
||||||
|
const data = Buffer.from(serialize(SCHEMA, value));
|
||||||
|
|
||||||
|
const keys = [
|
||||||
|
{
|
||||||
|
pubkey: auctionManagerKey,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pubkey: auctionKey,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pubkey: auctionExtended,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pubkey: auctionManagerAuthority,
|
||||||
|
isSigner: true,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pubkey: store,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pubkey: PROGRAM_IDS.auction,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pubkey: SYSVAR_CLOCK_PUBKEY,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
instructions.push(
|
||||||
|
new TransactionInstruction({
|
||||||
|
keys,
|
||||||
|
programId: PROGRAM_IDS.metaplex,
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
|
@ -320,6 +320,15 @@ export class RedeemFullRightsTransferBidArgs {
|
||||||
export class StartAuctionArgs {
|
export class StartAuctionArgs {
|
||||||
instruction = 5;
|
instruction = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class EndAuctionArgs {
|
||||||
|
instruction = 21;
|
||||||
|
reveal: BN[] | null;
|
||||||
|
constructor(args: { reveal: BN[] | null }) {
|
||||||
|
this.reveal = args.reveal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class ClaimBidArgs {
|
export class ClaimBidArgs {
|
||||||
instruction = 6;
|
instruction = 6;
|
||||||
}
|
}
|
||||||
|
@ -953,6 +962,16 @@ export const SCHEMA = new Map<any, any>([
|
||||||
fields: [['instruction', 'u8']],
|
fields: [['instruction', 'u8']],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
EndAuctionArgs,
|
||||||
|
{
|
||||||
|
kind: 'struct',
|
||||||
|
fields: [
|
||||||
|
['instruction', 'u8'],
|
||||||
|
['reveal', { kind: 'option', type: [BN] }],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
ClaimBidArgs,
|
ClaimBidArgs,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import { findProgramAddress, programIds, VAULT_PREFIX } from '@oyster/common';
|
import {
|
||||||
|
findProgramAddress,
|
||||||
|
getAuctionExtended,
|
||||||
|
programIds,
|
||||||
|
VAULT_PREFIX,
|
||||||
|
} from '@oyster/common';
|
||||||
import {
|
import {
|
||||||
PublicKey,
|
PublicKey,
|
||||||
SystemProgram,
|
SystemProgram,
|
||||||
|
@ -63,6 +68,11 @@ export async function redeemBid(
|
||||||
safetyDeposit,
|
safetyDeposit,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const auctionExtended = await getAuctionExtended({
|
||||||
|
auctionProgramId: PROGRAM_IDS.auction,
|
||||||
|
resource: vault,
|
||||||
|
});
|
||||||
|
|
||||||
const value =
|
const value =
|
||||||
auctioneerReclaimIndex !== undefined
|
auctioneerReclaimIndex !== undefined
|
||||||
? new RedeemUnusedWinningConfigItemsAsAuctioneerArgs({
|
? new RedeemUnusedWinningConfigItemsAsAuctioneerArgs({
|
||||||
|
@ -167,6 +177,11 @@ export async function redeemBid(
|
||||||
isSigner: false,
|
isSigner: false,
|
||||||
isWritable: false,
|
isWritable: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pubkey: auctionExtended,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (isPrintingType && masterEdition && reservationList) {
|
if (isPrintingType && masterEdition && reservationList) {
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import { programIds, VAULT_PREFIX, findProgramAddress } from '@oyster/common';
|
import {
|
||||||
|
programIds,
|
||||||
|
VAULT_PREFIX,
|
||||||
|
findProgramAddress,
|
||||||
|
getAuctionExtended,
|
||||||
|
} from '@oyster/common';
|
||||||
import {
|
import {
|
||||||
PublicKey,
|
PublicKey,
|
||||||
SystemProgram,
|
SystemProgram,
|
||||||
|
@ -62,6 +67,11 @@ export async function redeemFullRightsTransferBid(
|
||||||
safetyDeposit,
|
safetyDeposit,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const auctionExtended = await getAuctionExtended({
|
||||||
|
auctionProgramId: PROGRAM_IDS.auction,
|
||||||
|
resource: vault,
|
||||||
|
});
|
||||||
|
|
||||||
const value =
|
const value =
|
||||||
auctioneerReclaimIndex !== undefined
|
auctioneerReclaimIndex !== undefined
|
||||||
? new RedeemUnusedWinningConfigItemsAsAuctioneerArgs({
|
? new RedeemUnusedWinningConfigItemsAsAuctioneerArgs({
|
||||||
|
@ -176,6 +186,12 @@ export async function redeemFullRightsTransferBid(
|
||||||
isSigner: false,
|
isSigner: false,
|
||||||
isWritable: false,
|
isWritable: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
pubkey: auctionExtended,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
instructions.push(
|
instructions.push(
|
||||||
|
|
|
@ -36,14 +36,7 @@ import { Connection, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
|
||||||
import { MintLayout } from '@solana/spl-token';
|
import { MintLayout } from '@solana/spl-token';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { capitalize } from 'lodash';
|
import { capitalize } from 'lodash';
|
||||||
import {
|
import { WinningConfigType, AmountRange } from '../../models/metaplex';
|
||||||
WinningConfigType,
|
|
||||||
NonWinningConstraint,
|
|
||||||
WinningConstraint,
|
|
||||||
ParticipationConfigV2,
|
|
||||||
SafetyDepositConfig,
|
|
||||||
AmountRange,
|
|
||||||
} from '../../models/metaplex';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
createAuctionManager,
|
createAuctionManager,
|
||||||
|
@ -124,6 +117,8 @@ export interface AuctionState {
|
||||||
tiers?: Array<Tier>;
|
tiers?: Array<Tier>;
|
||||||
|
|
||||||
winnersCount: number;
|
winnersCount: number;
|
||||||
|
|
||||||
|
instantSalePrice?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AuctionCreateView = () => {
|
export const AuctionCreateView = () => {
|
||||||
|
@ -413,6 +408,10 @@ export const AuctionCreateView = () => {
|
||||||
tickSize: attributes.priceTick
|
tickSize: attributes.priceTick
|
||||||
? new BN(attributes.priceTick * LAMPORTS_PER_SOL)
|
? new BN(attributes.priceTick * LAMPORTS_PER_SOL)
|
||||||
: null,
|
: null,
|
||||||
|
instantSalePrice: attributes.instantSalePrice
|
||||||
|
? new BN((attributes.instantSalePrice || 0) * LAMPORTS_PER_SOL)
|
||||||
|
: null,
|
||||||
|
name: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const _auctionObj = await createAuctionManager(
|
const _auctionObj = await createAuctionManager(
|
||||||
|
@ -856,6 +855,22 @@ const SaleTypeStep = (props: {
|
||||||
Allow bidding on your NFT(s).
|
Allow bidding on your NFT(s).
|
||||||
</div>
|
</div>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
|
<Radio.Group
|
||||||
|
defaultValue={props.attributes.saleType}
|
||||||
|
onChange={info =>
|
||||||
|
props.setAttributes({
|
||||||
|
...props.attributes,
|
||||||
|
saleType: info.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Radio className="radio-field" value="auction">
|
||||||
|
Instant Sale
|
||||||
|
</Radio>
|
||||||
|
<div className="radio-subtitle">
|
||||||
|
Instant purchase and redemption of your NFT.
|
||||||
|
</div>
|
||||||
|
</Radio.Group>
|
||||||
</label>
|
</label>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -898,13 +913,13 @@ const PriceSale = (props: {
|
||||||
<>
|
<>
|
||||||
<Row className="call-to-action">
|
<Row className="call-to-action">
|
||||||
<h2>Price</h2>
|
<h2>Price</h2>
|
||||||
<p>Set the price for your auction.</p>
|
<p>Set the fixed price for your instant sale.</p>
|
||||||
</Row>
|
</Row>
|
||||||
<Row className="content-action">
|
<Row className="content-action">
|
||||||
<label className="action-field">
|
<label className="action-field">
|
||||||
<span className="field-title">Sale price</span>
|
<span className="field-title">Sale price</span>
|
||||||
<span className="field-info">
|
<span className="field-info">
|
||||||
This is the starting bid price for your auction.
|
This is the price of purchasing the item(s).
|
||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -917,7 +932,8 @@ const PriceSale = (props: {
|
||||||
onChange={info =>
|
onChange={info =>
|
||||||
props.setAttributes({
|
props.setAttributes({
|
||||||
...props.attributes,
|
...props.attributes,
|
||||||
price: parseFloat(info.target.value) || undefined,
|
priceFloor: parseFloat(info.target.value),
|
||||||
|
instantSalePrice: parseFloat(info.target.value),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -1228,7 +1244,10 @@ const EndingPhaseAuction = (props: {
|
||||||
<Row className="content-action">
|
<Row className="content-action">
|
||||||
<Col className="section" xl={24}>
|
<Col className="section" xl={24}>
|
||||||
<div className="action-field">
|
<div className="action-field">
|
||||||
<span className="field-title">Auction Duration</span>
|
<span className="field-title">
|
||||||
|
{props.attributes.saleType == 'auction' ? 'Auction' : 'Sale'}{' '}
|
||||||
|
Duration
|
||||||
|
</span>
|
||||||
<span className="field-info">
|
<span className="field-info">
|
||||||
This is how long the auction will last for.
|
This is how long the auction will last for.
|
||||||
</span>
|
</span>
|
||||||
|
@ -1261,12 +1280,14 @@ const EndingPhaseAuction = (props: {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{props.attributes.saleType == 'auction' && (
|
||||||
|
<>
|
||||||
<div className="action-field">
|
<div className="action-field">
|
||||||
<span className="field-title">Gap Time</span>
|
<span className="field-title">Gap Time</span>
|
||||||
<span className="field-info">
|
<span className="field-info">
|
||||||
The final phase of the auction will begin when there is this much
|
The final phase of the auction will begin when there is this
|
||||||
time left on the countdown. Any bids placed during the final phase
|
much time left on the countdown. Any bids placed during the
|
||||||
will extend the end time by this same duration.
|
final phase will extend the end time by this same duration.
|
||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
addonAfter={
|
addonAfter={
|
||||||
|
@ -1299,9 +1320,9 @@ const EndingPhaseAuction = (props: {
|
||||||
<label className="action-field">
|
<label className="action-field">
|
||||||
<span className="field-title">Tick Size for Ending Phase</span>
|
<span className="field-title">Tick Size for Ending Phase</span>
|
||||||
<span className="field-info">
|
<span className="field-info">
|
||||||
In order for winners to move up in the auction, they must place a
|
In order for winners to move up in the auction, they must
|
||||||
bid that’s at least this percentage higher than the next highest
|
place a bid that’s at least this percentage higher than the
|
||||||
bid.
|
next highest bid.
|
||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -1316,6 +1337,8 @@ const EndingPhaseAuction = (props: {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
|
|
|
@ -45,10 +45,10 @@ pub struct CreateAuctionArgsV2 {
|
||||||
pub tick_size: Option<u64>,
|
pub tick_size: Option<u64>,
|
||||||
/// Add a minimum percentage increase each bid must meet.
|
/// Add a minimum percentage increase each bid must meet.
|
||||||
pub gap_tick_size_percentage: Option<u8>,
|
pub gap_tick_size_percentage: Option<u8>,
|
||||||
/// Auction name
|
|
||||||
pub name: AuctionName,
|
|
||||||
/// Add a instant sale price.
|
/// Add a instant sale price.
|
||||||
pub instant_sale_price: Option<u64>,
|
pub instant_sale_price: Option<u64>,
|
||||||
|
/// Auction name
|
||||||
|
pub name: Option<AuctionName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Accounts<'a, 'b: 'a> {
|
struct Accounts<'a, 'b: 'a> {
|
||||||
|
@ -94,6 +94,6 @@ pub fn create_auction_v2(
|
||||||
gap_tick_size_percentage: args.gap_tick_size_percentage,
|
gap_tick_size_percentage: args.gap_tick_size_percentage,
|
||||||
},
|
},
|
||||||
args.instant_sale_price,
|
args.instant_sale_price,
|
||||||
Some(args.name),
|
args.name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue