Merge remote-tracking branch 'origin/master' into exromany-migrate-next
This commit is contained in:
parent
b1a4a0c392
commit
793799599b
|
@ -41,7 +41,7 @@ bindings that allow interactivity.
|
|||
We have a few channels for contact:
|
||||
|
||||
- [Discord](https://discord.gg/metaplex)
|
||||
- [@metaplexNFT](https://twitter.com/metaplexNFT) on Twitter
|
||||
- [@metaplex](https://twitter.com/metaplex) on Twitter
|
||||
- [GitHub Issues](https://github.com/metaplex-foundation/metaplex/issues)
|
||||
|
||||
# Protocol
|
||||
|
|
|
@ -42,6 +42,16 @@ export class BidState {
|
|||
bids: Bid[];
|
||||
max: BN;
|
||||
|
||||
public getWinnerAt(winnerIndex: number): PublicKey | null {
|
||||
const convertedIndex = this.bids.length - winnerIndex - 1;
|
||||
|
||||
if (convertedIndex >= 0 && convertedIndex < this.bids.length) {
|
||||
return this.bids[convertedIndex].key;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public getWinnerIndex(bidder: PublicKey): number | null {
|
||||
if (!this.bids) return null;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
SYSVAR_RENT_PUBKEY,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import { programIds, PROGRAM_IDS } from '../utils/ids';
|
||||
import { programIds } from '../utils/ids';
|
||||
import { deserializeUnchecked, serialize } from 'borsh';
|
||||
import BN from 'bn.js';
|
||||
import { findProgramAddress } from '../utils';
|
||||
|
@ -21,7 +21,6 @@ export const MAX_URI_LENGTH = 200;
|
|||
export const MAX_CREATOR_LIMIT = 5;
|
||||
|
||||
export const MAX_CREATOR_LEN = 32 + 1 + 1;
|
||||
|
||||
export const MAX_METADATA_LEN =
|
||||
1 +
|
||||
32 +
|
||||
|
@ -30,18 +29,22 @@ export const MAX_METADATA_LEN =
|
|||
MAX_SYMBOL_LENGTH +
|
||||
MAX_URI_LENGTH +
|
||||
MAX_CREATOR_LIMIT * MAX_CREATOR_LEN +
|
||||
2 +
|
||||
1 +
|
||||
1 +
|
||||
200;
|
||||
198;
|
||||
|
||||
export const MAX_MASTER_EDITION_KEN = 1 + 9 + 8 + 32 + 32;
|
||||
export const MAX_EDITION_LEN = 1 + 32 + 8 + 200;
|
||||
|
||||
export const EDITION_MARKER_BIT_SIZE = 248;
|
||||
|
||||
export enum MetadataKey {
|
||||
Uninitialized = 0,
|
||||
MetadataV1 = 4,
|
||||
EditionV1 = 1,
|
||||
MasterEditionV1 = 2,
|
||||
ReservationListV1 = 3,
|
||||
MasterEditionV2 = 6,
|
||||
EditionMarker = 7,
|
||||
}
|
||||
|
||||
export enum MetadataCategory {
|
||||
|
@ -84,7 +87,7 @@ export interface IMetadataExtension {
|
|||
};
|
||||
}
|
||||
|
||||
export class MasterEdition {
|
||||
export class MasterEditionV1 {
|
||||
key: MetadataKey;
|
||||
supply: BN;
|
||||
maxSupply?: BN;
|
||||
|
@ -118,6 +121,45 @@ export class MasterEdition {
|
|||
}
|
||||
}
|
||||
|
||||
export class MasterEditionV2 {
|
||||
key: MetadataKey;
|
||||
supply: BN;
|
||||
maxSupply?: BN;
|
||||
|
||||
constructor(args: { key: MetadataKey; supply: BN; maxSupply?: BN }) {
|
||||
this.key = MetadataKey.MasterEditionV2;
|
||||
this.supply = args.supply;
|
||||
this.maxSupply = args.maxSupply;
|
||||
}
|
||||
}
|
||||
|
||||
export class EditionMarker {
|
||||
key: MetadataKey;
|
||||
ledger: number[];
|
||||
|
||||
constructor(args: { key: MetadataKey; ledger: number[] }) {
|
||||
this.key = MetadataKey.EditionMarker;
|
||||
this.ledger = args.ledger;
|
||||
}
|
||||
|
||||
editionTaken(edition: number) {
|
||||
const editionOffset = edition % EDITION_MARKER_BIT_SIZE;
|
||||
const indexOffset = Math.floor(editionOffset / 8);
|
||||
|
||||
if (indexOffset > 30) {
|
||||
throw Error('bad index for edition');
|
||||
}
|
||||
|
||||
const positionInBitsetFromRight = 7 - (editionOffset % 8);
|
||||
|
||||
const mask = Math.pow(2, positionInBitsetFromRight);
|
||||
|
||||
const appliedMask = this.ledger[indexOffset] & mask;
|
||||
|
||||
return appliedMask != 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class Edition {
|
||||
key: MetadataKey;
|
||||
/// Points at MasterEdition struct
|
||||
|
@ -131,46 +173,6 @@ export class Edition {
|
|||
this.edition = args.edition;
|
||||
}
|
||||
}
|
||||
export class Reservation {
|
||||
address: PublicKey;
|
||||
spotsRemaining: number;
|
||||
totalSpots: number;
|
||||
constructor(args: {
|
||||
address: PublicKey;
|
||||
spotsRemaining: number;
|
||||
totalSpots: number;
|
||||
}) {
|
||||
this.address = args.address;
|
||||
this.spotsRemaining = args.spotsRemaining;
|
||||
this.totalSpots = args.totalSpots;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReservationList {
|
||||
key: MetadataKey = MetadataKey.ReservationListV1;
|
||||
/// Present for reverse lookups
|
||||
masterEdition: PublicKey;
|
||||
|
||||
/// What supply counter was on master_edition when this reservation was created.
|
||||
supplySnapshot: BN | null;
|
||||
reservations: Reservation[];
|
||||
totalReservationSpots: BN;
|
||||
|
||||
constructor(args: {
|
||||
key: MetadataKey;
|
||||
masterEdition: PublicKey;
|
||||
supplySnapshot: BN | null;
|
||||
reservations: Reservation[];
|
||||
totalReservationSpots: BN;
|
||||
}) {
|
||||
this.key = MetadataKey.EditionV1;
|
||||
this.masterEdition = args.masterEdition;
|
||||
this.supplySnapshot = args.supplySnapshot;
|
||||
this.reservations = args.reservations;
|
||||
this.totalReservationSpots = args.totalReservationSpots;
|
||||
}
|
||||
}
|
||||
|
||||
export class Creator {
|
||||
address: PublicKey;
|
||||
verified: boolean;
|
||||
|
@ -268,7 +270,7 @@ class UpdateMetadataArgs {
|
|||
}
|
||||
|
||||
class CreateMasterEditionArgs {
|
||||
instruction: number = 2;
|
||||
instruction: number = 10;
|
||||
maxSupply: BN | null;
|
||||
constructor(args: { maxSupply: BN | null }) {
|
||||
this.maxSupply = args.maxSupply;
|
||||
|
@ -330,7 +332,7 @@ export const METADATA_SCHEMA = new Map<any, any>([
|
|||
},
|
||||
],
|
||||
[
|
||||
MasterEdition,
|
||||
MasterEditionV1,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [
|
||||
|
@ -342,6 +344,17 @@ export const METADATA_SCHEMA = new Map<any, any>([
|
|||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
MasterEditionV2,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [
|
||||
['key', 'u8'],
|
||||
['supply', 'u64'],
|
||||
['maxSupply', { kind: 'option', type: 'u64' }],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
Edition,
|
||||
{
|
||||
|
@ -392,26 +405,12 @@ export const METADATA_SCHEMA = new Map<any, any>([
|
|||
},
|
||||
],
|
||||
[
|
||||
Reservation,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [
|
||||
['address', 'pubkey'],
|
||||
['spotsRemaining', 'u8'],
|
||||
['totalSpots', 'u8'],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
ReservationList,
|
||||
EditionMarker,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [
|
||||
['key', 'u8'],
|
||||
['masterEdition', 'pubkey'],
|
||||
['supplySnapshot', { kind: 'option', type: 'u64' }],
|
||||
['reservations', [Reservation]],
|
||||
['totalReservationSpots', 'u64'],
|
||||
['ledger', [31]],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -426,16 +425,35 @@ export const decodeMetadata = (buffer: Buffer): Metadata => {
|
|||
return metadata;
|
||||
};
|
||||
|
||||
export const decodeEditionMarker = (buffer: Buffer): EditionMarker => {
|
||||
const editionMarker = deserializeUnchecked(
|
||||
METADATA_SCHEMA,
|
||||
EditionMarker,
|
||||
buffer,
|
||||
) as EditionMarker;
|
||||
return editionMarker;
|
||||
};
|
||||
|
||||
export const decodeEdition = (buffer: Buffer) => {
|
||||
return deserializeUnchecked(METADATA_SCHEMA, Edition, buffer) as Edition;
|
||||
};
|
||||
|
||||
export const decodeMasterEdition = (buffer: Buffer) => {
|
||||
return deserializeUnchecked(
|
||||
METADATA_SCHEMA,
|
||||
MasterEdition,
|
||||
buffer,
|
||||
) as MasterEdition;
|
||||
export const decodeMasterEdition = (
|
||||
buffer: Buffer,
|
||||
): MasterEditionV1 | MasterEditionV2 => {
|
||||
if (buffer[0] == MetadataKey.MasterEditionV1) {
|
||||
return deserializeUnchecked(
|
||||
METADATA_SCHEMA,
|
||||
MasterEditionV1,
|
||||
buffer,
|
||||
) as MasterEditionV1;
|
||||
} else {
|
||||
return deserializeUnchecked(
|
||||
METADATA_SCHEMA,
|
||||
MasterEditionV2,
|
||||
buffer,
|
||||
) as MasterEditionV2;
|
||||
}
|
||||
};
|
||||
|
||||
export async function updateMetadata(
|
||||
|
@ -569,14 +587,10 @@ export async function createMetadata(
|
|||
export async function createMasterEdition(
|
||||
maxSupply: BN | undefined,
|
||||
mintKey: PublicKey,
|
||||
printingMintKey: PublicKey,
|
||||
oneTimePrintingAuthorizationMint: PublicKey,
|
||||
updateAuthorityKey: PublicKey,
|
||||
mintAuthorityKey: PublicKey,
|
||||
instructions: TransactionInstruction[],
|
||||
payer: PublicKey,
|
||||
printingMintAuthority: PublicKey,
|
||||
oneTimePrintingAuthorizationMintAuthority?: PublicKey,
|
||||
instructions: TransactionInstruction[],
|
||||
) {
|
||||
const metadataProgramId = programIds().metadata;
|
||||
|
||||
|
@ -617,41 +631,27 @@ export async function createMasterEdition(
|
|||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: printingMintKey,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: oneTimePrintingAuthorizationMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: updateAuthorityKey,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: printingMintAuthority,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: mintAuthorityKey,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: metadataAccount,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: payer,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: metadataAccount,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
|
||||
{
|
||||
pubkey: programIds().token,
|
||||
isSigner: false,
|
||||
|
@ -669,13 +669,6 @@ export async function createMasterEdition(
|
|||
},
|
||||
];
|
||||
|
||||
if (oneTimePrintingAuthorizationMintAuthority)
|
||||
keys.push({
|
||||
pubkey: oneTimePrintingAuthorizationMintAuthority,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
});
|
||||
|
||||
instructions.push(
|
||||
new TransactionInstruction({
|
||||
keys,
|
||||
|
@ -685,7 +678,7 @@ export async function createMasterEdition(
|
|||
);
|
||||
}
|
||||
|
||||
export async function mintNewEditionFromMasterEditionViaToken(
|
||||
export async function deprecatedMintNewEditionFromMasterEditionViaPrintingToken(
|
||||
newMint: PublicKey,
|
||||
tokenMint: PublicKey,
|
||||
newMintAuthority: PublicKey,
|
||||
|
@ -795,6 +788,109 @@ export async function mintNewEditionFromMasterEditionViaToken(
|
|||
);
|
||||
}
|
||||
|
||||
export async function mintNewEditionFromMasterEditionViaToken(
|
||||
newMint: PublicKey,
|
||||
tokenMint: PublicKey,
|
||||
newMintAuthority: PublicKey,
|
||||
newUpdateAuthority: PublicKey,
|
||||
tokenOwner: PublicKey,
|
||||
tokenAccount: PublicKey,
|
||||
instructions: TransactionInstruction[],
|
||||
payer: PublicKey,
|
||||
edition: BN,
|
||||
) {
|
||||
const metadataProgramId = programIds().metadata;
|
||||
|
||||
const newMetadataKey = await getMetadata(newMint);
|
||||
const masterMetadataKey = await getMetadata(tokenMint);
|
||||
const newEdition = await getEdition(newMint);
|
||||
const masterEdition = await getEdition(tokenMint);
|
||||
const editionMarkPda = await getEditionMarkPda(tokenMint, edition);
|
||||
|
||||
const data = Buffer.from([11]);
|
||||
|
||||
const keys = [
|
||||
{
|
||||
pubkey: newMetadataKey,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newEdition,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: masterEdition,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: editionMarkPda,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newMintAuthority,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: payer,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: tokenOwner,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: tokenAccount,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: newUpdateAuthority,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: masterMetadataKey,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: programIds().token,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: SystemProgram.programId,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: SYSVAR_RENT_PUBKEY,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
];
|
||||
|
||||
instructions.push(
|
||||
new TransactionInstruction({
|
||||
keys,
|
||||
programId: metadataProgramId,
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function updatePrimarySaleHappenedViaToken(
|
||||
metadata: PublicKey,
|
||||
owner: PublicKey,
|
||||
|
@ -831,7 +927,7 @@ export async function updatePrimarySaleHappenedViaToken(
|
|||
);
|
||||
}
|
||||
|
||||
export async function createReservationList(
|
||||
export async function deprecatedCreateReservationList(
|
||||
metadata: PublicKey,
|
||||
masterEdition: PublicKey,
|
||||
resource: PublicKey,
|
||||
|
@ -841,7 +937,10 @@ export async function createReservationList(
|
|||
) {
|
||||
const metadataProgramId = programIds().metadata;
|
||||
|
||||
const reservationList = await getReservationList(masterEdition, resource);
|
||||
const reservationList = await deprecatedGetReservationList(
|
||||
masterEdition,
|
||||
resource,
|
||||
);
|
||||
const data = Buffer.from([6]);
|
||||
|
||||
const keys = [
|
||||
|
@ -926,7 +1025,7 @@ export async function signMetadata(
|
|||
);
|
||||
}
|
||||
|
||||
export async function mintPrintingTokens(
|
||||
export async function deprecatedMintPrintingTokens(
|
||||
destination: PublicKey,
|
||||
printingMint: PublicKey,
|
||||
updateAuthority: PublicKey,
|
||||
|
@ -987,6 +1086,42 @@ export async function mintPrintingTokens(
|
|||
);
|
||||
}
|
||||
|
||||
export async function convertMasterEditionV1ToV2(
|
||||
masterEdition: PublicKey,
|
||||
oneTimeAuthMint: PublicKey,
|
||||
printingMint: PublicKey,
|
||||
instructions: TransactionInstruction[],
|
||||
) {
|
||||
const metadataProgramId = programIds().metadata;
|
||||
|
||||
const data = Buffer.from([12]);
|
||||
|
||||
const keys = [
|
||||
{
|
||||
pubkey: masterEdition,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: oneTimeAuthMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: printingMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
];
|
||||
instructions.push(
|
||||
new TransactionInstruction({
|
||||
keys,
|
||||
programId: metadataProgramId,
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getEdition(tokenMint: PublicKey): Promise<PublicKey> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
|
@ -1018,7 +1153,7 @@ export async function getMetadata(tokenMint: PublicKey): Promise<PublicKey> {
|
|||
)[0];
|
||||
}
|
||||
|
||||
export async function getReservationList(
|
||||
export async function deprecatedGetReservationList(
|
||||
masterEdition: PublicKey,
|
||||
resource: PublicKey,
|
||||
): Promise<PublicKey> {
|
||||
|
@ -1037,3 +1172,24 @@ export async function getReservationList(
|
|||
)
|
||||
)[0];
|
||||
}
|
||||
|
||||
export async function getEditionMarkPda(
|
||||
mint: PublicKey,
|
||||
edition: BN,
|
||||
): Promise<PublicKey> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
const editionNumber = Math.floor(edition.toNumber() / 248);
|
||||
|
||||
return (
|
||||
await findProgramAddress(
|
||||
[
|
||||
Buffer.from(METADATA_PREFIX),
|
||||
PROGRAM_IDS.metadata.toBuffer(),
|
||||
mint.toBuffer(),
|
||||
Buffer.from(EDITION),
|
||||
Buffer.from(editionNumber.toString()),
|
||||
],
|
||||
PROGRAM_IDS.metadata,
|
||||
)
|
||||
)[0];
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"dependencies": {
|
||||
"@ant-design/icons": "^4.4.0",
|
||||
"@babel/preset-typescript": "^7.12.13",
|
||||
"@bonfida/spl-name-service": "0.1.12",
|
||||
"@cloudflare/stream-react": "^1.1.0",
|
||||
"@oyster/common": "0.0.1",
|
||||
"@project-serum/serum": "^0.13.34",
|
||||
|
@ -90,7 +91,8 @@
|
|||
"gh-pages": "^3.1.0",
|
||||
"npm-link-shared": "0.5.6",
|
||||
"prettier": "^2.1.2",
|
||||
"typescript": "^4.1.3"
|
||||
"typescript": "^4.1.3",
|
||||
"webpack-dev-server": "3.11.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "*",
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# Draco 3D Data Compression
|
||||
|
||||
Draco is an open-source library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics.
|
||||
|
||||
[Website](https://google.github.io/draco/) | [GitHub](https://github.com/google/draco)
|
||||
|
||||
## Contents
|
||||
|
||||
This folder contains three utilities:
|
||||
|
||||
* `draco_decoder.js` — Emscripten-compiled decoder, compatible with any modern browser.
|
||||
* `draco_decoder.wasm` — WebAssembly decoder, compatible with newer browsers and devices.
|
||||
* `draco_wasm_wrapper.js` — JavaScript wrapper for the WASM decoder.
|
||||
|
||||
Each file is provided in two variations:
|
||||
|
||||
* **Default:** Latest stable builds, tracking the project's [master branch](https://github.com/google/draco).
|
||||
* **glTF:** Builds targeted by the [glTF mesh compression extension](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression), tracking the [corresponding Draco branch](https://github.com/google/draco/tree/gltf_2.0_draco_extension).
|
||||
|
||||
Either variation may be used with `THREE.DRACOLoader`:
|
||||
|
||||
```js
|
||||
var dracoLoader = new THREE.DRACOLoader();
|
||||
dracoLoader.setDecoderPath('path/to/decoders/');
|
||||
dracoLoader.setDecoderConfig({type: 'js'}); // (Optional) Override detection of WASM support.
|
||||
```
|
||||
|
||||
Further [documentation on GitHub](https://github.com/google/draco/tree/master/javascript/example#static-loading-javascript-decoder).
|
||||
|
||||
## License
|
||||
|
||||
[Apache License 2.0](https://github.com/google/draco/blob/master/LICENSE)
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,104 @@
|
|||
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(f){var m=0;return function(){return m<f.length?{done:!1,value:f[m++]}:{done:!0}}};$jscomp.arrayIterator=function(f){return{next:$jscomp.arrayIteratorImpl(f)}};$jscomp.makeIterator=function(f){var m="undefined"!=typeof Symbol&&Symbol.iterator&&f[Symbol.iterator];return m?m.call(f):$jscomp.arrayIterator(f)};
|
||||
$jscomp.getGlobal=function(f){return"undefined"!=typeof window&&window===f?f:"undefined"!=typeof global&&null!=global?global:f};$jscomp.global=$jscomp.getGlobal(this);$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(f,m,v){f!=Array.prototype&&f!=Object.prototype&&(f[m]=v.value)};
|
||||
$jscomp.polyfill=function(f,m,v,t){if(m){v=$jscomp.global;f=f.split(".");for(t=0;t<f.length-1;t++){var h=f[t];h in v||(v[h]={});v=v[h]}f=f[f.length-1];t=v[f];m=m(t);m!=t&&null!=m&&$jscomp.defineProperty(v,f,{configurable:!0,writable:!0,value:m})}};$jscomp.FORCE_POLYFILL_PROMISE=!1;
|
||||
$jscomp.polyfill("Promise",function(f){function m(){this.batch_=null}function v(e){return e instanceof h?e:new h(function(l,f){l(e)})}if(f&&!$jscomp.FORCE_POLYFILL_PROMISE)return f;m.prototype.asyncExecute=function(e){if(null==this.batch_){this.batch_=[];var l=this;this.asyncExecuteFunction(function(){l.executeBatch_()})}this.batch_.push(e)};var t=$jscomp.global.setTimeout;m.prototype.asyncExecuteFunction=function(e){t(e,0)};m.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var e=
|
||||
this.batch_;this.batch_=[];for(var l=0;l<e.length;++l){var f=e[l];e[l]=null;try{f()}catch(z){this.asyncThrow_(z)}}}this.batch_=null};m.prototype.asyncThrow_=function(e){this.asyncExecuteFunction(function(){throw e;})};var h=function(e){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var l=this.createResolveAndReject_();try{e(l.resolve,l.reject)}catch(S){l.reject(S)}};h.prototype.createResolveAndReject_=function(){function e(e){return function(h){f||(f=!0,e.call(l,h))}}var l=this,f=!1;
|
||||
return{resolve:e(this.resolveTo_),reject:e(this.reject_)}};h.prototype.resolveTo_=function(e){if(e===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(e instanceof h)this.settleSameAsPromise_(e);else{a:switch(typeof e){case "object":var l=null!=e;break a;case "function":l=!0;break a;default:l=!1}l?this.resolveToNonPromiseObj_(e):this.fulfill_(e)}};h.prototype.resolveToNonPromiseObj_=function(e){var l=void 0;try{l=e.then}catch(S){this.reject_(S);return}"function"==typeof l?
|
||||
this.settleSameAsThenable_(l,e):this.fulfill_(e)};h.prototype.reject_=function(e){this.settle_(2,e)};h.prototype.fulfill_=function(e){this.settle_(1,e)};h.prototype.settle_=function(e,l){if(0!=this.state_)throw Error("Cannot settle("+e+", "+l+"): Promise already settled in state"+this.state_);this.state_=e;this.result_=l;this.executeOnSettledCallbacks_()};h.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var e=0;e<this.onSettledCallbacks_.length;++e)X.asyncExecute(this.onSettledCallbacks_[e]);
|
||||
this.onSettledCallbacks_=null}};var X=new m;h.prototype.settleSameAsPromise_=function(e){var l=this.createResolveAndReject_();e.callWhenSettled_(l.resolve,l.reject)};h.prototype.settleSameAsThenable_=function(e,l){var f=this.createResolveAndReject_();try{e.call(l,f.resolve,f.reject)}catch(z){f.reject(z)}};h.prototype.then=function(e,f){function l(e,f){return"function"==typeof e?function(f){try{m(e(f))}catch(p){v(p)}}:f}var m,v,t=new h(function(e,f){m=e;v=f});this.callWhenSettled_(l(e,m),l(f,v));return t};
|
||||
h.prototype.catch=function(e){return this.then(void 0,e)};h.prototype.callWhenSettled_=function(e,f){function l(){switch(h.state_){case 1:e(h.result_);break;case 2:f(h.result_);break;default:throw Error("Unexpected state: "+h.state_);}}var h=this;null==this.onSettledCallbacks_?X.asyncExecute(l):this.onSettledCallbacks_.push(l)};h.resolve=v;h.reject=function(e){return new h(function(f,h){h(e)})};h.race=function(e){return new h(function(f,h){for(var l=$jscomp.makeIterator(e),m=l.next();!m.done;m=l.next())v(m.value).callWhenSettled_(f,
|
||||
h)})};h.all=function(e){var f=$jscomp.makeIterator(e),m=f.next();return m.done?v([]):new h(function(e,h){function l(f){return function(h){t[f]=h;z--;0==z&&e(t)}}var t=[],z=0;do t.push(void 0),z++,v(m.value).callWhenSettled_(l(t.length-1),h),m=f.next();while(!m.done)})};return h},"es6","es3");
|
||||
var DracoDecoderModule=function(){var f="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(f=f||__filename);return function(m){function v(k){return a.locateFile?a.locateFile(k,M):M+k}function t(a,c){a||z("Assertion failed: "+c)}function h(a,c,b){var d=c+b;for(b=c;a[b]&&!(b>=d);)++b;if(16<b-c&&a.subarray&&xa)return xa.decode(a.subarray(c,b));for(d="";c<b;){var k=a[c++];if(k&128){var e=a[c++]&63;if(192==(k&224))d+=String.fromCharCode((k&
|
||||
31)<<6|e);else{var f=a[c++]&63;k=224==(k&240)?(k&15)<<12|e<<6|f:(k&7)<<18|e<<12|f<<6|a[c++]&63;65536>k?d+=String.fromCharCode(k):(k-=65536,d+=String.fromCharCode(55296|k>>10,56320|k&1023))}}else d+=String.fromCharCode(k)}return d}function X(a,c){return a?h(ca,a,c):""}function e(a,c){0<a%c&&(a+=c-a%c);return a}function l(k){ka=k;a.HEAP8=T=new Int8Array(k);a.HEAP16=new Int16Array(k);a.HEAP32=P=new Int32Array(k);a.HEAPU8=ca=new Uint8Array(k);a.HEAPU16=new Uint16Array(k);a.HEAPU32=new Uint32Array(k);
|
||||
a.HEAPF32=new Float32Array(k);a.HEAPF64=new Float64Array(k)}function S(k){for(;0<k.length;){var c=k.shift();if("function"==typeof c)c();else{var b=c.func;"number"===typeof b?void 0===c.arg?a.dynCall_v(b):a.dynCall_vi(b,c.arg):b(void 0===c.arg?null:c.arg)}}}function z(k){if(a.onAbort)a.onAbort(k);k+="";ya(k);Y(k);za=!0;throw new WebAssembly.RuntimeError("abort("+k+"). Build with -s ASSERTIONS=1 for more info.");}function va(a){return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):
|
||||
0===a.indexOf("data:application/octet-stream;base64,")}function wa(){try{if(da)return new Uint8Array(da);if(la)return la(U);throw"both async and sync fetching of the wasm failed";}catch(k){z(k)}}function Ma(){return da||!ea&&!Z||"function"!==typeof fetch?new Promise(function(a,c){a(wa())}):fetch(U,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+U+"'";return a.arrayBuffer()}).catch(function(){return wa()})}function ba(){if(!ba.strings){var a={USER:"web_user",
|
||||
LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"===typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:na},c;for(c in Aa)a[c]=Aa[c];var b=[];for(c in a)b.push(c+"="+a[c]);ba.strings=b}return ba.strings}function ma(k){function c(){if(!fa&&(fa=!0,!za)){Ba=!0;S(Ca);S(Da);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)Ea.unshift(a.postRun.shift());
|
||||
S(Ea)}}if(!(0<aa)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)Fa.unshift(a.preRun.shift());S(Fa);0<aa||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);c()},1)):c())}}function p(){}function u(a){return(a||p).__cache__}function N(a,c){var b=u(c),d=b[a];if(d)return d;d=Object.create((c||p).prototype);d.ptr=a;return b[a]=d}function V(a){if("string"===typeof a){for(var c=0,b=0;b<a.length;++b){var d=a.charCodeAt(b);
|
||||
55296<=d&&57343>=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++b)&1023);127>=d?++c:c=2047>=d?c+2:65535>=d?c+3:c+4}c=Array(c+1);b=0;d=c.length;if(0<d){d=b+d-1;for(var k=0;k<a.length;++k){var e=a.charCodeAt(k);if(55296<=e&&57343>=e){var f=a.charCodeAt(++k);e=65536+((e&1023)<<10)|f&1023}if(127>=e){if(b>=d)break;c[b++]=e}else{if(2047>=e){if(b+1>=d)break;c[b++]=192|e>>6}else{if(65535>=e){if(b+2>=d)break;c[b++]=224|e>>12}else{if(b+3>=d)break;c[b++]=240|e>>18;c[b++]=128|e>>12&63}c[b++]=128|e>>6&63}c[b++]=128|
|
||||
e&63}}c[b]=0}a=n.alloc(c,T);n.copy(c,T,a)}return a}function x(){throw"cannot construct a Status, no constructor in IDL";}function A(){this.ptr=Oa();u(A)[this.ptr]=this}function B(){this.ptr=Pa();u(B)[this.ptr]=this}function C(){this.ptr=Qa();u(C)[this.ptr]=this}function D(){this.ptr=Ra();u(D)[this.ptr]=this}function E(){this.ptr=Sa();u(E)[this.ptr]=this}function q(){this.ptr=Ta();u(q)[this.ptr]=this}function J(){this.ptr=Ua();u(J)[this.ptr]=this}function w(){this.ptr=Va();u(w)[this.ptr]=this}function F(){this.ptr=
|
||||
Wa();u(F)[this.ptr]=this}function r(){this.ptr=Xa();u(r)[this.ptr]=this}function G(){this.ptr=Ya();u(G)[this.ptr]=this}function H(){this.ptr=Za();u(H)[this.ptr]=this}function O(){this.ptr=$a();u(O)[this.ptr]=this}function K(){this.ptr=ab();u(K)[this.ptr]=this}function g(){this.ptr=bb();u(g)[this.ptr]=this}function y(){this.ptr=cb();u(y)[this.ptr]=this}function Q(){throw"cannot construct a VoidPtr, no constructor in IDL";}function I(){this.ptr=db();u(I)[this.ptr]=this}function L(){this.ptr=eb();u(L)[this.ptr]=
|
||||
this}m=m||{};var a="undefined"!==typeof m?m:{},Ga=!1,Ha=!1;a.onRuntimeInitialized=function(){Ga=!0;if(Ha&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Ha=!0;if(Ga&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(a){if("string"!==typeof a)return!1;a=a.split(".");return 2>a.length||3<a.length?!1:1==a[0]&&0<=a[1]&&3>=a[1]?!0:0!=a[0]||10<a[1]?!1:!0};var ha={},W;for(W in a)a.hasOwnProperty(W)&&(ha[W]=a[W]);var na="./this.program",
|
||||
ea=!1,Z=!1,oa=!1,fb=!1,Ia=!1;ea="object"===typeof window;Z="function"===typeof importScripts;oa=(fb="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node)&&!ea&&!Z;Ia=!ea&&!oa&&!Z;var M="",pa,qa;if(oa){M=__dirname+"/";var ra=function(a,c){pa||(pa=require("fs"));qa||(qa=require("path"));a=qa.normalize(a);return pa.readFileSync(a,c?null:"utf8")};var la=function(a){a=ra(a,!0);a.buffer||(a=new Uint8Array(a));t(a.buffer);return a};1<process.argv.length&&
|
||||
(na=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);process.on("uncaughtException",function(a){throw a;});process.on("unhandledRejection",z);a.inspect=function(){return"[Emscripten Module object]"}}else if(Ia)"undefined"!=typeof read&&(ra=function(a){return read(a)}),la=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");t("object"===typeof a);return a},"undefined"!==typeof print&&("undefined"===typeof console&&(console={}),console.log=print,
|
||||
console.warn=console.error="undefined"!==typeof printErr?printErr:print);else if(ea||Z)Z?M=self.location.href:document.currentScript&&(M=document.currentScript.src),f&&(M=f),M=0!==M.indexOf("blob:")?M.substr(0,M.lastIndexOf("/")+1):"",ra=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.send(null);return c.responseText},Z&&(la=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.responseType="arraybuffer";c.send(null);return new Uint8Array(c.response)});var ya=a.print||console.log.bind(console),
|
||||
Y=a.printErr||console.warn.bind(console);for(W in ha)ha.hasOwnProperty(W)&&(a[W]=ha[W]);ha=null;a.thisProgram&&(na=a.thisProgram);var da;a.wasmBinary&&(da=a.wasmBinary);"object"!==typeof WebAssembly&&Y("no native wasm support detected");var ia,gb=new WebAssembly.Table({initial:381,maximum:381,element:"anyfunc"}),za=!1,xa="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");var T,ca,P,Ja=a.TOTAL_MEMORY||16777216;if(ia=a.wasmMemory?
|
||||
a.wasmMemory:new WebAssembly.Memory({initial:Ja/65536}))var ka=ia.buffer;Ja=ka.byteLength;l(ka);P[4604]=5261456;var Fa=[],Ca=[],Da=[],Ea=[],Ba=!1,aa=0,sa=null,ja=null;a.preloadedImages={};a.preloadedAudios={};var U="draco_decoder.wasm";va(U)||(U=v(U));Ca.push({func:function(){hb()}});var Aa={},R={buffers:[null,[],[]],printChar:function(a,c){var b=R.buffers[a];0===c||10===c?((1===a?ya:Y)(h(b,0)),b.length=0):b.push(c)},varargs:0,get:function(a){R.varargs+=4;return P[R.varargs-4>>2]},getStr:function(){return X(R.get())},
|
||||
get64:function(){var a=R.get();R.get();return a},getZero:function(){R.get()}},Ka={__cxa_allocate_exception:function(a){return ib(a)},__cxa_throw:function(a,c,b){"uncaught_exception"in ta?ta.uncaught_exceptions++:ta.uncaught_exceptions=1;throw a;},abort:function(){z()},emscripten_get_sbrk_ptr:function(){return 18416},emscripten_memcpy_big:function(a,c,b){ca.set(ca.subarray(c,c+b),a)},emscripten_resize_heap:function(a){if(2147418112<a)return!1;for(var c=Math.max(T.length,16777216);c<a;)c=536870912>=
|
||||
c?e(2*c,65536):Math.min(e((3*c+2147483648)/4,65536),2147418112);a:{try{ia.grow(c-ka.byteLength+65535>>16);l(ia.buffer);var b=1;break a}catch(d){}b=void 0}return b?!0:!1},environ_get:function(a,c){var b=0;ba().forEach(function(d,e){var f=c+b;e=P[a+4*e>>2]=f;for(f=0;f<d.length;++f)T[e++>>0]=d.charCodeAt(f);T[e>>0]=0;b+=d.length+1});return 0},environ_sizes_get:function(a,c){var b=ba();P[a>>2]=b.length;var d=0;b.forEach(function(a){d+=a.length+1});P[c>>2]=d;return 0},fd_close:function(a){return 0},fd_seek:function(a,
|
||||
c,b,d,e){return 0},fd_write:function(a,c,b,d){try{for(var e=0,f=0;f<b;f++){for(var g=P[c+8*f>>2],k=P[c+(8*f+4)>>2],h=0;h<k;h++)R.printChar(a,ca[g+h]);e+=k}P[d>>2]=e;return 0}catch(ua){return"undefined"!==typeof FS&&ua instanceof FS.ErrnoError||z(ua),ua.errno}},memory:ia,setTempRet0:function(a){},table:gb},La=function(){function e(c,b){a.asm=c.exports;aa--;a.monitorRunDependencies&&a.monitorRunDependencies(aa);0==aa&&(null!==sa&&(clearInterval(sa),sa=null),ja&&(c=ja,ja=null,c()))}function c(a){e(a.instance)}
|
||||
function b(a){return Ma().then(function(a){return WebAssembly.instantiate(a,d)}).then(a,function(a){Y("failed to asynchronously prepare wasm: "+a);z(a)})}var d={env:Ka,wasi_unstable:Ka};aa++;a.monitorRunDependencies&&a.monitorRunDependencies(aa);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(Na){return Y("Module.instantiateWasm callback failed with error: "+Na),!1}(function(){if(da||"function"!==typeof WebAssembly.instantiateStreaming||va(U)||"function"!==typeof fetch)return b(c);fetch(U,
|
||||
{credentials:"same-origin"}).then(function(a){return WebAssembly.instantiateStreaming(a,d).then(c,function(a){Y("wasm streaming compile failed: "+a);Y("falling back to ArrayBuffer instantiation");b(c)})})})();return{}}();a.asm=La;var hb=a.___wasm_call_ctors=function(){return a.asm.__wasm_call_ctors.apply(null,arguments)},jb=a._emscripten_bind_Status_code_0=function(){return a.asm.emscripten_bind_Status_code_0.apply(null,arguments)},kb=a._emscripten_bind_Status_ok_0=function(){return a.asm.emscripten_bind_Status_ok_0.apply(null,
|
||||
arguments)},lb=a._emscripten_bind_Status_error_msg_0=function(){return a.asm.emscripten_bind_Status_error_msg_0.apply(null,arguments)},mb=a._emscripten_bind_Status___destroy___0=function(){return a.asm.emscripten_bind_Status___destroy___0.apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return a.asm.emscripten_bind_DracoUInt16Array_DracoUInt16Array_0.apply(null,arguments)},nb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoUInt16Array_GetValue_1.apply(null,
|
||||
arguments)},ob=a._emscripten_bind_DracoUInt16Array_size_0=function(){return a.asm.emscripten_bind_DracoUInt16Array_size_0.apply(null,arguments)},pb=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return a.asm.emscripten_bind_DracoUInt16Array___destroy___0.apply(null,arguments)},Pa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return a.asm.emscripten_bind_PointCloud_PointCloud_0.apply(null,arguments)},qb=a._emscripten_bind_PointCloud_num_attributes_0=function(){return a.asm.emscripten_bind_PointCloud_num_attributes_0.apply(null,
|
||||
arguments)},rb=a._emscripten_bind_PointCloud_num_points_0=function(){return a.asm.emscripten_bind_PointCloud_num_points_0.apply(null,arguments)},sb=a._emscripten_bind_PointCloud___destroy___0=function(){return a.asm.emscripten_bind_PointCloud___destroy___0.apply(null,arguments)},Qa=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return a.asm.emscripten_bind_DracoUInt8Array_DracoUInt8Array_0.apply(null,arguments)},tb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoUInt8Array_GetValue_1.apply(null,
|
||||
arguments)},ub=a._emscripten_bind_DracoUInt8Array_size_0=function(){return a.asm.emscripten_bind_DracoUInt8Array_size_0.apply(null,arguments)},vb=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return a.asm.emscripten_bind_DracoUInt8Array___destroy___0.apply(null,arguments)},Ra=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return a.asm.emscripten_bind_DracoUInt32Array_DracoUInt32Array_0.apply(null,arguments)},wb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoUInt32Array_GetValue_1.apply(null,
|
||||
arguments)},xb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return a.asm.emscripten_bind_DracoUInt32Array_size_0.apply(null,arguments)},yb=a._emscripten_bind_DracoUInt32Array___destroy___0=function(){return a.asm.emscripten_bind_DracoUInt32Array___destroy___0.apply(null,arguments)},Sa=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return a.asm.emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0.apply(null,arguments)},zb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=
|
||||
function(){return a.asm.emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1.apply(null,arguments)},Ab=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return a.asm.emscripten_bind_AttributeOctahedronTransform_quantization_bits_0.apply(null,arguments)},Bb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return a.asm.emscripten_bind_AttributeOctahedronTransform___destroy___0.apply(null,arguments)},Ta=a._emscripten_bind_PointAttribute_PointAttribute_0=
|
||||
function(){return a.asm.emscripten_bind_PointAttribute_PointAttribute_0.apply(null,arguments)},Cb=a._emscripten_bind_PointAttribute_size_0=function(){return a.asm.emscripten_bind_PointAttribute_size_0.apply(null,arguments)},Db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=function(){return a.asm.emscripten_bind_PointAttribute_GetAttributeTransformData_0.apply(null,arguments)},Eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return a.asm.emscripten_bind_PointAttribute_attribute_type_0.apply(null,
|
||||
arguments)},Fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return a.asm.emscripten_bind_PointAttribute_data_type_0.apply(null,arguments)},Gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return a.asm.emscripten_bind_PointAttribute_num_components_0.apply(null,arguments)},Hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return a.asm.emscripten_bind_PointAttribute_normalized_0.apply(null,arguments)},Ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return a.asm.emscripten_bind_PointAttribute_byte_stride_0.apply(null,
|
||||
arguments)},Jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return a.asm.emscripten_bind_PointAttribute_byte_offset_0.apply(null,arguments)},Kb=a._emscripten_bind_PointAttribute_unique_id_0=function(){return a.asm.emscripten_bind_PointAttribute_unique_id_0.apply(null,arguments)},Lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return a.asm.emscripten_bind_PointAttribute___destroy___0.apply(null,arguments)},Ua=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=
|
||||
function(){return a.asm.emscripten_bind_AttributeTransformData_AttributeTransformData_0.apply(null,arguments)},Mb=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return a.asm.emscripten_bind_AttributeTransformData_transform_type_0.apply(null,arguments)},Nb=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return a.asm.emscripten_bind_AttributeTransformData___destroy___0.apply(null,arguments)},Va=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=
|
||||
function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0.apply(null,arguments)},Ob=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1.apply(null,arguments)},Pb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_quantization_bits_0.apply(null,arguments)},
|
||||
Qb=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_min_value_1.apply(null,arguments)},Rb=a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_range_0.apply(null,arguments)},Sb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform___destroy___0.apply(null,arguments)},
|
||||
Wa=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return a.asm.emscripten_bind_DracoInt8Array_DracoInt8Array_0.apply(null,arguments)},Tb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoInt8Array_GetValue_1.apply(null,arguments)},Ub=a._emscripten_bind_DracoInt8Array_size_0=function(){return a.asm.emscripten_bind_DracoInt8Array_size_0.apply(null,arguments)},Vb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return a.asm.emscripten_bind_DracoInt8Array___destroy___0.apply(null,
|
||||
arguments)},Xa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return a.asm.emscripten_bind_MetadataQuerier_MetadataQuerier_0.apply(null,arguments)},Wb=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_HasEntry_2.apply(null,arguments)},Xb=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetIntEntry_2.apply(null,arguments)},Yb=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=
|
||||
function(){return a.asm.emscripten_bind_MetadataQuerier_GetIntEntryArray_3.apply(null,arguments)},Zb=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetDoubleEntry_2.apply(null,arguments)},$b=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetStringEntry_2.apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return a.asm.emscripten_bind_MetadataQuerier_NumEntries_1.apply(null,
|
||||
arguments)},bc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetEntryName_2.apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return a.asm.emscripten_bind_MetadataQuerier___destroy___0.apply(null,arguments)},Ya=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return a.asm.emscripten_bind_DracoInt16Array_DracoInt16Array_0.apply(null,arguments)},dc=a._emscripten_bind_DracoInt16Array_GetValue_1=
|
||||
function(){return a.asm.emscripten_bind_DracoInt16Array_GetValue_1.apply(null,arguments)},ec=a._emscripten_bind_DracoInt16Array_size_0=function(){return a.asm.emscripten_bind_DracoInt16Array_size_0.apply(null,arguments)},fc=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return a.asm.emscripten_bind_DracoInt16Array___destroy___0.apply(null,arguments)},Za=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return a.asm.emscripten_bind_DracoFloat32Array_DracoFloat32Array_0.apply(null,
|
||||
arguments)},gc=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoFloat32Array_GetValue_1.apply(null,arguments)},hc=a._emscripten_bind_DracoFloat32Array_size_0=function(){return a.asm.emscripten_bind_DracoFloat32Array_size_0.apply(null,arguments)},ic=a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return a.asm.emscripten_bind_DracoFloat32Array___destroy___0.apply(null,arguments)},$a=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return a.asm.emscripten_bind_GeometryAttribute_GeometryAttribute_0.apply(null,
|
||||
arguments)},jc=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return a.asm.emscripten_bind_GeometryAttribute___destroy___0.apply(null,arguments)},ab=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=function(){return a.asm.emscripten_bind_DecoderBuffer_DecoderBuffer_0.apply(null,arguments)},kc=a._emscripten_bind_DecoderBuffer_Init_2=function(){return a.asm.emscripten_bind_DecoderBuffer_Init_2.apply(null,arguments)},lc=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return a.asm.emscripten_bind_DecoderBuffer___destroy___0.apply(null,
|
||||
arguments)},bb=a._emscripten_bind_Decoder_Decoder_0=function(){return a.asm.emscripten_bind_Decoder_Decoder_0.apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetEncodedGeometryType_1=function(){return a.asm.emscripten_bind_Decoder_GetEncodedGeometryType_1.apply(null,arguments)},nc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return a.asm.emscripten_bind_Decoder_DecodeBufferToPointCloud_2.apply(null,arguments)},oc=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return a.asm.emscripten_bind_Decoder_DecodeBufferToMesh_2.apply(null,
|
||||
arguments)},pc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeId_2.apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeIdByName_2.apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3.apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetAttribute_2=
|
||||
function(){return a.asm.emscripten_bind_Decoder_GetAttribute_2.apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeByUniqueId_2.apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return a.asm.emscripten_bind_Decoder_GetMetadata_1.apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeMetadata_2.apply(null,
|
||||
arguments)},wc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=function(){return a.asm.emscripten_bind_Decoder_GetFaceFromMesh_3.apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return a.asm.emscripten_bind_Decoder_GetTriangleStripsFromMesh_2.apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return a.asm.emscripten_bind_Decoder_GetTrianglesUInt16Array_3.apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=
|
||||
function(){return a.asm.emscripten_bind_Decoder_GetTrianglesUInt32Array_3.apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeFloat_3.apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3.apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeIntForAllPoints_3.apply(null,
|
||||
arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3.apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3.apply(null,arguments)},Fc=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3.apply(null,arguments)},
|
||||
Gc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3.apply(null,arguments)},Hc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3.apply(null,arguments)},Ic=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3.apply(null,arguments)},Jc=
|
||||
a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return a.asm.emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5.apply(null,arguments)},Kc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return a.asm.emscripten_bind_Decoder_SkipAttributeTransform_1.apply(null,arguments)},Lc=a._emscripten_bind_Decoder___destroy___0=function(){return a.asm.emscripten_bind_Decoder___destroy___0.apply(null,arguments)},cb=a._emscripten_bind_Mesh_Mesh_0=function(){return a.asm.emscripten_bind_Mesh_Mesh_0.apply(null,
|
||||
arguments)},Mc=a._emscripten_bind_Mesh_num_faces_0=function(){return a.asm.emscripten_bind_Mesh_num_faces_0.apply(null,arguments)},Nc=a._emscripten_bind_Mesh_num_attributes_0=function(){return a.asm.emscripten_bind_Mesh_num_attributes_0.apply(null,arguments)},Oc=a._emscripten_bind_Mesh_num_points_0=function(){return a.asm.emscripten_bind_Mesh_num_points_0.apply(null,arguments)},Pc=a._emscripten_bind_Mesh___destroy___0=function(){return a.asm.emscripten_bind_Mesh___destroy___0.apply(null,arguments)},
|
||||
Qc=a._emscripten_bind_VoidPtr___destroy___0=function(){return a.asm.emscripten_bind_VoidPtr___destroy___0.apply(null,arguments)},db=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=function(){return a.asm.emscripten_bind_DracoInt32Array_DracoInt32Array_0.apply(null,arguments)},Rc=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoInt32Array_GetValue_1.apply(null,arguments)},Sc=a._emscripten_bind_DracoInt32Array_size_0=function(){return a.asm.emscripten_bind_DracoInt32Array_size_0.apply(null,
|
||||
arguments)},Tc=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return a.asm.emscripten_bind_DracoInt32Array___destroy___0.apply(null,arguments)},eb=a._emscripten_bind_Metadata_Metadata_0=function(){return a.asm.emscripten_bind_Metadata_Metadata_0.apply(null,arguments)},Uc=a._emscripten_bind_Metadata___destroy___0=function(){return a.asm.emscripten_bind_Metadata___destroy___0.apply(null,arguments)},Vc=a._emscripten_enum_draco_StatusCode_OK=function(){return a.asm.emscripten_enum_draco_StatusCode_OK.apply(null,
|
||||
arguments)},Wc=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return a.asm.emscripten_enum_draco_StatusCode_DRACO_ERROR.apply(null,arguments)},Xc=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return a.asm.emscripten_enum_draco_StatusCode_IO_ERROR.apply(null,arguments)},Yc=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=function(){return a.asm.emscripten_enum_draco_StatusCode_INVALID_PARAMETER.apply(null,arguments)},Zc=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=
|
||||
function(){return a.asm.emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION.apply(null,arguments)},$c=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return a.asm.emscripten_enum_draco_StatusCode_UNKNOWN_VERSION.apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return a.asm.emscripten_enum_draco_DataType_DT_INVALID.apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT8=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT8.apply(null,
|
||||
arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT8=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT8.apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT16=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT16.apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT16.apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT32.apply(null,
|
||||
arguments)},gd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT32.apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT64.apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT64.apply(null,arguments)},jd=a._emscripten_enum_draco_DataType_DT_FLOAT32=function(){return a.asm.emscripten_enum_draco_DataType_DT_FLOAT32.apply(null,
|
||||
arguments)},kd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return a.asm.emscripten_enum_draco_DataType_DT_FLOAT64.apply(null,arguments)},ld=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return a.asm.emscripten_enum_draco_DataType_DT_BOOL.apply(null,arguments)},md=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return a.asm.emscripten_enum_draco_DataType_DT_TYPES_COUNT.apply(null,arguments)},nd=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return a.asm.emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE.apply(null,
|
||||
arguments)},od=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return a.asm.emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD.apply(null,arguments)},pd=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return a.asm.emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH.apply(null,arguments)},qd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM.apply(null,
|
||||
arguments)},rd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM.apply(null,arguments)},sd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM.apply(null,arguments)},td=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM.apply(null,
|
||||
arguments)},ud=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_INVALID.apply(null,arguments)},vd=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_POSITION.apply(null,arguments)},wd=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_NORMAL.apply(null,arguments)},xd=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=
|
||||
function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_COLOR.apply(null,arguments)},yd=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD.apply(null,arguments)},zd=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_GENERIC.apply(null,arguments)};a._setThrew=function(){return a.asm.setThrew.apply(null,arguments)};var ta=a.__ZSt18uncaught_exceptionv=
|
||||
function(){return a.asm._ZSt18uncaught_exceptionv.apply(null,arguments)};a._free=function(){return a.asm.free.apply(null,arguments)};var ib=a._malloc=function(){return a.asm.malloc.apply(null,arguments)};a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,arguments)};a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)};a.__growWasmMemory=function(){return a.asm.__growWasmMemory.apply(null,arguments)};
|
||||
a.dynCall_ii=function(){return a.asm.dynCall_ii.apply(null,arguments)};a.dynCall_vi=function(){return a.asm.dynCall_vi.apply(null,arguments)};a.dynCall_iii=function(){return a.asm.dynCall_iii.apply(null,arguments)};a.dynCall_vii=function(){return a.asm.dynCall_vii.apply(null,arguments)};a.dynCall_iiii=function(){return a.asm.dynCall_iiii.apply(null,arguments)};a.dynCall_v=function(){return a.asm.dynCall_v.apply(null,arguments)};a.dynCall_viii=function(){return a.asm.dynCall_viii.apply(null,arguments)};
|
||||
a.dynCall_viiii=function(){return a.asm.dynCall_viiii.apply(null,arguments)};a.dynCall_iiiiiii=function(){return a.asm.dynCall_iiiiiii.apply(null,arguments)};a.dynCall_iidiiii=function(){return a.asm.dynCall_iidiiii.apply(null,arguments)};a.dynCall_jiji=function(){return a.asm.dynCall_jiji.apply(null,arguments)};a.dynCall_viiiiii=function(){return a.asm.dynCall_viiiiii.apply(null,arguments)};a.dynCall_viiiii=function(){return a.asm.dynCall_viiiii.apply(null,arguments)};a.asm=La;var fa;a.then=function(e){if(fa)e(a);
|
||||
else{var c=a.onRuntimeInitialized;a.onRuntimeInitialized=function(){c&&c();e(a)}}return a};ja=function c(){fa||ma();fa||(ja=c)};a.run=ma;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();ma();p.prototype=Object.create(p.prototype);p.prototype.constructor=p;p.prototype.__class__=p;p.__cache__={};a.WrapperObject=p;a.getCache=u;a.wrapPointer=N;a.castObject=function(a,b){return N(a.ptr,b)};a.NULL=N(0);a.destroy=function(a){if(!a.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";
|
||||
a.__destroy__();delete u(a.__class__)[a.ptr]};a.compare=function(a,b){return a.ptr===b.ptr};a.getPointer=function(a){return a.ptr};a.getClass=function(a){return a.__class__};var n={buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(n.needed){for(var c=0;c<n.temps.length;c++)a._free(n.temps[c]);n.temps.length=0;a._free(n.buffer);n.buffer=0;n.size+=n.needed;n.needed=0}n.buffer||(n.size+=128,n.buffer=a._malloc(n.size),t(n.buffer));n.pos=0},alloc:function(c,b){t(n.buffer);c=c.length*b.BYTES_PER_ELEMENT;
|
||||
c=c+7&-8;n.pos+c>=n.size?(t(0<c),n.needed+=c,b=a._malloc(c),n.temps.push(b)):(b=n.buffer+n.pos,n.pos+=c);return b},copy:function(a,b,d){switch(b.BYTES_PER_ELEMENT){case 2:d>>=1;break;case 4:d>>=2;break;case 8:d>>=3}for(var c=0;c<a.length;c++)b[d+c]=a[c]}};x.prototype=Object.create(p.prototype);x.prototype.constructor=x;x.prototype.__class__=x;x.__cache__={};a.Status=x;x.prototype.code=x.prototype.code=function(){return jb(this.ptr)};x.prototype.ok=x.prototype.ok=function(){return!!kb(this.ptr)};x.prototype.error_msg=
|
||||
x.prototype.error_msg=function(){return X(lb(this.ptr))};x.prototype.__destroy__=x.prototype.__destroy__=function(){mb(this.ptr)};A.prototype=Object.create(p.prototype);A.prototype.constructor=A;A.prototype.__class__=A;A.__cache__={};a.DracoUInt16Array=A;A.prototype.GetValue=A.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return nb(c,a)};A.prototype.size=A.prototype.size=function(){return ob(this.ptr)};A.prototype.__destroy__=A.prototype.__destroy__=function(){pb(this.ptr)};
|
||||
B.prototype=Object.create(p.prototype);B.prototype.constructor=B;B.prototype.__class__=B;B.__cache__={};a.PointCloud=B;B.prototype.num_attributes=B.prototype.num_attributes=function(){return qb(this.ptr)};B.prototype.num_points=B.prototype.num_points=function(){return rb(this.ptr)};B.prototype.__destroy__=B.prototype.__destroy__=function(){sb(this.ptr)};C.prototype=Object.create(p.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.DracoUInt8Array=C;C.prototype.GetValue=
|
||||
C.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return tb(c,a)};C.prototype.size=C.prototype.size=function(){return ub(this.ptr)};C.prototype.__destroy__=C.prototype.__destroy__=function(){vb(this.ptr)};D.prototype=Object.create(p.prototype);D.prototype.constructor=D;D.prototype.__class__=D;D.__cache__={};a.DracoUInt32Array=D;D.prototype.GetValue=D.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return wb(c,a)};D.prototype.size=D.prototype.size=
|
||||
function(){return xb(this.ptr)};D.prototype.__destroy__=D.prototype.__destroy__=function(){yb(this.ptr)};E.prototype=Object.create(p.prototype);E.prototype.constructor=E;E.prototype.__class__=E;E.__cache__={};a.AttributeOctahedronTransform=E;E.prototype.InitFromAttribute=E.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!zb(c,a)};E.prototype.quantization_bits=E.prototype.quantization_bits=function(){return Ab(this.ptr)};E.prototype.__destroy__=E.prototype.__destroy__=
|
||||
function(){Bb(this.ptr)};q.prototype=Object.create(p.prototype);q.prototype.constructor=q;q.prototype.__class__=q;q.__cache__={};a.PointAttribute=q;q.prototype.size=q.prototype.size=function(){return Cb(this.ptr)};q.prototype.GetAttributeTransformData=q.prototype.GetAttributeTransformData=function(){return N(Db(this.ptr),J)};q.prototype.attribute_type=q.prototype.attribute_type=function(){return Eb(this.ptr)};q.prototype.data_type=q.prototype.data_type=function(){return Fb(this.ptr)};q.prototype.num_components=
|
||||
q.prototype.num_components=function(){return Gb(this.ptr)};q.prototype.normalized=q.prototype.normalized=function(){return!!Hb(this.ptr)};q.prototype.byte_stride=q.prototype.byte_stride=function(){return Ib(this.ptr)};q.prototype.byte_offset=q.prototype.byte_offset=function(){return Jb(this.ptr)};q.prototype.unique_id=q.prototype.unique_id=function(){return Kb(this.ptr)};q.prototype.__destroy__=q.prototype.__destroy__=function(){Lb(this.ptr)};J.prototype=Object.create(p.prototype);J.prototype.constructor=
|
||||
J;J.prototype.__class__=J;J.__cache__={};a.AttributeTransformData=J;J.prototype.transform_type=J.prototype.transform_type=function(){return Mb(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){Nb(this.ptr)};w.prototype=Object.create(p.prototype);w.prototype.constructor=w;w.prototype.__class__=w;w.__cache__={};a.AttributeQuantizationTransform=w;w.prototype.InitFromAttribute=w.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!Ob(c,a)};
|
||||
w.prototype.quantization_bits=w.prototype.quantization_bits=function(){return Pb(this.ptr)};w.prototype.min_value=w.prototype.min_value=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Qb(c,a)};w.prototype.range=w.prototype.range=function(){return Rb(this.ptr)};w.prototype.__destroy__=w.prototype.__destroy__=function(){Sb(this.ptr)};F.prototype=Object.create(p.prototype);F.prototype.constructor=F;F.prototype.__class__=F;F.__cache__={};a.DracoInt8Array=F;F.prototype.GetValue=F.prototype.GetValue=
|
||||
function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Tb(c,a)};F.prototype.size=F.prototype.size=function(){return Ub(this.ptr)};F.prototype.__destroy__=F.prototype.__destroy__=function(){Vb(this.ptr)};r.prototype=Object.create(p.prototype);r.prototype.constructor=r;r.prototype.__class__=r;r.__cache__={};a.MetadataQuerier=r;r.prototype.HasEntry=r.prototype.HasEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return!!Wb(c,
|
||||
a,b)};r.prototype.GetIntEntry=r.prototype.GetIntEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return Xb(c,a,b)};r.prototype.GetIntEntryArray=r.prototype.GetIntEntryArray=function(a,b,d){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);d&&"object"===typeof d&&(d=d.ptr);Yb(c,a,b,d)};r.prototype.GetDoubleEntry=r.prototype.GetDoubleEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===
|
||||
typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return Zb(c,a,b)};r.prototype.GetStringEntry=r.prototype.GetStringEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return X($b(c,a,b))};r.prototype.NumEntries=r.prototype.NumEntries=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return ac(c,a)};r.prototype.GetEntryName=r.prototype.GetEntryName=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===
|
||||
typeof b&&(b=b.ptr);return X(bc(c,a,b))};r.prototype.__destroy__=r.prototype.__destroy__=function(){cc(this.ptr)};G.prototype=Object.create(p.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.DracoInt16Array=G;G.prototype.GetValue=G.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return dc(c,a)};G.prototype.size=G.prototype.size=function(){return ec(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){fc(this.ptr)};H.prototype=
|
||||
Object.create(p.prototype);H.prototype.constructor=H;H.prototype.__class__=H;H.__cache__={};a.DracoFloat32Array=H;H.prototype.GetValue=H.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return gc(c,a)};H.prototype.size=H.prototype.size=function(){return hc(this.ptr)};H.prototype.__destroy__=H.prototype.__destroy__=function(){ic(this.ptr)};O.prototype=Object.create(p.prototype);O.prototype.constructor=O;O.prototype.__class__=O;O.__cache__={};a.GeometryAttribute=O;O.prototype.__destroy__=
|
||||
O.prototype.__destroy__=function(){jc(this.ptr)};K.prototype=Object.create(p.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.DecoderBuffer=K;K.prototype.Init=K.prototype.Init=function(a,b){var c=this.ptr;n.prepare();if("object"==typeof a&&"object"===typeof a){var e=n.alloc(a,T);n.copy(a,T,e);a=e}b&&"object"===typeof b&&(b=b.ptr);kc(c,a,b)};K.prototype.__destroy__=K.prototype.__destroy__=function(){lc(this.ptr)};g.prototype=Object.create(p.prototype);g.prototype.constructor=
|
||||
g;g.prototype.__class__=g;g.__cache__={};a.Decoder=g;g.prototype.GetEncodedGeometryType=g.prototype.GetEncodedGeometryType=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return mc(c,a)};g.prototype.DecodeBufferToPointCloud=g.prototype.DecodeBufferToPointCloud=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(nc(c,a,b),x)};g.prototype.DecodeBufferToMesh=g.prototype.DecodeBufferToMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&
|
||||
(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(oc(c,a,b),x)};g.prototype.GetAttributeId=g.prototype.GetAttributeId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return pc(c,a,b)};g.prototype.GetAttributeIdByName=g.prototype.GetAttributeIdByName=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return qc(c,a,b)};g.prototype.GetAttributeIdByMetadataEntry=g.prototype.GetAttributeIdByMetadataEntry=
|
||||
function(a,b,d){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);d=d&&"object"===typeof d?d.ptr:V(d);return rc(c,a,b,d)};g.prototype.GetAttribute=g.prototype.GetAttribute=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(sc(c,a,b),q)};g.prototype.GetAttributeByUniqueId=g.prototype.GetAttributeByUniqueId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);
|
||||
return N(tc(c,a,b),q)};g.prototype.GetMetadata=g.prototype.GetMetadata=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return N(uc(c,a),L)};g.prototype.GetAttributeMetadata=g.prototype.GetAttributeMetadata=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(vc(c,a,b),L)};g.prototype.GetFaceFromMesh=g.prototype.GetFaceFromMesh=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===
|
||||
typeof d&&(d=d.ptr);return!!wc(c,a,b,d)};g.prototype.GetTriangleStripsFromMesh=g.prototype.GetTriangleStripsFromMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return xc(c,a,b)};g.prototype.GetTrianglesUInt16Array=g.prototype.GetTrianglesUInt16Array=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!yc(c,a,b,d)};g.prototype.GetTrianglesUInt32Array=g.prototype.GetTrianglesUInt32Array=
|
||||
function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!zc(c,a,b,d)};g.prototype.GetAttributeFloat=g.prototype.GetAttributeFloat=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ac(c,a,b,d)};g.prototype.GetAttributeFloatForAllPoints=g.prototype.GetAttributeFloatForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&
|
||||
(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Bc(c,a,b,d)};g.prototype.GetAttributeIntForAllPoints=g.prototype.GetAttributeIntForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Cc(c,a,b,d)};g.prototype.GetAttributeInt8ForAllPoints=g.prototype.GetAttributeInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&
|
||||
(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Dc(c,a,b,d)};g.prototype.GetAttributeUInt8ForAllPoints=g.prototype.GetAttributeUInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ec(c,a,b,d)};g.prototype.GetAttributeInt16ForAllPoints=g.prototype.GetAttributeInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&
|
||||
(d=d.ptr);return!!Fc(c,a,b,d)};g.prototype.GetAttributeUInt16ForAllPoints=g.prototype.GetAttributeUInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Gc(c,a,b,d)};g.prototype.GetAttributeInt32ForAllPoints=g.prototype.GetAttributeInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Hc(c,
|
||||
a,b,d)};g.prototype.GetAttributeUInt32ForAllPoints=g.prototype.GetAttributeUInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ic(c,a,b,d)};g.prototype.GetAttributeDataArrayForAllPoints=g.prototype.GetAttributeDataArrayForAllPoints=function(a,b,d,e,f){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);e&&"object"===typeof e&&
|
||||
(e=e.ptr);f&&"object"===typeof f&&(f=f.ptr);return!!Jc(c,a,b,d,e,f)};g.prototype.SkipAttributeTransform=g.prototype.SkipAttributeTransform=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);Kc(b,a)};g.prototype.__destroy__=g.prototype.__destroy__=function(){Lc(this.ptr)};y.prototype=Object.create(p.prototype);y.prototype.constructor=y;y.prototype.__class__=y;y.__cache__={};a.Mesh=y;y.prototype.num_faces=y.prototype.num_faces=function(){return Mc(this.ptr)};y.prototype.num_attributes=y.prototype.num_attributes=
|
||||
function(){return Nc(this.ptr)};y.prototype.num_points=y.prototype.num_points=function(){return Oc(this.ptr)};y.prototype.__destroy__=y.prototype.__destroy__=function(){Pc(this.ptr)};Q.prototype=Object.create(p.prototype);Q.prototype.constructor=Q;Q.prototype.__class__=Q;Q.__cache__={};a.VoidPtr=Q;Q.prototype.__destroy__=Q.prototype.__destroy__=function(){Qc(this.ptr)};I.prototype=Object.create(p.prototype);I.prototype.constructor=I;I.prototype.__class__=I;I.__cache__={};a.DracoInt32Array=I;I.prototype.GetValue=
|
||||
I.prototype.GetValue=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Rc(b,a)};I.prototype.size=I.prototype.size=function(){return Sc(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){Tc(this.ptr)};L.prototype=Object.create(p.prototype);L.prototype.constructor=L;L.prototype.__class__=L;L.__cache__={};a.Metadata=L;L.prototype.__destroy__=L.prototype.__destroy__=function(){Uc(this.ptr)};(function(){function c(){a.OK=Vc();a.DRACO_ERROR=Wc();a.IO_ERROR=Xc();a.INVALID_PARAMETER=
|
||||
Yc();a.UNSUPPORTED_VERSION=Zc();a.UNKNOWN_VERSION=$c();a.DT_INVALID=ad();a.DT_INT8=bd();a.DT_UINT8=cd();a.DT_INT16=dd();a.DT_UINT16=ed();a.DT_INT32=fd();a.DT_UINT32=gd();a.DT_INT64=hd();a.DT_UINT64=id();a.DT_FLOAT32=jd();a.DT_FLOAT64=kd();a.DT_BOOL=ld();a.DT_TYPES_COUNT=md();a.INVALID_GEOMETRY_TYPE=nd();a.POINT_CLOUD=od();a.TRIANGULAR_MESH=pd();a.ATTRIBUTE_INVALID_TRANSFORM=qd();a.ATTRIBUTE_NO_TRANSFORM=rd();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=sd();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=td();a.INVALID=ud();
|
||||
a.POSITION=vd();a.NORMAL=wd();a.COLOR=xd();a.TEX_COORD=yd();a.GENERIC=zd()}Ba?c():Da.unshift(c)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();return m}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule);
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,104 @@
|
|||
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(f){var m=0;return function(){return m<f.length?{done:!1,value:f[m++]}:{done:!0}}};$jscomp.arrayIterator=function(f){return{next:$jscomp.arrayIteratorImpl(f)}};$jscomp.makeIterator=function(f){var m="undefined"!=typeof Symbol&&Symbol.iterator&&f[Symbol.iterator];return m?m.call(f):$jscomp.arrayIterator(f)};
|
||||
$jscomp.getGlobal=function(f){return"undefined"!=typeof window&&window===f?f:"undefined"!=typeof global&&null!=global?global:f};$jscomp.global=$jscomp.getGlobal(this);$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(f,m,v){f!=Array.prototype&&f!=Object.prototype&&(f[m]=v.value)};
|
||||
$jscomp.polyfill=function(f,m,v,t){if(m){v=$jscomp.global;f=f.split(".");for(t=0;t<f.length-1;t++){var h=f[t];h in v||(v[h]={});v=v[h]}f=f[f.length-1];t=v[f];m=m(t);m!=t&&null!=m&&$jscomp.defineProperty(v,f,{configurable:!0,writable:!0,value:m})}};$jscomp.FORCE_POLYFILL_PROMISE=!1;
|
||||
$jscomp.polyfill("Promise",function(f){function m(){this.batch_=null}function v(e){return e instanceof h?e:new h(function(l,f){l(e)})}if(f&&!$jscomp.FORCE_POLYFILL_PROMISE)return f;m.prototype.asyncExecute=function(e){if(null==this.batch_){this.batch_=[];var l=this;this.asyncExecuteFunction(function(){l.executeBatch_()})}this.batch_.push(e)};var t=$jscomp.global.setTimeout;m.prototype.asyncExecuteFunction=function(e){t(e,0)};m.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var e=
|
||||
this.batch_;this.batch_=[];for(var l=0;l<e.length;++l){var f=e[l];e[l]=null;try{f()}catch(z){this.asyncThrow_(z)}}}this.batch_=null};m.prototype.asyncThrow_=function(e){this.asyncExecuteFunction(function(){throw e;})};var h=function(e){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var l=this.createResolveAndReject_();try{e(l.resolve,l.reject)}catch(S){l.reject(S)}};h.prototype.createResolveAndReject_=function(){function e(e){return function(h){f||(f=!0,e.call(l,h))}}var l=this,f=!1;
|
||||
return{resolve:e(this.resolveTo_),reject:e(this.reject_)}};h.prototype.resolveTo_=function(e){if(e===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(e instanceof h)this.settleSameAsPromise_(e);else{a:switch(typeof e){case "object":var l=null!=e;break a;case "function":l=!0;break a;default:l=!1}l?this.resolveToNonPromiseObj_(e):this.fulfill_(e)}};h.prototype.resolveToNonPromiseObj_=function(e){var l=void 0;try{l=e.then}catch(S){this.reject_(S);return}"function"==typeof l?
|
||||
this.settleSameAsThenable_(l,e):this.fulfill_(e)};h.prototype.reject_=function(e){this.settle_(2,e)};h.prototype.fulfill_=function(e){this.settle_(1,e)};h.prototype.settle_=function(e,l){if(0!=this.state_)throw Error("Cannot settle("+e+", "+l+"): Promise already settled in state"+this.state_);this.state_=e;this.result_=l;this.executeOnSettledCallbacks_()};h.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var e=0;e<this.onSettledCallbacks_.length;++e)X.asyncExecute(this.onSettledCallbacks_[e]);
|
||||
this.onSettledCallbacks_=null}};var X=new m;h.prototype.settleSameAsPromise_=function(e){var l=this.createResolveAndReject_();e.callWhenSettled_(l.resolve,l.reject)};h.prototype.settleSameAsThenable_=function(e,l){var f=this.createResolveAndReject_();try{e.call(l,f.resolve,f.reject)}catch(z){f.reject(z)}};h.prototype.then=function(e,f){function l(e,f){return"function"==typeof e?function(f){try{m(e(f))}catch(p){v(p)}}:f}var m,v,t=new h(function(e,f){m=e;v=f});this.callWhenSettled_(l(e,m),l(f,v));return t};
|
||||
h.prototype.catch=function(e){return this.then(void 0,e)};h.prototype.callWhenSettled_=function(e,f){function l(){switch(h.state_){case 1:e(h.result_);break;case 2:f(h.result_);break;default:throw Error("Unexpected state: "+h.state_);}}var h=this;null==this.onSettledCallbacks_?X.asyncExecute(l):this.onSettledCallbacks_.push(l)};h.resolve=v;h.reject=function(e){return new h(function(f,h){h(e)})};h.race=function(e){return new h(function(f,h){for(var l=$jscomp.makeIterator(e),m=l.next();!m.done;m=l.next())v(m.value).callWhenSettled_(f,
|
||||
h)})};h.all=function(e){var f=$jscomp.makeIterator(e),m=f.next();return m.done?v([]):new h(function(e,h){function l(f){return function(h){t[f]=h;z--;0==z&&e(t)}}var t=[],z=0;do t.push(void 0),z++,v(m.value).callWhenSettled_(l(t.length-1),h),m=f.next();while(!m.done)})};return h},"es6","es3");
|
||||
var DracoDecoderModule=function(){var f="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(f=f||__filename);return function(m){function v(k){return a.locateFile?a.locateFile(k,M):M+k}function t(a,c){a||z("Assertion failed: "+c)}function h(a,c,b){var d=c+b;for(b=c;a[b]&&!(b>=d);)++b;if(16<b-c&&a.subarray&&xa)return xa.decode(a.subarray(c,b));for(d="";c<b;){var k=a[c++];if(k&128){var e=a[c++]&63;if(192==(k&224))d+=String.fromCharCode((k&
|
||||
31)<<6|e);else{var f=a[c++]&63;k=224==(k&240)?(k&15)<<12|e<<6|f:(k&7)<<18|e<<12|f<<6|a[c++]&63;65536>k?d+=String.fromCharCode(k):(k-=65536,d+=String.fromCharCode(55296|k>>10,56320|k&1023))}}else d+=String.fromCharCode(k)}return d}function X(a,c){return a?h(ca,a,c):""}function e(a,c){0<a%c&&(a+=c-a%c);return a}function l(k){ka=k;a.HEAP8=T=new Int8Array(k);a.HEAP16=new Int16Array(k);a.HEAP32=P=new Int32Array(k);a.HEAPU8=ca=new Uint8Array(k);a.HEAPU16=new Uint16Array(k);a.HEAPU32=new Uint32Array(k);
|
||||
a.HEAPF32=new Float32Array(k);a.HEAPF64=new Float64Array(k)}function S(k){for(;0<k.length;){var c=k.shift();if("function"==typeof c)c();else{var b=c.func;"number"===typeof b?void 0===c.arg?a.dynCall_v(b):a.dynCall_vi(b,c.arg):b(void 0===c.arg?null:c.arg)}}}function z(k){if(a.onAbort)a.onAbort(k);k+="";ya(k);Y(k);za=!0;throw new WebAssembly.RuntimeError("abort("+k+"). Build with -s ASSERTIONS=1 for more info.");}function va(a){return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):
|
||||
0===a.indexOf("data:application/octet-stream;base64,")}function wa(){try{if(da)return new Uint8Array(da);if(la)return la(U);throw"both async and sync fetching of the wasm failed";}catch(k){z(k)}}function Ma(){return da||!ea&&!Z||"function"!==typeof fetch?new Promise(function(a,c){a(wa())}):fetch(U,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+U+"'";return a.arrayBuffer()}).catch(function(){return wa()})}function ba(){if(!ba.strings){var a={USER:"web_user",
|
||||
LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"===typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:na},c;for(c in Aa)a[c]=Aa[c];var b=[];for(c in a)b.push(c+"="+a[c]);ba.strings=b}return ba.strings}function ma(k){function c(){if(!fa&&(fa=!0,!za)){Ba=!0;S(Ca);S(Da);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)Ea.unshift(a.postRun.shift());
|
||||
S(Ea)}}if(!(0<aa)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)Fa.unshift(a.preRun.shift());S(Fa);0<aa||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);c()},1)):c())}}function p(){}function u(a){return(a||p).__cache__}function N(a,c){var b=u(c),d=b[a];if(d)return d;d=Object.create((c||p).prototype);d.ptr=a;return b[a]=d}function V(a){if("string"===typeof a){for(var c=0,b=0;b<a.length;++b){var d=a.charCodeAt(b);
|
||||
55296<=d&&57343>=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++b)&1023);127>=d?++c:c=2047>=d?c+2:65535>=d?c+3:c+4}c=Array(c+1);b=0;d=c.length;if(0<d){d=b+d-1;for(var k=0;k<a.length;++k){var e=a.charCodeAt(k);if(55296<=e&&57343>=e){var f=a.charCodeAt(++k);e=65536+((e&1023)<<10)|f&1023}if(127>=e){if(b>=d)break;c[b++]=e}else{if(2047>=e){if(b+1>=d)break;c[b++]=192|e>>6}else{if(65535>=e){if(b+2>=d)break;c[b++]=224|e>>12}else{if(b+3>=d)break;c[b++]=240|e>>18;c[b++]=128|e>>12&63}c[b++]=128|e>>6&63}c[b++]=128|
|
||||
e&63}}c[b]=0}a=n.alloc(c,T);n.copy(c,T,a)}return a}function x(){throw"cannot construct a Status, no constructor in IDL";}function A(){this.ptr=Oa();u(A)[this.ptr]=this}function B(){this.ptr=Pa();u(B)[this.ptr]=this}function C(){this.ptr=Qa();u(C)[this.ptr]=this}function D(){this.ptr=Ra();u(D)[this.ptr]=this}function E(){this.ptr=Sa();u(E)[this.ptr]=this}function q(){this.ptr=Ta();u(q)[this.ptr]=this}function J(){this.ptr=Ua();u(J)[this.ptr]=this}function w(){this.ptr=Va();u(w)[this.ptr]=this}function F(){this.ptr=
|
||||
Wa();u(F)[this.ptr]=this}function r(){this.ptr=Xa();u(r)[this.ptr]=this}function G(){this.ptr=Ya();u(G)[this.ptr]=this}function H(){this.ptr=Za();u(H)[this.ptr]=this}function O(){this.ptr=$a();u(O)[this.ptr]=this}function K(){this.ptr=ab();u(K)[this.ptr]=this}function g(){this.ptr=bb();u(g)[this.ptr]=this}function y(){this.ptr=cb();u(y)[this.ptr]=this}function Q(){throw"cannot construct a VoidPtr, no constructor in IDL";}function I(){this.ptr=db();u(I)[this.ptr]=this}function L(){this.ptr=eb();u(L)[this.ptr]=
|
||||
this}m=m||{};var a="undefined"!==typeof m?m:{},Ga=!1,Ha=!1;a.onRuntimeInitialized=function(){Ga=!0;if(Ha&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Ha=!0;if(Ga&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(a){if("string"!==typeof a)return!1;a=a.split(".");return 2>a.length||3<a.length?!1:1==a[0]&&0<=a[1]&&3>=a[1]?!0:0!=a[0]||10<a[1]?!1:!0};var ha={},W;for(W in a)a.hasOwnProperty(W)&&(ha[W]=a[W]);var na="./this.program",
|
||||
ea=!1,Z=!1,oa=!1,fb=!1,Ia=!1;ea="object"===typeof window;Z="function"===typeof importScripts;oa=(fb="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node)&&!ea&&!Z;Ia=!ea&&!oa&&!Z;var M="",pa,qa;if(oa){M=__dirname+"/";var ra=function(a,c){pa||(pa=require("fs"));qa||(qa=require("path"));a=qa.normalize(a);return pa.readFileSync(a,c?null:"utf8")};var la=function(a){a=ra(a,!0);a.buffer||(a=new Uint8Array(a));t(a.buffer);return a};1<process.argv.length&&
|
||||
(na=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);process.on("uncaughtException",function(a){throw a;});process.on("unhandledRejection",z);a.inspect=function(){return"[Emscripten Module object]"}}else if(Ia)"undefined"!=typeof read&&(ra=function(a){return read(a)}),la=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");t("object"===typeof a);return a},"undefined"!==typeof print&&("undefined"===typeof console&&(console={}),console.log=print,
|
||||
console.warn=console.error="undefined"!==typeof printErr?printErr:print);else if(ea||Z)Z?M=self.location.href:document.currentScript&&(M=document.currentScript.src),f&&(M=f),M=0!==M.indexOf("blob:")?M.substr(0,M.lastIndexOf("/")+1):"",ra=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.send(null);return c.responseText},Z&&(la=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.responseType="arraybuffer";c.send(null);return new Uint8Array(c.response)});var ya=a.print||console.log.bind(console),
|
||||
Y=a.printErr||console.warn.bind(console);for(W in ha)ha.hasOwnProperty(W)&&(a[W]=ha[W]);ha=null;a.thisProgram&&(na=a.thisProgram);var da;a.wasmBinary&&(da=a.wasmBinary);"object"!==typeof WebAssembly&&Y("no native wasm support detected");var ia,gb=new WebAssembly.Table({initial:293,maximum:293,element:"anyfunc"}),za=!1,xa="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");var T,ca,P,Ja=a.TOTAL_MEMORY||16777216;if(ia=a.wasmMemory?
|
||||
a.wasmMemory:new WebAssembly.Memory({initial:Ja/65536}))var ka=ia.buffer;Ja=ka.byteLength;l(ka);P[3416]=5256704;var Fa=[],Ca=[],Da=[],Ea=[],Ba=!1,aa=0,sa=null,ja=null;a.preloadedImages={};a.preloadedAudios={};var U="draco_decoder.wasm";va(U)||(U=v(U));Ca.push({func:function(){hb()}});var Aa={},R={buffers:[null,[],[]],printChar:function(a,c){var b=R.buffers[a];0===c||10===c?((1===a?ya:Y)(h(b,0)),b.length=0):b.push(c)},varargs:0,get:function(a){R.varargs+=4;return P[R.varargs-4>>2]},getStr:function(){return X(R.get())},
|
||||
get64:function(){var a=R.get();R.get();return a},getZero:function(){R.get()}},Ka={__cxa_allocate_exception:function(a){return ib(a)},__cxa_throw:function(a,c,b){"uncaught_exception"in ta?ta.uncaught_exceptions++:ta.uncaught_exceptions=1;throw a;},abort:function(){z()},emscripten_get_sbrk_ptr:function(){return 13664},emscripten_memcpy_big:function(a,c,b){ca.set(ca.subarray(c,c+b),a)},emscripten_resize_heap:function(a){if(2147418112<a)return!1;for(var c=Math.max(T.length,16777216);c<a;)c=536870912>=
|
||||
c?e(2*c,65536):Math.min(e((3*c+2147483648)/4,65536),2147418112);a:{try{ia.grow(c-ka.byteLength+65535>>16);l(ia.buffer);var b=1;break a}catch(d){}b=void 0}return b?!0:!1},environ_get:function(a,c){var b=0;ba().forEach(function(d,e){var f=c+b;e=P[a+4*e>>2]=f;for(f=0;f<d.length;++f)T[e++>>0]=d.charCodeAt(f);T[e>>0]=0;b+=d.length+1});return 0},environ_sizes_get:function(a,c){var b=ba();P[a>>2]=b.length;var d=0;b.forEach(function(a){d+=a.length+1});P[c>>2]=d;return 0},fd_close:function(a){return 0},fd_seek:function(a,
|
||||
c,b,d,e){return 0},fd_write:function(a,c,b,d){try{for(var e=0,f=0;f<b;f++){for(var g=P[c+8*f>>2],k=P[c+(8*f+4)>>2],h=0;h<k;h++)R.printChar(a,ca[g+h]);e+=k}P[d>>2]=e;return 0}catch(ua){return"undefined"!==typeof FS&&ua instanceof FS.ErrnoError||z(ua),ua.errno}},memory:ia,setTempRet0:function(a){},table:gb},La=function(){function e(c,b){a.asm=c.exports;aa--;a.monitorRunDependencies&&a.monitorRunDependencies(aa);0==aa&&(null!==sa&&(clearInterval(sa),sa=null),ja&&(c=ja,ja=null,c()))}function c(a){e(a.instance)}
|
||||
function b(a){return Ma().then(function(a){return WebAssembly.instantiate(a,d)}).then(a,function(a){Y("failed to asynchronously prepare wasm: "+a);z(a)})}var d={env:Ka,wasi_unstable:Ka};aa++;a.monitorRunDependencies&&a.monitorRunDependencies(aa);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(Na){return Y("Module.instantiateWasm callback failed with error: "+Na),!1}(function(){if(da||"function"!==typeof WebAssembly.instantiateStreaming||va(U)||"function"!==typeof fetch)return b(c);fetch(U,
|
||||
{credentials:"same-origin"}).then(function(a){return WebAssembly.instantiateStreaming(a,d).then(c,function(a){Y("wasm streaming compile failed: "+a);Y("falling back to ArrayBuffer instantiation");b(c)})})})();return{}}();a.asm=La;var hb=a.___wasm_call_ctors=function(){return a.asm.__wasm_call_ctors.apply(null,arguments)},jb=a._emscripten_bind_Status_code_0=function(){return a.asm.emscripten_bind_Status_code_0.apply(null,arguments)},kb=a._emscripten_bind_Status_ok_0=function(){return a.asm.emscripten_bind_Status_ok_0.apply(null,
|
||||
arguments)},lb=a._emscripten_bind_Status_error_msg_0=function(){return a.asm.emscripten_bind_Status_error_msg_0.apply(null,arguments)},mb=a._emscripten_bind_Status___destroy___0=function(){return a.asm.emscripten_bind_Status___destroy___0.apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return a.asm.emscripten_bind_DracoUInt16Array_DracoUInt16Array_0.apply(null,arguments)},nb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoUInt16Array_GetValue_1.apply(null,
|
||||
arguments)},ob=a._emscripten_bind_DracoUInt16Array_size_0=function(){return a.asm.emscripten_bind_DracoUInt16Array_size_0.apply(null,arguments)},pb=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return a.asm.emscripten_bind_DracoUInt16Array___destroy___0.apply(null,arguments)},Pa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return a.asm.emscripten_bind_PointCloud_PointCloud_0.apply(null,arguments)},qb=a._emscripten_bind_PointCloud_num_attributes_0=function(){return a.asm.emscripten_bind_PointCloud_num_attributes_0.apply(null,
|
||||
arguments)},rb=a._emscripten_bind_PointCloud_num_points_0=function(){return a.asm.emscripten_bind_PointCloud_num_points_0.apply(null,arguments)},sb=a._emscripten_bind_PointCloud___destroy___0=function(){return a.asm.emscripten_bind_PointCloud___destroy___0.apply(null,arguments)},Qa=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return a.asm.emscripten_bind_DracoUInt8Array_DracoUInt8Array_0.apply(null,arguments)},tb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoUInt8Array_GetValue_1.apply(null,
|
||||
arguments)},ub=a._emscripten_bind_DracoUInt8Array_size_0=function(){return a.asm.emscripten_bind_DracoUInt8Array_size_0.apply(null,arguments)},vb=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return a.asm.emscripten_bind_DracoUInt8Array___destroy___0.apply(null,arguments)},Ra=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return a.asm.emscripten_bind_DracoUInt32Array_DracoUInt32Array_0.apply(null,arguments)},wb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoUInt32Array_GetValue_1.apply(null,
|
||||
arguments)},xb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return a.asm.emscripten_bind_DracoUInt32Array_size_0.apply(null,arguments)},yb=a._emscripten_bind_DracoUInt32Array___destroy___0=function(){return a.asm.emscripten_bind_DracoUInt32Array___destroy___0.apply(null,arguments)},Sa=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return a.asm.emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0.apply(null,arguments)},zb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=
|
||||
function(){return a.asm.emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1.apply(null,arguments)},Ab=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return a.asm.emscripten_bind_AttributeOctahedronTransform_quantization_bits_0.apply(null,arguments)},Bb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return a.asm.emscripten_bind_AttributeOctahedronTransform___destroy___0.apply(null,arguments)},Ta=a._emscripten_bind_PointAttribute_PointAttribute_0=
|
||||
function(){return a.asm.emscripten_bind_PointAttribute_PointAttribute_0.apply(null,arguments)},Cb=a._emscripten_bind_PointAttribute_size_0=function(){return a.asm.emscripten_bind_PointAttribute_size_0.apply(null,arguments)},Db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=function(){return a.asm.emscripten_bind_PointAttribute_GetAttributeTransformData_0.apply(null,arguments)},Eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return a.asm.emscripten_bind_PointAttribute_attribute_type_0.apply(null,
|
||||
arguments)},Fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return a.asm.emscripten_bind_PointAttribute_data_type_0.apply(null,arguments)},Gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return a.asm.emscripten_bind_PointAttribute_num_components_0.apply(null,arguments)},Hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return a.asm.emscripten_bind_PointAttribute_normalized_0.apply(null,arguments)},Ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return a.asm.emscripten_bind_PointAttribute_byte_stride_0.apply(null,
|
||||
arguments)},Jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return a.asm.emscripten_bind_PointAttribute_byte_offset_0.apply(null,arguments)},Kb=a._emscripten_bind_PointAttribute_unique_id_0=function(){return a.asm.emscripten_bind_PointAttribute_unique_id_0.apply(null,arguments)},Lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return a.asm.emscripten_bind_PointAttribute___destroy___0.apply(null,arguments)},Ua=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=
|
||||
function(){return a.asm.emscripten_bind_AttributeTransformData_AttributeTransformData_0.apply(null,arguments)},Mb=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return a.asm.emscripten_bind_AttributeTransformData_transform_type_0.apply(null,arguments)},Nb=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return a.asm.emscripten_bind_AttributeTransformData___destroy___0.apply(null,arguments)},Va=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=
|
||||
function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0.apply(null,arguments)},Ob=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1.apply(null,arguments)},Pb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_quantization_bits_0.apply(null,arguments)},
|
||||
Qb=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_min_value_1.apply(null,arguments)},Rb=a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform_range_0.apply(null,arguments)},Sb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return a.asm.emscripten_bind_AttributeQuantizationTransform___destroy___0.apply(null,arguments)},
|
||||
Wa=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return a.asm.emscripten_bind_DracoInt8Array_DracoInt8Array_0.apply(null,arguments)},Tb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoInt8Array_GetValue_1.apply(null,arguments)},Ub=a._emscripten_bind_DracoInt8Array_size_0=function(){return a.asm.emscripten_bind_DracoInt8Array_size_0.apply(null,arguments)},Vb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return a.asm.emscripten_bind_DracoInt8Array___destroy___0.apply(null,
|
||||
arguments)},Xa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return a.asm.emscripten_bind_MetadataQuerier_MetadataQuerier_0.apply(null,arguments)},Wb=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_HasEntry_2.apply(null,arguments)},Xb=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetIntEntry_2.apply(null,arguments)},Yb=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=
|
||||
function(){return a.asm.emscripten_bind_MetadataQuerier_GetIntEntryArray_3.apply(null,arguments)},Zb=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetDoubleEntry_2.apply(null,arguments)},$b=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetStringEntry_2.apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return a.asm.emscripten_bind_MetadataQuerier_NumEntries_1.apply(null,
|
||||
arguments)},bc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return a.asm.emscripten_bind_MetadataQuerier_GetEntryName_2.apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return a.asm.emscripten_bind_MetadataQuerier___destroy___0.apply(null,arguments)},Ya=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return a.asm.emscripten_bind_DracoInt16Array_DracoInt16Array_0.apply(null,arguments)},dc=a._emscripten_bind_DracoInt16Array_GetValue_1=
|
||||
function(){return a.asm.emscripten_bind_DracoInt16Array_GetValue_1.apply(null,arguments)},ec=a._emscripten_bind_DracoInt16Array_size_0=function(){return a.asm.emscripten_bind_DracoInt16Array_size_0.apply(null,arguments)},fc=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return a.asm.emscripten_bind_DracoInt16Array___destroy___0.apply(null,arguments)},Za=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return a.asm.emscripten_bind_DracoFloat32Array_DracoFloat32Array_0.apply(null,
|
||||
arguments)},gc=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoFloat32Array_GetValue_1.apply(null,arguments)},hc=a._emscripten_bind_DracoFloat32Array_size_0=function(){return a.asm.emscripten_bind_DracoFloat32Array_size_0.apply(null,arguments)},ic=a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return a.asm.emscripten_bind_DracoFloat32Array___destroy___0.apply(null,arguments)},$a=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return a.asm.emscripten_bind_GeometryAttribute_GeometryAttribute_0.apply(null,
|
||||
arguments)},jc=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return a.asm.emscripten_bind_GeometryAttribute___destroy___0.apply(null,arguments)},ab=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=function(){return a.asm.emscripten_bind_DecoderBuffer_DecoderBuffer_0.apply(null,arguments)},kc=a._emscripten_bind_DecoderBuffer_Init_2=function(){return a.asm.emscripten_bind_DecoderBuffer_Init_2.apply(null,arguments)},lc=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return a.asm.emscripten_bind_DecoderBuffer___destroy___0.apply(null,
|
||||
arguments)},bb=a._emscripten_bind_Decoder_Decoder_0=function(){return a.asm.emscripten_bind_Decoder_Decoder_0.apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetEncodedGeometryType_1=function(){return a.asm.emscripten_bind_Decoder_GetEncodedGeometryType_1.apply(null,arguments)},nc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return a.asm.emscripten_bind_Decoder_DecodeBufferToPointCloud_2.apply(null,arguments)},oc=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return a.asm.emscripten_bind_Decoder_DecodeBufferToMesh_2.apply(null,
|
||||
arguments)},pc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeId_2.apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeIdByName_2.apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3.apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetAttribute_2=
|
||||
function(){return a.asm.emscripten_bind_Decoder_GetAttribute_2.apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeByUniqueId_2.apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return a.asm.emscripten_bind_Decoder_GetMetadata_1.apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return a.asm.emscripten_bind_Decoder_GetAttributeMetadata_2.apply(null,
|
||||
arguments)},wc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=function(){return a.asm.emscripten_bind_Decoder_GetFaceFromMesh_3.apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return a.asm.emscripten_bind_Decoder_GetTriangleStripsFromMesh_2.apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return a.asm.emscripten_bind_Decoder_GetTrianglesUInt16Array_3.apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=
|
||||
function(){return a.asm.emscripten_bind_Decoder_GetTrianglesUInt32Array_3.apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeFloat_3.apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3.apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeIntForAllPoints_3.apply(null,
|
||||
arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3.apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3.apply(null,arguments)},Fc=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3.apply(null,arguments)},
|
||||
Gc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3.apply(null,arguments)},Hc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3.apply(null,arguments)},Ic=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return a.asm.emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3.apply(null,arguments)},Jc=
|
||||
a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return a.asm.emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5.apply(null,arguments)},Kc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return a.asm.emscripten_bind_Decoder_SkipAttributeTransform_1.apply(null,arguments)},Lc=a._emscripten_bind_Decoder___destroy___0=function(){return a.asm.emscripten_bind_Decoder___destroy___0.apply(null,arguments)},cb=a._emscripten_bind_Mesh_Mesh_0=function(){return a.asm.emscripten_bind_Mesh_Mesh_0.apply(null,
|
||||
arguments)},Mc=a._emscripten_bind_Mesh_num_faces_0=function(){return a.asm.emscripten_bind_Mesh_num_faces_0.apply(null,arguments)},Nc=a._emscripten_bind_Mesh_num_attributes_0=function(){return a.asm.emscripten_bind_Mesh_num_attributes_0.apply(null,arguments)},Oc=a._emscripten_bind_Mesh_num_points_0=function(){return a.asm.emscripten_bind_Mesh_num_points_0.apply(null,arguments)},Pc=a._emscripten_bind_Mesh___destroy___0=function(){return a.asm.emscripten_bind_Mesh___destroy___0.apply(null,arguments)},
|
||||
Qc=a._emscripten_bind_VoidPtr___destroy___0=function(){return a.asm.emscripten_bind_VoidPtr___destroy___0.apply(null,arguments)},db=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=function(){return a.asm.emscripten_bind_DracoInt32Array_DracoInt32Array_0.apply(null,arguments)},Rc=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return a.asm.emscripten_bind_DracoInt32Array_GetValue_1.apply(null,arguments)},Sc=a._emscripten_bind_DracoInt32Array_size_0=function(){return a.asm.emscripten_bind_DracoInt32Array_size_0.apply(null,
|
||||
arguments)},Tc=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return a.asm.emscripten_bind_DracoInt32Array___destroy___0.apply(null,arguments)},eb=a._emscripten_bind_Metadata_Metadata_0=function(){return a.asm.emscripten_bind_Metadata_Metadata_0.apply(null,arguments)},Uc=a._emscripten_bind_Metadata___destroy___0=function(){return a.asm.emscripten_bind_Metadata___destroy___0.apply(null,arguments)},Vc=a._emscripten_enum_draco_StatusCode_OK=function(){return a.asm.emscripten_enum_draco_StatusCode_OK.apply(null,
|
||||
arguments)},Wc=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return a.asm.emscripten_enum_draco_StatusCode_DRACO_ERROR.apply(null,arguments)},Xc=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return a.asm.emscripten_enum_draco_StatusCode_IO_ERROR.apply(null,arguments)},Yc=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=function(){return a.asm.emscripten_enum_draco_StatusCode_INVALID_PARAMETER.apply(null,arguments)},Zc=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=
|
||||
function(){return a.asm.emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION.apply(null,arguments)},$c=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return a.asm.emscripten_enum_draco_StatusCode_UNKNOWN_VERSION.apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return a.asm.emscripten_enum_draco_DataType_DT_INVALID.apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT8=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT8.apply(null,
|
||||
arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT8=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT8.apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT16=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT16.apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT16.apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT32.apply(null,
|
||||
arguments)},gd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT32.apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return a.asm.emscripten_enum_draco_DataType_DT_INT64.apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return a.asm.emscripten_enum_draco_DataType_DT_UINT64.apply(null,arguments)},jd=a._emscripten_enum_draco_DataType_DT_FLOAT32=function(){return a.asm.emscripten_enum_draco_DataType_DT_FLOAT32.apply(null,
|
||||
arguments)},kd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return a.asm.emscripten_enum_draco_DataType_DT_FLOAT64.apply(null,arguments)},ld=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return a.asm.emscripten_enum_draco_DataType_DT_BOOL.apply(null,arguments)},md=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return a.asm.emscripten_enum_draco_DataType_DT_TYPES_COUNT.apply(null,arguments)},nd=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return a.asm.emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE.apply(null,
|
||||
arguments)},od=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return a.asm.emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD.apply(null,arguments)},pd=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return a.asm.emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH.apply(null,arguments)},qd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM.apply(null,
|
||||
arguments)},rd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM.apply(null,arguments)},sd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM.apply(null,arguments)},td=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return a.asm.emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM.apply(null,
|
||||
arguments)},ud=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_INVALID.apply(null,arguments)},vd=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_POSITION.apply(null,arguments)},wd=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_NORMAL.apply(null,arguments)},xd=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=
|
||||
function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_COLOR.apply(null,arguments)},yd=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD.apply(null,arguments)},zd=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return a.asm.emscripten_enum_draco_GeometryAttribute_Type_GENERIC.apply(null,arguments)};a._setThrew=function(){return a.asm.setThrew.apply(null,arguments)};var ta=a.__ZSt18uncaught_exceptionv=
|
||||
function(){return a.asm._ZSt18uncaught_exceptionv.apply(null,arguments)};a._free=function(){return a.asm.free.apply(null,arguments)};var ib=a._malloc=function(){return a.asm.malloc.apply(null,arguments)};a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,arguments)};a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)};a.__growWasmMemory=function(){return a.asm.__growWasmMemory.apply(null,arguments)};
|
||||
a.dynCall_ii=function(){return a.asm.dynCall_ii.apply(null,arguments)};a.dynCall_vi=function(){return a.asm.dynCall_vi.apply(null,arguments)};a.dynCall_iii=function(){return a.asm.dynCall_iii.apply(null,arguments)};a.dynCall_vii=function(){return a.asm.dynCall_vii.apply(null,arguments)};a.dynCall_iiii=function(){return a.asm.dynCall_iiii.apply(null,arguments)};a.dynCall_v=function(){return a.asm.dynCall_v.apply(null,arguments)};a.dynCall_viii=function(){return a.asm.dynCall_viii.apply(null,arguments)};
|
||||
a.dynCall_viiii=function(){return a.asm.dynCall_viiii.apply(null,arguments)};a.dynCall_iiiiiii=function(){return a.asm.dynCall_iiiiiii.apply(null,arguments)};a.dynCall_iidiiii=function(){return a.asm.dynCall_iidiiii.apply(null,arguments)};a.dynCall_jiji=function(){return a.asm.dynCall_jiji.apply(null,arguments)};a.dynCall_viiiiii=function(){return a.asm.dynCall_viiiiii.apply(null,arguments)};a.dynCall_viiiii=function(){return a.asm.dynCall_viiiii.apply(null,arguments)};a.asm=La;var fa;a.then=function(e){if(fa)e(a);
|
||||
else{var c=a.onRuntimeInitialized;a.onRuntimeInitialized=function(){c&&c();e(a)}}return a};ja=function c(){fa||ma();fa||(ja=c)};a.run=ma;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();ma();p.prototype=Object.create(p.prototype);p.prototype.constructor=p;p.prototype.__class__=p;p.__cache__={};a.WrapperObject=p;a.getCache=u;a.wrapPointer=N;a.castObject=function(a,b){return N(a.ptr,b)};a.NULL=N(0);a.destroy=function(a){if(!a.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";
|
||||
a.__destroy__();delete u(a.__class__)[a.ptr]};a.compare=function(a,b){return a.ptr===b.ptr};a.getPointer=function(a){return a.ptr};a.getClass=function(a){return a.__class__};var n={buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(n.needed){for(var c=0;c<n.temps.length;c++)a._free(n.temps[c]);n.temps.length=0;a._free(n.buffer);n.buffer=0;n.size+=n.needed;n.needed=0}n.buffer||(n.size+=128,n.buffer=a._malloc(n.size),t(n.buffer));n.pos=0},alloc:function(c,b){t(n.buffer);c=c.length*b.BYTES_PER_ELEMENT;
|
||||
c=c+7&-8;n.pos+c>=n.size?(t(0<c),n.needed+=c,b=a._malloc(c),n.temps.push(b)):(b=n.buffer+n.pos,n.pos+=c);return b},copy:function(a,b,d){switch(b.BYTES_PER_ELEMENT){case 2:d>>=1;break;case 4:d>>=2;break;case 8:d>>=3}for(var c=0;c<a.length;c++)b[d+c]=a[c]}};x.prototype=Object.create(p.prototype);x.prototype.constructor=x;x.prototype.__class__=x;x.__cache__={};a.Status=x;x.prototype.code=x.prototype.code=function(){return jb(this.ptr)};x.prototype.ok=x.prototype.ok=function(){return!!kb(this.ptr)};x.prototype.error_msg=
|
||||
x.prototype.error_msg=function(){return X(lb(this.ptr))};x.prototype.__destroy__=x.prototype.__destroy__=function(){mb(this.ptr)};A.prototype=Object.create(p.prototype);A.prototype.constructor=A;A.prototype.__class__=A;A.__cache__={};a.DracoUInt16Array=A;A.prototype.GetValue=A.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return nb(c,a)};A.prototype.size=A.prototype.size=function(){return ob(this.ptr)};A.prototype.__destroy__=A.prototype.__destroy__=function(){pb(this.ptr)};
|
||||
B.prototype=Object.create(p.prototype);B.prototype.constructor=B;B.prototype.__class__=B;B.__cache__={};a.PointCloud=B;B.prototype.num_attributes=B.prototype.num_attributes=function(){return qb(this.ptr)};B.prototype.num_points=B.prototype.num_points=function(){return rb(this.ptr)};B.prototype.__destroy__=B.prototype.__destroy__=function(){sb(this.ptr)};C.prototype=Object.create(p.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.DracoUInt8Array=C;C.prototype.GetValue=
|
||||
C.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return tb(c,a)};C.prototype.size=C.prototype.size=function(){return ub(this.ptr)};C.prototype.__destroy__=C.prototype.__destroy__=function(){vb(this.ptr)};D.prototype=Object.create(p.prototype);D.prototype.constructor=D;D.prototype.__class__=D;D.__cache__={};a.DracoUInt32Array=D;D.prototype.GetValue=D.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return wb(c,a)};D.prototype.size=D.prototype.size=
|
||||
function(){return xb(this.ptr)};D.prototype.__destroy__=D.prototype.__destroy__=function(){yb(this.ptr)};E.prototype=Object.create(p.prototype);E.prototype.constructor=E;E.prototype.__class__=E;E.__cache__={};a.AttributeOctahedronTransform=E;E.prototype.InitFromAttribute=E.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!zb(c,a)};E.prototype.quantization_bits=E.prototype.quantization_bits=function(){return Ab(this.ptr)};E.prototype.__destroy__=E.prototype.__destroy__=
|
||||
function(){Bb(this.ptr)};q.prototype=Object.create(p.prototype);q.prototype.constructor=q;q.prototype.__class__=q;q.__cache__={};a.PointAttribute=q;q.prototype.size=q.prototype.size=function(){return Cb(this.ptr)};q.prototype.GetAttributeTransformData=q.prototype.GetAttributeTransformData=function(){return N(Db(this.ptr),J)};q.prototype.attribute_type=q.prototype.attribute_type=function(){return Eb(this.ptr)};q.prototype.data_type=q.prototype.data_type=function(){return Fb(this.ptr)};q.prototype.num_components=
|
||||
q.prototype.num_components=function(){return Gb(this.ptr)};q.prototype.normalized=q.prototype.normalized=function(){return!!Hb(this.ptr)};q.prototype.byte_stride=q.prototype.byte_stride=function(){return Ib(this.ptr)};q.prototype.byte_offset=q.prototype.byte_offset=function(){return Jb(this.ptr)};q.prototype.unique_id=q.prototype.unique_id=function(){return Kb(this.ptr)};q.prototype.__destroy__=q.prototype.__destroy__=function(){Lb(this.ptr)};J.prototype=Object.create(p.prototype);J.prototype.constructor=
|
||||
J;J.prototype.__class__=J;J.__cache__={};a.AttributeTransformData=J;J.prototype.transform_type=J.prototype.transform_type=function(){return Mb(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){Nb(this.ptr)};w.prototype=Object.create(p.prototype);w.prototype.constructor=w;w.prototype.__class__=w;w.__cache__={};a.AttributeQuantizationTransform=w;w.prototype.InitFromAttribute=w.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!Ob(c,a)};
|
||||
w.prototype.quantization_bits=w.prototype.quantization_bits=function(){return Pb(this.ptr)};w.prototype.min_value=w.prototype.min_value=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Qb(c,a)};w.prototype.range=w.prototype.range=function(){return Rb(this.ptr)};w.prototype.__destroy__=w.prototype.__destroy__=function(){Sb(this.ptr)};F.prototype=Object.create(p.prototype);F.prototype.constructor=F;F.prototype.__class__=F;F.__cache__={};a.DracoInt8Array=F;F.prototype.GetValue=F.prototype.GetValue=
|
||||
function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Tb(c,a)};F.prototype.size=F.prototype.size=function(){return Ub(this.ptr)};F.prototype.__destroy__=F.prototype.__destroy__=function(){Vb(this.ptr)};r.prototype=Object.create(p.prototype);r.prototype.constructor=r;r.prototype.__class__=r;r.__cache__={};a.MetadataQuerier=r;r.prototype.HasEntry=r.prototype.HasEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return!!Wb(c,
|
||||
a,b)};r.prototype.GetIntEntry=r.prototype.GetIntEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return Xb(c,a,b)};r.prototype.GetIntEntryArray=r.prototype.GetIntEntryArray=function(a,b,d){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);d&&"object"===typeof d&&(d=d.ptr);Yb(c,a,b,d)};r.prototype.GetDoubleEntry=r.prototype.GetDoubleEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===
|
||||
typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return Zb(c,a,b)};r.prototype.GetStringEntry=r.prototype.GetStringEntry=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return X($b(c,a,b))};r.prototype.NumEntries=r.prototype.NumEntries=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return ac(c,a)};r.prototype.GetEntryName=r.prototype.GetEntryName=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===
|
||||
typeof b&&(b=b.ptr);return X(bc(c,a,b))};r.prototype.__destroy__=r.prototype.__destroy__=function(){cc(this.ptr)};G.prototype=Object.create(p.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.DracoInt16Array=G;G.prototype.GetValue=G.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return dc(c,a)};G.prototype.size=G.prototype.size=function(){return ec(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){fc(this.ptr)};H.prototype=
|
||||
Object.create(p.prototype);H.prototype.constructor=H;H.prototype.__class__=H;H.__cache__={};a.DracoFloat32Array=H;H.prototype.GetValue=H.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return gc(c,a)};H.prototype.size=H.prototype.size=function(){return hc(this.ptr)};H.prototype.__destroy__=H.prototype.__destroy__=function(){ic(this.ptr)};O.prototype=Object.create(p.prototype);O.prototype.constructor=O;O.prototype.__class__=O;O.__cache__={};a.GeometryAttribute=O;O.prototype.__destroy__=
|
||||
O.prototype.__destroy__=function(){jc(this.ptr)};K.prototype=Object.create(p.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.DecoderBuffer=K;K.prototype.Init=K.prototype.Init=function(a,b){var c=this.ptr;n.prepare();if("object"==typeof a&&"object"===typeof a){var e=n.alloc(a,T);n.copy(a,T,e);a=e}b&&"object"===typeof b&&(b=b.ptr);kc(c,a,b)};K.prototype.__destroy__=K.prototype.__destroy__=function(){lc(this.ptr)};g.prototype=Object.create(p.prototype);g.prototype.constructor=
|
||||
g;g.prototype.__class__=g;g.__cache__={};a.Decoder=g;g.prototype.GetEncodedGeometryType=g.prototype.GetEncodedGeometryType=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return mc(c,a)};g.prototype.DecodeBufferToPointCloud=g.prototype.DecodeBufferToPointCloud=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(nc(c,a,b),x)};g.prototype.DecodeBufferToMesh=g.prototype.DecodeBufferToMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&
|
||||
(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(oc(c,a,b),x)};g.prototype.GetAttributeId=g.prototype.GetAttributeId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return pc(c,a,b)};g.prototype.GetAttributeIdByName=g.prototype.GetAttributeIdByName=function(a,b){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);return qc(c,a,b)};g.prototype.GetAttributeIdByMetadataEntry=g.prototype.GetAttributeIdByMetadataEntry=
|
||||
function(a,b,d){var c=this.ptr;n.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:V(b);d=d&&"object"===typeof d?d.ptr:V(d);return rc(c,a,b,d)};g.prototype.GetAttribute=g.prototype.GetAttribute=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(sc(c,a,b),q)};g.prototype.GetAttributeByUniqueId=g.prototype.GetAttributeByUniqueId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);
|
||||
return N(tc(c,a,b),q)};g.prototype.GetMetadata=g.prototype.GetMetadata=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return N(uc(c,a),L)};g.prototype.GetAttributeMetadata=g.prototype.GetAttributeMetadata=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return N(vc(c,a,b),L)};g.prototype.GetFaceFromMesh=g.prototype.GetFaceFromMesh=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===
|
||||
typeof d&&(d=d.ptr);return!!wc(c,a,b,d)};g.prototype.GetTriangleStripsFromMesh=g.prototype.GetTriangleStripsFromMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return xc(c,a,b)};g.prototype.GetTrianglesUInt16Array=g.prototype.GetTrianglesUInt16Array=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!yc(c,a,b,d)};g.prototype.GetTrianglesUInt32Array=g.prototype.GetTrianglesUInt32Array=
|
||||
function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!zc(c,a,b,d)};g.prototype.GetAttributeFloat=g.prototype.GetAttributeFloat=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ac(c,a,b,d)};g.prototype.GetAttributeFloatForAllPoints=g.prototype.GetAttributeFloatForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&
|
||||
(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Bc(c,a,b,d)};g.prototype.GetAttributeIntForAllPoints=g.prototype.GetAttributeIntForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Cc(c,a,b,d)};g.prototype.GetAttributeInt8ForAllPoints=g.prototype.GetAttributeInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&
|
||||
(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Dc(c,a,b,d)};g.prototype.GetAttributeUInt8ForAllPoints=g.prototype.GetAttributeUInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ec(c,a,b,d)};g.prototype.GetAttributeInt16ForAllPoints=g.prototype.GetAttributeInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&
|
||||
(d=d.ptr);return!!Fc(c,a,b,d)};g.prototype.GetAttributeUInt16ForAllPoints=g.prototype.GetAttributeUInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Gc(c,a,b,d)};g.prototype.GetAttributeInt32ForAllPoints=g.prototype.GetAttributeInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Hc(c,
|
||||
a,b,d)};g.prototype.GetAttributeUInt32ForAllPoints=g.prototype.GetAttributeUInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ic(c,a,b,d)};g.prototype.GetAttributeDataArrayForAllPoints=g.prototype.GetAttributeDataArrayForAllPoints=function(a,b,d,e,f){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);e&&"object"===typeof e&&
|
||||
(e=e.ptr);f&&"object"===typeof f&&(f=f.ptr);return!!Jc(c,a,b,d,e,f)};g.prototype.SkipAttributeTransform=g.prototype.SkipAttributeTransform=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);Kc(b,a)};g.prototype.__destroy__=g.prototype.__destroy__=function(){Lc(this.ptr)};y.prototype=Object.create(p.prototype);y.prototype.constructor=y;y.prototype.__class__=y;y.__cache__={};a.Mesh=y;y.prototype.num_faces=y.prototype.num_faces=function(){return Mc(this.ptr)};y.prototype.num_attributes=y.prototype.num_attributes=
|
||||
function(){return Nc(this.ptr)};y.prototype.num_points=y.prototype.num_points=function(){return Oc(this.ptr)};y.prototype.__destroy__=y.prototype.__destroy__=function(){Pc(this.ptr)};Q.prototype=Object.create(p.prototype);Q.prototype.constructor=Q;Q.prototype.__class__=Q;Q.__cache__={};a.VoidPtr=Q;Q.prototype.__destroy__=Q.prototype.__destroy__=function(){Qc(this.ptr)};I.prototype=Object.create(p.prototype);I.prototype.constructor=I;I.prototype.__class__=I;I.__cache__={};a.DracoInt32Array=I;I.prototype.GetValue=
|
||||
I.prototype.GetValue=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Rc(b,a)};I.prototype.size=I.prototype.size=function(){return Sc(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){Tc(this.ptr)};L.prototype=Object.create(p.prototype);L.prototype.constructor=L;L.prototype.__class__=L;L.__cache__={};a.Metadata=L;L.prototype.__destroy__=L.prototype.__destroy__=function(){Uc(this.ptr)};(function(){function c(){a.OK=Vc();a.DRACO_ERROR=Wc();a.IO_ERROR=Xc();a.INVALID_PARAMETER=
|
||||
Yc();a.UNSUPPORTED_VERSION=Zc();a.UNKNOWN_VERSION=$c();a.DT_INVALID=ad();a.DT_INT8=bd();a.DT_UINT8=cd();a.DT_INT16=dd();a.DT_UINT16=ed();a.DT_INT32=fd();a.DT_UINT32=gd();a.DT_INT64=hd();a.DT_UINT64=id();a.DT_FLOAT32=jd();a.DT_FLOAT64=kd();a.DT_BOOL=ld();a.DT_TYPES_COUNT=md();a.INVALID_GEOMETRY_TYPE=nd();a.POINT_CLOUD=od();a.TRIANGULAR_MESH=pd();a.ATTRIBUTE_INVALID_TRANSFORM=qd();a.ATTRIBUTE_NO_TRANSFORM=rd();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=sd();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=td();a.INVALID=ud();
|
||||
a.POSITION=vd();a.NORMAL=wd();a.COLOR=xd();a.TEX_COORD=yd();a.GENERIC=zd()}Ba?c():Da.unshift(c)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();return m}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule);
|
|
@ -4,7 +4,13 @@ import {
|
|||
PublicKey,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import { utils, actions, models, findProgramAddress } from '@oyster/common';
|
||||
import {
|
||||
utils,
|
||||
actions,
|
||||
models,
|
||||
findProgramAddress,
|
||||
MetadataKey,
|
||||
} from '@oyster/common';
|
||||
|
||||
import { AccountLayout } from '@solana/spl-token';
|
||||
import BN from 'bn.js';
|
||||
|
@ -81,7 +87,10 @@ export async function addTokensToVault(
|
|||
currSigners.push(transferAuthority);
|
||||
|
||||
await addTokenToInactiveVault(
|
||||
nft.amount,
|
||||
nft.draft.masterEdition &&
|
||||
nft.draft.masterEdition.info.key === MetadataKey.MasterEditionV2
|
||||
? new BN(1)
|
||||
: nft.amount,
|
||||
nft.tokenMint,
|
||||
nft.tokenAccount,
|
||||
newStoreAccount,
|
||||
|
|
|
@ -7,6 +7,8 @@ import {
|
|||
AuctionState,
|
||||
SequenceType,
|
||||
sendTransactions,
|
||||
ParsedAccount,
|
||||
BidderMetadata,
|
||||
} from '@oyster/common';
|
||||
import { AccountLayout } from '@solana/spl-token';
|
||||
import {
|
||||
|
@ -16,6 +18,8 @@ import {
|
|||
PublicKey,
|
||||
} from '@solana/web3.js';
|
||||
import { AuctionView } from '../hooks';
|
||||
import { BidRedemptionTicket, PrizeTrackingTicket } from '../models/metaplex';
|
||||
import { claimUnusedPrizes } from './claimUnusedPrizes';
|
||||
import { setupPlaceBid } from './sendPlaceBid';
|
||||
|
||||
export async function sendCancelBid(
|
||||
|
@ -24,6 +28,9 @@ export async function sendCancelBid(
|
|||
payingAccount: PublicKey,
|
||||
auctionView: AuctionView,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
bids: ParsedAccount<BidderMetadata>[],
|
||||
bidRedemptions: Record<string, ParsedAccount<BidRedemptionTicket>>,
|
||||
prizeTrackingTickets: Record<string, ParsedAccount<PrizeTrackingTicket>>,
|
||||
) {
|
||||
let signers: Array<Keypair[]> = [];
|
||||
let instructions: Array<TransactionInstruction[]> = [];
|
||||
|
@ -56,6 +63,23 @@ export async function sendCancelBid(
|
|||
instructions,
|
||||
);
|
||||
|
||||
if (
|
||||
wallet?.publicKey?.equals(auctionView.auctionManager.info.authority) &&
|
||||
auctionView.auction.info.ended()
|
||||
) {
|
||||
await claimUnusedPrizes(
|
||||
connection,
|
||||
wallet,
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
bids,
|
||||
bidRedemptions,
|
||||
prizeTrackingTickets,
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
}
|
||||
|
||||
instructions.length === 1
|
||||
? await sendTransactionWithRetry(
|
||||
connection,
|
||||
|
|
|
@ -9,34 +9,152 @@ import {
|
|||
ParsedAccount,
|
||||
TokenAccount,
|
||||
SafetyDepositBox,
|
||||
getReservationList,
|
||||
deprecatedGetReservationList,
|
||||
MasterEditionV1,
|
||||
MasterEditionV2,
|
||||
findProgramAddress,
|
||||
programIds,
|
||||
createAssociatedTokenAccountInstruction,
|
||||
MetadataKey,
|
||||
BidderMetadata,
|
||||
} from '@oyster/common';
|
||||
|
||||
import { AccountLayout } from '@solana/spl-token';
|
||||
import { AccountLayout, MintLayout } from '@solana/spl-token';
|
||||
import { AuctionView, AuctionViewItem } from '../hooks';
|
||||
import {
|
||||
WinningConfigType,
|
||||
redeemBid,
|
||||
redeemFullRightsTransferBid,
|
||||
WinningConfigStateItem,
|
||||
withdrawMasterEdition,
|
||||
BidRedemptionTicket,
|
||||
getBidRedemption,
|
||||
WinningConfigItem,
|
||||
PrizeTrackingTicket,
|
||||
} from '../models/metaplex';
|
||||
import {
|
||||
eligibleForParticipationPrizeGivenWinningIndex,
|
||||
setupRedeemParticipationInstructions,
|
||||
setupRedeemPrintingV2Instructions,
|
||||
} from './sendRedeemBid';
|
||||
const { createTokenAccount } = actions;
|
||||
|
||||
export async function findEligibleParticipationBidsForRedemption(
|
||||
auctionView: AuctionView,
|
||||
bids: ParsedAccount<BidderMetadata>[],
|
||||
bidRedemptions: Record<string, ParsedAccount<BidRedemptionTicket>>,
|
||||
): Promise<
|
||||
{
|
||||
bid: ParsedAccount<BidderMetadata>;
|
||||
bidRedemption: ParsedAccount<BidRedemptionTicket>;
|
||||
}[]
|
||||
> {
|
||||
const unredeemedParticipations: {
|
||||
bid: ParsedAccount<BidderMetadata>;
|
||||
bidRedemption: ParsedAccount<BidRedemptionTicket>;
|
||||
}[] = [];
|
||||
for (let i = 0; i < bids.length; i++) {
|
||||
const bid = bids[i];
|
||||
if (!bid.info.cancelled) {
|
||||
const winnerIndex = auctionView.auction.info.bidState.getWinnerIndex(
|
||||
bid.info.bidderPubkey,
|
||||
);
|
||||
const bidRedemption =
|
||||
bidRedemptions[
|
||||
(
|
||||
await getBidRedemption(auctionView.auction.pubkey, bid.pubkey)
|
||||
).toBase58()
|
||||
];
|
||||
const eligible = eligibleForParticipationPrizeGivenWinningIndex(
|
||||
winnerIndex,
|
||||
auctionView,
|
||||
bid,
|
||||
bidRedemption,
|
||||
);
|
||||
console.log(bid.pubkey.toBase58(), 'eligible?', eligible);
|
||||
if (eligible) {
|
||||
unredeemedParticipations.push({ bid, bidRedemption });
|
||||
}
|
||||
}
|
||||
}
|
||||
return unredeemedParticipations;
|
||||
}
|
||||
|
||||
export async function claimUnusedPrizes(
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
auctionView: AuctionView,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
bids: ParsedAccount<BidderMetadata>[],
|
||||
bidRedemptions: Record<string, ParsedAccount<BidRedemptionTicket>>,
|
||||
prizeTrackingTickets: Record<string, ParsedAccount<PrizeTrackingTicket>>,
|
||||
signers: Array<Keypair[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
AccountLayout.span,
|
||||
);
|
||||
const mintRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
MintLayout.span,
|
||||
);
|
||||
|
||||
if (
|
||||
auctionView.participationItem &&
|
||||
auctionView.participationItem.safetyDeposit &&
|
||||
auctionView.participationItem.masterEdition?.info.key ==
|
||||
MetadataKey.MasterEditionV2
|
||||
) {
|
||||
const balance = await connection.getTokenAccountBalance(
|
||||
auctionView.participationItem.safetyDeposit.info.store,
|
||||
);
|
||||
if (balance.value.uiAmount || 0 > 0) {
|
||||
// before we can redeem, check if we need to print other people's stuff.
|
||||
|
||||
const unredeemedParticipations =
|
||||
await findEligibleParticipationBidsForRedemption(
|
||||
auctionView,
|
||||
bids,
|
||||
bidRedemptions,
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
unredeemedParticipations.map(
|
||||
p =>
|
||||
auctionView.participationItem &&
|
||||
setupRedeemParticipationInstructions(
|
||||
connection,
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
accountRentExempt,
|
||||
mintRentExempt,
|
||||
wallet,
|
||||
p.bid.info.bidderPubkey,
|
||||
auctionView.participationItem.safetyDeposit,
|
||||
p.bidRedemption,
|
||||
p.bid,
|
||||
auctionView.participationItem,
|
||||
signers,
|
||||
instructions,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await setupWithdrawMasterEditionInstructions(
|
||||
connection,
|
||||
auctionView,
|
||||
wallet,
|
||||
auctionView.participationItem.safetyDeposit,
|
||||
auctionView.participationItem,
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let printingV2ByMint: Record<string, AuctionViewItem> = {};
|
||||
|
||||
for (
|
||||
let winnerIndex = auctionView.auction.info.bidState.bids.length;
|
||||
let winnerIndex = 0;
|
||||
winnerIndex <
|
||||
auctionView.auctionManager.info.settings.winningConfigs.length;
|
||||
winnerIndex++
|
||||
|
@ -47,16 +165,26 @@ export async function claimUnusedPrizes(
|
|||
|
||||
for (let i = 0; i < winningSet.length; i++) {
|
||||
const item = winningSet[i];
|
||||
|
||||
const safetyDeposit = item.safetyDeposit;
|
||||
const tokenBalance = await connection.getTokenAccountBalance(
|
||||
safetyDeposit.info.store,
|
||||
);
|
||||
// If box is empty, we cant redeem this. Could be broken AM we are claiming against.
|
||||
if (tokenBalance.value.uiAmount === 0) continue;
|
||||
if (tokenBalance.value.uiAmount === 0) {
|
||||
console.log('Skipping', i, ' due to empty balance');
|
||||
continue;
|
||||
}
|
||||
// In principle it is possible to have two winning config items of same safety deposit box
|
||||
// so we cover for that possibility by doing an array not a find
|
||||
for (let j = 0; j < winningConfig.items.length; j++) {
|
||||
const winningConfigItem = winningConfig.items[j];
|
||||
if (
|
||||
winnerIndex < auctionView.auction.info.bidState.bids.length &&
|
||||
winningConfigItem.winningConfigType != WinningConfigType.PrintingV2
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
winningConfigItem.safetyDepositBoxIndex === safetyDeposit.info.order
|
||||
|
@ -66,11 +194,11 @@ export async function claimUnusedPrizes(
|
|||
winnerIndex
|
||||
].items[j];
|
||||
switch (winningConfigItem.winningConfigType) {
|
||||
case WinningConfigType.Printing:
|
||||
case WinningConfigType.PrintingV1:
|
||||
console.log(
|
||||
'Redeeming printing same way we redeem a normal bid because we arent printing it',
|
||||
'Redeeming printing v1 same way we redeem a normal bid because we arent printing it',
|
||||
);
|
||||
await setupRedeemPrintingInstructions(
|
||||
await deprecatedSetupRedeemPrintingInstructions(
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
accountRentExempt,
|
||||
|
@ -83,6 +211,37 @@ export async function claimUnusedPrizes(
|
|||
winnerIndex,
|
||||
);
|
||||
break;
|
||||
case WinningConfigType.PrintingV2:
|
||||
const winningBidder =
|
||||
auctionView.auction.info.bidState.getWinnerAt(winnerIndex);
|
||||
if (winningBidder) {
|
||||
const bidderMetadata = bids.find(b =>
|
||||
b.info.bidderPubkey.equals(winningBidder),
|
||||
);
|
||||
if (bidderMetadata) {
|
||||
console.log(
|
||||
'Redeeming v2 for bid by wallet',
|
||||
winningBidder.toBase58(),
|
||||
);
|
||||
await setupRedeemPrintingV2Instructions(
|
||||
connection,
|
||||
auctionView,
|
||||
mintRentExempt,
|
||||
wallet,
|
||||
winningBidder,
|
||||
item.safetyDeposit,
|
||||
item,
|
||||
signers,
|
||||
instructions,
|
||||
winningConfigItem,
|
||||
stateItem,
|
||||
winnerIndex,
|
||||
prizeTrackingTickets,
|
||||
);
|
||||
}
|
||||
}
|
||||
printingV2ByMint[item.metadata.info.mint.toBase58()] = item;
|
||||
break;
|
||||
case WinningConfigType.FullRightsTransfer:
|
||||
console.log('Redeeming Full Rights');
|
||||
await setupRedeemFullRightsTransferInstructions(
|
||||
|
@ -117,6 +276,20 @@ export async function claimUnusedPrizes(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let allV2s = Object.values(printingV2ByMint);
|
||||
for (let i = 0; i < allV2s.length; i++) {
|
||||
let item = allV2s[i];
|
||||
await setupWithdrawMasterEditionInstructions(
|
||||
connection,
|
||||
auctionView,
|
||||
wallet,
|
||||
item.safetyDeposit,
|
||||
item,
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function setupRedeemInstructions(
|
||||
|
@ -213,7 +386,59 @@ async function setupRedeemFullRightsTransferInstructions(
|
|||
}
|
||||
}
|
||||
|
||||
async function setupRedeemPrintingInstructions(
|
||||
async function setupWithdrawMasterEditionInstructions(
|
||||
connection: Connection,
|
||||
auctionView: AuctionView,
|
||||
wallet: any,
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>,
|
||||
item: AuctionViewItem,
|
||||
signers: Array<Keypair[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
if (!item.masterEdition || !item.metadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
const myInstructions: TransactionInstruction[] = [];
|
||||
const mySigners: Keypair[] = [];
|
||||
const ata = (
|
||||
await findProgramAddress(
|
||||
[
|
||||
wallet.publicKey.toBuffer(),
|
||||
programIds().token.toBuffer(),
|
||||
item.metadata.info.mint.toBuffer(),
|
||||
],
|
||||
programIds().associatedToken,
|
||||
)
|
||||
)[0];
|
||||
|
||||
const existingAta = await connection.getAccountInfo(ata);
|
||||
console.log('Existing ata?', existingAta);
|
||||
if (!existingAta) {
|
||||
createAssociatedTokenAccountInstruction(
|
||||
myInstructions,
|
||||
ata,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
item.metadata.info.mint,
|
||||
);
|
||||
}
|
||||
|
||||
await withdrawMasterEdition(
|
||||
auctionView.vault.pubkey,
|
||||
safetyDeposit.info.store,
|
||||
ata,
|
||||
safetyDeposit.pubkey,
|
||||
auctionView.vault.info.fractionMint,
|
||||
item.metadata.info.mint,
|
||||
myInstructions,
|
||||
);
|
||||
|
||||
instructions.push(myInstructions);
|
||||
signers.push(mySigners);
|
||||
}
|
||||
|
||||
async function deprecatedSetupRedeemPrintingInstructions(
|
||||
auctionView: AuctionView,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
accountRentExempt: number,
|
||||
|
@ -229,15 +454,13 @@ async function setupRedeemPrintingInstructions(
|
|||
return;
|
||||
}
|
||||
const updateAuth = item.metadata.info.updateAuthority;
|
||||
|
||||
const reservationList = await getReservationList(
|
||||
const me = item.masterEdition as ParsedAccount<MasterEditionV1>;
|
||||
const reservationList = await deprecatedGetReservationList(
|
||||
item.masterEdition.pubkey,
|
||||
auctionView.auctionManager.pubkey,
|
||||
);
|
||||
|
||||
const newTokenAccount = accountsByMint.get(
|
||||
item.masterEdition.info.printingMint.toBase58(),
|
||||
);
|
||||
const newTokenAccount = accountsByMint.get(me.info.printingMint.toBase58());
|
||||
let newTokenAccountKey: PublicKey | undefined = newTokenAccount?.pubkey;
|
||||
|
||||
if (updateAuth) {
|
||||
|
@ -254,7 +477,7 @@ async function setupRedeemPrintingInstructions(
|
|||
winningPrizeInstructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
item.masterEdition.info.printingMint,
|
||||
me.info.printingMint,
|
||||
wallet.publicKey,
|
||||
winningPrizeSigner,
|
||||
);
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
import { Keypair, Connection, TransactionInstruction } from '@solana/web3.js';
|
||||
import {
|
||||
ParsedAccount,
|
||||
sendTransactions,
|
||||
SequenceType,
|
||||
sendTransactionWithRetry,
|
||||
Metadata,
|
||||
MasterEditionV1,
|
||||
MasterEditionV2,
|
||||
MetadataKey,
|
||||
convertMasterEditionV1ToV2,
|
||||
TokenAccount,
|
||||
programIds,
|
||||
} from '@oyster/common';
|
||||
import { Token } from '@solana/spl-token';
|
||||
const BATCH_SIZE = 10;
|
||||
const CONVERT_TRANSACTION_SIZE = 10;
|
||||
|
||||
export async function filterMetadata(
|
||||
connection: Connection,
|
||||
metadata: ParsedAccount<Metadata>[],
|
||||
masterEditions: Record<
|
||||
string,
|
||||
ParsedAccount<MasterEditionV1 | MasterEditionV2>
|
||||
>,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
): Promise<{
|
||||
available: ParsedAccount<MasterEditionV1>[];
|
||||
unavailable: ParsedAccount<MasterEditionV1>[];
|
||||
}> {
|
||||
const available = [];
|
||||
const unavailable = [];
|
||||
|
||||
for (let i = 0; i < metadata.length; i++) {
|
||||
const md = metadata[i];
|
||||
const masterEdition = masterEditions[
|
||||
md.info.masterEdition?.toBase58() || ''
|
||||
] as ParsedAccount<MasterEditionV1>;
|
||||
if (
|
||||
masterEdition &&
|
||||
masterEdition?.info.key == MetadataKey.MasterEditionV1
|
||||
) {
|
||||
console.log('Reviewing', masterEdition.pubkey.toBase58());
|
||||
let printingBal = 0;
|
||||
try {
|
||||
let printingBalResp = await connection.getTokenSupply(
|
||||
masterEdition.info.printingMint,
|
||||
);
|
||||
printingBal = printingBalResp.value.uiAmount || 0;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
const myAcct = accountsByMint.get(
|
||||
masterEdition.info.printingMint.toBase58(),
|
||||
);
|
||||
if (myAcct) {
|
||||
console.log(
|
||||
'Existing print account subtracts',
|
||||
myAcct.info.amount.toNumber(),
|
||||
'from',
|
||||
printingBal,
|
||||
);
|
||||
printingBal -= myAcct.info.amount.toNumber();
|
||||
}
|
||||
|
||||
if (printingBal > 0) {
|
||||
console.log(
|
||||
'Reject',
|
||||
masterEdition.pubkey.toBase58(),
|
||||
'due to printing bal of',
|
||||
printingBal,
|
||||
);
|
||||
unavailable.push(masterEdition);
|
||||
} else {
|
||||
let oneTimeBal = 0;
|
||||
try {
|
||||
let oneTimeBalResp = await connection.getTokenSupply(
|
||||
masterEdition.info.oneTimePrintingAuthorizationMint,
|
||||
);
|
||||
oneTimeBal = oneTimeBalResp.value.uiAmount || 0;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
const myAcct = accountsByMint.get(
|
||||
masterEdition.info.oneTimePrintingAuthorizationMint.toBase58(),
|
||||
);
|
||||
if (myAcct) {
|
||||
console.log(
|
||||
'Existing one time account subtracts',
|
||||
myAcct.info.amount.toNumber(),
|
||||
'from',
|
||||
oneTimeBal,
|
||||
);
|
||||
oneTimeBal -= myAcct.info.amount.toNumber();
|
||||
}
|
||||
|
||||
if (oneTimeBal > 0) {
|
||||
console.log(
|
||||
'Reject',
|
||||
masterEdition.pubkey.toBase58(),
|
||||
'due to one time auth bal of',
|
||||
oneTimeBal,
|
||||
);
|
||||
unavailable.push(masterEdition);
|
||||
} else {
|
||||
available.push(masterEdition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { available, unavailable };
|
||||
}
|
||||
// Given a vault you own, unwind all the tokens out of it.
|
||||
export async function convertMasterEditions(
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
masterEditions: ParsedAccount<MasterEditionV1>[],
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
) {
|
||||
const PROGRAM_IDS = programIds();
|
||||
let signers: Array<Array<Keypair[]>> = [];
|
||||
let instructions: Array<Array<TransactionInstruction[]>> = [];
|
||||
|
||||
let currSignerBatch: Array<Keypair[]> = [];
|
||||
let currInstrBatch: Array<TransactionInstruction[]> = [];
|
||||
|
||||
let convertSigners: Keypair[] = [];
|
||||
let convertInstructions: TransactionInstruction[] = [];
|
||||
|
||||
// TODO replace all this with payer account so user doesnt need to click approve several times.
|
||||
|
||||
for (let i = 0; i < masterEditions.length; i++) {
|
||||
const masterEdition = masterEditions[i] as ParsedAccount<MasterEditionV1>;
|
||||
|
||||
console.log('Converting', masterEdition.pubkey.toBase58());
|
||||
const printingMintAcct = accountsByMint.get(
|
||||
masterEdition.info.printingMint.toBase58(),
|
||||
);
|
||||
const oneTimeAuthMintAcct = accountsByMint.get(
|
||||
masterEdition.info.oneTimePrintingAuthorizationMint.toBase58(),
|
||||
);
|
||||
if (printingMintAcct) {
|
||||
if (printingMintAcct.info.amount.toNumber() > 0) {
|
||||
convertInstructions.push(
|
||||
Token.createBurnInstruction(
|
||||
PROGRAM_IDS.token,
|
||||
masterEdition.info.printingMint,
|
||||
printingMintAcct.pubkey,
|
||||
wallet.publicKey,
|
||||
[],
|
||||
printingMintAcct.info.amount,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
convertInstructions.push(
|
||||
Token.createCloseAccountInstruction(
|
||||
PROGRAM_IDS.token,
|
||||
printingMintAcct.pubkey,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
[],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (oneTimeAuthMintAcct) {
|
||||
if (oneTimeAuthMintAcct.info.amount.toNumber() > 0) {
|
||||
convertInstructions.push(
|
||||
Token.createBurnInstruction(
|
||||
PROGRAM_IDS.token,
|
||||
masterEdition.info.oneTimePrintingAuthorizationMint,
|
||||
oneTimeAuthMintAcct.pubkey,
|
||||
wallet.publicKey,
|
||||
[],
|
||||
oneTimeAuthMintAcct.info.amount,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
convertInstructions.push(
|
||||
Token.createCloseAccountInstruction(
|
||||
PROGRAM_IDS.token,
|
||||
oneTimeAuthMintAcct.pubkey,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
[],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await convertMasterEditionV1ToV2(
|
||||
masterEdition.pubkey,
|
||||
masterEdition.info.oneTimePrintingAuthorizationMint,
|
||||
masterEdition.info.printingMint,
|
||||
convertInstructions,
|
||||
);
|
||||
|
||||
if (convertInstructions.length === CONVERT_TRANSACTION_SIZE) {
|
||||
currSignerBatch.push(convertSigners);
|
||||
currInstrBatch.push(convertInstructions);
|
||||
convertSigners = [];
|
||||
convertInstructions = [];
|
||||
}
|
||||
|
||||
if (currInstrBatch.length === BATCH_SIZE) {
|
||||
signers.push(currSignerBatch);
|
||||
instructions.push(currInstrBatch);
|
||||
currSignerBatch = [];
|
||||
currInstrBatch = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
convertInstructions.length < CONVERT_TRANSACTION_SIZE &&
|
||||
convertInstructions.length > 0
|
||||
) {
|
||||
currSignerBatch.push(convertSigners);
|
||||
currInstrBatch.push(convertInstructions);
|
||||
}
|
||||
|
||||
if (currInstrBatch.length <= BATCH_SIZE && currInstrBatch.length > 0) {
|
||||
// add the last one on
|
||||
signers.push(currSignerBatch);
|
||||
instructions.push(currInstrBatch);
|
||||
}
|
||||
console.log('Instructions', instructions);
|
||||
for (let i = 0; i < instructions.length; i++) {
|
||||
const instructionBatch = instructions[i];
|
||||
const signerBatch = signers[i];
|
||||
console.log('Running batch', i);
|
||||
if (instructionBatch.length >= 2)
|
||||
// Pump em through!
|
||||
await sendTransactions(
|
||||
connection,
|
||||
wallet,
|
||||
instructionBatch,
|
||||
signerBatch,
|
||||
SequenceType.StopOnFailure,
|
||||
'single',
|
||||
);
|
||||
else
|
||||
await sendTransactionWithRetry(
|
||||
connection,
|
||||
wallet,
|
||||
instructionBatch[0],
|
||||
signerBatch[0],
|
||||
'single',
|
||||
);
|
||||
console.log('Done');
|
||||
}
|
||||
}
|
|
@ -8,7 +8,8 @@ import {
|
|||
actions,
|
||||
Metadata,
|
||||
ParsedAccount,
|
||||
MasterEdition,
|
||||
MasterEditionV1,
|
||||
MasterEditionV2,
|
||||
SequenceType,
|
||||
sendTransactions,
|
||||
getSafetyDepositBox,
|
||||
|
@ -21,6 +22,7 @@ import {
|
|||
sendTransactionWithRetry,
|
||||
findProgramAddress,
|
||||
IPartialCreateAuctionArgs,
|
||||
MetadataKey,
|
||||
} from '@oyster/common';
|
||||
|
||||
import { AccountLayout, Token } from '@solana/spl-token';
|
||||
|
@ -45,29 +47,27 @@ import {
|
|||
} from './addTokensToVault';
|
||||
import { makeAuction } from './makeAuction';
|
||||
import { createExternalPriceAccount } from './createExternalPriceAccount';
|
||||
import { validateParticipation } from '../models/metaplex/validateParticipation';
|
||||
import { createReservationListForTokens } from './createReservationListsForTokens';
|
||||
import { populatePrintingTokens } from './populatePrintingTokens';
|
||||
import { deprecatedValidateParticipation } from '../models/metaplex/deprecatedValidateParticipation';
|
||||
import { deprecatedCreateReservationListForTokens } from './deprecatedCreateReservationListsForTokens';
|
||||
import { deprecatedPopulatePrintingTokens } from './deprecatedPopulatePrintingTokens';
|
||||
import { setVaultAndAuctionAuthorities } from './setVaultAndAuctionAuthorities';
|
||||
import { markItemsThatArentMineAsSold } from './markItemsThatArentMineAsSold';
|
||||
const { createTokenAccount } = actions;
|
||||
|
||||
interface normalPattern {
|
||||
instructions: TransactionInstruction[];
|
||||
signers: Keypair[];
|
||||
}
|
||||
|
||||
interface arrayPattern {
|
||||
instructions: TransactionInstruction[][];
|
||||
signers: Keypair[][];
|
||||
}
|
||||
interface byType {
|
||||
addTokens: {
|
||||
instructions: Array<TransactionInstruction[]>;
|
||||
signers: Array<Keypair[]>;
|
||||
};
|
||||
createReservationList: {
|
||||
instructions: Array<TransactionInstruction[]>;
|
||||
signers: Array<Keypair[]>;
|
||||
};
|
||||
validateBoxes: {
|
||||
instructions: Array<TransactionInstruction[]>;
|
||||
signers: Array<Keypair[]>;
|
||||
};
|
||||
markItemsThatArentMineAsSold: arrayPattern;
|
||||
addTokens: arrayPattern;
|
||||
deprecatedCreateReservationList: arrayPattern;
|
||||
validateBoxes: arrayPattern;
|
||||
createVault: normalPattern;
|
||||
closeVault: normalPattern;
|
||||
makeAuction: normalPattern;
|
||||
|
@ -75,17 +75,14 @@ interface byType {
|
|||
startAuction: normalPattern;
|
||||
setVaultAndAuctionAuthorities: normalPattern;
|
||||
externalPriceAccount: normalPattern;
|
||||
validateParticipation?: normalPattern;
|
||||
buildAndPopulateOneTimeAuthorizationAccount?: normalPattern;
|
||||
populatePrintingTokens: {
|
||||
instructions: Array<TransactionInstruction[]>;
|
||||
signers: Array<Keypair[]>;
|
||||
};
|
||||
deprecatedValidateParticipation?: normalPattern;
|
||||
deprecatedBuildAndPopulateOneTimeAuthorizationAccount?: normalPattern;
|
||||
deprecatedPopulatePrintingTokens: arrayPattern;
|
||||
}
|
||||
|
||||
export interface SafetyDepositDraft {
|
||||
metadata: ParsedAccount<Metadata>;
|
||||
masterEdition?: ParsedAccount<MasterEdition>;
|
||||
masterEdition?: ParsedAccount<MasterEditionV1 | MasterEditionV2>;
|
||||
edition?: ParsedAccount<Edition>;
|
||||
holding: PublicKey;
|
||||
printingMintHolding?: PublicKey;
|
||||
|
@ -144,12 +141,12 @@ export async function createAuctionManager(
|
|||
settings.winningConfigs,
|
||||
);
|
||||
|
||||
// Note that
|
||||
// Only creates for PrintingV1 deprecated configs
|
||||
const {
|
||||
instructions: populateInstr,
|
||||
signers: populateSigners,
|
||||
safetyDepositConfigs,
|
||||
} = await populatePrintingTokens(
|
||||
} = await deprecatedPopulatePrintingTokens(
|
||||
connection,
|
||||
wallet,
|
||||
safetyDepositConfigsWithPotentiallyUnsetTokens,
|
||||
|
@ -174,10 +171,11 @@ export async function createAuctionManager(
|
|||
safetyDepositTokenStores,
|
||||
} = await addTokensToVault(connection, wallet, vault, safetyDepositConfigs);
|
||||
|
||||
// Only creates for deprecated PrintingV1 configs
|
||||
const {
|
||||
instructions: createReservationInstructions,
|
||||
signers: createReservationSigners,
|
||||
} = await createReservationListForTokens(
|
||||
} = await deprecatedCreateReservationListForTokens(
|
||||
wallet,
|
||||
auctionManager,
|
||||
settings,
|
||||
|
@ -185,6 +183,10 @@ export async function createAuctionManager(
|
|||
);
|
||||
|
||||
let lookup: byType = {
|
||||
markItemsThatArentMineAsSold: await markItemsThatArentMineAsSold(
|
||||
wallet,
|
||||
safetyDepositDrafts,
|
||||
),
|
||||
externalPriceAccount: {
|
||||
instructions: epaInstructions,
|
||||
signers: epaSigners,
|
||||
|
@ -204,7 +206,7 @@ export async function createAuctionManager(
|
|||
externalPriceAccount,
|
||||
),
|
||||
addTokens: { instructions: addTokenInstructions, signers: addTokenSigners },
|
||||
createReservationList: {
|
||||
deprecatedCreateReservationList: {
|
||||
instructions: createReservationInstructions,
|
||||
signers: createReservationSigners,
|
||||
},
|
||||
|
@ -223,8 +225,8 @@ export async function createAuctionManager(
|
|||
auctionManager,
|
||||
),
|
||||
startAuction: await setupStartAuction(wallet, vault),
|
||||
validateParticipation: participationSafetyDepositDraft
|
||||
? await validateParticipationHelper(
|
||||
deprecatedValidateParticipation: participationSafetyDepositDraft
|
||||
? await deprecatedValidateParticipationHelper(
|
||||
wallet,
|
||||
auctionManager,
|
||||
whitelistedCreatorsByCreator,
|
||||
|
@ -234,14 +236,16 @@ export async function createAuctionManager(
|
|||
accountRentExempt,
|
||||
)
|
||||
: undefined,
|
||||
buildAndPopulateOneTimeAuthorizationAccount: participationSafetyDepositDraft
|
||||
? await buildAndPopulateOneTimeAuthorizationAccount(
|
||||
connection,
|
||||
wallet,
|
||||
participationSafetyDepositDraft?.masterEdition?.info
|
||||
.oneTimePrintingAuthorizationMint,
|
||||
)
|
||||
: undefined,
|
||||
deprecatedBuildAndPopulateOneTimeAuthorizationAccount:
|
||||
participationSafetyDepositDraft
|
||||
? await deprecatedBuildAndPopulateOneTimeAuthorizationAccount(
|
||||
connection,
|
||||
wallet,
|
||||
(
|
||||
participationSafetyDepositDraft?.masterEdition as ParsedAccount<MasterEditionV1>
|
||||
)?.info.oneTimePrintingAuthorizationMint,
|
||||
)
|
||||
: undefined,
|
||||
validateBoxes: await validateBoxes(
|
||||
wallet,
|
||||
whitelistedCreatorsByCreator,
|
||||
|
@ -250,46 +254,55 @@ export async function createAuctionManager(
|
|||
safetyDepositConfigs.filter(
|
||||
c =>
|
||||
!participationSafetyDepositDraft ||
|
||||
c.draft.metadata.pubkey.toBase58() !==
|
||||
participationSafetyDepositDraft.metadata.pubkey.toBase58(),
|
||||
// Only V1s need to skip normal validation and use special endpoint
|
||||
(participationSafetyDepositDraft.masterEdition?.info.key ==
|
||||
MetadataKey.MasterEditionV1 &&
|
||||
!c.draft.metadata.pubkey.equals(
|
||||
participationSafetyDepositDraft.metadata.pubkey,
|
||||
)) ||
|
||||
participationSafetyDepositDraft.masterEdition?.info.key ==
|
||||
MetadataKey.MasterEditionV2,
|
||||
),
|
||||
safetyDepositTokenStores,
|
||||
settings,
|
||||
),
|
||||
populatePrintingTokens: {
|
||||
deprecatedPopulatePrintingTokens: {
|
||||
instructions: populateInstr,
|
||||
signers: populateSigners,
|
||||
},
|
||||
};
|
||||
|
||||
let signers: Keypair[][] = [
|
||||
...lookup.markItemsThatArentMineAsSold.signers,
|
||||
lookup.externalPriceAccount.signers,
|
||||
lookup.buildAndPopulateOneTimeAuthorizationAccount?.signers || [],
|
||||
...lookup.populatePrintingTokens.signers,
|
||||
lookup.deprecatedBuildAndPopulateOneTimeAuthorizationAccount?.signers || [],
|
||||
...lookup.deprecatedPopulatePrintingTokens.signers,
|
||||
lookup.createVault.signers,
|
||||
...lookup.addTokens.signers,
|
||||
...lookup.createReservationList.signers,
|
||||
...lookup.deprecatedCreateReservationList.signers,
|
||||
lookup.closeVault.signers,
|
||||
lookup.makeAuction.signers,
|
||||
lookup.initAuctionManager.signers,
|
||||
lookup.setVaultAndAuctionAuthorities.signers,
|
||||
lookup.validateParticipation?.signers || [],
|
||||
lookup.deprecatedValidateParticipation?.signers || [],
|
||||
...lookup.validateBoxes.signers,
|
||||
lookup.startAuction.signers,
|
||||
];
|
||||
const toRemoveSigners: Record<number, boolean> = {};
|
||||
let instructions: TransactionInstruction[][] = [
|
||||
...lookup.markItemsThatArentMineAsSold.instructions,
|
||||
lookup.externalPriceAccount.instructions,
|
||||
lookup.buildAndPopulateOneTimeAuthorizationAccount?.instructions || [],
|
||||
...lookup.populatePrintingTokens.instructions,
|
||||
lookup.deprecatedBuildAndPopulateOneTimeAuthorizationAccount
|
||||
?.instructions || [],
|
||||
...lookup.deprecatedPopulatePrintingTokens.instructions,
|
||||
lookup.createVault.instructions,
|
||||
...lookup.addTokens.instructions,
|
||||
...lookup.createReservationList.instructions,
|
||||
...lookup.deprecatedCreateReservationList.instructions,
|
||||
lookup.closeVault.instructions,
|
||||
lookup.makeAuction.instructions,
|
||||
lookup.initAuctionManager.instructions,
|
||||
lookup.setVaultAndAuctionAuthorities.instructions,
|
||||
lookup.validateParticipation?.instructions || [],
|
||||
lookup.deprecatedValidateParticipation?.instructions || [],
|
||||
...lookup.validateBoxes.instructions,
|
||||
lookup.startAuction.instructions,
|
||||
].filter((instr, i) => {
|
||||
|
@ -367,11 +380,12 @@ async function buildSafetyDepositArray(
|
|||
winningConfigs.forEach(ow => {
|
||||
ow.items.forEach(it => {
|
||||
if (it.safetyDepositBoxIndex === i) {
|
||||
if (it.winningConfigType !== WinningConfigType.Printing)
|
||||
if (it.winningConfigType !== WinningConfigType.PrintingV1) {
|
||||
nonPrintingConfigs.push(it);
|
||||
// we may also have an auction where we are selling prints of the master too as secondary prizes
|
||||
else if (it.winningConfigType === WinningConfigType.Printing)
|
||||
// we may also have an auction where we are selling prints of the master too as secondary prizes
|
||||
} else if (it.winningConfigType === WinningConfigType.PrintingV1) {
|
||||
printingConfigs.push(it);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -392,10 +406,14 @@ async function buildSafetyDepositArray(
|
|||
});
|
||||
}
|
||||
|
||||
if (printingTotal > 0 && w.masterEdition?.info.printingMint) {
|
||||
if (
|
||||
printingTotal > 0 &&
|
||||
(w.masterEdition as ParsedAccount<MasterEditionV1>)?.info.printingMint
|
||||
) {
|
||||
safetyDepositConfig.push({
|
||||
tokenAccount: w.printingMintHolding,
|
||||
tokenMint: w.masterEdition?.info.printingMint,
|
||||
tokenMint: (w.masterEdition as ParsedAccount<MasterEditionV1>)?.info
|
||||
.printingMint,
|
||||
amount: new BN(printingTotal),
|
||||
draft: w,
|
||||
});
|
||||
|
@ -406,23 +424,35 @@ async function buildSafetyDepositArray(
|
|||
participationSafetyDepositDraft &&
|
||||
participationSafetyDepositDraft.masterEdition
|
||||
) {
|
||||
safetyDepositConfig.push({
|
||||
tokenAccount: (
|
||||
await findProgramAddress(
|
||||
[
|
||||
wallet.publicKey.toBuffer(),
|
||||
programIds().token.toBuffer(),
|
||||
participationSafetyDepositDraft.masterEdition?.info.oneTimePrintingAuthorizationMint.toBuffer(),
|
||||
],
|
||||
programIds().associatedToken,
|
||||
)
|
||||
)[0],
|
||||
tokenMint:
|
||||
participationSafetyDepositDraft.masterEdition?.info
|
||||
.oneTimePrintingAuthorizationMint,
|
||||
amount: new BN(1),
|
||||
draft: participationSafetyDepositDraft,
|
||||
});
|
||||
if (
|
||||
participationSafetyDepositDraft.masterEdition.info.key ==
|
||||
MetadataKey.MasterEditionV1
|
||||
) {
|
||||
const me =
|
||||
participationSafetyDepositDraft.masterEdition as ParsedAccount<MasterEditionV1>;
|
||||
safetyDepositConfig.push({
|
||||
tokenAccount: (
|
||||
await findProgramAddress(
|
||||
[
|
||||
wallet.publicKey.toBuffer(),
|
||||
programIds().token.toBuffer(),
|
||||
me?.info.oneTimePrintingAuthorizationMint.toBuffer(),
|
||||
],
|
||||
programIds().associatedToken,
|
||||
)
|
||||
)[0],
|
||||
tokenMint: me?.info.oneTimePrintingAuthorizationMint,
|
||||
amount: new BN(1),
|
||||
draft: participationSafetyDepositDraft,
|
||||
});
|
||||
} else {
|
||||
safetyDepositConfig.push({
|
||||
tokenAccount: participationSafetyDepositDraft.holding,
|
||||
tokenMint: participationSafetyDepositDraft.metadata.info.mint,
|
||||
amount: new BN(1),
|
||||
draft: participationSafetyDepositDraft,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return safetyDepositConfig;
|
||||
|
@ -487,7 +517,7 @@ async function setupStartAuction(
|
|||
return { instructions, signers };
|
||||
}
|
||||
|
||||
async function validateParticipationHelper(
|
||||
async function deprecatedValidateParticipationHelper(
|
||||
wallet: any,
|
||||
auctionManager: PublicKey,
|
||||
whitelistedCreatorsByCreator: Record<
|
||||
|
@ -517,16 +547,23 @@ async function validateParticipationHelper(
|
|||
|
||||
const { auctionManagerKey } = await getAuctionKeys(vault);
|
||||
|
||||
if (participationSafetyDepositDraft.masterEdition) {
|
||||
// V2s do not need to call this special endpoint.
|
||||
if (
|
||||
participationSafetyDepositDraft.masterEdition &&
|
||||
participationSafetyDepositDraft.masterEdition.info.key ==
|
||||
MetadataKey.MasterEditionV1
|
||||
) {
|
||||
const me =
|
||||
participationSafetyDepositDraft.masterEdition as ParsedAccount<MasterEditionV1>;
|
||||
const printingTokenHoldingAccount = createTokenAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
participationSafetyDepositDraft.masterEdition.info.printingMint,
|
||||
me.info.printingMint,
|
||||
auctionManagerKey,
|
||||
signers,
|
||||
);
|
||||
await validateParticipation(
|
||||
await deprecatedValidateParticipation(
|
||||
auctionManager,
|
||||
participationSafetyDepositDraft.metadata.pubkey,
|
||||
participationSafetyDepositDraft.masterEdition?.pubkey,
|
||||
|
@ -536,8 +573,7 @@ async function validateParticipationHelper(
|
|||
store,
|
||||
await getSafetyDepositBoxAddress(
|
||||
vault,
|
||||
participationSafetyDepositDraft.masterEdition.info
|
||||
.oneTimePrintingAuthorizationMint,
|
||||
me.info.oneTimePrintingAuthorizationMint,
|
||||
),
|
||||
tokenStore,
|
||||
vault,
|
||||
|
@ -584,7 +620,6 @@ async function validateBoxes(
|
|||
if (!store) {
|
||||
throw new Error('Store not initialized');
|
||||
}
|
||||
|
||||
let signers: Keypair[][] = [];
|
||||
let instructions: TransactionInstruction[][] = [];
|
||||
|
||||
|
@ -601,62 +636,63 @@ async function validateBoxes(
|
|||
ow => ow.safetyDepositBoxIndex === i,
|
||||
);
|
||||
|
||||
if (winningConfigItem) {
|
||||
if (
|
||||
winningConfigItem.winningConfigType === WinningConfigType.Printing &&
|
||||
safetyDeposits[i].draft.masterEdition &&
|
||||
safetyDeposits[i].draft.masterEdition?.info.printingMint
|
||||
)
|
||||
safetyDepositBox = await getSafetyDepositBox(
|
||||
vault,
|
||||
//@ts-ignore
|
||||
safetyDeposits[i].draft.masterEdition.info.printingMint,
|
||||
);
|
||||
else
|
||||
safetyDepositBox = await getSafetyDepositBox(
|
||||
vault,
|
||||
safetyDeposits[i].draft.metadata.info.mint,
|
||||
);
|
||||
const edition: PublicKey = await getEdition(
|
||||
const me = safetyDeposits[i].draft
|
||||
.masterEdition as ParsedAccount<MasterEditionV1>;
|
||||
if (
|
||||
winningConfigItem?.winningConfigType === WinningConfigType.PrintingV1 &&
|
||||
me &&
|
||||
me.info.printingMint
|
||||
) {
|
||||
safetyDepositBox = await getSafetyDepositBox(
|
||||
vault,
|
||||
//@ts-ignore
|
||||
safetyDeposits[i].draft.masterEdition.info.printingMint,
|
||||
);
|
||||
} else {
|
||||
safetyDepositBox = await getSafetyDepositBox(
|
||||
vault,
|
||||
safetyDeposits[i].draft.metadata.info.mint,
|
||||
);
|
||||
|
||||
const whitelistedCreator = safetyDeposits[i].draft.metadata.info.data
|
||||
.creators
|
||||
? await findValidWhitelistedCreator(
|
||||
whitelistedCreatorsByCreator,
|
||||
//@ts-ignore
|
||||
safetyDeposits[i].draft.metadata.info.data.creators,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
await validateSafetyDepositBox(
|
||||
vault,
|
||||
safetyDeposits[i].draft.metadata.pubkey,
|
||||
safetyDepositBox,
|
||||
safetyDepositTokenStores[i],
|
||||
//@ts-ignore
|
||||
winningConfigItem.winningConfigType === WinningConfigType.Printing
|
||||
? safetyDeposits[i].draft.masterEdition?.info.printingMint
|
||||
: safetyDeposits[i].draft.metadata.info.mint,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
tokenInstructions,
|
||||
edition,
|
||||
whitelistedCreator,
|
||||
store,
|
||||
safetyDeposits[i].draft.masterEdition?.info.printingMint,
|
||||
safetyDeposits[i].draft.masterEdition ? wallet.publicKey : undefined,
|
||||
);
|
||||
}
|
||||
const edition: PublicKey = await getEdition(
|
||||
safetyDeposits[i].draft.metadata.info.mint,
|
||||
);
|
||||
|
||||
const whitelistedCreator = safetyDeposits[i].draft.metadata.info.data
|
||||
.creators
|
||||
? await findValidWhitelistedCreator(
|
||||
whitelistedCreatorsByCreator,
|
||||
//@ts-ignore
|
||||
safetyDeposits[i].draft.metadata.info.data.creators,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
await validateSafetyDepositBox(
|
||||
vault,
|
||||
safetyDeposits[i].draft.metadata.pubkey,
|
||||
safetyDepositBox,
|
||||
safetyDepositTokenStores[i],
|
||||
winningConfigItem?.winningConfigType === WinningConfigType.PrintingV1
|
||||
? me?.info.printingMint
|
||||
: safetyDeposits[i].draft.metadata.info.mint,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
tokenInstructions,
|
||||
edition,
|
||||
whitelistedCreator,
|
||||
store,
|
||||
me?.info.printingMint,
|
||||
safetyDeposits[i].draft.masterEdition ? wallet.publicKey : undefined,
|
||||
);
|
||||
|
||||
signers.push(tokenSigners);
|
||||
instructions.push(tokenInstructions);
|
||||
}
|
||||
return { instructions, signers };
|
||||
}
|
||||
|
||||
async function buildAndPopulateOneTimeAuthorizationAccount(
|
||||
async function deprecatedBuildAndPopulateOneTimeAuthorizationAccount(
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
oneTimePrintingAuthorizationMint: PublicKey | undefined,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { Keypair, Connection, TransactionInstruction } from '@solana/web3.js';
|
||||
import {
|
||||
BidderMetadata,
|
||||
ParsedAccount,
|
||||
sendTransactionsWithManualRetry,
|
||||
setAuctionAuthority,
|
||||
setVaultAuthority,
|
||||
|
@ -7,7 +9,11 @@ import {
|
|||
} from '@oyster/common';
|
||||
|
||||
import { AuctionView } from '../hooks';
|
||||
import { AuctionManagerStatus } from '../models/metaplex';
|
||||
import {
|
||||
AuctionManagerStatus,
|
||||
BidRedemptionTicket,
|
||||
PrizeTrackingTicket,
|
||||
} from '../models/metaplex';
|
||||
import { decommissionAuctionManager } from '../models/metaplex/decommissionAuctionManager';
|
||||
import { claimUnusedPrizes } from './claimUnusedPrizes';
|
||||
|
||||
|
@ -59,6 +65,9 @@ export async function decommAuctionManagerAndReturnPrizes(
|
|||
wallet,
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
[],
|
||||
{},
|
||||
{},
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js';
|
||||
import { createReservationList } from '@oyster/common';
|
||||
import { deprecatedCreateReservationList } from '@oyster/common';
|
||||
|
||||
import { SafetyDepositInstructionConfig } from './addTokensToVault';
|
||||
import { AuctionManagerSettings, WinningConfigType } from '../models/metaplex';
|
||||
|
||||
const BATCH_SIZE = 10;
|
||||
// This command batches out creating reservation lists for those tokens who are being sold in Printing mode.
|
||||
// This command batches out creating reservation lists for those tokens who are being sold in PrintingV1 mode.
|
||||
// Reservation lists are used to insure printing order among limited editions.
|
||||
export async function createReservationListForTokens(
|
||||
export async function deprecatedCreateReservationListForTokens(
|
||||
wallet: any,
|
||||
auctionManager: PublicKey,
|
||||
settings: AuctionManagerSettings,
|
||||
|
@ -30,10 +30,10 @@ export async function createReservationListForTokens(
|
|||
.flat()
|
||||
.find(it => it.safetyDepositBoxIndex === i);
|
||||
if (
|
||||
relevantConfig?.winningConfigType === WinningConfigType.Printing &&
|
||||
relevantConfig?.winningConfigType === WinningConfigType.PrintingV1 &&
|
||||
safetyDeposit.draft.masterEdition
|
||||
)
|
||||
await createReservationList(
|
||||
await deprecatedCreateReservationList(
|
||||
safetyDeposit.draft.metadata.pubkey,
|
||||
safetyDeposit.draft.masterEdition.pubkey,
|
||||
auctionManager,
|
|
@ -7,8 +7,11 @@ import {
|
|||
import {
|
||||
utils,
|
||||
createAssociatedTokenAccountInstruction,
|
||||
mintPrintingTokens,
|
||||
deprecatedMintPrintingTokens,
|
||||
findProgramAddress,
|
||||
MasterEditionV1,
|
||||
ParsedAccount,
|
||||
MetadataKey,
|
||||
} from '@oyster/common';
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
@ -17,7 +20,7 @@ import { SafetyDepositInstructionConfig } from './addTokensToVault';
|
|||
const BATCH_SIZE = 4;
|
||||
// Printing tokens are minted on the fly as needed. We need to pre-mint them to give to the vault
|
||||
// for all relevant NFTs.
|
||||
export async function populatePrintingTokens(
|
||||
export async function deprecatedPopulatePrintingTokens(
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
safetyDepositConfigs: SafetyDepositInstructionConfig[],
|
||||
|
@ -37,17 +40,19 @@ export async function populatePrintingTokens(
|
|||
let currInstructions: TransactionInstruction[] = [];
|
||||
for (let i = 0; i < safetyDepositConfigs.length; i++) {
|
||||
let nft = safetyDepositConfigs[i];
|
||||
if (
|
||||
nft.tokenMint.toBase58() ===
|
||||
nft.draft.masterEdition?.info.printingMint.toBase58() &&
|
||||
!nft.tokenAccount
|
||||
) {
|
||||
if (nft.draft.masterEdition?.info.key != MetadataKey.MasterEditionV1) {
|
||||
continue;
|
||||
}
|
||||
const printingMint = (
|
||||
nft.draft.masterEdition as ParsedAccount<MasterEditionV1>
|
||||
)?.info.printingMint;
|
||||
if (nft.tokenMint.equals(printingMint) && !nft.tokenAccount) {
|
||||
const holdingKey: PublicKey = (
|
||||
await findProgramAddress(
|
||||
[
|
||||
wallet.publicKey.toBuffer(),
|
||||
PROGRAM_IDS.token.toBuffer(),
|
||||
nft.draft.masterEdition.info.printingMint.toBuffer(),
|
||||
printingMint.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.associatedToken,
|
||||
)
|
||||
|
@ -58,18 +63,14 @@ export async function populatePrintingTokens(
|
|||
holdingKey,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
nft.draft.masterEdition.info.printingMint,
|
||||
printingMint,
|
||||
);
|
||||
console.log('Making atas');
|
||||
|
||||
nft.draft.printingMintHolding = holdingKey;
|
||||
nft.tokenAccount = holdingKey;
|
||||
}
|
||||
if (
|
||||
nft.tokenAccount &&
|
||||
nft.tokenMint.toBase58() ===
|
||||
nft.draft.masterEdition?.info.printingMint.toBase58()
|
||||
) {
|
||||
if (nft.tokenAccount && nft.tokenMint.equals(printingMint)) {
|
||||
let balance = 0;
|
||||
try {
|
||||
balance =
|
||||
|
@ -78,9 +79,9 @@ export async function populatePrintingTokens(
|
|||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
console.log('bal', balance);
|
||||
|
||||
if (balance < nft.amount.toNumber() && nft.draft.masterEdition)
|
||||
await mintPrintingTokens(
|
||||
await deprecatedMintPrintingTokens(
|
||||
nft.tokenAccount,
|
||||
nft.tokenMint,
|
||||
wallet.publicKey,
|
|
@ -0,0 +1,55 @@
|
|||
import { Keypair, Connection, TransactionInstruction } from '@solana/web3.js';
|
||||
import { updatePrimarySaleHappenedViaToken } from '@oyster/common';
|
||||
import { SafetyDepositDraft } from './createAuctionManager';
|
||||
const SALE_TRANSACTION_SIZE = 10;
|
||||
|
||||
export async function markItemsThatArentMineAsSold(
|
||||
wallet: any,
|
||||
safetyDepositDrafts: SafetyDepositDraft[],
|
||||
): Promise<{ instructions: TransactionInstruction[][]; signers: Keypair[][] }> {
|
||||
let signers: Array<Keypair[]> = [];
|
||||
let instructions: Array<TransactionInstruction[]> = [];
|
||||
|
||||
let markSigners: Keypair[] = [];
|
||||
let markInstructions: TransactionInstruction[] = [];
|
||||
|
||||
// TODO replace all this with payer account so user doesnt need to click approve several times.
|
||||
|
||||
for (let i = 0; i < safetyDepositDrafts.length; i++) {
|
||||
const item = safetyDepositDrafts[i].metadata;
|
||||
|
||||
if (
|
||||
!item.info.data.creators?.find(c => c.address.equals(wallet.publicKey)) &&
|
||||
!item.info.primarySaleHappened
|
||||
) {
|
||||
console.log(
|
||||
'For token',
|
||||
item.info.data.name,
|
||||
'marking it sold because i didnt make it but i want to keep proceeds',
|
||||
);
|
||||
await updatePrimarySaleHappenedViaToken(
|
||||
item.pubkey,
|
||||
wallet.publicKey,
|
||||
safetyDepositDrafts[i].holding,
|
||||
markInstructions,
|
||||
);
|
||||
|
||||
if (markInstructions.length === SALE_TRANSACTION_SIZE) {
|
||||
signers.push(markSigners);
|
||||
instructions.push(markInstructions);
|
||||
markSigners = [];
|
||||
markInstructions = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
markInstructions.length < SALE_TRANSACTION_SIZE &&
|
||||
markInstructions.length > 0
|
||||
) {
|
||||
signers.push(markSigners);
|
||||
instructions.push(markInstructions);
|
||||
}
|
||||
|
||||
return { instructions, signers };
|
||||
}
|
|
@ -83,12 +83,7 @@ export const mintNFT = async (
|
|||
|
||||
const realFiles: File[] = [
|
||||
...files,
|
||||
new File(
|
||||
[
|
||||
JSON.stringify(metadataContent),
|
||||
],
|
||||
'metadata.json',
|
||||
),
|
||||
new File([JSON.stringify(metadataContent)], 'metadata.json'),
|
||||
];
|
||||
|
||||
const { instructions: pushInstructions, signers: pushSigners } =
|
||||
|
@ -249,61 +244,15 @@ export const mintNFT = async (
|
|||
1,
|
||||
),
|
||||
);
|
||||
|
||||
// This mint, which allows limited editions to be made, stays with user's wallet.
|
||||
const printingMint = createMint(
|
||||
updateInstructions,
|
||||
payerPublicKey,
|
||||
mintRent,
|
||||
0,
|
||||
payerPublicKey,
|
||||
payerPublicKey,
|
||||
updateSigners,
|
||||
);
|
||||
|
||||
const oneTimePrintingAuthorizationMint = createMint(
|
||||
updateInstructions,
|
||||
payerPublicKey,
|
||||
mintRent,
|
||||
0,
|
||||
payerPublicKey,
|
||||
payerPublicKey,
|
||||
updateSigners,
|
||||
);
|
||||
|
||||
if (maxSupply !== undefined) {
|
||||
// make this so we can use it later.
|
||||
const authTokenAccount: PublicKey = (
|
||||
await findProgramAddress(
|
||||
[
|
||||
wallet.publicKey.toBuffer(),
|
||||
programIds().token.toBuffer(),
|
||||
printingMint.toBuffer(),
|
||||
],
|
||||
programIds().associatedToken,
|
||||
)
|
||||
)[0];
|
||||
createAssociatedTokenAccountInstruction(
|
||||
instructions,
|
||||
authTokenAccount,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
printingMint,
|
||||
);
|
||||
}
|
||||
// // In this instruction, mint authority will be removed from the main mint, while
|
||||
// // minting authority will be maintained for the Printing mint (which we want.)
|
||||
await createMasterEdition(
|
||||
maxSupply !== undefined ? new BN(maxSupply) : undefined,
|
||||
mintKey,
|
||||
printingMint,
|
||||
oneTimePrintingAuthorizationMint,
|
||||
payerPublicKey,
|
||||
payerPublicKey,
|
||||
payerPublicKey,
|
||||
updateInstructions,
|
||||
payerPublicKey,
|
||||
payerPublicKey,
|
||||
maxSupply !== undefined ? payerPublicKey : undefined,
|
||||
);
|
||||
|
||||
// TODO: enable when using payer account to avoid 2nd popup
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
Connection,
|
||||
PublicKey,
|
||||
TransactionInstruction,
|
||||
AccountInfo,
|
||||
} from '@solana/web3.js';
|
||||
import {
|
||||
actions,
|
||||
|
@ -11,15 +12,24 @@ import {
|
|||
models,
|
||||
TokenAccount,
|
||||
createMint,
|
||||
mintNewEditionFromMasterEditionViaToken,
|
||||
SafetyDepositBox,
|
||||
cache,
|
||||
ensureWrappedAccount,
|
||||
updatePrimarySaleHappenedViaToken,
|
||||
getMetadata,
|
||||
getReservationList,
|
||||
deprecatedGetReservationList,
|
||||
AuctionState,
|
||||
sendTransactionsWithManualRetry,
|
||||
MasterEditionV1,
|
||||
MasterEditionV2,
|
||||
findProgramAddress,
|
||||
createAssociatedTokenAccountInstruction,
|
||||
deprecatedMintNewEditionFromMasterEditionViaPrintingToken,
|
||||
MetadataKey,
|
||||
TokenAccountParser,
|
||||
BidderMetadata,
|
||||
getEditionMarkPda,
|
||||
decodeEditionMarker,
|
||||
} from '@oyster/common';
|
||||
|
||||
import { AccountLayout, MintLayout, Token } from '@solana/spl-token';
|
||||
|
@ -29,23 +39,35 @@ import {
|
|||
NonWinningConstraint,
|
||||
redeemBid,
|
||||
redeemFullRightsTransferBid,
|
||||
redeemParticipationBid,
|
||||
deprecatedRedeemParticipationBid,
|
||||
redeemParticipationBidV2,
|
||||
WinningConstraint,
|
||||
WinningConfigItem,
|
||||
WinningConfigStateItem,
|
||||
redeemPrintingV2Bid,
|
||||
PrizeTrackingTicket,
|
||||
getPrizeTrackingTicket,
|
||||
BidRedemptionTicket,
|
||||
getBidRedemption,
|
||||
} from '../models/metaplex';
|
||||
import { claimBid } from '../models/metaplex/claimBid';
|
||||
import { setupCancelBid } from './cancelBid';
|
||||
import { populateParticipationPrintingAccount } from '../models/metaplex/populateParticipationPrintingAccount';
|
||||
import { deprecatedPopulateParticipationPrintingAccount } from '../models/metaplex/deprecatedPopulateParticipationPrintingAccount';
|
||||
import { setupPlaceBid } from './sendPlaceBid';
|
||||
import { claimUnusedPrizes } from './claimUnusedPrizes';
|
||||
import { BN } from 'bn.js';
|
||||
import { QUOTE_MINT } from '../constants';
|
||||
const { createTokenAccount } = actions;
|
||||
const { approve } = models;
|
||||
|
||||
export function eligibleForParticipationPrizeGivenWinningIndex(
|
||||
winnerIndex: number | null,
|
||||
auctionView: AuctionView,
|
||||
bidderMetadata: ParsedAccount<BidderMetadata> | undefined,
|
||||
bidRedemption: ParsedAccount<BidRedemptionTicket> | undefined,
|
||||
) {
|
||||
if (!bidderMetadata || bidRedemption?.info.participationRedeemed)
|
||||
return false;
|
||||
return (
|
||||
(winnerIndex === null &&
|
||||
auctionView.auctionManager.info.settings.participationConfig
|
||||
|
@ -62,6 +84,9 @@ export async function sendRedeemBid(
|
|||
payingAccount: PublicKey,
|
||||
auctionView: AuctionView,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
prizeTrackingTickets: Record<string, ParsedAccount<PrizeTrackingTicket>>,
|
||||
bidRedemptions: Record<string, ParsedAccount<BidRedemptionTicket>>,
|
||||
bids: ParsedAccount<BidderMetadata>[],
|
||||
) {
|
||||
let signers: Array<Keypair[]> = [];
|
||||
let instructions: Array<TransactionInstruction[]> = [];
|
||||
|
@ -118,9 +143,9 @@ export async function sendRedeemBid(
|
|||
winnerIndex
|
||||
].items[j];
|
||||
switch (winningConfigItem.winningConfigType) {
|
||||
case WinningConfigType.Printing:
|
||||
console.log('Redeeming printing');
|
||||
await setupRedeemPrintingInstructions(
|
||||
case WinningConfigType.PrintingV1:
|
||||
console.log('Redeeming printing v1');
|
||||
await deprecatedSetupRedeemPrintingV1Instructions(
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
accountRentExempt,
|
||||
|
@ -134,6 +159,24 @@ export async function sendRedeemBid(
|
|||
stateItem,
|
||||
);
|
||||
break;
|
||||
case WinningConfigType.PrintingV2:
|
||||
console.log('Redeeming printing v2');
|
||||
await setupRedeemPrintingV2Instructions(
|
||||
connection,
|
||||
auctionView,
|
||||
mintRentExempt,
|
||||
wallet,
|
||||
wallet.publicKey,
|
||||
safetyDeposit,
|
||||
item,
|
||||
signers,
|
||||
instructions,
|
||||
winningConfigItem,
|
||||
stateItem,
|
||||
winnerIndex,
|
||||
prizeTrackingTickets,
|
||||
);
|
||||
break;
|
||||
case WinningConfigType.FullRightsTransfer:
|
||||
console.log('Redeeming Full Rights');
|
||||
await setupRedeemFullRightsTransferInstructions(
|
||||
|
@ -195,33 +238,57 @@ export async function sendRedeemBid(
|
|||
|
||||
if (
|
||||
auctionView.participationItem &&
|
||||
eligibleForParticipationPrizeGivenWinningIndex(winnerIndex, auctionView)
|
||||
eligibleForParticipationPrizeGivenWinningIndex(
|
||||
winnerIndex,
|
||||
auctionView,
|
||||
auctionView.myBidderMetadata,
|
||||
auctionView.myBidRedemption,
|
||||
)
|
||||
) {
|
||||
console.log('eligible for participation');
|
||||
const item = auctionView.participationItem;
|
||||
const safetyDeposit = item.safetyDeposit;
|
||||
await setupRedeemParticipationInstructions(
|
||||
connection,
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
accountRentExempt,
|
||||
mintRentExempt,
|
||||
wallet,
|
||||
safetyDeposit,
|
||||
item,
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
if (item.masterEdition?.info.key == MetadataKey.MasterEditionV1) {
|
||||
await deprecatedSetupRedeemParticipationInstructions(
|
||||
connection,
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
accountRentExempt,
|
||||
mintRentExempt,
|
||||
wallet,
|
||||
safetyDeposit,
|
||||
item,
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
} else {
|
||||
await setupRedeemParticipationInstructions(
|
||||
connection,
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
accountRentExempt,
|
||||
mintRentExempt,
|
||||
wallet,
|
||||
wallet.publicKey,
|
||||
safetyDeposit,
|
||||
auctionView.myBidRedemption,
|
||||
auctionView.myBidderMetadata,
|
||||
item,
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
wallet.publicKey.toBase58() ===
|
||||
auctionView.auctionManager.info.authority.toBase58()
|
||||
) {
|
||||
if (wallet.publicKey.equals(auctionView.auctionManager.info.authority)) {
|
||||
await claimUnusedPrizes(
|
||||
connection,
|
||||
wallet,
|
||||
auctionView,
|
||||
accountsByMint,
|
||||
bids,
|
||||
bidRedemptions,
|
||||
prizeTrackingTickets,
|
||||
signers,
|
||||
instructions,
|
||||
);
|
||||
|
@ -341,7 +408,176 @@ async function setupRedeemFullRightsTransferInstructions(
|
|||
}
|
||||
}
|
||||
|
||||
async function setupRedeemPrintingInstructions(
|
||||
async function createMintAndAccountWithOne(
|
||||
wallet: any,
|
||||
receiverWallet: PublicKey,
|
||||
mintRent: any,
|
||||
instructions: TransactionInstruction[],
|
||||
signers: Keypair[],
|
||||
): Promise<{ mint: PublicKey; account: PublicKey }> {
|
||||
const mint = createMint(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
mintRent,
|
||||
0,
|
||||
wallet.publicKey,
|
||||
wallet.publicKey,
|
||||
signers,
|
||||
);
|
||||
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
const account: PublicKey = (
|
||||
await findProgramAddress(
|
||||
[
|
||||
receiverWallet.toBuffer(),
|
||||
PROGRAM_IDS.token.toBuffer(),
|
||||
mint.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.associatedToken,
|
||||
)
|
||||
)[0];
|
||||
|
||||
createAssociatedTokenAccountInstruction(
|
||||
instructions,
|
||||
account,
|
||||
wallet.publicKey,
|
||||
receiverWallet,
|
||||
mint,
|
||||
);
|
||||
|
||||
instructions.push(
|
||||
Token.createMintToInstruction(
|
||||
PROGRAM_IDS.token,
|
||||
mint,
|
||||
account,
|
||||
wallet.publicKey,
|
||||
[],
|
||||
1,
|
||||
),
|
||||
);
|
||||
|
||||
return { mint, account };
|
||||
}
|
||||
|
||||
export async function setupRedeemPrintingV2Instructions(
|
||||
connection: Connection,
|
||||
auctionView: AuctionView,
|
||||
mintRentExempt: number,
|
||||
wallet: any,
|
||||
receiverWallet: PublicKey,
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>,
|
||||
item: AuctionViewItem,
|
||||
signers: Array<Keypair[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
winningConfigItem: WinningConfigItem,
|
||||
stateItem: WinningConfigStateItem,
|
||||
winningIndex: number,
|
||||
prizeTrackingTickets: Record<string, ParsedAccount<PrizeTrackingTicket>>,
|
||||
) {
|
||||
if (!item.masterEdition || !item.metadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
const me = item.masterEdition as ParsedAccount<MasterEditionV2>;
|
||||
|
||||
const myPrizeTrackingTicketKey = await getPrizeTrackingTicket(
|
||||
auctionView.auctionManager.pubkey,
|
||||
item.metadata.info.mint,
|
||||
);
|
||||
|
||||
const myPrizeTrackingTicket =
|
||||
prizeTrackingTickets[myPrizeTrackingTicketKey.toBase58()];
|
||||
// We are not entirely guaranteed this is right. Someone could be clicking at the same time. Contract will throw error if this
|
||||
// is the case and they'll need to refresh to get tracking ticket which may not have existed when they first clicked.
|
||||
const editionBase = myPrizeTrackingTicket
|
||||
? myPrizeTrackingTicket.info.supplySnapshot
|
||||
: me.info.supply;
|
||||
let offset = 1;
|
||||
|
||||
auctionView.auctionManager.info.settings.winningConfigs.forEach(
|
||||
(wc, index) =>
|
||||
index < winningIndex &&
|
||||
wc.items.forEach(i => {
|
||||
if (
|
||||
i.safetyDepositBoxIndex === item.safetyDeposit.info.order &&
|
||||
i.winningConfigType === winningConfigItem.winningConfigType
|
||||
) {
|
||||
offset += i.amount;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
for (let i = 0; i < winningConfigItem.amount; i++) {
|
||||
let myInstructions: TransactionInstruction[] = [];
|
||||
let mySigners: Keypair[] = [];
|
||||
|
||||
const { mint, account } = await createMintAndAccountWithOne(
|
||||
wallet,
|
||||
receiverWallet,
|
||||
mintRentExempt,
|
||||
myInstructions,
|
||||
mySigners,
|
||||
);
|
||||
|
||||
const winIndex =
|
||||
auctionView.auction.info.bidState.getWinnerIndex(receiverWallet) || 0;
|
||||
|
||||
const desiredEdition = editionBase.add(new BN(offset + i));
|
||||
const editionMarkPda = await getEditionMarkPda(
|
||||
item.metadata.info.mint,
|
||||
desiredEdition,
|
||||
);
|
||||
|
||||
try {
|
||||
const editionData = await connection.getAccountInfo(editionMarkPda);
|
||||
|
||||
if (editionData) {
|
||||
const marker = decodeEditionMarker(editionData.data);
|
||||
|
||||
if (marker.editionTaken(desiredEdition.toNumber())) {
|
||||
console.log('Edition', desiredEdition, 'taken, continuing');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
await redeemPrintingV2Bid(
|
||||
auctionView.vault.pubkey,
|
||||
safetyDeposit.info.store,
|
||||
account,
|
||||
safetyDeposit.pubkey,
|
||||
auctionView.vault.info.fractionMint,
|
||||
receiverWallet,
|
||||
wallet.publicKey,
|
||||
item.metadata.pubkey,
|
||||
me.pubkey,
|
||||
item.metadata.info.mint,
|
||||
mint,
|
||||
desiredEdition,
|
||||
new BN(offset + i),
|
||||
new BN(winIndex),
|
||||
myInstructions,
|
||||
);
|
||||
|
||||
const metadata = await getMetadata(mint);
|
||||
|
||||
if (wallet.publicKey.equals(receiverWallet)) {
|
||||
await updatePrimarySaleHappenedViaToken(
|
||||
metadata,
|
||||
wallet.publicKey,
|
||||
account,
|
||||
myInstructions,
|
||||
);
|
||||
}
|
||||
instructions.push(myInstructions);
|
||||
signers.push(mySigners);
|
||||
}
|
||||
}
|
||||
|
||||
async function deprecatedSetupRedeemPrintingV1Instructions(
|
||||
auctionView: AuctionView,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
accountRentExempt: number,
|
||||
|
@ -359,14 +595,14 @@ async function setupRedeemPrintingInstructions(
|
|||
}
|
||||
const updateAuth = item.metadata.info.updateAuthority;
|
||||
|
||||
const reservationList = await getReservationList(
|
||||
const reservationList = await deprecatedGetReservationList(
|
||||
item.masterEdition.pubkey,
|
||||
auctionView.auctionManager.pubkey,
|
||||
);
|
||||
|
||||
const newTokenAccount = accountsByMint.get(
|
||||
item.masterEdition.info.printingMint.toBase58(),
|
||||
);
|
||||
const me = item.masterEdition as ParsedAccount<MasterEditionV1>;
|
||||
|
||||
const newTokenAccount = accountsByMint.get(me.info.printingMint.toBase58());
|
||||
let newTokenAccountKey: PublicKey | undefined = newTokenAccount?.pubkey;
|
||||
|
||||
let newTokenAccountBalance: number = newTokenAccount
|
||||
|
@ -387,7 +623,7 @@ async function setupRedeemPrintingInstructions(
|
|||
winningPrizeInstructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
item.masterEdition.info.printingMint,
|
||||
me.info.printingMint,
|
||||
wallet.publicKey,
|
||||
winningPrizeSigner,
|
||||
);
|
||||
|
@ -410,8 +646,8 @@ async function setupRedeemPrintingInstructions(
|
|||
|
||||
if (newTokenAccountKey && newTokenAccountBalance > 0)
|
||||
for (let i = 0; i < newTokenAccountBalance; i++) {
|
||||
console.log('Redeeming token', i);
|
||||
await redeemPrintingToken(
|
||||
console.log('Redeeming v1 token', i);
|
||||
await deprecatedRedeemPrintingV1Token(
|
||||
wallet,
|
||||
updateAuth,
|
||||
item,
|
||||
|
@ -426,7 +662,7 @@ async function setupRedeemPrintingInstructions(
|
|||
}
|
||||
}
|
||||
|
||||
async function redeemPrintingToken(
|
||||
async function deprecatedRedeemPrintingV1Token(
|
||||
wallet: any,
|
||||
updateAuth: PublicKey,
|
||||
item: AuctionViewItem,
|
||||
|
@ -483,11 +719,13 @@ async function redeemPrintingToken(
|
|||
|
||||
cashInLimitedPrizeAuthorizationTokenSigner.push(burnAuthority);
|
||||
|
||||
await mintNewEditionFromMasterEditionViaToken(
|
||||
const me = item.masterEdition as ParsedAccount<MasterEditionV1>;
|
||||
|
||||
await deprecatedMintNewEditionFromMasterEditionViaPrintingToken(
|
||||
newLimitedEditionMint,
|
||||
item.metadata.info.mint,
|
||||
wallet.publicKey,
|
||||
item.masterEdition.info.printingMint,
|
||||
me.info.printingMint,
|
||||
newTokenAccount,
|
||||
burnAuthority.publicKey,
|
||||
updateAuth,
|
||||
|
@ -505,7 +743,139 @@ async function redeemPrintingToken(
|
|||
);
|
||||
}
|
||||
|
||||
async function setupRedeemParticipationInstructions(
|
||||
export async function setupRedeemParticipationInstructions(
|
||||
connection: Connection,
|
||||
auctionView: AuctionView,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
accountRentExempt: number,
|
||||
mintRentExempt: number,
|
||||
wallet: any,
|
||||
receiverWallet: PublicKey,
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>,
|
||||
bidRedemption: ParsedAccount<BidRedemptionTicket> | undefined,
|
||||
bid: ParsedAccount<BidderMetadata> | undefined,
|
||||
item: AuctionViewItem,
|
||||
signers: Array<Keypair[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
if (!item.masterEdition || !item.metadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Forgive me, for i have sinned. I had to split up the commands
|
||||
// here into multiple txns because participation redemption is huge.
|
||||
if (!bidRedemption?.info?.participationRedeemed) {
|
||||
const me = item.masterEdition as ParsedAccount<MasterEditionV2>;
|
||||
|
||||
// Super unfortunate but cant fit this all in one txn
|
||||
let mintingInstructions: TransactionInstruction[] = [];
|
||||
let mintingSigners: Keypair[] = [];
|
||||
|
||||
const cleanupInstructions: TransactionInstruction[] = [];
|
||||
|
||||
const { mint, account } = await createMintAndAccountWithOne(
|
||||
wallet,
|
||||
receiverWallet,
|
||||
mintRentExempt,
|
||||
mintingInstructions,
|
||||
mintingSigners,
|
||||
);
|
||||
|
||||
const fixedPrice =
|
||||
auctionView.auctionManager.info.settings.participationConfig?.fixedPrice;
|
||||
let price: number =
|
||||
fixedPrice !== undefined && fixedPrice !== null
|
||||
? fixedPrice.toNumber()
|
||||
: bid?.info.lastBid.toNumber() || 0;
|
||||
|
||||
let tokenAccount = accountsByMint.get(
|
||||
auctionView.auction.info.tokenMint.toBase58(),
|
||||
);
|
||||
|
||||
console.log('Have token account', tokenAccount);
|
||||
if (!tokenAccount) {
|
||||
// In case accountsByMint missed it(which it does sometimes)
|
||||
const allAccounts = await connection.getTokenAccountsByOwner(
|
||||
wallet.publicKey,
|
||||
{ mint: QUOTE_MINT },
|
||||
);
|
||||
|
||||
if (allAccounts.value.length > 0) {
|
||||
tokenAccount = TokenAccountParser(
|
||||
allAccounts.value[0].pubkey,
|
||||
allAccounts.value[0].account,
|
||||
);
|
||||
}
|
||||
console.log('Found token account', tokenAccount);
|
||||
}
|
||||
|
||||
const payingSolAccount = ensureWrappedAccount(
|
||||
mintingInstructions,
|
||||
cleanupInstructions,
|
||||
tokenAccount,
|
||||
wallet.publicKey,
|
||||
price + accountRentExempt,
|
||||
mintingSigners,
|
||||
);
|
||||
|
||||
instructions.push(mintingInstructions);
|
||||
signers.push(mintingSigners);
|
||||
|
||||
let myInstructions: TransactionInstruction[] = [];
|
||||
|
||||
let mySigners: Keypair[] = [];
|
||||
|
||||
const transferAuthority = approve(
|
||||
myInstructions,
|
||||
cleanupInstructions,
|
||||
payingSolAccount,
|
||||
wallet.publicKey,
|
||||
price,
|
||||
);
|
||||
|
||||
mySigners.push(transferAuthority);
|
||||
|
||||
await redeemParticipationBidV2(
|
||||
auctionView.vault.pubkey,
|
||||
safetyDeposit.info.store,
|
||||
account,
|
||||
safetyDeposit.pubkey,
|
||||
auctionView.vault.info.fractionMint,
|
||||
receiverWallet,
|
||||
wallet.publicKey,
|
||||
item.metadata.pubkey,
|
||||
me.pubkey,
|
||||
item.metadata.info.mint,
|
||||
transferAuthority.publicKey,
|
||||
auctionView.auctionManager.info.acceptPayment,
|
||||
payingSolAccount,
|
||||
mint,
|
||||
me.info.supply.add(new BN(1)),
|
||||
myInstructions,
|
||||
);
|
||||
instructions.push([...myInstructions, ...cleanupInstructions]);
|
||||
signers.push(mySigners);
|
||||
const metadata = await getMetadata(mint);
|
||||
|
||||
if (receiverWallet.equals(wallet.publicKey)) {
|
||||
let updatePrimarySaleHappenedInstructions: TransactionInstruction[] = [];
|
||||
let updatePrimarySaleHappenedSigners: Keypair[] = [];
|
||||
|
||||
await updatePrimarySaleHappenedViaToken(
|
||||
metadata,
|
||||
wallet.publicKey,
|
||||
account,
|
||||
updatePrimarySaleHappenedInstructions,
|
||||
);
|
||||
instructions.push(updatePrimarySaleHappenedInstructions);
|
||||
signers.push(updatePrimarySaleHappenedSigners);
|
||||
}
|
||||
} else {
|
||||
console.log('Item is already claimed!', item.metadata.info.mint.toBase58());
|
||||
}
|
||||
}
|
||||
|
||||
async function deprecatedSetupRedeemParticipationInstructions(
|
||||
connection: Connection,
|
||||
auctionView: AuctionView,
|
||||
accountsByMint: Map<string, TokenAccount>,
|
||||
|
@ -517,10 +887,11 @@ async function setupRedeemParticipationInstructions(
|
|||
signers: Array<Keypair[]>,
|
||||
instructions: Array<TransactionInstruction[]>,
|
||||
) {
|
||||
const me = item.masterEdition as ParsedAccount<MasterEditionV1>;
|
||||
if (
|
||||
!auctionView.auctionManager.info.state.participationState
|
||||
?.printingAuthorizationTokenAccount ||
|
||||
!item.masterEdition?.info.oneTimePrintingAuthorizationMint ||
|
||||
!me?.info.oneTimePrintingAuthorizationMint ||
|
||||
!item.metadata
|
||||
)
|
||||
return;
|
||||
|
@ -550,12 +921,12 @@ async function setupRedeemParticipationInstructions(
|
|||
fillParticipationStashInstructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
item.masterEdition?.info.oneTimePrintingAuthorizationMint,
|
||||
me?.info.oneTimePrintingAuthorizationMint,
|
||||
auctionView.auctionManager.pubkey,
|
||||
fillParticipationStashSigners,
|
||||
);
|
||||
|
||||
await populateParticipationPrintingAccount(
|
||||
await deprecatedPopulateParticipationPrintingAccount(
|
||||
auctionView.vault.pubkey,
|
||||
auctionView.auctionManager.pubkey,
|
||||
auctionView.auction.pubkey,
|
||||
|
@ -565,9 +936,9 @@ async function setupRedeemParticipationInstructions(
|
|||
.printingAuthorizationTokenAccount,
|
||||
safetyDeposit.pubkey,
|
||||
auctionView.vault.info.fractionMint,
|
||||
item.masterEdition.info.printingMint,
|
||||
item.masterEdition.info.oneTimePrintingAuthorizationMint,
|
||||
item.masterEdition.pubkey,
|
||||
me.info.printingMint,
|
||||
me.info.oneTimePrintingAuthorizationMint,
|
||||
me.pubkey,
|
||||
item.metadata.pubkey,
|
||||
wallet.publicKey,
|
||||
fillParticipationStashInstructions,
|
||||
|
@ -578,15 +949,14 @@ async function setupRedeemParticipationInstructions(
|
|||
}
|
||||
|
||||
let newTokenAccount: PublicKey | undefined = accountsByMint.get(
|
||||
item.masterEdition.info.printingMint.toBase58(),
|
||||
me.info.printingMint.toBase58(),
|
||||
)?.pubkey;
|
||||
|
||||
let newTokenBalance =
|
||||
accountsByMint.get(item.masterEdition.info.printingMint.toBase58())?.info
|
||||
.amount || 0;
|
||||
accountsByMint.get(me.info.printingMint.toBase58())?.info.amount || 0;
|
||||
|
||||
if (
|
||||
item.masterEdition &&
|
||||
me &&
|
||||
updateAuth &&
|
||||
auctionView.myBidderMetadata &&
|
||||
mint &&
|
||||
|
@ -607,17 +977,20 @@ async function setupRedeemParticipationInstructions(
|
|||
newTokenAccountInstructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
item.masterEdition.info.printingMint,
|
||||
me.info.printingMint,
|
||||
wallet.publicKey,
|
||||
newTokenAccountSigner,
|
||||
);
|
||||
}
|
||||
signers.push(winningPrizeSigner);
|
||||
|
||||
let price: number = auctionView.auctionManager.info.settings
|
||||
.participationConfig?.fixedPrice
|
||||
? auctionView.auctionManager.info.settings.participationConfig?.fixedPrice.toNumber()
|
||||
: auctionView.myBidderMetadata.info.lastBid.toNumber() || 0;
|
||||
const fixedPrice =
|
||||
auctionView.auctionManager.info.settings.participationConfig
|
||||
?.fixedPrice;
|
||||
let price: number =
|
||||
fixedPrice !== undefined && fixedPrice !== null
|
||||
? fixedPrice.toNumber()
|
||||
: auctionView.myBidderMetadata.info.lastBid.toNumber() || 0;
|
||||
|
||||
const payingSolAccount = ensureWrappedAccount(
|
||||
winningPrizeInstructions,
|
||||
|
@ -638,7 +1011,7 @@ async function setupRedeemParticipationInstructions(
|
|||
|
||||
winningPrizeSigner.push(transferAuthority);
|
||||
|
||||
await redeemParticipationBid(
|
||||
await deprecatedRedeemParticipationBid(
|
||||
auctionView.auctionManager.info.vault,
|
||||
safetyDeposit.info.store,
|
||||
newTokenAccount,
|
||||
|
@ -660,7 +1033,7 @@ async function setupRedeemParticipationInstructions(
|
|||
}
|
||||
|
||||
if (newTokenAccount && newTokenBalance === 1) {
|
||||
await redeemPrintingToken(
|
||||
await deprecatedRedeemPrintingV1Token(
|
||||
wallet,
|
||||
updateAuth,
|
||||
item,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import { Connection, Keypair, TransactionInstruction } from '@solana/web3.js';
|
||||
import { startAuction } from '../models/metaplex';
|
||||
import { notify, sendTransactionWithRetry } from '@oyster/common';
|
||||
import { AuctionView } from '../hooks';
|
||||
|
||||
export async function startAuctionManually(
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
auctionView: AuctionView,
|
||||
) {
|
||||
try {
|
||||
const signers: Keypair[] = [];
|
||||
let instructions: TransactionInstruction[] = [];
|
||||
|
||||
await startAuction(
|
||||
auctionView.vault.pubkey,
|
||||
auctionView.auctionManager.info.authority,
|
||||
instructions,
|
||||
);
|
||||
|
||||
await sendTransactionWithRetry(connection, wallet, instructions, signers);
|
||||
|
||||
notify({
|
||||
message: 'Auction started',
|
||||
type: 'success',
|
||||
});
|
||||
} catch (e) {
|
||||
notify({
|
||||
message: 'Transaction failed...',
|
||||
description: 'Failed to start the auction',
|
||||
type: 'error',
|
||||
});
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}
|
|
@ -16,8 +16,12 @@ import {
|
|||
ParsedAccount,
|
||||
getAuctionExtended,
|
||||
programIds,
|
||||
AuctionState,
|
||||
BidderMetadata,
|
||||
MAX_METADATA_LEN,
|
||||
MAX_EDITION_LEN,
|
||||
} from '@oyster/common';
|
||||
import { AuctionView, useUserBalance } from '../../hooks';
|
||||
import { AuctionView, useBidsForAuction, useUserBalance } from '../../hooks';
|
||||
import { sendPlaceBid } from '../../actions/sendPlaceBid';
|
||||
import { AuctionNumbers } from './../AuctionNumbers';
|
||||
import {
|
||||
|
@ -25,15 +29,82 @@ import {
|
|||
eligibleForParticipationPrizeGivenWinningIndex,
|
||||
} from '../../actions/sendRedeemBid';
|
||||
import { sendCancelBid } from '../../actions/cancelBid';
|
||||
import { startAuctionManually } from '../../actions/startAuctionManually';
|
||||
import BN from 'bn.js';
|
||||
import { Confetti } from '../Confetti';
|
||||
import { QUOTE_MINT } from '../../constants';
|
||||
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
|
||||
import { Connection, LAMPORTS_PER_SOL } from '@solana/web3.js';
|
||||
import { useMeta } from '../../contexts';
|
||||
import moment from 'moment';
|
||||
import { AccountLayout, MintLayout } from '@solana/spl-token';
|
||||
import { findEligibleParticipationBidsForRedemption } from '../../actions/claimUnusedPrizes';
|
||||
import {
|
||||
BidRedemptionTicket,
|
||||
MAX_BID_REDEMPTION_TICKET_SIZE,
|
||||
MAX_PRIZE_TRACKING_TICKET_SIZE,
|
||||
} from '../../models/metaplex';
|
||||
|
||||
const { useWallet } = contexts.Wallet;
|
||||
|
||||
async function calculateTotalCostOfRedeemingOtherPeoplesBids(
|
||||
connection: Connection,
|
||||
auctionView: AuctionView,
|
||||
bids: ParsedAccount<BidderMetadata>[],
|
||||
bidRedemptions: Record<string, ParsedAccount<BidRedemptionTicket>>,
|
||||
): Promise<number> {
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
AccountLayout.span,
|
||||
);
|
||||
const mintRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
MintLayout.span,
|
||||
);
|
||||
const metadataRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
MAX_METADATA_LEN,
|
||||
);
|
||||
const editionRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
MAX_EDITION_LEN,
|
||||
);
|
||||
const bidRedemptionTicketExempt =
|
||||
await connection.getMinimumBalanceForRentExemption(
|
||||
MAX_BID_REDEMPTION_TICKET_SIZE,
|
||||
);
|
||||
const prizeTrackingTicketExempt =
|
||||
await connection.getMinimumBalanceForRentExemption(
|
||||
MAX_PRIZE_TRACKING_TICKET_SIZE,
|
||||
);
|
||||
|
||||
const eligibleParticipations =
|
||||
await findEligibleParticipationBidsForRedemption(
|
||||
auctionView,
|
||||
bids,
|
||||
bidRedemptions,
|
||||
);
|
||||
const max = auctionView.auction.info.bidState.max.toNumber();
|
||||
let totalWinnerItems = 0;
|
||||
for (let i = 0; i < max; i++) {
|
||||
const winner = auctionView.auction.info.bidState.getWinnerAt(i);
|
||||
if (!winner) {
|
||||
break;
|
||||
} else {
|
||||
const bid = bids.find(b => b.info.bidderPubkey.equals(winner));
|
||||
if (bid) {
|
||||
totalWinnerItems +=
|
||||
auctionView.auctionManager.info.settings.winningConfigs[i]?.items
|
||||
.map(i => i.amount)
|
||||
.reduce((acc, s) => (acc += s), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
(mintRentExempt +
|
||||
accountRentExempt +
|
||||
metadataRentExempt +
|
||||
editionRentExempt +
|
||||
bidRedemptionTicketExempt +
|
||||
prizeTrackingTicketExempt) *
|
||||
(eligibleParticipations.length + totalWinnerItems)
|
||||
);
|
||||
}
|
||||
function useGapTickCheck(
|
||||
value: number | undefined,
|
||||
gapTick: number | null,
|
||||
|
@ -115,6 +186,8 @@ export const AuctionCard = ({
|
|||
const connection = useConnection();
|
||||
const { wallet, connected, connect } = useWallet();
|
||||
const mintInfo = useMint(auctionView.auction.info.tokenMint);
|
||||
const { prizeTrackingTickets, bidRedemptions } = useMeta();
|
||||
const bids = useBidsForAuction(auctionView.auction.pubkey);
|
||||
|
||||
const [value, setValue] = useState<number>();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
@ -126,6 +199,8 @@ export const AuctionCard = ({
|
|||
const [showBidPlaced, setShowBidPlaced] = useState<boolean>(false);
|
||||
const [lastBid, setLastBid] = useState<{ amount: BN } | undefined>(undefined);
|
||||
const [modalHistory, setModalHistory] = useState<any>();
|
||||
const [showWarningModal, setShowWarningModal] = useState<boolean>(false);
|
||||
const [printingCost, setPrintingCost] = useState<number>();
|
||||
|
||||
const { accountByMint } = useUserAccounts();
|
||||
|
||||
|
@ -145,6 +220,8 @@ export const AuctionCard = ({
|
|||
const eligibleForOpenEdition = eligibleForParticipationPrizeGivenWinningIndex(
|
||||
winnerIndex,
|
||||
auctionView,
|
||||
auctionView.myBidderMetadata,
|
||||
auctionView.myBidRedemption,
|
||||
);
|
||||
const auctionExtended = useAuctionExtended(auctionView);
|
||||
|
||||
|
@ -162,6 +239,13 @@ export const AuctionCard = ({
|
|||
|
||||
const gapBidInvalid = useGapTickCheck(value, gapTick, gapTime, auctionView);
|
||||
|
||||
const isAuctionManagerAuthorityNotWalletOwner =
|
||||
auctionView.auctionManager.info.authority.toBase58() !=
|
||||
wallet?.publicKey?.toBase58();
|
||||
|
||||
const isAuctionNotStarted =
|
||||
auctionView.auction.info.state === AuctionState.Created;
|
||||
|
||||
return (
|
||||
<div className="auction-container" style={style}>
|
||||
<Col>
|
||||
|
@ -181,31 +265,52 @@ export const AuctionCard = ({
|
|||
disabled={
|
||||
!myPayingAccount ||
|
||||
(!auctionView.myBidderMetadata &&
|
||||
auctionView.auctionManager.info.authority.toBase58() !=
|
||||
wallet?.publicKey?.toBase58()) ||
|
||||
isAuctionManagerAuthorityNotWalletOwner) ||
|
||||
loading ||
|
||||
!!auctionView.items.find(i => i.find(it => !it.metadata))
|
||||
}
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
setShowRedemptionIssue(false);
|
||||
if (
|
||||
wallet?.publicKey?.equals(
|
||||
auctionView.auctionManager.info.authority,
|
||||
)
|
||||
) {
|
||||
const totalCost =
|
||||
await calculateTotalCostOfRedeemingOtherPeoplesBids(
|
||||
connection,
|
||||
auctionView,
|
||||
bids,
|
||||
bidRedemptions,
|
||||
);
|
||||
setPrintingCost(totalCost);
|
||||
setShowWarningModal(true);
|
||||
}
|
||||
try {
|
||||
if (eligibleForAnything)
|
||||
if (eligibleForAnything) {
|
||||
await sendRedeemBid(
|
||||
connection,
|
||||
wallet,
|
||||
myPayingAccount.pubkey,
|
||||
auctionView,
|
||||
accountByMint,
|
||||
prizeTrackingTickets,
|
||||
bidRedemptions,
|
||||
bids,
|
||||
).then(() => setShowRedeemedBidModal(true));
|
||||
else
|
||||
} else {
|
||||
await sendCancelBid(
|
||||
connection,
|
||||
wallet,
|
||||
myPayingAccount.pubkey,
|
||||
auctionView,
|
||||
accountByMint,
|
||||
bids,
|
||||
bidRedemptions,
|
||||
prizeTrackingTickets,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setShowRedemptionIssue(true);
|
||||
|
@ -219,25 +324,54 @@ export const AuctionCard = ({
|
|||
!myPayingAccount ? (
|
||||
<Spin />
|
||||
) : eligibleForAnything ? (
|
||||
'Redeem bid'
|
||||
`Redeem bid`
|
||||
) : (
|
||||
'Refund bid'
|
||||
`${
|
||||
wallet?.publicKey &&
|
||||
auctionView.auctionManager.info.authority.equals(
|
||||
wallet.publicKey,
|
||||
)
|
||||
? 'Reclaim Items'
|
||||
: 'Refund bid'
|
||||
}`
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!hideDefaultAction && connected && !auctionView.auction.info.ended() && (
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
className="action-btn"
|
||||
disabled={loading}
|
||||
onClick={() => setShowBidModal(true)}
|
||||
style={{ marginTop: 20 }}
|
||||
>
|
||||
{loading ? <Spin /> : 'Place bid'}
|
||||
</Button>
|
||||
)}
|
||||
{!hideDefaultAction &&
|
||||
connected &&
|
||||
!auctionView.auction.info.ended() &&
|
||||
(isAuctionNotStarted && !isAuctionManagerAuthorityNotWalletOwner ? (
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
className="action-btn"
|
||||
disabled={loading}
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await startAuctionManually(connection, wallet, auctionView);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
setLoading(false);
|
||||
}}
|
||||
style={{ marginTop: 20 }}
|
||||
>
|
||||
{loading ? <Spin /> : 'Start auction'}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
className="action-btn"
|
||||
disabled={loading}
|
||||
onClick={() => setShowBidModal(true)}
|
||||
style={{ marginTop: 20 }}
|
||||
>
|
||||
{loading ? <Spin /> : 'Place bid'}
|
||||
</Button>
|
||||
))}
|
||||
|
||||
{!hideDefaultAction && !connected && (
|
||||
<Button
|
||||
|
@ -548,6 +682,22 @@ export const AuctionCard = ({
|
|||
</Route>
|
||||
</MemoryRouter>
|
||||
</MetaplexModal>
|
||||
|
||||
<MetaplexModal
|
||||
visible={showWarningModal}
|
||||
onCancel={() => setShowWarningModal(false)}
|
||||
bodyStyle={{
|
||||
alignItems: 'start',
|
||||
}}
|
||||
>
|
||||
<h3 style={{ color: 'white' }}>
|
||||
Warning: There may be some items in this auction that still are
|
||||
required by the auction for printing bidders' limited or open edition
|
||||
NFTs. If you wish to withdraw them, you are agreeing to foot the cost
|
||||
of up to an estimated ◎<b>{(printingCost || 0) / LAMPORTS_PER_SOL}</b>{' '}
|
||||
plus transaction fees to redeem their bids for them right now.
|
||||
</h3>
|
||||
</MetaplexModal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { TouchableOrbitControls } from './utils';
|
||||
|
||||
|
@ -112,6 +113,10 @@ export class MeshViewer extends React.Component<MeshViewerProps, {}> {
|
|||
meshURL = this.props.url;
|
||||
}
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath('js/libs/draco/');
|
||||
this.gltfLoader.setDRACOLoader(dracoLoader);
|
||||
|
||||
this.gltfLoader.load(
|
||||
meshURL,
|
||||
(gltf) => {
|
||||
|
|
|
@ -20,6 +20,7 @@ import { decommAuctionManagerAndReturnPrizes } from '../../actions/decommAuction
|
|||
import { sendSignMetadata } from '../../actions/sendSignMetadata';
|
||||
import { unwindVault } from '../../actions/unwindVault';
|
||||
import { settle } from '../../actions/settle';
|
||||
import { startAuctionManually } from '../../actions/startAuctionManually';
|
||||
|
||||
import { QUOTE_MINT } from '../../constants';
|
||||
import { useMeta } from '../../contexts';
|
||||
|
@ -94,7 +95,7 @@ function RunAction({
|
|||
return component;
|
||||
}
|
||||
|
||||
async function getPersonalEscrowAta(
|
||||
export async function getPersonalEscrowAta(
|
||||
wallet: WalletAdapter | undefined,
|
||||
): Promise<PublicKey | undefined> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
@ -197,21 +198,25 @@ export function useSettlementAuctions({
|
|||
const av = nextBatch[i];
|
||||
if (!CALLING_MUTEX[av.auctionManager.pubkey.toBase58()]) {
|
||||
CALLING_MUTEX[av.auctionManager.pubkey.toBase58()] = true;
|
||||
const balance = await connection.getTokenAccountBalance(
|
||||
av.auctionManager.info.acceptPayment,
|
||||
);
|
||||
if (
|
||||
((balance.value.uiAmount || 0) === 0 &&
|
||||
av.auction.info.bidState.bids
|
||||
.map(b => b.amount.toNumber())
|
||||
.reduce((acc, r) => (acc += r), 0) > 0) ||
|
||||
(balance.value.uiAmount || 0) > 0.01
|
||||
) {
|
||||
setValidDiscoveredEndedAuctions(old => ({
|
||||
...old,
|
||||
[av.auctionManager.pubkey.toBase58()]:
|
||||
balance.value.uiAmount || 0,
|
||||
}));
|
||||
try {
|
||||
const balance = await connection.getTokenAccountBalance(
|
||||
av.auctionManager.info.acceptPayment,
|
||||
);
|
||||
if (
|
||||
((balance.value.uiAmount || 0) === 0 &&
|
||||
av.auction.info.bidState.bids
|
||||
.map(b => b.amount.toNumber())
|
||||
.reduce((acc, r) => (acc += r), 0) > 0) ||
|
||||
(balance.value.uiAmount || 0) > 0.01
|
||||
) {
|
||||
setValidDiscoveredEndedAuctions(old => ({
|
||||
...old,
|
||||
[av.auctionManager.pubkey.toBase58()]:
|
||||
balance.value.uiAmount || 0,
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,6 +294,7 @@ export function Notifications() {
|
|||
const possiblyBrokenAuctionManagerSetups = useAuctions(
|
||||
AuctionViewState.Defective,
|
||||
);
|
||||
const upcomingAuctions = useAuctions(AuctionViewState.Upcoming);
|
||||
const connection = useConnection();
|
||||
const { wallet } = useWallet();
|
||||
const { accountByMint } = useUserAccounts();
|
||||
|
@ -408,6 +414,25 @@ export function Notifications() {
|
|||
});
|
||||
});
|
||||
|
||||
upcomingAuctions
|
||||
.filter(v => v.auctionManager.info.authority.toBase58() === walletPubkey)
|
||||
.forEach(v => {
|
||||
notifications.push({
|
||||
id: v.auctionManager.pubkey.toBase58(),
|
||||
title: 'You have an auction which is not started yet!',
|
||||
description: <span>You can activate it now if you wish.</span>,
|
||||
action: async () => {
|
||||
try {
|
||||
await startAuctionManually(connection, wallet, v);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const content = notifications.length ? (
|
||||
<div style={{ width: '300px' }}>
|
||||
<List
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
ParsedAccount,
|
||||
actions,
|
||||
Edition,
|
||||
MasterEdition,
|
||||
AuctionData,
|
||||
SafetyDepositBox,
|
||||
VaultKey,
|
||||
|
@ -30,6 +29,8 @@ import {
|
|||
AuctionDataExtended,
|
||||
MAX_AUCTION_DATA_EXTENDED_SIZE,
|
||||
AuctionDataExtendedParser,
|
||||
MasterEditionV1,
|
||||
MasterEditionV2,
|
||||
} from '@oyster/common';
|
||||
import { MintInfo } from '@solana/spl-token';
|
||||
import { Connection, PublicKey, PublicKeyAndAccount } from '@solana/web3.js';
|
||||
|
@ -54,6 +55,8 @@ import {
|
|||
WhitelistedCreatorParser,
|
||||
PayoutTicket,
|
||||
decodePayoutTicket,
|
||||
PrizeTrackingTicket,
|
||||
decodePrizeTrackingTicket,
|
||||
} from '../models/metaplex';
|
||||
import names from './../config/userNames.json';
|
||||
|
||||
|
@ -62,9 +65,16 @@ interface MetaState {
|
|||
metadataByMint: Record<string, ParsedAccount<Metadata>>;
|
||||
metadataByMasterEdition: Record<string, ParsedAccount<Metadata>>;
|
||||
editions: Record<string, ParsedAccount<Edition>>;
|
||||
masterEditions: Record<string, ParsedAccount<MasterEdition>>;
|
||||
masterEditionsByPrintingMint: Record<string, ParsedAccount<MasterEdition>>;
|
||||
masterEditionsByOneTimeAuthMint: Record<string, ParsedAccount<MasterEdition>>;
|
||||
masterEditions: Record<
|
||||
string,
|
||||
ParsedAccount<MasterEditionV1 | MasterEditionV2>
|
||||
>;
|
||||
masterEditionsByPrintingMint: Record<string, ParsedAccount<MasterEditionV1>>;
|
||||
masterEditionsByOneTimeAuthMint: Record<
|
||||
string,
|
||||
ParsedAccount<MasterEditionV1>
|
||||
>;
|
||||
prizeTrackingTickets: Record<string, ParsedAccount<PrizeTrackingTicket>>;
|
||||
auctionManagersByAuction: Record<string, ParsedAccount<AuctionManager>>;
|
||||
auctions: Record<string, ParsedAccount<AuctionData>>;
|
||||
auctionDataExtended: Record<string, ParsedAccount<AuctionDataExtended>>;
|
||||
|
@ -142,6 +152,7 @@ const MetaContext = React.createContext<MetaContextState>({
|
|||
bidRedemptions: {},
|
||||
whitelistedCreatorsByCreator: {},
|
||||
payoutTickets: {},
|
||||
prizeTrackingTickets: {},
|
||||
});
|
||||
|
||||
export function MetaProvider({ children = null as any }) {
|
||||
|
@ -151,14 +162,17 @@ export function MetaProvider({ children = null as any }) {
|
|||
const [state, setState] = useState<MetaState>({
|
||||
metadata: [] as Array<ParsedAccount<Metadata>>,
|
||||
metadataByMint: {} as Record<string, ParsedAccount<Metadata>>,
|
||||
masterEditions: {} as Record<string, ParsedAccount<MasterEdition>>,
|
||||
masterEditions: {} as Record<
|
||||
string,
|
||||
ParsedAccount<MasterEditionV1 | MasterEditionV2>
|
||||
>,
|
||||
masterEditionsByPrintingMint: {} as Record<
|
||||
string,
|
||||
ParsedAccount<MasterEdition>
|
||||
ParsedAccount<MasterEditionV1>
|
||||
>,
|
||||
masterEditionsByOneTimeAuthMint: {} as Record<
|
||||
string,
|
||||
ParsedAccount<MasterEdition>
|
||||
ParsedAccount<MasterEditionV1>
|
||||
>,
|
||||
metadataByMasterEdition: {} as any,
|
||||
editions: {},
|
||||
|
@ -173,6 +187,7 @@ export function MetaProvider({ children = null as any }) {
|
|||
bidderMetadataByAuctionAndBidder: {},
|
||||
bidderPotsByAuctionAndBidder: {},
|
||||
safetyDepositBoxesByVaultAndIndex: {},
|
||||
prizeTrackingTickets: {},
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
@ -229,6 +244,7 @@ export function MetaProvider({ children = null as any }) {
|
|||
bidderMetadataByAuctionAndBidder: {},
|
||||
bidderPotsByAuctionAndBidder: {},
|
||||
safetyDepositBoxesByVaultAndIndex: {},
|
||||
prizeTrackingTickets: {},
|
||||
};
|
||||
|
||||
const updateTemp = (prop: keyof MetaState, key: string, value: any) => {
|
||||
|
@ -270,7 +286,6 @@ export function MetaProvider({ children = null as any }) {
|
|||
|
||||
tempCache.metadata.push(metadata);
|
||||
} else {
|
||||
|
||||
delete tempCache.metadataByMint[metadata.info.mint.toBase58() || ''];
|
||||
}
|
||||
}
|
||||
|
@ -481,6 +496,7 @@ export function MetaProvider({ children = null as any }) {
|
|||
store: state.store,
|
||||
payoutTickets: state.payoutTickets,
|
||||
masterEditionsByOneTimeAuthMint: state.masterEditionsByOneTimeAuthMint,
|
||||
prizeTrackingTickets: state.prizeTrackingTickets,
|
||||
isLoading,
|
||||
}}
|
||||
>
|
||||
|
@ -662,6 +678,14 @@ const processMetaplexAccounts = async (
|
|||
info: ticket,
|
||||
};
|
||||
setter('payoutTickets', a.pubkey.toBase58(), account);
|
||||
} else if (a.account.data[0] === MetaplexKey.PrizeTrackingTicketV1) {
|
||||
const ticket = decodePrizeTrackingTicket(a.account.data);
|
||||
const account: ParsedAccount<PrizeTrackingTicket> = {
|
||||
pubkey: a.pubkey,
|
||||
account: a.account,
|
||||
info: ticket,
|
||||
};
|
||||
setter('prizeTrackingTickets', a.pubkey.toBase58(), account);
|
||||
} else if (a.account.data[0] === MetaplexKey.StoreV1) {
|
||||
const store = decodeStore(a.account.data);
|
||||
const account: ParsedAccount<Store> = {
|
||||
|
@ -741,24 +765,40 @@ const processMetaData = (
|
|||
info: edition,
|
||||
};
|
||||
setter('editions', meta.pubkey.toBase58(), account);
|
||||
} else if (meta.account.data[0] === MetadataKey.MasterEditionV1) {
|
||||
} else if (
|
||||
meta.account.data[0] === MetadataKey.MasterEditionV1 ||
|
||||
meta.account.data[0] === MetadataKey.MasterEditionV2
|
||||
) {
|
||||
const masterEdition = decodeMasterEdition(meta.account.data);
|
||||
const account: ParsedAccount<MasterEdition> = {
|
||||
pubkey: meta.pubkey,
|
||||
account: meta.account,
|
||||
info: masterEdition,
|
||||
};
|
||||
setter('masterEditions', meta.pubkey.toBase58(), account);
|
||||
setter(
|
||||
'masterEditionsByPrintingMint',
|
||||
masterEdition.printingMint.toBase58(),
|
||||
account,
|
||||
);
|
||||
setter(
|
||||
'masterEditionsByOneTimeAuthMint',
|
||||
masterEdition.oneTimePrintingAuthorizationMint.toBase58(),
|
||||
account,
|
||||
);
|
||||
|
||||
if (masterEdition.key == MetadataKey.MasterEditionV1) {
|
||||
const account: ParsedAccount<MasterEditionV1> = {
|
||||
pubkey: meta.pubkey,
|
||||
account: meta.account,
|
||||
info: masterEdition as MasterEditionV1,
|
||||
};
|
||||
setter('masterEditions', meta.pubkey.toBase58(), account);
|
||||
|
||||
setter(
|
||||
'masterEditionsByPrintingMint',
|
||||
(masterEdition as MasterEditionV1).printingMint.toBase58(),
|
||||
account,
|
||||
);
|
||||
setter(
|
||||
'masterEditionsByOneTimeAuthMint',
|
||||
(
|
||||
masterEdition as MasterEditionV1
|
||||
).oneTimePrintingAuthorizationMint.toBase58(),
|
||||
account,
|
||||
);
|
||||
} else {
|
||||
const account: ParsedAccount<MasterEditionV2> = {
|
||||
pubkey: meta.pubkey,
|
||||
account: meta.account,
|
||||
info: masterEdition as MasterEditionV2,
|
||||
};
|
||||
setter('masterEditions', meta.pubkey.toBase58(), account);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore errors
|
||||
|
|
|
@ -5,7 +5,8 @@ import { Art, Artist, ArtType } from '../types';
|
|||
import {
|
||||
Edition,
|
||||
IMetadataExtension,
|
||||
MasterEdition,
|
||||
MasterEditionV1,
|
||||
MasterEditionV2,
|
||||
Metadata,
|
||||
ParsedAccount,
|
||||
} from '@oyster/common';
|
||||
|
@ -16,7 +17,10 @@ import { useInView } from 'react-intersection-observer';
|
|||
const metadataToArt = (
|
||||
info: Metadata | undefined,
|
||||
editions: Record<string, ParsedAccount<Edition>>,
|
||||
masterEditions: Record<string, ParsedAccount<MasterEdition>>,
|
||||
masterEditions: Record<
|
||||
string,
|
||||
ParsedAccount<MasterEditionV1 | MasterEditionV2>
|
||||
>,
|
||||
whitelistedCreatorsByCreator: Record<
|
||||
string,
|
||||
ParsedAccount<WhitelistedCreator>
|
||||
|
|
|
@ -7,7 +7,8 @@ import {
|
|||
BidderMetadata,
|
||||
BidderPot,
|
||||
Vault,
|
||||
MasterEdition,
|
||||
MasterEditionV1,
|
||||
MasterEditionV2,
|
||||
useWallet,
|
||||
} from '@oyster/common';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
|
@ -32,7 +33,7 @@ export enum AuctionViewState {
|
|||
export interface AuctionViewItem {
|
||||
metadata: ParsedAccount<Metadata>;
|
||||
safetyDeposit: ParsedAccount<SafetyDepositBox>;
|
||||
masterEdition?: ParsedAccount<MasterEdition>;
|
||||
masterEdition?: ParsedAccount<MasterEditionV1 | MasterEditionV2>;
|
||||
}
|
||||
|
||||
// Flattened surface item for easy display
|
||||
|
@ -188,10 +189,16 @@ export function processAccountsIntoAuctionView(
|
|||
ParsedAccount<BidderMetadata>
|
||||
>,
|
||||
bidderPotsByAuctionAndBidder: Record<string, ParsedAccount<BidderPot>>,
|
||||
masterEditions: Record<string, ParsedAccount<MasterEdition>>,
|
||||
masterEditions: Record<
|
||||
string,
|
||||
ParsedAccount<MasterEditionV1 | MasterEditionV2>
|
||||
>,
|
||||
vaults: Record<string, ParsedAccount<Vault>>,
|
||||
masterEditionsByPrintingMint: Record<string, ParsedAccount<MasterEdition>>,
|
||||
masterEditionsByOneTimeAuthMint: Record<string, ParsedAccount<MasterEdition>>,
|
||||
masterEditionsByPrintingMint: Record<string, ParsedAccount<MasterEditionV1>>,
|
||||
masterEditionsByOneTimeAuthMint: Record<
|
||||
string,
|
||||
ParsedAccount<MasterEditionV1>
|
||||
>,
|
||||
metadataByMasterEdition: Record<string, ParsedAccount<Metadata>>,
|
||||
cachedRedemptionKeysByWallet: Record<
|
||||
string,
|
||||
|
@ -317,6 +324,42 @@ export function processAccountsIntoAuctionView(
|
|||
}
|
||||
|
||||
if (boxes.length > 0) {
|
||||
let participationMetadata: ParsedAccount<Metadata> | undefined =
|
||||
undefined;
|
||||
let participationBox: ParsedAccount<SafetyDepositBox> | undefined =
|
||||
undefined;
|
||||
let participationMaster:
|
||||
| ParsedAccount<MasterEditionV1 | MasterEditionV2>
|
||||
| undefined = undefined;
|
||||
if (
|
||||
auctionManager.info.settings.participationConfig !== null &&
|
||||
auctionManager.info.settings.participationConfig !== undefined
|
||||
) {
|
||||
participationBox =
|
||||
boxes[
|
||||
auctionManager.info.settings.participationConfig
|
||||
?.safetyDepositBoxIndex
|
||||
];
|
||||
// Cover case of V1 master edition (where we're using one time auth mint in storage)
|
||||
// and case of v2 master edition where the edition itself is stored
|
||||
participationMetadata =
|
||||
metadataByMasterEdition[
|
||||
masterEditionsByOneTimeAuthMint[
|
||||
participationBox.info.tokenMint.toBase58()
|
||||
]?.pubkey.toBase58()
|
||||
] || metadataByMint[participationBox.info.tokenMint.toBase58()];
|
||||
if (participationMetadata) {
|
||||
participationMaster =
|
||||
masterEditionsByOneTimeAuthMint[
|
||||
participationBox.info.tokenMint.toBase58()
|
||||
] ||
|
||||
(participationMetadata.info.masterEdition &&
|
||||
masterEditions[
|
||||
participationMetadata.info.masterEdition?.toBase58()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
let view: Partial<AuctionView> = {
|
||||
auction,
|
||||
auctionManager,
|
||||
|
@ -329,7 +372,7 @@ export function processAccountsIntoAuctionView(
|
|||
boxes[it.safetyDepositBoxIndex]?.info.tokenMint.toBase58()
|
||||
];
|
||||
if (!metadata) {
|
||||
// Means is a limited edition, so the tokenMint is the printingMint
|
||||
// Means is a limited edition v1, so the tokenMint is the printingMint
|
||||
let masterEdition =
|
||||
masterEditionsByPrintingMint[
|
||||
boxes[it.safetyDepositBoxIndex]?.info.tokenMint.toBase58()
|
||||
|
@ -349,30 +392,11 @@ export function processAccountsIntoAuctionView(
|
|||
});
|
||||
}),
|
||||
participationItem:
|
||||
auctionManager.info.settings.participationConfig !== null &&
|
||||
auctionManager.info.settings.participationConfig !== undefined
|
||||
participationMetadata && participationBox
|
||||
? {
|
||||
metadata:
|
||||
metadataByMasterEdition[
|
||||
masterEditionsByOneTimeAuthMint[
|
||||
boxes[
|
||||
auctionManager.info.settings.participationConfig
|
||||
?.safetyDepositBoxIndex
|
||||
]?.info.tokenMint.toBase58()
|
||||
]?.pubkey.toBase58()
|
||||
],
|
||||
safetyDeposit:
|
||||
boxes[
|
||||
auctionManager.info.settings.participationConfig
|
||||
?.safetyDepositBoxIndex
|
||||
],
|
||||
masterEdition:
|
||||
masterEditionsByOneTimeAuthMint[
|
||||
boxes[
|
||||
auctionManager.info.settings.participationConfig
|
||||
?.safetyDepositBoxIndex
|
||||
]?.info.tokenMint.toBase58()
|
||||
],
|
||||
metadata: participationMetadata,
|
||||
safetyDeposit: participationBox,
|
||||
masterEdition: participationMaster,
|
||||
}
|
||||
: undefined,
|
||||
myBidderMetadata: bidderMetadata,
|
||||
|
|
|
@ -4,9 +4,11 @@ import { PublicKey } from '@solana/web3.js';
|
|||
export const useCreatorArts = (id?: PublicKey | string) => {
|
||||
const { metadata } = useMeta();
|
||||
const filtered = metadata.filter(
|
||||
m =>
|
||||
m.info.data.creators !== null
|
||||
&& m.info.data.creators.findIndex(c => c.address.toBase58() === id) >= 0
|
||||
m =>
|
||||
m.info.data.creators !== null &&
|
||||
m.info.data.creators?.findIndex(c => c.address.toBase58() === id) !==
|
||||
undefined &&
|
||||
m.info.data.creators.findIndex(c => c.address.toBase58() === id) >= 0,
|
||||
);
|
||||
|
||||
return filtered;
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { TokenAccount, useUserAccounts } from '@oyster/common';
|
||||
import {
|
||||
MasterEditionV1,
|
||||
MetadataKey,
|
||||
ParsedAccount,
|
||||
TokenAccount,
|
||||
useUserAccounts,
|
||||
} from '@oyster/common';
|
||||
import { SafetyDepositDraft } from '../actions/createAuctionManager';
|
||||
import { useMeta } from './../contexts';
|
||||
|
||||
|
@ -32,9 +38,15 @@ export const useUserArts = (): SafetyDepositDraft[] => {
|
|||
let i = 0;
|
||||
ownedMetadata.forEach(m => {
|
||||
let a = accountByMint.get(m.info.mint.toBase58());
|
||||
let masterA = accountByMint.get(
|
||||
possibleMasterEditions[i]?.info.printingMint?.toBase58() || '',
|
||||
);
|
||||
let masterA;
|
||||
|
||||
if (possibleMasterEditions[i]?.info.key == MetadataKey.MasterEditionV1) {
|
||||
masterA = accountByMint.get(
|
||||
(
|
||||
possibleMasterEditions[i] as ParsedAccount<MasterEditionV1>
|
||||
)?.info.printingMint?.toBase58() || '',
|
||||
);
|
||||
}
|
||||
|
||||
if (a) {
|
||||
safetyDeposits.push({
|
||||
|
|
|
@ -11,9 +11,9 @@ import {
|
|||
} from '@solana/web3.js';
|
||||
import { serialize } from 'borsh';
|
||||
|
||||
import { PopulateParticipationPrintingAccountArgs, SCHEMA } from '.';
|
||||
import { DeprecatedPopulateParticipationPrintingAccountArgs, SCHEMA } from '.';
|
||||
|
||||
export async function populateParticipationPrintingAccount(
|
||||
export async function deprecatedPopulateParticipationPrintingAccount(
|
||||
vault: PublicKey,
|
||||
auctionManager: PublicKey,
|
||||
auction: PublicKey,
|
||||
|
@ -46,7 +46,7 @@ export async function populateParticipationPrintingAccount(
|
|||
)
|
||||
)[0];
|
||||
|
||||
const value = new PopulateParticipationPrintingAccountArgs();
|
||||
const value = new DeprecatedPopulateParticipationPrintingAccountArgs();
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
|
||||
const keys = [
|
|
@ -10,11 +10,11 @@ import { serialize } from 'borsh';
|
|||
import {
|
||||
getAuctionKeys,
|
||||
getBidderKeys,
|
||||
RedeemParticipationBidArgs,
|
||||
DeprecatedRedeemParticipationBidArgs,
|
||||
SCHEMA,
|
||||
} from '.';
|
||||
|
||||
export async function redeemParticipationBid(
|
||||
export async function deprecatedRedeemParticipationBid(
|
||||
vault: PublicKey,
|
||||
safetyDepositTokenStore: PublicKey,
|
||||
destination: PublicKey,
|
||||
|
@ -41,7 +41,7 @@ export async function redeemParticipationBid(
|
|||
auctionKey,
|
||||
bidder,
|
||||
);
|
||||
const value = new RedeemParticipationBidArgs();
|
||||
const value = new DeprecatedRedeemParticipationBidArgs();
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const keys = [
|
||||
{
|
|
@ -7,9 +7,9 @@ import {
|
|||
} from '@solana/web3.js';
|
||||
import { serialize } from 'borsh';
|
||||
|
||||
import { SCHEMA, ValidateParticipationArgs } from '.';
|
||||
import { SCHEMA, DeprecatedValidateParticipationArgs } from '.';
|
||||
|
||||
export async function validateParticipation(
|
||||
export async function deprecatedValidateParticipation(
|
||||
auctionManager: PublicKey,
|
||||
openEditionMetadata: PublicKey,
|
||||
openEditionMasterAccount: PublicKey,
|
||||
|
@ -24,7 +24,7 @@ export async function validateParticipation(
|
|||
) {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
const value = new ValidateParticipationArgs();
|
||||
const value = new DeprecatedValidateParticipationArgs();
|
||||
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
|
|
@ -12,13 +12,17 @@ import { deserializeUnchecked } from 'borsh';
|
|||
export * from './initAuctionManager';
|
||||
export * from './redeemBid';
|
||||
export * from './redeemFullRightsTransferBid';
|
||||
export * from './redeemParticipationBid';
|
||||
export * from './deprecatedRedeemParticipationBid';
|
||||
export * from './startAuction';
|
||||
export * from './validateSafetyDepositBox';
|
||||
export * from './redeemParticipationBidV2';
|
||||
export * from './redeemPrintingV2Bid';
|
||||
export * from './withdrawMasterEdition';
|
||||
|
||||
export const METAPLEX_PREFIX = 'metaplex';
|
||||
export const ORIGINAL_AUTHORITY_LOOKUP_SIZE = 33;
|
||||
|
||||
export const MAX_BID_REDEMPTION_TICKET_SIZE = 3;
|
||||
export const MAX_PRIZE_TRACKING_TICKET_SIZE = 1 + 32 + 8 + 8 + 8 + 50;
|
||||
export enum MetaplexKey {
|
||||
Uninitialized = 0,
|
||||
OriginalAuthorityLookupV1 = 1,
|
||||
|
@ -28,8 +32,28 @@ export enum MetaplexKey {
|
|||
PayoutTicketV1 = 5,
|
||||
SafetyDepositValidationTicketV1 = 6,
|
||||
AuctionManagerV1 = 7,
|
||||
PrizeTrackingTicketV1 = 8,
|
||||
}
|
||||
export class PrizeTrackingTicket {
|
||||
key: MetaplexKey = MetaplexKey.PrizeTrackingTicketV1;
|
||||
metadata: PublicKey;
|
||||
supplySnapshot: BN;
|
||||
expectedRedemptions: BN;
|
||||
redemptions: BN;
|
||||
|
||||
constructor(args: {
|
||||
metadata: PublicKey;
|
||||
supplySnapshot: BN;
|
||||
expectedRedemptions: BN;
|
||||
redemptions: BN;
|
||||
}) {
|
||||
this.key = MetaplexKey.PrizeTrackingTicketV1;
|
||||
this.metadata = args.metadata;
|
||||
this.supplySnapshot = args.supplySnapshot;
|
||||
this.expectedRedemptions = args.expectedRedemptions;
|
||||
this.redemptions = args.redemptions;
|
||||
}
|
||||
}
|
||||
export class PayoutTicket {
|
||||
key: MetaplexKey = MetaplexKey.PayoutTicketV1;
|
||||
recipient: PublicKey;
|
||||
|
@ -92,7 +116,7 @@ export class RedeemFullRightsTransferBidArgs {
|
|||
instruction = 3;
|
||||
}
|
||||
|
||||
export class RedeemParticipationBidArgs {
|
||||
export class DeprecatedRedeemParticipationBidArgs {
|
||||
instruction = 4;
|
||||
}
|
||||
|
||||
|
@ -103,7 +127,7 @@ export class ClaimBidArgs {
|
|||
instruction = 6;
|
||||
}
|
||||
|
||||
export class PopulateParticipationPrintingAccountArgs {
|
||||
export class DeprecatedPopulateParticipationPrintingAccountArgs {
|
||||
instruction = 11;
|
||||
}
|
||||
|
||||
|
@ -156,7 +180,7 @@ export class SetWhitelistedCreatorArgs {
|
|||
}
|
||||
}
|
||||
|
||||
export class ValidateParticipationArgs {
|
||||
export class DeprecatedValidateParticipationArgs {
|
||||
instruction = 10;
|
||||
}
|
||||
|
||||
|
@ -164,6 +188,22 @@ export class DecommissionAuctionManagerArgs {
|
|||
instruction = 13;
|
||||
}
|
||||
|
||||
export class RedeemPrintingV2BidArgs {
|
||||
instruction = 14;
|
||||
editionOffset: BN;
|
||||
winIndex: BN;
|
||||
constructor(args: { editionOffset: BN; winIndex: BN }) {
|
||||
this.editionOffset = args.editionOffset;
|
||||
this.winIndex = args.winIndex;
|
||||
}
|
||||
}
|
||||
export class WithdrawMasterEditionArgs {
|
||||
instruction = 15;
|
||||
}
|
||||
export class RedeemParticipationBidV2Args {
|
||||
instruction = 16;
|
||||
}
|
||||
|
||||
export enum WinningConstraint {
|
||||
NoParticipationPrize = 0,
|
||||
ParticipationPrizeGiven = 1,
|
||||
|
@ -202,8 +242,11 @@ export enum WinningConfigType {
|
|||
/// token itself. The other person will be able to mint authorization tokens and make changes to the
|
||||
/// artwork.
|
||||
FullRightsTransfer,
|
||||
/// Means you are using authorization tokens to print off editions during the auction
|
||||
Printing,
|
||||
/// Means you are using authorization tokens to print off editions during the auction using
|
||||
/// from a MasterEditionV1
|
||||
PrintingV1,
|
||||
/// Means you are using the MasterEditionV2 to print off editions
|
||||
PrintingV2,
|
||||
}
|
||||
export class ParticipationState {
|
||||
collectedToAcceptPayment: BN = new BN(0);
|
||||
|
@ -246,6 +289,14 @@ export class WinningConfigItem {
|
|||
}
|
||||
}
|
||||
|
||||
export const decodePrizeTrackingTicket = (buffer: Buffer) => {
|
||||
return deserializeUnchecked(
|
||||
SCHEMA,
|
||||
PrizeTrackingTicket,
|
||||
buffer,
|
||||
) as PrizeTrackingTicket;
|
||||
};
|
||||
|
||||
export const decodeWhitelistedCreator = (buffer: Buffer) => {
|
||||
return deserializeUnchecked(
|
||||
SCHEMA,
|
||||
|
@ -374,6 +425,19 @@ export class BidRedemptionTicket {
|
|||
}
|
||||
|
||||
export const SCHEMA = new Map<any, any>([
|
||||
[
|
||||
PrizeTrackingTicket,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [
|
||||
['key', 'u8'],
|
||||
['metadata', 'pubkey'],
|
||||
['supplySnapshot', 'u64'],
|
||||
['expectedRedemptions', 'u64'],
|
||||
['redemptions', 'u64'],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
AuctionManager,
|
||||
{
|
||||
|
@ -525,7 +589,7 @@ export const SCHEMA = new Map<any, any>([
|
|||
},
|
||||
],
|
||||
[
|
||||
PopulateParticipationPrintingAccountArgs,
|
||||
DeprecatedPopulateParticipationPrintingAccountArgs,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [['instruction', 'u8']],
|
||||
|
@ -549,6 +613,32 @@ export const SCHEMA = new Map<any, any>([
|
|||
fields: [['instruction', 'u8']],
|
||||
},
|
||||
],
|
||||
[
|
||||
RedeemPrintingV2BidArgs,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [
|
||||
['instruction', 'u8'],
|
||||
['editionOffset', 'u64'],
|
||||
['winIndex', 'u64'],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
WithdrawMasterEditionArgs,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [['instruction', 'u8']],
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
RedeemParticipationBidV2Args,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [['instruction', 'u8']],
|
||||
},
|
||||
],
|
||||
[
|
||||
InitAuctionManagerArgs,
|
||||
{
|
||||
|
@ -581,7 +671,7 @@ export const SCHEMA = new Map<any, any>([
|
|||
},
|
||||
],
|
||||
[
|
||||
RedeemParticipationBidArgs,
|
||||
DeprecatedRedeemParticipationBidArgs,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [['instruction', 'u8']],
|
||||
|
@ -634,7 +724,7 @@ export const SCHEMA = new Map<any, any>([
|
|||
},
|
||||
],
|
||||
[
|
||||
ValidateParticipationArgs,
|
||||
DeprecatedValidateParticipationArgs,
|
||||
{
|
||||
kind: 'struct',
|
||||
fields: [['instruction', 'u8']],
|
||||
|
@ -677,6 +767,24 @@ export async function getAuctionKeys(
|
|||
return { auctionKey, auctionManagerKey };
|
||||
}
|
||||
|
||||
export async function getBidRedemption(
|
||||
auctionKey: PublicKey,
|
||||
bidMetadata: PublicKey,
|
||||
): Promise<PublicKey> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
return (
|
||||
await findProgramAddress(
|
||||
[
|
||||
Buffer.from(METAPLEX_PREFIX),
|
||||
auctionKey.toBuffer(),
|
||||
bidMetadata.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.metaplex,
|
||||
)
|
||||
)[0];
|
||||
}
|
||||
|
||||
export async function getBidderKeys(
|
||||
auctionKey: PublicKey,
|
||||
bidder: PublicKey,
|
||||
|
@ -696,16 +804,10 @@ export async function getBidderKeys(
|
|||
)
|
||||
)[0];
|
||||
|
||||
const bidRedemption: PublicKey = (
|
||||
await findProgramAddress(
|
||||
[
|
||||
Buffer.from(METAPLEX_PREFIX),
|
||||
auctionKey.toBuffer(),
|
||||
bidMetadata.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.metaplex,
|
||||
)
|
||||
)[0];
|
||||
const bidRedemption: PublicKey = await getBidRedemption(
|
||||
auctionKey,
|
||||
bidMetadata,
|
||||
);
|
||||
|
||||
return { bidMetadata, bidRedemption };
|
||||
}
|
||||
|
@ -748,6 +850,29 @@ export async function getWhitelistedCreator(creator: PublicKey) {
|
|||
)[0];
|
||||
}
|
||||
|
||||
export async function getPrizeTrackingTicket(
|
||||
auctionManager: PublicKey,
|
||||
mint: PublicKey,
|
||||
) {
|
||||
const PROGRAM_IDS = programIds();
|
||||
const store = PROGRAM_IDS.store;
|
||||
if (!store) {
|
||||
throw new Error('Store not initialized');
|
||||
}
|
||||
|
||||
return (
|
||||
await findProgramAddress(
|
||||
[
|
||||
Buffer.from(METAPLEX_PREFIX),
|
||||
PROGRAM_IDS.metaplex.toBuffer(),
|
||||
auctionManager.toBuffer(),
|
||||
mint.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.metaplex,
|
||||
)
|
||||
)[0];
|
||||
}
|
||||
|
||||
export async function getSafetyDepositBoxValidationTicket(
|
||||
auctionManager: PublicKey,
|
||||
safetyDepositBox: PublicKey,
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
import {
|
||||
getEdition,
|
||||
programIds,
|
||||
getMetadata,
|
||||
findProgramAddress,
|
||||
VAULT_PREFIX,
|
||||
getEditionMarkPda,
|
||||
getAuctionExtended,
|
||||
} from '@oyster/common';
|
||||
import {
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
SYSVAR_RENT_PUBKEY,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import BN from 'bn.js';
|
||||
import { serialize } from 'borsh';
|
||||
|
||||
import {
|
||||
getAuctionKeys,
|
||||
getBidderKeys,
|
||||
RedeemParticipationBidV2Args,
|
||||
SCHEMA,
|
||||
getPrizeTrackingTicket,
|
||||
} from '.';
|
||||
|
||||
export async function redeemParticipationBidV2(
|
||||
vault: PublicKey,
|
||||
safetyDepositTokenStore: PublicKey,
|
||||
destination: PublicKey,
|
||||
safetyDeposit: PublicKey,
|
||||
fractionMint: PublicKey,
|
||||
bidder: PublicKey,
|
||||
payer: PublicKey,
|
||||
metadata: PublicKey,
|
||||
masterEdition: PublicKey,
|
||||
originalMint: PublicKey,
|
||||
transferAuthority: PublicKey,
|
||||
acceptPaymentAccount: PublicKey,
|
||||
tokenPaymentAccount: PublicKey,
|
||||
newMint: PublicKey,
|
||||
edition: BN,
|
||||
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 auctionDataExtended = await getAuctionExtended({
|
||||
auctionProgramId: PROGRAM_IDS.auction,
|
||||
resource: vault,
|
||||
});
|
||||
|
||||
const { bidRedemption, bidMetadata } = await getBidderKeys(
|
||||
auctionKey,
|
||||
bidder,
|
||||
);
|
||||
|
||||
const prizeTrackingTicket = await getPrizeTrackingTicket(
|
||||
auctionManagerKey,
|
||||
originalMint,
|
||||
);
|
||||
|
||||
const newMetadata = await getMetadata(newMint);
|
||||
const newEdition = await getEdition(newMint);
|
||||
|
||||
const editionMarkPda = await getEditionMarkPda(originalMint, edition);
|
||||
|
||||
const value = new RedeemParticipationBidV2Args();
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const keys = [
|
||||
{
|
||||
pubkey: auctionManagerKey,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: safetyDepositTokenStore,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: destination,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: bidRedemption,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: safetyDeposit,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: vault,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: fractionMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: auctionKey,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: bidMetadata,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: bidder,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: payer,
|
||||
isSigner: true,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.token,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.vault,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.metadata,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: store,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: SystemProgram.programId,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: SYSVAR_RENT_PUBKEY,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: transferAuthority,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: acceptPaymentAccount,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: tokenPaymentAccount,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: prizeTrackingTicket,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newMetadata,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newEdition,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: masterEdition,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: editionMarkPda,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
// Mint authority (this) is going to be the payer since the bidder
|
||||
// may not be signer hre - we may be redeeming for someone else (permissionless)
|
||||
// and during the txn, mint authority is removed from us and given to master edition.
|
||||
// The ATA account is already owned by bidder by default. No signing needed
|
||||
pubkey: payer,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: metadata,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
|
||||
{ pubkey: auctionDataExtended, isSigner: false, isWritable: false },
|
||||
];
|
||||
|
||||
instructions.push(
|
||||
new TransactionInstruction({
|
||||
keys,
|
||||
programId: PROGRAM_IDS.metaplex,
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
import {
|
||||
findProgramAddress,
|
||||
getEdition,
|
||||
getEditionMarkPda,
|
||||
getMetadata,
|
||||
programIds,
|
||||
VAULT_PREFIX,
|
||||
} from '@oyster/common';
|
||||
import {
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
SYSVAR_RENT_PUBKEY,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import BN from 'bn.js';
|
||||
import { serialize } from 'borsh';
|
||||
|
||||
import {
|
||||
getAuctionKeys,
|
||||
getBidderKeys,
|
||||
RedeemPrintingV2BidArgs,
|
||||
getPrizeTrackingTicket,
|
||||
SCHEMA,
|
||||
} from '.';
|
||||
|
||||
export async function redeemPrintingV2Bid(
|
||||
vault: PublicKey,
|
||||
safetyDepositTokenStore: PublicKey,
|
||||
tokenAccount: PublicKey,
|
||||
safetyDeposit: PublicKey,
|
||||
fractionMint: PublicKey,
|
||||
bidder: PublicKey,
|
||||
payer: PublicKey,
|
||||
metadata: PublicKey,
|
||||
masterEdition: PublicKey,
|
||||
originalMint: PublicKey,
|
||||
newMint: PublicKey,
|
||||
edition: BN,
|
||||
editionOffset: BN,
|
||||
winIndex: BN,
|
||||
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 { bidRedemption, bidMetadata } = await getBidderKeys(
|
||||
auctionKey,
|
||||
bidder,
|
||||
);
|
||||
|
||||
const prizeTrackingTicket = await getPrizeTrackingTicket(
|
||||
auctionManagerKey,
|
||||
originalMint,
|
||||
);
|
||||
|
||||
const newMetadata = await getMetadata(newMint);
|
||||
const newEdition = await getEdition(newMint);
|
||||
|
||||
const editionMarkPda = await getEditionMarkPda(originalMint, edition);
|
||||
|
||||
const value = new RedeemPrintingV2BidArgs({ editionOffset, winIndex });
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const keys = [
|
||||
{
|
||||
pubkey: auctionManagerKey,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: safetyDepositTokenStore,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: tokenAccount,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: bidRedemption,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: safetyDeposit,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: vault,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: fractionMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: auctionKey,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: bidMetadata,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: bidder,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: payer,
|
||||
isSigner: true,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.token,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.vault,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.metadata,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: store,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: SystemProgram.programId,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: SYSVAR_RENT_PUBKEY,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: prizeTrackingTicket,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newMetadata,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newEdition,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: masterEdition,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: newMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: editionMarkPda,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
// Mint authority (this) is going to be the payer since the bidder
|
||||
// may not be signer hre - we may be redeeming for someone else (permissionless)
|
||||
// and during the txn, mint authority is removed from us and given to master edition.
|
||||
// The ATA account is already owned by bidder by default. No signing needed
|
||||
pubkey: payer,
|
||||
isSigner: true,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: metadata,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
];
|
||||
|
||||
instructions.push(
|
||||
new TransactionInstruction({
|
||||
keys,
|
||||
programId: PROGRAM_IDS.metaplex,
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
import {
|
||||
AUCTION_PREFIX,
|
||||
EXTENDED,
|
||||
findProgramAddress,
|
||||
programIds,
|
||||
VAULT_PREFIX,
|
||||
} from '@oyster/common';
|
||||
import {
|
||||
PublicKey,
|
||||
SYSVAR_RENT_PUBKEY,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import { serialize } from 'borsh';
|
||||
|
||||
import {
|
||||
getAuctionKeys,
|
||||
WithdrawMasterEditionArgs,
|
||||
SCHEMA,
|
||||
getPrizeTrackingTicket,
|
||||
} from '.';
|
||||
|
||||
export async function withdrawMasterEdition(
|
||||
vault: PublicKey,
|
||||
safetyDepositTokenStore: PublicKey,
|
||||
destination: PublicKey,
|
||||
safetyDeposit: PublicKey,
|
||||
fractionMint: PublicKey,
|
||||
mint: 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 prizeTrackingTicket = await getPrizeTrackingTicket(
|
||||
auctionManagerKey,
|
||||
mint,
|
||||
);
|
||||
const vaultAuthority: PublicKey = (
|
||||
await findProgramAddress(
|
||||
[
|
||||
Buffer.from(VAULT_PREFIX),
|
||||
PROGRAM_IDS.vault.toBuffer(),
|
||||
vault.toBuffer(),
|
||||
],
|
||||
PROGRAM_IDS.vault,
|
||||
)
|
||||
)[0];
|
||||
|
||||
const auctionExtended: PublicKey = (
|
||||
await findProgramAddress(
|
||||
[
|
||||
Buffer.from(AUCTION_PREFIX),
|
||||
PROGRAM_IDS.auction.toBuffer(),
|
||||
vault.toBuffer(),
|
||||
Buffer.from(EXTENDED),
|
||||
],
|
||||
PROGRAM_IDS.auction,
|
||||
)
|
||||
)[0];
|
||||
|
||||
const value = new WithdrawMasterEditionArgs();
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const keys = [
|
||||
{
|
||||
pubkey: auctionManagerKey,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: safetyDepositTokenStore,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: destination,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: safetyDeposit,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: vault,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: fractionMint,
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
{
|
||||
pubkey: prizeTrackingTicket,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: vaultAuthority,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: auctionKey,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: auctionExtended,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.token,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: PROGRAM_IDS.vault,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: store,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{
|
||||
pubkey: SYSVAR_RENT_PUBKEY,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
];
|
||||
|
||||
instructions.push(
|
||||
new TransactionInstruction({
|
||||
keys,
|
||||
programId: PROGRAM_IDS.metaplex,
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
|
@ -13,28 +13,36 @@ import {
|
|||
import { useMeta } from '../../contexts';
|
||||
import { Store, WhitelistedCreator } from '../../models/metaplex';
|
||||
import {
|
||||
MasterEditionV1,
|
||||
notify,
|
||||
ParsedAccount,
|
||||
shortenAddress,
|
||||
useConnection,
|
||||
useUserAccounts,
|
||||
useWallet,
|
||||
} from '@oyster/common';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { saveAdmin } from '../../actions/saveAdmin';
|
||||
import { WalletAdapter } from '@solana/wallet-base';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
convertMasterEditions,
|
||||
filterMetadata,
|
||||
} from '../../actions/convertMasterEditions';
|
||||
|
||||
const { Content } = Layout;
|
||||
export const AdminView = () => {
|
||||
const { store, whitelistedCreatorsByCreator } = useMeta();
|
||||
const connection = useConnection();
|
||||
const { wallet } = useWallet();
|
||||
const { wallet, connected } = useWallet();
|
||||
|
||||
return store && connection && wallet ? (
|
||||
return store && connection && wallet && connected ? (
|
||||
<InnerAdminView
|
||||
store={store}
|
||||
whitelistedCreatorsByCreator={whitelistedCreatorsByCreator}
|
||||
connection={connection}
|
||||
wallet={wallet}
|
||||
connected={connected}
|
||||
/>
|
||||
) : (
|
||||
<Spin />
|
||||
|
@ -107,6 +115,7 @@ function InnerAdminView({
|
|||
whitelistedCreatorsByCreator,
|
||||
connection,
|
||||
wallet,
|
||||
connected,
|
||||
}: {
|
||||
store: ParsedAccount<Store>;
|
||||
whitelistedCreatorsByCreator: Record<
|
||||
|
@ -115,6 +124,7 @@ function InnerAdminView({
|
|||
>;
|
||||
connection: Connection;
|
||||
wallet: WalletAdapter;
|
||||
connected: boolean;
|
||||
}) {
|
||||
const [newStore, setNewStore] = useState(
|
||||
store && store.info && new Store(store.info),
|
||||
|
@ -122,6 +132,27 @@ function InnerAdminView({
|
|||
const [updatedCreators, setUpdatedCreators] = useState<
|
||||
Record<string, WhitelistedCreator>
|
||||
>({});
|
||||
const [filteredMetadata, setFilteredMetadata] = useState<{
|
||||
available: ParsedAccount<MasterEditionV1>[];
|
||||
unavailable: ParsedAccount<MasterEditionV1>[];
|
||||
}>();
|
||||
const [loading, setLoading] = useState<boolean>();
|
||||
const { metadata, masterEditions } = useMeta();
|
||||
|
||||
const { accountByMint } = useUserAccounts();
|
||||
useMemo(() => {
|
||||
const fn = async () => {
|
||||
setFilteredMetadata(
|
||||
await filterMetadata(
|
||||
connection,
|
||||
metadata,
|
||||
masterEditions,
|
||||
accountByMint,
|
||||
),
|
||||
);
|
||||
};
|
||||
fn();
|
||||
}, [connected]);
|
||||
|
||||
if (!store || !newStore) {
|
||||
return <p>Store is not defined</p>;
|
||||
|
@ -244,6 +275,31 @@ function InnerAdminView({
|
|||
></Table>
|
||||
</Row>
|
||||
</Col>
|
||||
|
||||
<h1>
|
||||
You have {filteredMetadata?.available.length} MasterEditionV1s that can
|
||||
be converted right now and {filteredMetadata?.unavailable.length} still
|
||||
in unfinished auctions that cannot be converted yet.
|
||||
</h1>
|
||||
<Col>
|
||||
<Row>
|
||||
<Button
|
||||
disabled={loading}
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
await convertMasterEditions(
|
||||
connection,
|
||||
wallet,
|
||||
filteredMetadata?.available || [],
|
||||
accountByMint,
|
||||
);
|
||||
setLoading(false);
|
||||
}}
|
||||
>
|
||||
{loading ? <Spin /> : <span>Convert Eligible Master Editions</span>}
|
||||
</Button>
|
||||
</Row>
|
||||
</Col>
|
||||
</Content>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -33,3 +33,9 @@
|
|||
font-weight: 600;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.art-edition {
|
||||
font-weight: 600;
|
||||
font-size: 1.3rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { MetaAvatar } from '../../components/MetaAvatar';
|
|||
import { sendSignMetadata } from '../../actions/sendSignMetadata';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
import { ViewOn } from './../../components/ViewOn';
|
||||
import { ArtType } from '../../types';
|
||||
|
||||
const { Content } = Layout;
|
||||
|
||||
|
@ -18,6 +19,14 @@ export const ArtView = () => {
|
|||
|
||||
const connection = useConnection();
|
||||
const art = useArt(id);
|
||||
let badge = '';
|
||||
if (art.type === ArtType.NFT) {
|
||||
badge = 'Unique';
|
||||
} else if (art.type === ArtType.Master) {
|
||||
badge = 'NFT 0';
|
||||
} else if (art.type === ArtType.Print) {
|
||||
badge = `${art.edition} of ${art.supply}`;
|
||||
}
|
||||
const { ref, data } = useExtendedArt(id);
|
||||
|
||||
// const { userAccounts } = useUserAccounts();
|
||||
|
@ -138,6 +147,12 @@ export const ArtView = () => {
|
|||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<h6 style={{ marginTop: 5 }}>Edition</h6>
|
||||
<div className="art-edition">{badge}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* <Button
|
||||
onClick={async () => {
|
||||
|
|
|
@ -54,8 +54,9 @@ export const ArtCreateView = () => {
|
|||
const [step, setStep] = useState<number>(0);
|
||||
const [stepsVisible, setStepsVisible] = useState<boolean>(true);
|
||||
const [progress, setProgress] = useState<number>(0);
|
||||
const [nft, setNft] =
|
||||
useState<{ metadataAccount: PublicKey } | undefined>(undefined);
|
||||
const [nft, setNft] = useState<{ metadataAccount: PublicKey } | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
const [attributes, setAttributes] = useState<IMetadataExtension>({
|
||||
name: '',
|
||||
|
@ -471,8 +472,8 @@ const UploadStep = (props: {
|
|||
} as MetadataFile;
|
||||
}),
|
||||
},
|
||||
image: cleanName(coverFile?.name) || '',
|
||||
animation_url: cleanName(mainFile && mainFile.name),
|
||||
image: coverFile?.name || '',
|
||||
animation_url: mainFile && mainFile.name,
|
||||
});
|
||||
props.setFiles([coverFile, mainFile].filter(f => f) as File[]);
|
||||
props.confirm();
|
||||
|
|
|
@ -246,7 +246,7 @@ export function useBillingInfo({ auctionView }: { auctionView: AuctionView }) {
|
|||
// Uncancelled bids or bids that were cancelled for refunds but only after redeemed
|
||||
// for participation
|
||||
const usableBids = bids.filter(
|
||||
b =>
|
||||
b =>
|
||||
!b.info.cancelled ||
|
||||
bidRedemptions[
|
||||
participationBidRedemptionKeys[b.pubkey.toBase58()]?.toBase58()
|
||||
|
|
|
@ -78,3 +78,9 @@ h6 {
|
|||
.ant-carousel {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.auction-art-edition {
|
||||
font-weight: 600;
|
||||
font-size: 1.3rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React, { useRef, useState } from 'react';
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Row, Col, Button, Skeleton, Carousel } from 'antd';
|
||||
import { AuctionCard } from '../../components/AuctionCard';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import {
|
||||
AuctionView as Auction,
|
||||
AuctionViewItem,
|
||||
|
@ -18,6 +19,7 @@ import {
|
|||
Identicon,
|
||||
MetaplexModal,
|
||||
shortenAddress,
|
||||
useConnection,
|
||||
useConnectionConfig,
|
||||
fromLamports,
|
||||
useMint,
|
||||
|
@ -25,9 +27,11 @@ import {
|
|||
AuctionState,
|
||||
} from '@oyster/common';
|
||||
import { MintInfo } from '@solana/spl-token';
|
||||
import { getHandleAndRegistryKey } from '@bonfida/spl-name-service';
|
||||
import useWindowDimensions from '../../utils/layout';
|
||||
import { CheckOutlined } from '@ant-design/icons';
|
||||
import { useMemo } from 'react';
|
||||
import { ArtType } from '../../types';
|
||||
|
||||
export const AuctionItem = ({
|
||||
item,
|
||||
|
@ -76,7 +80,14 @@ export const AuctionView = () => {
|
|||
const art = useArt(auction?.thumbnail.metadata.pubkey);
|
||||
const { ref, data } = useExtendedArt(auction?.thumbnail.metadata.pubkey);
|
||||
const creators = useCreators(auction);
|
||||
const edition = '1 of 1';
|
||||
let edition = ''
|
||||
if (art.type === ArtType.NFT) {
|
||||
edition = 'Unique';
|
||||
} else if (art.type === ArtType.Master) {
|
||||
edition = 'NFT 0';
|
||||
} else if (art.type === ArtType.Print) {
|
||||
edition = `${art.edition} of ${art.supply}`;
|
||||
}
|
||||
const nftCount = auction?.items.flat().length;
|
||||
const winnerCount = auction?.items.length;
|
||||
|
||||
|
@ -161,7 +172,8 @@ export const AuctionView = () => {
|
|||
<Row gutter={[50, 0]} style={{ marginRight: 'unset' }}>
|
||||
<Col>
|
||||
<h6>Edition</h6>
|
||||
<p>{(auction?.items.length || 0) > 1 ? 'Multiple' : edition}</p>
|
||||
{!auction && <Skeleton title={{ width: "100%" }} paragraph={{ rows: 0 }} />}
|
||||
{auction && <p className="auction-art-edition">{(auction?.items.length || 0) > 1 ? 'Multiple' : edition}</p>}
|
||||
</Col>
|
||||
|
||||
<Col>
|
||||
|
@ -205,6 +217,28 @@ const BidLine = (props: { bid: any; index: number; mint?: MintInfo, isCancelled?
|
|||
const bidder = bid.info.bidderPubkey.toBase58();
|
||||
const isme = wallet?.publicKey?.toBase58() === bidder;
|
||||
|
||||
// Get Twitter Handle from address
|
||||
const connection = useConnection();
|
||||
const [bidderTwitterHandle, setBidderTwitterHandle] = useState('');
|
||||
useEffect(() => {
|
||||
const getTwitterHandle = async (
|
||||
connection: Connection,
|
||||
bidder: PublicKey,
|
||||
): Promise<string | undefined> => {
|
||||
try {
|
||||
const [twitterHandle] = await getHandleAndRegistryKey(
|
||||
connection,
|
||||
bidder,
|
||||
);
|
||||
setBidderTwitterHandle(twitterHandle);
|
||||
} catch (err) {
|
||||
console.warn(`err`);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
getTwitterHandle(connection, bidder);
|
||||
}, [bidderTwitterHandle]);
|
||||
|
||||
return (
|
||||
<Row
|
||||
style={{
|
||||
|
@ -254,7 +288,15 @@ const BidLine = (props: { bid: any; index: number; mint?: MintInfo, isCancelled?
|
|||
}}
|
||||
address={bidder}
|
||||
/>{' '}
|
||||
{shortenAddress(bidder)}
|
||||
{bidderTwitterHandle ? (
|
||||
<a
|
||||
target="_blank"
|
||||
title={shortenAddress(bidder)}
|
||||
href={`https://twitter.com/${bidderTwitterHandle}`}
|
||||
>{`@${bidderTwitterHandle}`}</a>
|
||||
) : (
|
||||
shortenAddress(bidder)
|
||||
)}
|
||||
{isme && <span style={{ color: '#6479f6' }}> (you)</span>}
|
||||
</Row>
|
||||
</Col>
|
||||
|
|
|
@ -30,6 +30,7 @@ import {
|
|||
PriceFloor,
|
||||
PriceFloorType,
|
||||
IPartialCreateAuctionArgs,
|
||||
MetadataKey,
|
||||
} from '@oyster/common';
|
||||
import { Connection, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
|
||||
import { MintLayout } from '@solana/spl-token';
|
||||
|
@ -193,7 +194,7 @@ export const AuctionCreateView = () => {
|
|||
// In these cases there is only ever one item in the array.
|
||||
|
||||
let winningConfigs: WinningConfig[];
|
||||
if (attributes.category === AuctionCategory.Single)
|
||||
if (attributes.category === AuctionCategory.Single) {
|
||||
winningConfigs = [
|
||||
new WinningConfig({
|
||||
items: [
|
||||
|
@ -210,7 +211,7 @@ export const AuctionCreateView = () => {
|
|||
],
|
||||
}),
|
||||
];
|
||||
else {
|
||||
} else {
|
||||
winningConfigs = [];
|
||||
for (let i = 0; i < (attributes.editions || 1); i++) {
|
||||
winningConfigs.push(
|
||||
|
@ -219,7 +220,11 @@ export const AuctionCreateView = () => {
|
|||
new WinningConfigItem({
|
||||
safetyDepositBoxIndex: 0,
|
||||
amount: 1,
|
||||
winningConfigType: WinningConfigType.Printing,
|
||||
winningConfigType:
|
||||
attributes.items[0].masterEdition?.info.key ==
|
||||
MetadataKey.MasterEditionV1
|
||||
? WinningConfigType.PrintingV1
|
||||
: WinningConfigType.PrintingV2,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
@ -879,8 +884,8 @@ const PriceAuction = (props: {
|
|||
<label className="action-field">
|
||||
<span className="field-title">Price</span>
|
||||
<span className="field-info">
|
||||
This is an optional fixed price that non-winners will pay for
|
||||
your Participation NFT.
|
||||
This is the fixed price that everybody will pay for your
|
||||
Participation NFT.
|
||||
</span>
|
||||
<Input
|
||||
type="number"
|
||||
|
@ -1413,26 +1418,34 @@ const TierTableStep = (props: {
|
|||
|
||||
const newTiers = newImmutableTiers(props.attributes.tiers);
|
||||
if (items[0]) {
|
||||
const existing = props.attributes.items.find(
|
||||
it =>
|
||||
it.metadata.pubkey.toBase58() ===
|
||||
items[0].metadata.pubkey.toBase58(),
|
||||
const existing = props.attributes.items.find(it =>
|
||||
it.metadata.pubkey.equals(items[0].metadata.pubkey),
|
||||
);
|
||||
if (!existing) newItems.push(items[0]);
|
||||
const index = newItems.findIndex(
|
||||
it =>
|
||||
it.metadata.pubkey.toBase58() ===
|
||||
items[0].metadata.pubkey.toBase58(),
|
||||
const index = newItems.findIndex(it =>
|
||||
it.metadata.pubkey.equals(items[0].metadata.pubkey),
|
||||
);
|
||||
|
||||
const myNewTier = newTiers[configIndex].items[itemIndex];
|
||||
myNewTier.safetyDepositBoxIndex = index;
|
||||
if (items[0].masterEdition)
|
||||
if (
|
||||
items[0].masterEdition &&
|
||||
items[0].masterEdition.info.key ==
|
||||
MetadataKey.MasterEditionV1
|
||||
) {
|
||||
myNewTier.winningConfigType =
|
||||
WinningConfigType.Printing;
|
||||
else
|
||||
WinningConfigType.PrintingV1;
|
||||
} else if (
|
||||
items[0].masterEdition &&
|
||||
items[0].masterEdition.info.key ==
|
||||
MetadataKey.MasterEditionV2
|
||||
) {
|
||||
myNewTier.winningConfigType =
|
||||
WinningConfigType.PrintingV2;
|
||||
} else {
|
||||
myNewTier.winningConfigType =
|
||||
WinningConfigType.TokenOnlyTransfer;
|
||||
}
|
||||
myNewTier.amount = 1;
|
||||
} else if (
|
||||
(i as WinningConfigItem).safetyDepositBoxIndex !==
|
||||
|
@ -1495,6 +1508,17 @@ const TierTableStep = (props: {
|
|||
const myNewTier =
|
||||
newTiers[configIndex].items[itemIndex];
|
||||
|
||||
// Legacy hack...
|
||||
if (
|
||||
value == WinningConfigType.PrintingV2 &&
|
||||
myNewTier.safetyDepositBoxIndex &&
|
||||
props.attributes.items[
|
||||
myNewTier.safetyDepositBoxIndex
|
||||
].masterEdition?.info.key ==
|
||||
MetadataKey.MasterEditionV1
|
||||
) {
|
||||
value = WinningConfigType.PrintingV1;
|
||||
}
|
||||
myNewTier.winningConfigType = value;
|
||||
props.setAttributes({
|
||||
...props.attributes,
|
||||
|
@ -1508,13 +1532,19 @@ const TierTableStep = (props: {
|
|||
<Option value={WinningConfigType.TokenOnlyTransfer}>
|
||||
Token Only Transfer
|
||||
</Option>
|
||||
<Option value={WinningConfigType.Printing}>
|
||||
Printing
|
||||
<Option value={WinningConfigType.PrintingV2}>
|
||||
Printing V2
|
||||
</Option>
|
||||
|
||||
<Option value={WinningConfigType.PrintingV1}>
|
||||
Printing V1
|
||||
</Option>
|
||||
</Select>
|
||||
|
||||
{(i as WinningConfigItem).winningConfigType ===
|
||||
WinningConfigType.Printing && (
|
||||
{((i as WinningConfigItem).winningConfigType ===
|
||||
WinningConfigType.PrintingV1 ||
|
||||
(i as WinningConfigItem).winningConfigType ===
|
||||
WinningConfigType.PrintingV2) && (
|
||||
<label className="action-field">
|
||||
<span className="field-title">
|
||||
How many copies do you want to create for each winner?
|
||||
|
|
|
@ -17,14 +17,22 @@ import { WhitelistedCreator } from '../../models/metaplex';
|
|||
const { TabPane } = Tabs;
|
||||
|
||||
const { Content } = Layout;
|
||||
|
||||
export enum LiveAuctionViewState {
|
||||
All = '0',
|
||||
Participated = '1',
|
||||
Ended = '2',
|
||||
};
|
||||
|
||||
export const HomeView = () => {
|
||||
const auctions = useAuctions(AuctionViewState.Live);
|
||||
const auctionsEnded = useAuctions(AuctionViewState.Ended);
|
||||
const [activeKey, setActiveKey] = useState(LiveAuctionViewState.All);
|
||||
const { isLoading, store } = useMeta();
|
||||
const [isInitalizingStore, setIsInitalizingStore] = useState(false);
|
||||
const connection = useConnection();
|
||||
const history = useHistory();
|
||||
const { wallet, connect } = useWallet();
|
||||
const { wallet, connect, connected } = useWallet();
|
||||
const breakpointColumnsObj = {
|
||||
default: 4,
|
||||
1100: 3,
|
||||
|
@ -50,6 +58,13 @@ export const HomeView = () => {
|
|||
.toNumber() || 0,
|
||||
);
|
||||
|
||||
const items =
|
||||
activeKey === LiveAuctionViewState.All
|
||||
? liveAuctions
|
||||
: activeKey === LiveAuctionViewState.Participated ?
|
||||
liveAuctions.concat(auctionsEnded).filter((m, idx) => m.myBidderMetadata?.info.bidderPubkey.toBase58() == wallet?.publicKey?.toBase58()):
|
||||
auctionsEnded;
|
||||
|
||||
const liveAuctionsView = (
|
||||
<Masonry
|
||||
breakpointCols={breakpointColumnsObj}
|
||||
|
@ -57,10 +72,10 @@ export const HomeView = () => {
|
|||
columnClassName="my-masonry-grid_column"
|
||||
>
|
||||
{!isLoading
|
||||
? liveAuctions.map((m, idx) => {
|
||||
if (m === heroAuction) {
|
||||
return;
|
||||
}
|
||||
? items.map((m, idx) => {
|
||||
if (m === heroAuction) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = m.auction.pubkey.toBase58();
|
||||
return (
|
||||
|
@ -80,7 +95,6 @@ export const HomeView = () => {
|
|||
>
|
||||
{!isLoading
|
||||
? auctionsEnded
|
||||
.filter((m, idx) => idx < 10)
|
||||
.map((m, idx) => {
|
||||
if (m === heroAuction) {
|
||||
return;
|
||||
|
@ -158,27 +172,36 @@ export const HomeView = () => {
|
|||
<Layout>
|
||||
<Content style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Col style={{ width: '100%', marginTop: 10 }}>
|
||||
{liveAuctions.length > 1 && (
|
||||
<Row>
|
||||
<Tabs>
|
||||
<TabPane>
|
||||
<h2>Live Auctions</h2>
|
||||
{liveAuctions.length > 1 && (<Row>
|
||||
<Tabs activeKey={activeKey}
|
||||
onTabClick={key => setActiveKey(key as LiveAuctionViewState)}>
|
||||
<TabPane
|
||||
tab={<span className="tab-title">Live Auctions</span>}
|
||||
key={LiveAuctionViewState.All}
|
||||
>
|
||||
{liveAuctionsView}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Row>
|
||||
)}
|
||||
<Row>
|
||||
{auctionsEnded.length > 0 && (
|
||||
<Tabs>
|
||||
<TabPane>
|
||||
<h2>Ended Auctions</h2>
|
||||
{auctionsEnded.length > 0 && (
|
||||
<TabPane
|
||||
tab={<span className="tab-title">Ended Auctions</span>}
|
||||
key={LiveAuctionViewState.Ended}
|
||||
>
|
||||
{endedAuctions}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
)}
|
||||
<br />
|
||||
</Row>
|
||||
)}
|
||||
{
|
||||
// Show all participated live and ended auctions except hero auction
|
||||
}
|
||||
{connected && (
|
||||
<TabPane
|
||||
tab={<span className="tab-title">Participated</span>}
|
||||
key={LiveAuctionViewState.Participated}
|
||||
>
|
||||
{liveAuctionsView}
|
||||
</TabPane>
|
||||
)}
|
||||
</Tabs>
|
||||
</Row>)}
|
||||
</Col>
|
||||
</Content>
|
||||
</Layout>
|
||||
|
|
101
js/yarn.lock
101
js/yarn.lock
|
@ -386,6 +386,25 @@
|
|||
"@babel/helper-validator-identifier" "^7.14.0"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bonfida/spl-name-service@0.1.12":
|
||||
version "0.1.12"
|
||||
resolved "https://registry.yarnpkg.com/@bonfida/spl-name-service/-/spl-name-service-0.1.12.tgz#ab186fe0c907efe66cb6818e2f429f9f4b3ab0d2"
|
||||
integrity sha512-zVZiOjhZK+VZAs4aqOmxj6vplbGGwcin/gJ3Xm/gn+wV1GzgeqDkYrrDJclEpQ7WcmA4WV/Pad6tWfPtGt12/g==
|
||||
dependencies:
|
||||
"@solana/spl-token" "0.1.4"
|
||||
"@solana/web3.js" "^1.11.0"
|
||||
bip32 "^2.0.6"
|
||||
bn.js "^5.1.3"
|
||||
borsh "^0.4.0"
|
||||
bs58 "4.0.1"
|
||||
buffer-layout "^1.2.0"
|
||||
core-util-is "^1.0.2"
|
||||
crypto "^1.0.1"
|
||||
crypto-ts "^1.0.2"
|
||||
fs "^0.0.1-security"
|
||||
tweetnacl "^1.0.3"
|
||||
webpack-dev-server "^3.11.2"
|
||||
|
||||
"@chaitanyapotti/random-id@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@chaitanyapotti/random-id/-/random-id-1.0.3.tgz#f52f647cfe9f79fc7723ea2b01b0ad3889204002"
|
||||
|
@ -5627,7 +5646,7 @@ debug@3.1.0, debug@=3.1.0:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.1.0, debug@^3.1.1, debug@^3.2.6:
|
||||
debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
||||
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
|
||||
|
@ -7199,7 +7218,14 @@ fastq@^1.6.0:
|
|||
dependencies:
|
||||
reusify "^1.0.4"
|
||||
|
||||
faye-websocket@^0.11.3:
|
||||
faye-websocket@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
|
||||
integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=
|
||||
dependencies:
|
||||
websocket-driver ">=0.5.1"
|
||||
|
||||
faye-websocket@^0.11.3, faye-websocket@~0.11.1:
|
||||
version "0.11.4"
|
||||
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da"
|
||||
integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==
|
||||
|
@ -9466,7 +9492,7 @@ json2mq@^0.2.0:
|
|||
dependencies:
|
||||
string-convert "^0.2.0"
|
||||
|
||||
json3@^3.3.3:
|
||||
json3@^3.3.2, json3@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81"
|
||||
integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==
|
||||
|
@ -13202,7 +13228,7 @@ select-hose@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
|
||||
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
|
||||
|
||||
selfsigned@^1.10.8:
|
||||
selfsigned@^1.10.7, selfsigned@^1.10.8:
|
||||
version "1.10.11"
|
||||
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9"
|
||||
integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==
|
||||
|
@ -13511,6 +13537,18 @@ snapdragon@^0.8.1:
|
|||
source-map-resolve "^0.5.0"
|
||||
use "^3.1.0"
|
||||
|
||||
sockjs-client@1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5"
|
||||
integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==
|
||||
dependencies:
|
||||
debug "^3.2.5"
|
||||
eventsource "^1.0.7"
|
||||
faye-websocket "~0.11.1"
|
||||
inherits "^2.0.3"
|
||||
json3 "^3.3.2"
|
||||
url-parse "^1.4.3"
|
||||
|
||||
sockjs-client@^1.5.0:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6"
|
||||
|
@ -13523,6 +13561,15 @@ sockjs-client@^1.5.0:
|
|||
json3 "^3.3.3"
|
||||
url-parse "^1.5.1"
|
||||
|
||||
sockjs@0.3.20:
|
||||
version "0.3.20"
|
||||
resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.20.tgz#b26a283ec562ef8b2687b44033a4eeceac75d855"
|
||||
integrity sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==
|
||||
dependencies:
|
||||
faye-websocket "^0.10.0"
|
||||
uuid "^3.4.0"
|
||||
websocket-driver "0.6.5"
|
||||
|
||||
sockjs@^0.3.21:
|
||||
version "0.3.21"
|
||||
resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417"
|
||||
|
@ -15219,6 +15266,45 @@ webpack-dev-middleware@^3.7.2:
|
|||
range-parser "^1.2.1"
|
||||
webpack-log "^2.0.0"
|
||||
|
||||
webpack-dev-server@3.11.0:
|
||||
version "3.11.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz#8f154a3bce1bcfd1cc618ef4e703278855e7ff8c"
|
||||
integrity sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==
|
||||
dependencies:
|
||||
ansi-html "0.0.7"
|
||||
bonjour "^3.5.0"
|
||||
chokidar "^2.1.8"
|
||||
compression "^1.7.4"
|
||||
connect-history-api-fallback "^1.6.0"
|
||||
debug "^4.1.1"
|
||||
del "^4.1.1"
|
||||
express "^4.17.1"
|
||||
html-entities "^1.3.1"
|
||||
http-proxy-middleware "0.19.1"
|
||||
import-local "^2.0.0"
|
||||
internal-ip "^4.3.0"
|
||||
ip "^1.1.5"
|
||||
is-absolute-url "^3.0.3"
|
||||
killable "^1.0.1"
|
||||
loglevel "^1.6.8"
|
||||
opn "^5.5.0"
|
||||
p-retry "^3.0.1"
|
||||
portfinder "^1.0.26"
|
||||
schema-utils "^1.0.0"
|
||||
selfsigned "^1.10.7"
|
||||
semver "^6.3.0"
|
||||
serve-index "^1.9.1"
|
||||
sockjs "0.3.20"
|
||||
sockjs-client "1.4.0"
|
||||
spdy "^4.0.2"
|
||||
strip-ansi "^3.0.1"
|
||||
supports-color "^6.1.0"
|
||||
url "^0.11.0"
|
||||
webpack-dev-middleware "^3.7.2"
|
||||
webpack-log "^2.0.0"
|
||||
ws "^6.2.1"
|
||||
yargs "^13.3.2"
|
||||
|
||||
webpack-dev-server@^3.11.2:
|
||||
version "3.11.2"
|
||||
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708"
|
||||
|
@ -15266,6 +15352,13 @@ webpack-log@^2.0.0:
|
|||
ansi-colors "^3.0.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
websocket-driver@0.6.5:
|
||||
version "0.6.5"
|
||||
resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36"
|
||||
integrity sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=
|
||||
dependencies:
|
||||
websocket-extensions ">=0.1.1"
|
||||
|
||||
websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
|
||||
version "0.7.4"
|
||||
resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760"
|
||||
|
|
|
@ -3301,6 +3301,7 @@ dependencies = [
|
|||
name = "spl-auction"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"borsh",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
|
@ -3394,11 +3395,13 @@ dependencies = [
|
|||
name = "spl-token-metadata"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"borsh",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"solana-program",
|
||||
"spl-token",
|
||||
"spl-token-vault",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ test-bpf = []
|
|||
borsh = "0.8.2"
|
||||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
arrayref = "0.3.6"
|
||||
solana-program = "1.6.10"
|
||||
spl-token = { version="3.1.1", features = [ "no-entrypoint" ] }
|
||||
thiserror = "1.0"
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::errors::AuctionError;
|
||||
use arrayref::array_ref;
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use solana_program::{
|
||||
account_info::AccountInfo, borsh::try_from_slice_unchecked, clock::UnixTimestamp,
|
||||
entrypoint::ProgramResult, hash::Hash, msg, program_error::ProgramError, pubkey::Pubkey,
|
||||
};
|
||||
use std::{cmp, mem};
|
||||
use std::{cell::Ref, cmp, mem};
|
||||
|
||||
// Declare submodules, each contains a single handler for each instruction variant in the program.
|
||||
pub mod cancel_bid;
|
||||
|
@ -57,7 +58,10 @@ pub enum PriceFloor {
|
|||
|
||||
// The two extra 8's are present, one 8 is for the Vec's amount of elements and one is for the max
|
||||
// usize in bid state.
|
||||
// NOTE: New research suggests u32s are used for vecs in borsh, not u64s, so the first extra 8 should be a 4
|
||||
// but for legacy reasons we leave it behind.
|
||||
pub const BASE_AUCTION_DATA_SIZE: usize = 32 + 32 + 9 + 9 + 9 + 9 + 1 + 32 + 1 + 8 + 8 + 8;
|
||||
pub const BID_LENGTH: usize = 32 + 8;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, BorshSerialize, BorshDeserialize, PartialEq, Debug)]
|
||||
pub struct AuctionData {
|
||||
|
@ -115,6 +119,123 @@ impl AuctionDataExtended {
|
|||
}
|
||||
|
||||
impl AuctionData {
|
||||
// Cheap methods to get at AuctionData without supremely expensive borsh deserialization calls.
|
||||
|
||||
pub fn get_token_mint(a: &AccountInfo) -> Pubkey {
|
||||
let data = a.data.borrow();
|
||||
let token_mint_data = array_ref![data, 32, 32];
|
||||
Pubkey::new_from_array(*token_mint_data)
|
||||
}
|
||||
|
||||
pub fn get_state(a: &AccountInfo) -> Result<AuctionState, ProgramError> {
|
||||
match a.data.borrow()[133] {
|
||||
0 => Ok(AuctionState::Created),
|
||||
1 => Ok(AuctionState::Started),
|
||||
2 => Ok(AuctionState::Ended),
|
||||
_ => Err(ProgramError::InvalidAccountData),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_num_winners(a: &AccountInfo) -> usize {
|
||||
let (bid_state_beginning, num_elements, max) = AuctionData::get_vec_info(a);
|
||||
std::cmp::min(num_elements, max)
|
||||
}
|
||||
|
||||
fn find_bid_state_beginning(a: &AccountInfo) -> usize {
|
||||
let data = a.data.borrow();
|
||||
let mut bid_state_beginning = 32 + 32;
|
||||
|
||||
for i in 0..4 {
|
||||
// One for each unix timestamp
|
||||
if data[bid_state_beginning] == 1 {
|
||||
bid_state_beginning += 9
|
||||
} else {
|
||||
bid_state_beginning += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally add price floor (enum + hash) and state, then the u32,
|
||||
// then add 1 to position at the beginning of first bid.
|
||||
bid_state_beginning += 1 + 32 + 1 + 4 + 1;
|
||||
return bid_state_beginning;
|
||||
}
|
||||
|
||||
fn get_vec_info(a: &AccountInfo) -> (usize, usize, usize) {
|
||||
let bid_state_beginning = AuctionData::find_bid_state_beginning(a);
|
||||
let data = a.data.borrow();
|
||||
|
||||
let num_elements_data = array_ref![data, bid_state_beginning - 4, 4];
|
||||
let num_elements = u32::from_le_bytes(*num_elements_data) as usize;
|
||||
let max_data = array_ref![data, bid_state_beginning + BID_LENGTH * num_elements, 8];
|
||||
let max = u64::from_le_bytes(*max_data) as usize;
|
||||
|
||||
(bid_state_beginning, num_elements, max)
|
||||
}
|
||||
|
||||
pub fn get_is_winner(a: &AccountInfo, key: &Pubkey) -> Option<usize> {
|
||||
let bid_state_beginning = AuctionData::find_bid_state_beginning(a);
|
||||
let data = a.data.borrow();
|
||||
let as_bytes = key.to_bytes();
|
||||
let (bid_state_beginning, num_elements, max) = AuctionData::get_vec_info(a);
|
||||
for idx in 0..std::cmp::min(num_elements, max) {
|
||||
match AuctionData::get_winner_at_inner(
|
||||
&a.data.borrow(),
|
||||
idx,
|
||||
bid_state_beginning,
|
||||
num_elements,
|
||||
max,
|
||||
) {
|
||||
Some(bid_key) => {
|
||||
// why deserialize the entire key to compare the two with a short circuit comparison
|
||||
// when we can compare them immediately?
|
||||
let mut matching = true;
|
||||
for bid_key_idx in 0..32 {
|
||||
if bid_key[bid_key_idx] != as_bytes[bid_key_idx] {
|
||||
matching = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if matching {
|
||||
return Some(idx as usize);
|
||||
}
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_winner_at(a: &AccountInfo, idx: usize) -> Option<Pubkey> {
|
||||
let (bid_state_beginning, num_elements, max) = AuctionData::get_vec_info(a);
|
||||
match AuctionData::get_winner_at_inner(
|
||||
&a.data.borrow(),
|
||||
idx,
|
||||
bid_state_beginning,
|
||||
num_elements,
|
||||
max,
|
||||
) {
|
||||
Some(bid_key) => Some(Pubkey::new_from_array(*bid_key)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_winner_at_inner<'a>(
|
||||
data: &'a Ref<'a, &'a mut [u8]>,
|
||||
idx: usize,
|
||||
bid_state_beginning: usize,
|
||||
num_elements: usize,
|
||||
max: usize,
|
||||
) -> Option<&'a [u8; 32]> {
|
||||
if idx + 1 > num_elements || idx + 1 > max {
|
||||
return None;
|
||||
}
|
||||
Some(array_ref![
|
||||
data,
|
||||
bid_state_beginning + (num_elements - idx - 1) * BID_LENGTH,
|
||||
32
|
||||
])
|
||||
}
|
||||
|
||||
pub fn from_account_info(a: &AccountInfo) -> Result<AuctionData, ProgramError> {
|
||||
if (a.data_len() - BASE_AUCTION_DATA_SIZE) % mem::size_of::<Bid>() != 0 {
|
||||
return Err(AuctionError::DataTypeMismatch.into());
|
||||
|
@ -161,11 +282,7 @@ impl AuctionData {
|
|||
}
|
||||
|
||||
pub fn num_winners(&self) -> u64 {
|
||||
let minimum = match self.price_floor {
|
||||
PriceFloor::MinimumPrice(min) => min[0],
|
||||
_ => 0,
|
||||
};
|
||||
self.bid_state.num_winners(minimum)
|
||||
self.bid_state.num_winners()
|
||||
}
|
||||
|
||||
pub fn num_possible_winners(&self) -> u64 {
|
||||
|
@ -173,11 +290,7 @@ impl AuctionData {
|
|||
}
|
||||
|
||||
pub fn winner_at(&self, idx: usize) -> Option<Pubkey> {
|
||||
let minimum = match self.price_floor {
|
||||
PriceFloor::MinimumPrice(min) => min[0],
|
||||
_ => 0,
|
||||
};
|
||||
self.bid_state.winner_at(idx, minimum)
|
||||
self.bid_state.winner_at(idx)
|
||||
}
|
||||
|
||||
pub fn place_bid(
|
||||
|
@ -199,7 +312,11 @@ impl AuctionData {
|
|||
}
|
||||
None => None,
|
||||
};
|
||||
self.bid_state.place_bid(bid, tick_size, gap_val)
|
||||
let minimum = match self.price_floor {
|
||||
PriceFloor::MinimumPrice(min) => min[0],
|
||||
_ => 0,
|
||||
};
|
||||
self.bid_state.place_bid(bid, tick_size, gap_val, minimum)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,9 +444,13 @@ impl BidState {
|
|||
bid: Bid,
|
||||
tick_size: Option<u64>,
|
||||
gap_tick_size_percentage: Option<u8>,
|
||||
minimum: u64,
|
||||
) -> Result<(), ProgramError> {
|
||||
msg!("Placing bid {:?}", &bid.1.to_string());
|
||||
BidState::assert_valid_tick_size_bid(&bid, tick_size)?;
|
||||
if bid.1 < minimum {
|
||||
return Err(AuctionError::BidTooSmall.into());
|
||||
}
|
||||
|
||||
match self {
|
||||
// In a capped auction, track the limited number of winners.
|
||||
|
@ -454,15 +575,9 @@ impl BidState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn num_winners(&self, min: u64) -> u64 {
|
||||
pub fn num_winners(&self) -> u64 {
|
||||
match self {
|
||||
BidState::EnglishAuction { bids, max } => cmp::min(
|
||||
bids.iter()
|
||||
.filter(|b| b.1 >= min)
|
||||
.collect::<Vec<&Bid>>()
|
||||
.len(),
|
||||
*max,
|
||||
) as u64,
|
||||
BidState::EnglishAuction { bids, max } => cmp::min(bids.len(), *max) as u64,
|
||||
BidState::OpenEdition { bids, max } => 0,
|
||||
}
|
||||
}
|
||||
|
@ -474,17 +589,13 @@ impl BidState {
|
|||
}
|
||||
}
|
||||
|
||||
// Idea is to present winner as index 0 to outside world
|
||||
pub fn winner_at(&self, index: usize, min: u64) -> Option<Pubkey> {
|
||||
/// Idea is to present #1 winner as index 0 to outside world with this method
|
||||
pub fn winner_at(&self, index: usize) -> Option<Pubkey> {
|
||||
match self {
|
||||
BidState::EnglishAuction { bids, max } => {
|
||||
if index < *max && index < bids.len() {
|
||||
let bid = &bids[bids.len() - index - 1];
|
||||
if bid.1 >= min {
|
||||
Some(bids[bids.len() - index - 1].0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(bids[bids.len() - index - 1].0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -228,18 +228,6 @@ pub fn place_bid<'r, 'b: 'r>(
|
|||
return Err(AuctionError::InvalidState.into());
|
||||
}
|
||||
|
||||
// Can't bid smaller than the minimum price.
|
||||
if let PriceFloor::MinimumPrice(min) = auction.price_floor {
|
||||
msg!(
|
||||
"Amount is too small: {:?}, compared to price floor of {:?}",
|
||||
args.amount,
|
||||
min[0]
|
||||
);
|
||||
if args.amount < min[0] {
|
||||
return Err(AuctionError::BidTooSmall.into());
|
||||
}
|
||||
}
|
||||
|
||||
let bump_authority_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
|
|
|
@ -390,6 +390,26 @@ pub enum MetaplexError {
|
|||
/// Invalid Auction Manager Status
|
||||
#[error("Invalid Auction Manager Status")]
|
||||
InvalidStatus,
|
||||
|
||||
/// You are not eligible for this edition offset
|
||||
#[error("You are not eligible for this edition offset")]
|
||||
InvalidEditionNumber,
|
||||
|
||||
/// Invalid operation
|
||||
#[error("Invalid operation")]
|
||||
InvalidOperation,
|
||||
|
||||
/// The provided account needs to contain one token of this mint type
|
||||
#[error("The provided account needs to contain one token of this mint type")]
|
||||
ProvidedAccountDoesNotContainOneToken,
|
||||
|
||||
/// You are not the winner at this index
|
||||
#[error("You are not the winner at this index")]
|
||||
WinnerIndexMismatch,
|
||||
|
||||
/// You supplied a safety deposit index in a winning configuration that does not exist
|
||||
#[error("You supplied a safety deposit index in a winning configuration that does not exist")]
|
||||
InvalidWinningConfigSafetyDepositIndex,
|
||||
}
|
||||
|
||||
impl PrintProgramError for MetaplexError {
|
||||
|
|
|
@ -6,6 +6,7 @@ use {
|
|||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
spl_token_metadata::state::EDITION_MARKER_BIT_SIZE,
|
||||
};
|
||||
#[derive(BorshSerialize, BorshDeserialize, Clone)]
|
||||
pub struct SetStoreArgs {
|
||||
|
@ -39,6 +40,12 @@ pub struct RedeemUnusedWinningConfigItemsAsAuctioneerArgs {
|
|||
pub proxy_call: ProxyCallAddress,
|
||||
}
|
||||
|
||||
#[derive(BorshSerialize, BorshDeserialize, Clone)]
|
||||
pub struct RedeemPrintingV2BidArgs {
|
||||
pub edition_offset: u64,
|
||||
pub win_index: u64,
|
||||
}
|
||||
|
||||
/// Instructions supported by the Fraction program.
|
||||
#[derive(BorshSerialize, BorshDeserialize, Clone)]
|
||||
pub enum MetaplexInstruction {
|
||||
|
@ -111,12 +118,12 @@ pub enum MetaplexInstruction {
|
|||
/// 14. `[]` Store
|
||||
/// 15. `[]` System
|
||||
/// 16. `[]` Rent sysvar
|
||||
/// 17. `[]` PDA-based Transfer authority to move the tokens from the store to the destination seed ['vault', program_id]
|
||||
/// 17. `[]` PDA-based Transfer authority to move the tokens from the store to the destination seed ['vault', program_id, vault key]
|
||||
/// but please note that this is a PDA relative to the Token Vault program, with the 'vault' prefix
|
||||
/// 18. `[optional/writable]` Master edition (if Printing type of WinningConfig)
|
||||
/// 19. `[optional/writable]` Reservation list PDA ['metadata', program id, master edition key, 'reservation', auction manager key]
|
||||
/// relative to token metadata program (if Printing type of WinningConfig)
|
||||
RedeemBid,
|
||||
DeprecatedRedeemBid,
|
||||
|
||||
/// Note: This requires that auction manager be in a Running state.
|
||||
///
|
||||
|
@ -150,7 +157,7 @@ pub enum MetaplexInstruction {
|
|||
/// 18. `[]` New authority for Master Metadata - If you are taking ownership of a Master Edition in and of itself, or a Limited Edition that isn't newly minted for you during this auction
|
||||
/// ie someone else had it minted for themselves in a prior auction or through some other means, this is the account the metadata for these tokens will be delegated to
|
||||
/// after this transaction. Otherwise this account will be ignored.
|
||||
/// 19. `[]` PDA-based Transfer authority to move the tokens from the store to the destination seed ['vault', program_id]
|
||||
/// 19. `[]` PDA-based Transfer authority to move the tokens from the store to the destination seed ['vault', program_id, vault key]
|
||||
/// but please note that this is a PDA relative to the Token Vault program, with the 'vault' prefix
|
||||
RedeemFullRightsTransferBid,
|
||||
|
||||
|
@ -184,12 +191,12 @@ pub enum MetaplexInstruction {
|
|||
/// 14. `[]` Store
|
||||
/// 15. `[]` System
|
||||
/// 16. `[]` Rent sysvar
|
||||
/// 18. `[signer]` Transfer authority to move the payment in the auction's token_mint coin from the bidder account for the participation_fixed_price
|
||||
/// 17. `[signer]` Transfer authority to move the payment in the auction's token_mint coin from the bidder account for the participation_fixed_price
|
||||
/// on the auction manager to the auction manager account itself.
|
||||
/// 19. `[writable]` The accept payment account for the auction manager
|
||||
/// 20. `[writable]` The token account you will potentially pay for the open edition bid with if necessary
|
||||
/// 21. `[writable]` Participation NFT printing holding account (present on participation_state)
|
||||
RedeemParticipationBid,
|
||||
/// 18. `[writable]` The accept payment account for the auction manager
|
||||
/// 19. `[writable]` The token account you will potentially pay for the open edition bid with if necessary
|
||||
/// 20. `[writable]` Participation NFT printing holding account (present on participation_state)
|
||||
DeprecatedRedeemParticipationBid,
|
||||
|
||||
/// If the auction manager is in Validated state, it can invoke the start command via calling this command here.
|
||||
///
|
||||
|
@ -303,7 +310,7 @@ pub enum MetaplexInstruction {
|
|||
/// 8. `[]` Safety deposit token store
|
||||
/// 9. `[]` Vault
|
||||
/// 10. `[]` Rent sysvar
|
||||
ValidateParticipation,
|
||||
DeprecatedValidateParticipation,
|
||||
|
||||
/// Needs to be called by someone at the end of the auction - will use the one time authorization token
|
||||
/// to fire up a bunch of printing tokens for use in participation redemptions.
|
||||
|
@ -327,7 +334,7 @@ pub enum MetaplexInstruction {
|
|||
/// but please note that this is a PDA relative to the Token Vault program, with the 'vault' prefix
|
||||
/// 16. `[]` Payer who wishes to receive refund for closing of one time transient account once we're done here
|
||||
/// 17. `[]` Rent
|
||||
PopulateParticipationPrintingAccount,
|
||||
DeprecatedPopulateParticipationPrintingAccount,
|
||||
|
||||
/// If you are an auctioneer, redeem an unused winning config entry. You provide the winning index, and if the winning
|
||||
/// index has no winner, then the correct redemption method is called with a special flag set to ignore bidder_metadata checks
|
||||
|
@ -362,6 +369,115 @@ pub enum MetaplexInstruction {
|
|||
/// 5. `[]` Auction program
|
||||
/// 6. `[]` Clock sysvar
|
||||
DecommissionAuctionManager,
|
||||
|
||||
/// Note: This requires that auction manager be in a Running state.
|
||||
///
|
||||
/// If an auction is complete, you can redeem your printing v2 bid for a specific item here. If you are the first to do this,
|
||||
/// The auction manager will switch from Running state to Disbursing state. If you are the last, this may change
|
||||
/// the auction manager state to Finished provided that no authorities remain to be delegated for Master Edition tokens.
|
||||
///
|
||||
/// NOTE: Please note that it is totally possible to redeem a bid 2x - once for a prize you won and once at the RedeemParticipationBid point for an open edition
|
||||
/// that comes as a 'token of appreciation' for bidding. They are not mutually exclusive unless explicitly set to be that way.
|
||||
///
|
||||
/// 0. `[writable]` Auction manager
|
||||
/// 1. `[writable]` Safety deposit token storage account
|
||||
/// 2. `[writable]` Account containing 1 token of your new mint type.
|
||||
/// MUST be an associated token account of pda [wallet, token program, mint] relative to ata program.
|
||||
/// 3. `[writable]` Bid redemption key -
|
||||
/// Just a PDA with seed ['metaplex', auction_key, bidder_metadata_key] that we will allocate to mark that you redeemed your bid
|
||||
/// 4. `[writable]` Safety deposit box account
|
||||
/// 5. `[writable]` Vault account
|
||||
/// 6. `[writable]` Fraction mint of the vault
|
||||
/// 7. `[]` Auction
|
||||
/// 8. `[]` Your BidderMetadata account
|
||||
/// 9. `[]` Your Bidder account - Only needs to be signer if payer does not own
|
||||
/// 10. `[signer]` Payer
|
||||
/// 11. `[]` Token program
|
||||
/// 12. `[]` Token Vault program
|
||||
/// 13. `[]` Token metadata program
|
||||
/// 14. `[]` Store
|
||||
/// 15. `[]` System
|
||||
/// 16. `[]` Rent sysvar
|
||||
/// 17. `[writable]` Prize tracking ticket (pda of ['metaplex', program id, auction manager key, metadata mint id])
|
||||
/// 18. `[writable]` New Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 19. `[writable]` New Edition (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 20. `[writable]` Master Edition of token in vault V2 (pda of ['metadata', program id, master metadata mint id, 'edition']) PDA is relative to token metadata.
|
||||
/// 21. `[writable]` Mint of new token
|
||||
/// 22. `[writable]` Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number])
|
||||
/// where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE). PDA is relative to token metadata.
|
||||
/// 23. `[signer]` Mint authority of new mint - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY
|
||||
/// 24. `[]` Metadata account of token in vault
|
||||
RedeemPrintingV2Bid(RedeemPrintingV2BidArgs),
|
||||
|
||||
/// Permissionless call to redeem the master edition in a given safety deposit for a PrintingV2 winning config to the
|
||||
/// ATA of the Auctioneer. Can only be called once all redemptions have been met.
|
||||
///
|
||||
/// 0. `[writable]` Auction manager
|
||||
/// 1. `[writable]` Safety deposit token storage account
|
||||
/// 2. `[writable]` Associated token account owned by auction manager authority of same mint as token storage account
|
||||
/// 3. `[writable]` Safety deposit box account
|
||||
/// 4. `[writable]` Vault account
|
||||
/// 5. `[writable]` Fraction mint of the vault
|
||||
/// 6. `[]` Prize tracking ticket (pda of ['metaplex', program id, auction manager key, metadata mint id])
|
||||
/// 7. `[]` PDA-based Vault transfer authority ['vault', program_id, vault key]
|
||||
/// but please note that this is a PDA relative to the Token Vault program, with the 'vault' prefix
|
||||
/// 8. `[]` Auction
|
||||
/// 9. `[]` Auction data extended (pda relative to auction of ['auction', program id, vault key, 'extended'])
|
||||
/// 10. `[]` Token program
|
||||
/// 11. `[]` Token Vault program
|
||||
/// 12. `[]` Store
|
||||
/// 13. `[]` Rent sysvar
|
||||
WithdrawMasterEdition,
|
||||
|
||||
/// Note: This requires that auction manager be in a Running state.
|
||||
///
|
||||
/// Second note: Unlike it's predecessor, V2 is permissionless.
|
||||
/// You can in theory pay for someone else's participation NFT and gift it to them.
|
||||
///
|
||||
/// If an auction is complete, you can redeem your bid for an Open Edition token if it is eligible. If you are the first to do this,
|
||||
/// The auction manager will switch from Running state to Disbursing state. If you are the last, this may change
|
||||
/// the auction manager state to Finished provided that no authorities remain to be delegated for Master Edition tokens.
|
||||
///
|
||||
/// NOTE: Please note that it is totally possible to redeem a bid 2x - once for a prize you won and once at this end point for a open edition
|
||||
/// that comes as a 'token of appreciation' for bidding. They are not mutually exclusive unless explicitly set to be that way.
|
||||
///
|
||||
/// NOTE: If you are redeeming a newly minted Open Edition, you must actually supply a destination account containing a token from a brand new
|
||||
/// mint. We do not provide the token to you. Our job with this action is to christen this mint + token combo as an official Open Edition.
|
||||
///
|
||||
/// 0. `[writable]` Auction manager
|
||||
/// 1. `[writable]` Safety deposit token storage account
|
||||
/// 2. `[writable]` Account containing 1 token of your new mint type.
|
||||
/// MUST be an associated token account of pda [wallet, token program, mint] relative to ata program.
|
||||
/// 3. `[writable]` Bid redemption key -
|
||||
/// Just a PDA with seed ['metaplex', auction_key, bidder_metadata_key] that we will allocate to mark that you redeemed your bid
|
||||
/// 4. `[]` Safety deposit box account
|
||||
/// 5. `[]` Vault account
|
||||
/// 6. `[]` Fraction mint of the vault
|
||||
/// 7. `[]` Auction
|
||||
/// 8. `[]` Your BidderMetadata account
|
||||
/// 9. `[]` Your Bidder account
|
||||
/// 10. `[signer]` Payer
|
||||
/// 11. `[]` Token program
|
||||
/// 12. `[]` Token Vault program
|
||||
/// 13. `[]` Token metadata program
|
||||
/// 14. `[]` Store
|
||||
/// 15. `[]` System
|
||||
/// 16. `[]` Rent sysvar
|
||||
/// 17. `[signer]` Transfer authority to move the payment in the auction's token_mint coin from the bidder account for the participation_fixed_price
|
||||
/// on the auction manager to the auction manager account itself.
|
||||
/// 18. `[writable]` The accept payment account for the auction manager
|
||||
/// 19. `[writable]` The token account you will potentially pay for the open edition bid with if necessary.
|
||||
/// 20. `[writable]` Prize tracking ticket (pda of ['metaplex', program id, auction manager key, metadata mint id])
|
||||
/// 21. `[writable]` New Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 22. `[writable]` New Edition (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 23. `[writable]` Master Edition of token in vault V2 (pda of ['metadata', program id, master metadata mint id, 'edition']) PDA is relative to token metadata.
|
||||
/// 24. `[writable]` Mint of new token
|
||||
/// 25. `[writable]` Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number])
|
||||
/// where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE). PDA is relative to token metadata.
|
||||
/// 26. `[signer]` Mint authority of new mint - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY
|
||||
/// 27. `[]` Metadata account of token in vault
|
||||
// 28. `[]` Auction data extended - pda of ['auction', auction program id, vault key, 'extended'] relative to auction program
|
||||
RedeemParticipationBidV2,
|
||||
}
|
||||
|
||||
/// Creates an InitAuctionManager instruction
|
||||
|
@ -398,7 +514,7 @@ pub fn create_init_auction_manager_instruction(
|
|||
|
||||
/// Creates an ValidateParticipation instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_validate_participation_instruction(
|
||||
pub fn deprecated_create_validate_participation_instruction(
|
||||
program_id: Pubkey,
|
||||
auction_manager: Pubkey,
|
||||
open_edition_metadata: Pubkey,
|
||||
|
@ -426,7 +542,7 @@ pub fn create_validate_participation_instruction(
|
|||
AccountMeta::new_readonly(vault, false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetaplexInstruction::ValidateParticipation
|
||||
data: MetaplexInstruction::DeprecatedValidateParticipation
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
|
@ -498,9 +614,9 @@ pub fn create_validate_safety_deposit_box_instruction(
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates an RedeemBid instruction
|
||||
/// Creates an Deprecated RedeemBid instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_redeem_bid_instruction(
|
||||
pub fn create_deprecated_redeem_bid_instruction(
|
||||
program_id: Pubkey,
|
||||
auction_manager: Pubkey,
|
||||
safety_deposit_token_store: Pubkey,
|
||||
|
@ -538,7 +654,9 @@ pub fn create_redeem_bid_instruction(
|
|||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(transfer_authority, false),
|
||||
],
|
||||
data: MetaplexInstruction::RedeemBid.try_to_vec().unwrap(),
|
||||
data: MetaplexInstruction::DeprecatedRedeemBid
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -594,7 +712,7 @@ pub fn create_redeem_full_rights_transfer_bid_instruction(
|
|||
|
||||
/// Creates an RedeemOpenEditionBid instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_redeem_participation_bid_instruction(
|
||||
pub fn create_deprecated_redeem_participation_bid_instruction(
|
||||
program_id: Pubkey,
|
||||
auction_manager: Pubkey,
|
||||
safety_deposit_token_store: Pubkey,
|
||||
|
@ -638,7 +756,7 @@ pub fn create_redeem_participation_bid_instruction(
|
|||
AccountMeta::new(paying_token_account, false),
|
||||
AccountMeta::new(printing_authorization_token_account, false),
|
||||
],
|
||||
data: MetaplexInstruction::RedeemParticipationBid
|
||||
data: MetaplexInstruction::DeprecatedRedeemParticipationBid
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
|
@ -695,7 +813,7 @@ pub fn create_set_store_instruction(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_populate_participation_printing_account_instruction(
|
||||
pub fn create_deprecated_populate_participation_printing_account_instruction(
|
||||
program_id: Pubkey,
|
||||
safety_deposit_token_store: Pubkey,
|
||||
transient_one_time_mint_account: Pubkey,
|
||||
|
@ -735,7 +853,343 @@ pub fn create_populate_participation_printing_account_instruction(
|
|||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetaplexInstruction::PopulateParticipationPrintingAccount
|
||||
data: MetaplexInstruction::DeprecatedPopulateParticipationPrintingAccount
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an DecommissionAuctionManager instruction
|
||||
pub fn create_decommission_auction_manager_instruction(
|
||||
program_id: Pubkey,
|
||||
auction_manager: Pubkey,
|
||||
auction: Pubkey,
|
||||
authority: Pubkey,
|
||||
vault: Pubkey,
|
||||
store: Pubkey,
|
||||
) -> Instruction {
|
||||
let accounts = vec![
|
||||
AccountMeta::new(auction_manager, false),
|
||||
AccountMeta::new(auction, false),
|
||||
AccountMeta::new_readonly(authority, true),
|
||||
AccountMeta::new_readonly(vault, false),
|
||||
AccountMeta::new_readonly(store, false),
|
||||
AccountMeta::new_readonly(spl_auction::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
];
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetaplexInstruction::DecommissionAuctionManager
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an RedeemPrintingV2Bid instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_redeem_printing_v2_bid_instruction(
|
||||
program_id: Pubkey,
|
||||
auction_manager: Pubkey,
|
||||
safety_deposit_token_store: Pubkey,
|
||||
destination: Pubkey,
|
||||
bid_redemption: Pubkey,
|
||||
safety_deposit_box: Pubkey,
|
||||
vault: Pubkey,
|
||||
fraction_mint: Pubkey,
|
||||
auction: Pubkey,
|
||||
bidder_metadata: Pubkey,
|
||||
bidder: Pubkey,
|
||||
payer: Pubkey,
|
||||
store: Pubkey,
|
||||
new_metadata: Pubkey,
|
||||
original_mint: Pubkey,
|
||||
new_mint: Pubkey,
|
||||
new_mint_authority: Pubkey,
|
||||
edition: u64,
|
||||
win_index: u64,
|
||||
) -> Instruction {
|
||||
let (prize_tracking_ticket, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
auction_manager.as_ref(),
|
||||
original_mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
);
|
||||
|
||||
let edition_offset = edition.checked_rem(EDITION_MARKER_BIT_SIZE).unwrap();
|
||||
let edition_number = edition.checked_div(EDITION_MARKER_BIT_SIZE).unwrap();
|
||||
|
||||
let (edition_mark_pda, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
original_mint.as_ref(),
|
||||
spl_token_metadata::state::EDITION.as_bytes(),
|
||||
edition_number.to_string().as_bytes(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
let (metadata, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
original_mint.as_ref(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
let (master_edition, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
original_mint.as_ref(),
|
||||
spl_token_metadata::state::EDITION.as_bytes(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
let (new_edition, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
new_mint.as_ref(),
|
||||
spl_token_metadata::state::EDITION.as_bytes(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(auction_manager, false),
|
||||
AccountMeta::new(safety_deposit_token_store, false),
|
||||
AccountMeta::new(destination, false),
|
||||
AccountMeta::new(bid_redemption, false),
|
||||
AccountMeta::new(safety_deposit_box, false),
|
||||
AccountMeta::new(vault, false),
|
||||
AccountMeta::new(fraction_mint, false),
|
||||
AccountMeta::new_readonly(auction, false),
|
||||
AccountMeta::new_readonly(bidder_metadata, false),
|
||||
AccountMeta::new_readonly(bidder, false),
|
||||
AccountMeta::new(payer, true),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(spl_token_vault::id(), false),
|
||||
AccountMeta::new_readonly(spl_token_metadata::id(), false),
|
||||
AccountMeta::new_readonly(store, false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new(prize_tracking_ticket, false),
|
||||
AccountMeta::new(new_metadata, false),
|
||||
AccountMeta::new(new_edition, false),
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(new_mint, false),
|
||||
AccountMeta::new(edition_mark_pda, false),
|
||||
AccountMeta::new_readonly(new_mint_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
],
|
||||
data: MetaplexInstruction::RedeemPrintingV2Bid(RedeemPrintingV2BidArgs {
|
||||
edition_offset,
|
||||
win_index,
|
||||
})
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an WithdrawMasterEdition instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_withdraw_master_edition(
|
||||
program_id: Pubkey,
|
||||
auction_manager: Pubkey,
|
||||
safety_deposit_token_store: Pubkey,
|
||||
destination: Pubkey,
|
||||
safety_deposit_box: Pubkey,
|
||||
vault: Pubkey,
|
||||
fraction_mint: Pubkey,
|
||||
auction: Pubkey,
|
||||
store: Pubkey,
|
||||
mint: Pubkey,
|
||||
) -> Instruction {
|
||||
let (prize_tracking_ticket, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
auction_manager.as_ref(),
|
||||
mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
);
|
||||
|
||||
let (vault_authority, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
spl_token_vault::id().as_ref(),
|
||||
vault.as_ref(),
|
||||
],
|
||||
&spl_token_vault::id(),
|
||||
);
|
||||
|
||||
let (auction_data_extended, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
spl_auction::id().as_ref(),
|
||||
vault.as_ref(),
|
||||
spl_auction::EXTENDED.as_bytes(),
|
||||
],
|
||||
&spl_auction::id(),
|
||||
);
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(auction_manager, false),
|
||||
AccountMeta::new(safety_deposit_token_store, false),
|
||||
AccountMeta::new(destination, false),
|
||||
AccountMeta::new(safety_deposit_box, false),
|
||||
AccountMeta::new(vault, false),
|
||||
AccountMeta::new(fraction_mint, false),
|
||||
AccountMeta::new_readonly(prize_tracking_ticket, false),
|
||||
AccountMeta::new_readonly(vault_authority, false),
|
||||
AccountMeta::new_readonly(auction, false),
|
||||
AccountMeta::new_readonly(auction_data_extended, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(spl_token_vault::id(), false),
|
||||
AccountMeta::new_readonly(store, false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetaplexInstruction::WithdrawMasterEdition
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an RedeemParticipationBidV2 instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_redeem_participation_bid_v2_instruction(
|
||||
program_id: Pubkey,
|
||||
auction_manager: Pubkey,
|
||||
safety_deposit_token_store: Pubkey,
|
||||
destination: Pubkey,
|
||||
bid_redemption: Pubkey,
|
||||
safety_deposit_box: Pubkey,
|
||||
vault: Pubkey,
|
||||
fraction_mint: Pubkey,
|
||||
auction: Pubkey,
|
||||
bidder_metadata: Pubkey,
|
||||
bidder: Pubkey,
|
||||
payer: Pubkey,
|
||||
store: Pubkey,
|
||||
transfer_authority: Pubkey,
|
||||
accept_payment: Pubkey,
|
||||
paying_token_account: Pubkey,
|
||||
new_metadata: Pubkey,
|
||||
original_mint: Pubkey,
|
||||
new_mint: Pubkey,
|
||||
new_mint_authority: Pubkey,
|
||||
desired_edition: u64,
|
||||
) -> Instruction {
|
||||
let (prize_tracking_ticket, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
auction_manager.as_ref(),
|
||||
original_mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
);
|
||||
|
||||
let edition_number = desired_edition
|
||||
.checked_div(EDITION_MARKER_BIT_SIZE)
|
||||
.unwrap();
|
||||
|
||||
let (edition_mark_pda, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
original_mint.as_ref(),
|
||||
spl_token_metadata::state::EDITION.as_bytes(),
|
||||
edition_number.to_string().as_bytes(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
let (metadata, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
original_mint.as_ref(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
let (master_edition, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
original_mint.as_ref(),
|
||||
spl_token_metadata::state::EDITION.as_bytes(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
let (new_edition, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
spl_token_metadata::id().as_ref(),
|
||||
new_mint.as_ref(),
|
||||
spl_token_metadata::state::EDITION.as_bytes(),
|
||||
],
|
||||
&spl_token_metadata::id(),
|
||||
);
|
||||
|
||||
let (extended, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
spl_auction::id().as_ref(),
|
||||
vault.as_ref(),
|
||||
spl_auction::EXTENDED.as_bytes(),
|
||||
],
|
||||
&spl_auction::id(),
|
||||
);
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(auction_manager, false),
|
||||
AccountMeta::new(safety_deposit_token_store, false),
|
||||
AccountMeta::new(destination, false),
|
||||
AccountMeta::new(bid_redemption, false),
|
||||
AccountMeta::new_readonly(safety_deposit_box, false),
|
||||
AccountMeta::new_readonly(vault, false),
|
||||
AccountMeta::new_readonly(fraction_mint, false),
|
||||
AccountMeta::new_readonly(auction, false),
|
||||
AccountMeta::new_readonly(bidder_metadata, false),
|
||||
AccountMeta::new_readonly(bidder, true),
|
||||
AccountMeta::new(payer, true),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(spl_token_vault::id(), false),
|
||||
AccountMeta::new_readonly(spl_token_metadata::id(), false),
|
||||
AccountMeta::new_readonly(store, false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
AccountMeta::new_readonly(transfer_authority, true),
|
||||
AccountMeta::new(accept_payment, false),
|
||||
AccountMeta::new(paying_token_account, false),
|
||||
AccountMeta::new(prize_tracking_ticket, false),
|
||||
AccountMeta::new(new_metadata, false),
|
||||
AccountMeta::new(new_edition, false),
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(new_mint, false),
|
||||
AccountMeta::new(edition_mark_pda, false),
|
||||
AccountMeta::new_readonly(new_mint_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(extended, false),
|
||||
],
|
||||
data: MetaplexInstruction::RedeemParticipationBidV2
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
|
|
|
@ -3,35 +3,39 @@ use {
|
|||
borsh::BorshDeserialize,
|
||||
claim_bid::process_claim_bid,
|
||||
decommission_auction_manager::process_decommission_auction_manager,
|
||||
deprecated_populate_participation_printing_account::process_deprecated_populate_participation_printing_account,
|
||||
deprecated_validate_participation::process_deprecated_validate_participation,
|
||||
empty_payment_account::process_empty_payment_account,
|
||||
init_auction_manager::process_init_auction_manager,
|
||||
populate_participation_printing_account::process_populate_participation_printing_account,
|
||||
redeem_bid::process_redeem_bid,
|
||||
redeem_full_rights_transfer_bid::process_full_rights_transfer_bid,
|
||||
redeem_participation_bid::process_redeem_participation_bid,
|
||||
redeem_printing_v2_bid::process_redeem_printing_v2_bid,
|
||||
redeem_unused_winning_config_items_as_auctioneer::process_redeem_unused_winning_config_items_as_auctioneer,
|
||||
set_store::process_set_store,
|
||||
set_whitelisted_creator::process_set_whitelisted_creator,
|
||||
solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg, pubkey::Pubkey},
|
||||
start_auction::process_start_auction,
|
||||
validate_participation::process_validate_participation,
|
||||
validate_safety_deposit_box::process_validate_safety_deposit_box,
|
||||
withdraw_master_edition::process_withdraw_master_edition,
|
||||
};
|
||||
|
||||
pub mod claim_bid;
|
||||
pub mod decommission_auction_manager;
|
||||
pub mod deprecated_populate_participation_printing_account;
|
||||
pub mod deprecated_validate_participation;
|
||||
pub mod empty_payment_account;
|
||||
pub mod init_auction_manager;
|
||||
pub mod populate_participation_printing_account;
|
||||
pub mod redeem_bid;
|
||||
pub mod redeem_full_rights_transfer_bid;
|
||||
pub mod redeem_participation_bid;
|
||||
pub mod redeem_printing_v2_bid;
|
||||
pub mod redeem_unused_winning_config_items_as_auctioneer;
|
||||
pub mod set_store;
|
||||
pub mod set_whitelisted_creator;
|
||||
pub mod start_auction;
|
||||
pub mod validate_participation;
|
||||
pub mod validate_safety_deposit_box;
|
||||
pub mod withdraw_master_edition;
|
||||
|
||||
pub fn process_instruction<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
|
@ -48,7 +52,7 @@ pub fn process_instruction<'a>(
|
|||
msg!("Instruction: Validate Safety Deposit Box");
|
||||
process_validate_safety_deposit_box(program_id, accounts)
|
||||
}
|
||||
MetaplexInstruction::RedeemBid => {
|
||||
MetaplexInstruction::DeprecatedRedeemBid => {
|
||||
msg!("Instruction: Redeem Normal Token Bid");
|
||||
process_redeem_bid(program_id, accounts, None)
|
||||
}
|
||||
|
@ -56,9 +60,9 @@ pub fn process_instruction<'a>(
|
|||
msg!("Instruction: Redeem Full Rights Transfer Bid");
|
||||
process_full_rights_transfer_bid(program_id, accounts, None)
|
||||
}
|
||||
MetaplexInstruction::RedeemParticipationBid => {
|
||||
msg!("Instruction: Redeem Participation Bid");
|
||||
process_redeem_participation_bid(program_id, accounts)
|
||||
MetaplexInstruction::DeprecatedRedeemParticipationBid => {
|
||||
msg!("Instruction: Deprecated Redeem Participation Bid");
|
||||
process_redeem_participation_bid(program_id, accounts, true)
|
||||
}
|
||||
MetaplexInstruction::StartAuction => {
|
||||
msg!("Instruction: Start Auction");
|
||||
|
@ -80,13 +84,13 @@ pub fn process_instruction<'a>(
|
|||
msg!("Instruction: Set Whitelisted Creator");
|
||||
process_set_whitelisted_creator(program_id, accounts, args.activated)
|
||||
}
|
||||
MetaplexInstruction::ValidateParticipation => {
|
||||
msg!("Instruction: Validate Open Edition");
|
||||
process_validate_participation(program_id, accounts)
|
||||
MetaplexInstruction::DeprecatedValidateParticipation => {
|
||||
msg!("Instruction: Deprecated Validate Open Edition");
|
||||
process_deprecated_validate_participation(program_id, accounts)
|
||||
}
|
||||
MetaplexInstruction::PopulateParticipationPrintingAccount => {
|
||||
msg!("Instruction: Populate Participation Printing Account");
|
||||
process_populate_participation_printing_account(program_id, accounts)
|
||||
MetaplexInstruction::DeprecatedPopulateParticipationPrintingAccount => {
|
||||
msg!("Instruction: Deprecated Populate Participation Printing Account");
|
||||
process_deprecated_populate_participation_printing_account(program_id, accounts)
|
||||
}
|
||||
MetaplexInstruction::RedeemUnusedWinningConfigItemsAsAuctioneer(args) => {
|
||||
msg!("Instruction: Redeem Unused Winning Config Items As Auctioneer");
|
||||
|
@ -96,5 +100,22 @@ pub fn process_instruction<'a>(
|
|||
msg!("Instruction: Decomission Auction Manager");
|
||||
process_decommission_auction_manager(program_id, accounts)
|
||||
}
|
||||
MetaplexInstruction::RedeemPrintingV2Bid(args) => {
|
||||
msg!("Instruction: Redeem Printing V2 Bid");
|
||||
process_redeem_printing_v2_bid(
|
||||
program_id,
|
||||
accounts,
|
||||
args.edition_offset,
|
||||
args.win_index,
|
||||
)
|
||||
}
|
||||
MetaplexInstruction::WithdrawMasterEdition => {
|
||||
msg!("Instruction: Withdraw Master Edition");
|
||||
process_withdraw_master_edition(program_id, accounts)
|
||||
}
|
||||
MetaplexInstruction::RedeemParticipationBidV2 => {
|
||||
msg!("Instruction: Redeem Participation Bid V2");
|
||||
process_redeem_participation_bid(program_id, accounts, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@ use {
|
|||
},
|
||||
spl_auction::processor::{AuctionData, AuctionDataExtended, AuctionState},
|
||||
spl_token::{instruction::close_account, state::Account},
|
||||
spl_token_metadata::{instruction::mint_printing_tokens_via_token, state::MasterEdition},
|
||||
spl_token_metadata::{
|
||||
deprecated_instruction::deprecated_mint_printing_tokens_via_token, state::MasterEditionV1,
|
||||
},
|
||||
spl_token_vault::state::SafetyDepositBox,
|
||||
};
|
||||
|
||||
|
@ -37,7 +39,7 @@ fn mint_printing_tokens<'a: 'b, 'b>(
|
|||
authority_signer_seeds: &'b [&'b [u8]],
|
||||
) -> ProgramResult {
|
||||
let result = invoke_signed(
|
||||
&mint_printing_tokens_via_token(
|
||||
&deprecated_mint_printing_tokens_via_token(
|
||||
*program.key,
|
||||
*destination.key,
|
||||
*token.key,
|
||||
|
@ -68,7 +70,7 @@ fn mint_printing_tokens<'a: 'b, 'b>(
|
|||
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
#[allow(clippy::absurd_extreme_comparisons)]
|
||||
pub fn process_populate_participation_printing_account<'a>(
|
||||
pub fn process_deprecated_populate_participation_printing_account<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
) -> ProgramResult {
|
||||
|
@ -99,7 +101,7 @@ pub fn process_populate_participation_printing_account<'a>(
|
|||
let safety_deposit_token_store: Account = assert_initialized(&safety_deposit_token_store_info)?;
|
||||
let auction = AuctionData::from_account_info(auction_info)?;
|
||||
let auction_extended = AuctionDataExtended::from_account_info(auction_extended_info)?;
|
||||
let master_edition = MasterEdition::from_account_info(master_edition_info)?;
|
||||
let master_edition = MasterEditionV1::from_account_info(master_edition_info)?;
|
||||
let transient_one_time_auth_holding_account: Account =
|
||||
assert_initialized(transient_one_time_holding_info)?;
|
||||
let participation_printing_account: Account =
|
|
@ -18,11 +18,11 @@ use {
|
|||
sysvar::Sysvar,
|
||||
},
|
||||
spl_token::state::Account,
|
||||
spl_token_metadata::state::{MasterEdition, Metadata},
|
||||
spl_token_metadata::state::{MasterEditionV1, Metadata},
|
||||
spl_token_vault::state::{SafetyDepositBox, Vault},
|
||||
};
|
||||
|
||||
pub fn process_validate_participation(
|
||||
pub fn process_deprecated_validate_participation(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
) -> ProgramResult {
|
||||
|
@ -50,7 +50,7 @@ pub fn process_validate_participation(
|
|||
let printing_token_account: Account =
|
||||
assert_initialized(printing_authorization_token_account_info)?;
|
||||
let open_edition_metadata = Metadata::from_account_info(open_edition_metadata_info)?;
|
||||
let master_edition = MasterEdition::from_account_info(open_master_edition_info)?;
|
||||
let master_edition = MasterEditionV1::from_account_info(open_master_edition_info)?;
|
||||
|
||||
if vault.authority != *auction_manager_info.key {
|
||||
return Err(MetaplexError::VaultAuthorityMismatch.into());
|
|
@ -6,8 +6,8 @@ use {
|
|||
instruction::EmptyPaymentAccountArgs,
|
||||
state::{AuctionManager, Key, PayoutTicket, Store, MAX_PAYOUT_TICKET_SIZE, PREFIX},
|
||||
utils::{
|
||||
assert_derivation, assert_initialized, assert_owned_by, assert_rent_exempt,
|
||||
create_or_allocate_account_raw, spl_token_transfer,
|
||||
assert_derivation, assert_initialized, assert_is_ata, assert_owned_by,
|
||||
assert_rent_exempt, create_or_allocate_account_raw, spl_token_transfer,
|
||||
},
|
||||
},
|
||||
borsh::BorshSerialize,
|
||||
|
@ -22,9 +22,8 @@ use {
|
|||
},
|
||||
spl_auction::processor::AuctionData,
|
||||
spl_token::state::Account,
|
||||
spl_token_metadata::state::{MasterEdition, Metadata},
|
||||
spl_token_metadata::state::{MasterEditionV1, Metadata},
|
||||
spl_token_vault::state::SafetyDepositBox,
|
||||
std::str::FromStr,
|
||||
};
|
||||
|
||||
fn assert_winning_config_safety_deposit_validity(
|
||||
|
@ -78,14 +77,11 @@ fn assert_destination_ownership_validity(
|
|||
|
||||
// Let's avoid importing the entire ATA library here just to get a helper and an ID.
|
||||
// Assert destination is, in fact, an ATA.
|
||||
assert_derivation(
|
||||
&Pubkey::from_str("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").unwrap(),
|
||||
assert_is_ata(
|
||||
destination_info,
|
||||
&[
|
||||
creator.address.as_ref(),
|
||||
&store.token_program.as_ref(),
|
||||
&destination.mint.as_ref(),
|
||||
],
|
||||
&creator.address,
|
||||
&store.token_program,
|
||||
&destination.mint,
|
||||
)?;
|
||||
} else {
|
||||
return Err(MetaplexError::InvalidCreatorIndex.into());
|
||||
|
@ -362,11 +358,18 @@ pub fn process_empty_payment_account(
|
|||
|
||||
// assert that the metadata sent up is the metadata in the safety deposit
|
||||
if metadata.mint != safety_deposit.token_mint {
|
||||
// Could be a limited edition, in which case printing tokens or auth tokens were offered, not the original.
|
||||
let master_edition: MasterEdition = MasterEdition::from_account_info(master_edition_info)?;
|
||||
if master_edition.printing_mint != safety_deposit.token_mint
|
||||
&& master_edition.one_time_printing_authorization_mint != safety_deposit.token_mint
|
||||
if master_edition_info.data.borrow()[0]
|
||||
== spl_token_metadata::state::Key::MasterEditionV1 as u8
|
||||
{
|
||||
// Could be a limited edition, in which case printing tokens or auth tokens were offered, not the original.
|
||||
let master_edition: MasterEditionV1 =
|
||||
MasterEditionV1::from_account_info(master_edition_info)?;
|
||||
if master_edition.printing_mint != safety_deposit.token_mint
|
||||
&& master_edition.one_time_printing_authorization_mint != safety_deposit.token_mint
|
||||
{
|
||||
return Err(MetaplexError::SafetyDepositBoxMetadataMismatch.into());
|
||||
}
|
||||
} else {
|
||||
return Err(MetaplexError::SafetyDepositBoxMetadataMismatch.into());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,18 +107,27 @@ pub fn process_init_auction_manager(
|
|||
|
||||
let mut winning_config_states: Vec<WinningConfigState> = vec![];
|
||||
let mut winning_item_count: u8 = 0;
|
||||
let mut any_with_more_than_one = false;
|
||||
for winning_config in &auction_manager_settings.winning_configs {
|
||||
let mut winning_config_state_items = vec![];
|
||||
let mut safety_deposit_box_found_lookup: Vec<bool> = vec![];
|
||||
for _ in 0..vault.token_type_count {
|
||||
safety_deposit_box_found_lookup.push(false)
|
||||
}
|
||||
if winning_config.items.len() > 1 {
|
||||
any_with_more_than_one = true;
|
||||
}
|
||||
for item in &winning_config.items {
|
||||
// If this blows then they have more than 255 total items which is unacceptable in current impl
|
||||
winning_item_count = winning_item_count
|
||||
.checked_add(1)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
|
||||
// Check if index referenced exists
|
||||
if item.safety_deposit_box_index as usize >= safety_deposit_box_found_lookup.len() {
|
||||
return Err(MetaplexError::InvalidWinningConfigSafetyDepositIndex.into());
|
||||
}
|
||||
|
||||
// Should never have same deposit index appear twice in one config.
|
||||
let lookup = safety_deposit_box_found_lookup[item.safety_deposit_box_index as usize];
|
||||
if lookup {
|
||||
|
@ -166,6 +175,7 @@ pub fn process_init_auction_manager(
|
|||
auction_manager.accept_payment = *accept_payment_info.key;
|
||||
auction_manager.state.winning_config_items_validated = 0;
|
||||
auction_manager.state.winning_config_states = winning_config_states;
|
||||
auction_manager.straight_shot_optimization = !any_with_more_than_one;
|
||||
|
||||
if auction_manager.settings.participation_config.is_some() {
|
||||
auction_manager.state.participation_state = Some(ParticipationState {
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
use {
|
||||
crate::{
|
||||
error::MetaplexError,
|
||||
state::{AuctionManager, WinningConfigItem, WinningConfigType, PREFIX},
|
||||
state::{WinningConfigType, PREFIX},
|
||||
utils::{
|
||||
assert_derivation, common_redeem_checks, common_redeem_finish,
|
||||
common_winning_config_checks, transfer_safety_deposit_box_items, CommonRedeemCheckArgs,
|
||||
CommonRedeemFinishArgs, CommonRedeemReturn, CommonWinningConfigCheckReturn,
|
||||
common_winning_config_checks, get_amount_from_token_account,
|
||||
transfer_safety_deposit_box_items, CommonRedeemCheckArgs, CommonRedeemFinishArgs,
|
||||
CommonRedeemReturn, CommonWinningConfigCheckReturn,
|
||||
},
|
||||
},
|
||||
arrayref::array_ref,
|
||||
solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint::ProgramResult,
|
||||
program::invoke_signed,
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
spl_auction::processor::AuctionData,
|
||||
spl_token_metadata::{
|
||||
instruction::set_reservation_list,
|
||||
state::{get_reservation_list, Reservation},
|
||||
deprecated_instruction::deprecated_set_reservation_list, state::Reservation,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -33,7 +35,7 @@ fn set_reservation_list_wrapper<'a>(
|
|||
total_spot_offset: u64,
|
||||
) -> ProgramResult {
|
||||
invoke_signed(
|
||||
&set_reservation_list(
|
||||
&deprecated_set_reservation_list(
|
||||
*program_id,
|
||||
*master_edition_info.key,
|
||||
*reservation_list_info.key,
|
||||
|
@ -54,68 +56,52 @@ fn set_reservation_list_wrapper<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn calc_spots(
|
||||
winning_config_item: &WinningConfigItem,
|
||||
auction_manager: &AuctionManager,
|
||||
n: usize,
|
||||
) -> u64 {
|
||||
auction_manager.settings.winning_configs[n]
|
||||
.items
|
||||
.iter()
|
||||
.filter(|i| i.safety_deposit_box_index == winning_config_item.safety_deposit_box_index)
|
||||
.map(|i| i.amount as u64)
|
||||
.sum()
|
||||
fn get_supply_snapshot_off_reservation_list(
|
||||
reservation_list_info: &AccountInfo,
|
||||
) -> Result<Option<u64>, ProgramError> {
|
||||
let data = reservation_list_info.try_borrow_data()?;
|
||||
// this is an option, 9 bytes, first is 0 means is none
|
||||
if data[33] == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
let amount_data = array_ref![data, 34, 8];
|
||||
Ok(Some(u64::from_le_bytes(*amount_data)))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn reserve_list_if_needed<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
auction_manager: &AuctionManager,
|
||||
auction: &AuctionData,
|
||||
winning_config_item: &WinningConfigItem,
|
||||
winning_index: usize,
|
||||
auction_info: &AccountInfo<'a>,
|
||||
bidder_info: &AccountInfo<'a>,
|
||||
master_edition_info: &AccountInfo<'a>,
|
||||
reservation_list_info: &AccountInfo<'a>,
|
||||
auction_manager_info: &AccountInfo<'a>,
|
||||
safety_deposit_token_store_info: &AccountInfo<'a>,
|
||||
signer_seeds: &[&[u8]],
|
||||
) -> ProgramResult {
|
||||
let reservation_list = get_reservation_list(reservation_list_info)?;
|
||||
|
||||
let total_reservation_spot_opt: Option<u64>;
|
||||
|
||||
// Auction specifically does not expose internal state workings as it may change someday,
|
||||
// but it does expose a point get-winner-at-index method. Right now this is just array access
|
||||
// but may be invocation someday. It's inefficient style but better for the interface maintenance
|
||||
// in the long run if we move to better storage solutions (so that this action doesnt need to change if
|
||||
// storage does.)
|
||||
// This math will explicitly be off in custom cases where you are giving away multiple editions to a single
|
||||
// person. However these are rare. This optimization will literally break this case because
|
||||
// there will be fewer reservation spots than those available. However I'm switching to it
|
||||
// because we need to support those 50 person legacy auctions out there which are mostly limited editions
|
||||
// and get them redeemed so we can move to the newer system which works.
|
||||
|
||||
let mut total_reservation_spots: u64 = 0;
|
||||
let mut total_spot_offset: u64 = 0;
|
||||
for n in 0..auction_manager.settings.winning_configs.len() {
|
||||
match auction.winner_at(n) {
|
||||
Some(_) => {
|
||||
let spots: u64 = calc_spots(winning_config_item, auction_manager, n);
|
||||
total_reservation_spots = total_reservation_spots
|
||||
.checked_add(spots)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
if n < winning_index {
|
||||
total_spot_offset = total_spot_offset
|
||||
.checked_add(spots)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
}
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
let total_spot_offset: u64 = winning_index as u64;
|
||||
|
||||
if reservation_list.supply_snapshot().is_none() {
|
||||
total_reservation_spot_opt = Some(total_reservation_spots)
|
||||
if get_supply_snapshot_off_reservation_list(reservation_list_info)?.is_none() {
|
||||
total_reservation_spot_opt = Some(std::cmp::min(
|
||||
get_amount_from_token_account(safety_deposit_token_store_info)?,
|
||||
AuctionData::get_num_winners(auction_info) as u64,
|
||||
));
|
||||
} else {
|
||||
total_reservation_spot_opt = None
|
||||
}
|
||||
|
||||
let my_spots: u64 = calc_spots(winning_config_item, auction_manager, winning_index);
|
||||
let my_spots: u64 = 1;
|
||||
|
||||
set_reservation_list_wrapper(
|
||||
program_id,
|
||||
master_edition_info,
|
||||
|
@ -128,6 +114,9 @@ pub fn reserve_list_if_needed<'a>(
|
|||
total_spots: my_spots,
|
||||
}],
|
||||
total_reservation_spot_opt,
|
||||
// Note this logic is explicitly wrong in cases of tiered auctions where the edition
|
||||
// is not present in every single winning config. But that would require iteration to figure out,
|
||||
// and we are optimizing for the 99.8% case in this legacy logic.
|
||||
winning_index as u64,
|
||||
total_spot_offset,
|
||||
)?;
|
||||
|
@ -166,8 +155,7 @@ pub fn process_redeem_bid<'a>(
|
|||
let CommonRedeemReturn {
|
||||
auction_manager,
|
||||
redemption_bump_seed,
|
||||
bidder_metadata,
|
||||
auction,
|
||||
cancelled,
|
||||
rent: _rent,
|
||||
win_index,
|
||||
token_metadata_program: _t,
|
||||
|
@ -188,11 +176,14 @@ pub fn process_redeem_bid<'a>(
|
|||
rent_info,
|
||||
store_info,
|
||||
is_participation: false,
|
||||
user_provided_win_index: None,
|
||||
overwrite_win_index,
|
||||
assert_bidder_signer: true,
|
||||
ignore_bid_redeemed_item_check: false,
|
||||
})?;
|
||||
|
||||
let mut winning_item_index = None;
|
||||
if !bidder_metadata.cancelled {
|
||||
if !cancelled {
|
||||
if let Some(winning_index) = win_index {
|
||||
if winning_index < auction_manager.settings.winning_configs.len() {
|
||||
// Okay, so they placed in the auction winning prizes section!
|
||||
|
@ -204,10 +195,11 @@ pub fn process_redeem_bid<'a>(
|
|||
&auction_manager,
|
||||
&safety_deposit_info,
|
||||
winning_index,
|
||||
false,
|
||||
)?;
|
||||
winning_item_index = wii;
|
||||
if winning_config_item.winning_config_type != WinningConfigType::TokenOnlyTransfer
|
||||
&& winning_config_item.winning_config_type != WinningConfigType::Printing
|
||||
&& winning_config_item.winning_config_type != WinningConfigType::PrintingV1
|
||||
{
|
||||
return Err(MetaplexError::WrongBidEndpointForPrize.into());
|
||||
}
|
||||
|
@ -224,20 +216,21 @@ pub fn process_redeem_bid<'a>(
|
|||
&[auction_bump_seed],
|
||||
];
|
||||
|
||||
if winning_config_item.winning_config_type == WinningConfigType::Printing {
|
||||
if winning_config_item.winning_config_type == WinningConfigType::PrintingV1
|
||||
&& overwrite_win_index.is_none()
|
||||
{
|
||||
let master_edition_info = next_account_info(account_info_iter)?;
|
||||
let reservation_list_info = next_account_info(account_info_iter)?;
|
||||
|
||||
reserve_list_if_needed(
|
||||
token_metadata_program_info.key,
|
||||
&auction_manager,
|
||||
&auction,
|
||||
&winning_config_item,
|
||||
winning_index,
|
||||
auction_info,
|
||||
bidder_info,
|
||||
master_edition_info,
|
||||
reservation_list_info,
|
||||
auction_manager_info,
|
||||
safety_deposit_token_store_info,
|
||||
auction_auth_seeds,
|
||||
)?;
|
||||
}
|
||||
|
|
|
@ -51,8 +51,7 @@ pub fn process_full_rights_transfer_bid<'a>(
|
|||
let CommonRedeemReturn {
|
||||
auction_manager,
|
||||
redemption_bump_seed,
|
||||
bidder_metadata,
|
||||
auction: _a,
|
||||
cancelled,
|
||||
rent: _rent,
|
||||
win_index,
|
||||
token_metadata_program,
|
||||
|
@ -73,13 +72,16 @@ pub fn process_full_rights_transfer_bid<'a>(
|
|||
store_info,
|
||||
rent_info,
|
||||
is_participation: false,
|
||||
user_provided_win_index: None,
|
||||
overwrite_win_index,
|
||||
assert_bidder_signer: true,
|
||||
ignore_bid_redeemed_item_check: false,
|
||||
})?;
|
||||
|
||||
assert_owned_by(metadata_info, &token_metadata_program)?;
|
||||
|
||||
let mut winning_item_index = None;
|
||||
if !bidder_metadata.cancelled {
|
||||
if !cancelled {
|
||||
if let Some(winning_index) = win_index {
|
||||
if winning_index < auction_manager.settings.winning_configs.len() {
|
||||
let CommonWinningConfigCheckReturn {
|
||||
|
@ -89,6 +91,7 @@ pub fn process_full_rights_transfer_bid<'a>(
|
|||
&auction_manager,
|
||||
&safety_deposit_info,
|
||||
winning_index,
|
||||
false,
|
||||
)?;
|
||||
|
||||
winning_item_index = wii;
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use {
|
||||
crate::{
|
||||
error::MetaplexError,
|
||||
processor::redeem_printing_v2_bid::{create_or_update_prize_tracking, mint_edition},
|
||||
state::{
|
||||
NonWinningConstraint, ParticipationConfig, ParticipationState, WinningConstraint,
|
||||
PREFIX,
|
||||
AuctionManager, NonWinningConstraint, ParticipationConfig, ParticipationState, Store,
|
||||
WinningConstraint, PREFIX,
|
||||
},
|
||||
utils::{
|
||||
assert_initialized, assert_owned_by, common_redeem_checks, common_redeem_finish,
|
||||
assert_derivation, assert_initialized, assert_is_ata, assert_owned_by,
|
||||
common_redeem_checks, common_redeem_finish, get_amount_from_token_account,
|
||||
spl_token_transfer, CommonRedeemCheckArgs, CommonRedeemFinishArgs, CommonRedeemReturn,
|
||||
},
|
||||
},
|
||||
|
@ -15,14 +17,240 @@ use {
|
|||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
spl_auction::processor::{AuctionData, AuctionDataExtended, BidderMetadata},
|
||||
spl_token::state::Account,
|
||||
spl_token_metadata::utils::get_supply_off_master_edition,
|
||||
};
|
||||
|
||||
struct LegacyAccounts<'a> {
|
||||
pub participation_printing_holding_account_info: &'a AccountInfo<'a>,
|
||||
}
|
||||
|
||||
struct V2Accounts<'a> {
|
||||
pub prize_tracking_ticket_info: &'a AccountInfo<'a>,
|
||||
pub new_metadata_account_info: &'a AccountInfo<'a>,
|
||||
pub new_edition_account_info: &'a AccountInfo<'a>,
|
||||
pub master_edition_account_info: &'a AccountInfo<'a>,
|
||||
pub mint_info: &'a AccountInfo<'a>,
|
||||
pub edition_marker_info: &'a AccountInfo<'a>,
|
||||
pub mint_authority_info: &'a AccountInfo<'a>,
|
||||
pub metadata_account_info: &'a AccountInfo<'a>,
|
||||
pub auction_extended_info: &'a AccountInfo<'a>,
|
||||
}
|
||||
|
||||
fn legacy_validation(
|
||||
token_program_info: &AccountInfo,
|
||||
auction_manager: &AuctionManager,
|
||||
accounts: &LegacyAccounts,
|
||||
) -> ProgramResult {
|
||||
assert_owned_by(
|
||||
accounts.participation_printing_holding_account_info,
|
||||
token_program_info.key,
|
||||
)?;
|
||||
|
||||
let participation_printing_account: Account =
|
||||
assert_initialized(accounts.participation_printing_holding_account_info)?;
|
||||
|
||||
if participation_printing_account.amount == 0 {
|
||||
return Err(MetaplexError::ParticipationPrintingEmpty.into());
|
||||
}
|
||||
|
||||
if let Some(state) = &auction_manager.state.participation_state {
|
||||
if let Some(token) = state.printing_authorization_token_account {
|
||||
if *accounts.participation_printing_holding_account_info.key != token {
|
||||
return Err(MetaplexError::PrintingAuthorizationTokenAccountMismatch.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn v2_validation<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
auction_manager_info: &AccountInfo<'a>,
|
||||
store_info: &AccountInfo<'a>,
|
||||
vault_info: &AccountInfo<'a>,
|
||||
payer_info: &AccountInfo<'a>,
|
||||
token_program_info: &AccountInfo<'a>,
|
||||
system_info: &AccountInfo<'a>,
|
||||
rent_info: &AccountInfo<'a>,
|
||||
bidder_info: &AccountInfo<'a>,
|
||||
master_edition_account_info: &AccountInfo<'a>,
|
||||
destination_info: &AccountInfo<'a>,
|
||||
auction_info: &AccountInfo<'a>,
|
||||
config: &ParticipationConfig,
|
||||
accounts: &V2Accounts<'a>,
|
||||
) -> ProgramResult {
|
||||
let extended = AuctionDataExtended::from_account_info(accounts.auction_extended_info)?;
|
||||
let store = Store::from_account_info(store_info)?;
|
||||
let destination_amount = get_amount_from_token_account(destination_info)?;
|
||||
assert_is_ata(
|
||||
destination_info,
|
||||
bidder_info.key,
|
||||
token_program_info.key,
|
||||
accounts.mint_info.key,
|
||||
)?;
|
||||
|
||||
if destination_amount != 1 {
|
||||
return Err(MetaplexError::ProvidedAccountDoesNotContainOneToken.into());
|
||||
}
|
||||
|
||||
assert_derivation(
|
||||
&store.auction_program,
|
||||
accounts.auction_extended_info,
|
||||
&[
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
store.auction_program.as_ref(),
|
||||
vault_info.key.as_ref(),
|
||||
spl_auction::EXTENDED.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let mut amount_to_mint = extended.total_uncancelled_bids;
|
||||
let num_winners = AuctionData::get_num_winners(auction_info) as u64;
|
||||
if config.winner_constraint == WinningConstraint::NoParticipationPrize {
|
||||
amount_to_mint = amount_to_mint
|
||||
.checked_sub(num_winners)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
} else if config.non_winning_constraint == NonWinningConstraint::NoParticipationPrize {
|
||||
amount_to_mint = num_winners
|
||||
}
|
||||
|
||||
create_or_update_prize_tracking(
|
||||
program_id,
|
||||
auction_manager_info,
|
||||
accounts.prize_tracking_ticket_info,
|
||||
accounts.metadata_account_info,
|
||||
payer_info,
|
||||
rent_info,
|
||||
system_info,
|
||||
master_edition_account_info,
|
||||
amount_to_mint,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn v2_transfer<'a>(
|
||||
auction_manager_info: &AccountInfo<'a>,
|
||||
auction_info: &AccountInfo<'a>,
|
||||
vault_info: &AccountInfo<'a>,
|
||||
bidder_info: &AccountInfo<'a>,
|
||||
token_vault_program_info: &AccountInfo<'a>,
|
||||
token_metadata_program_info: &AccountInfo<'a>,
|
||||
token_program_info: &AccountInfo<'a>,
|
||||
payer_info: &AccountInfo<'a>,
|
||||
safety_deposit_info: &AccountInfo<'a>,
|
||||
safety_deposit_token_store_info: &AccountInfo<'a>,
|
||||
system_info: &AccountInfo<'a>,
|
||||
rent_info: &AccountInfo<'a>,
|
||||
auction_manager_bump: u8,
|
||||
me_supply: u64,
|
||||
accounts: &V2Accounts<'a>,
|
||||
) -> ProgramResult {
|
||||
let actual_edition = me_supply
|
||||
.checked_add(1)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
|
||||
let signer_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
auction_info.key.as_ref(),
|
||||
&[auction_manager_bump],
|
||||
];
|
||||
mint_edition(
|
||||
token_metadata_program_info,
|
||||
token_vault_program_info,
|
||||
accounts.new_metadata_account_info,
|
||||
accounts.new_edition_account_info,
|
||||
accounts.master_edition_account_info,
|
||||
accounts.edition_marker_info,
|
||||
accounts.mint_info,
|
||||
accounts.mint_authority_info,
|
||||
payer_info,
|
||||
auction_manager_info,
|
||||
safety_deposit_token_store_info,
|
||||
safety_deposit_info,
|
||||
vault_info,
|
||||
bidder_info,
|
||||
accounts.metadata_account_info,
|
||||
token_program_info,
|
||||
system_info,
|
||||
rent_info,
|
||||
actual_edition,
|
||||
signer_seeds,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn charge_for_participation<'a>(
|
||||
bidder_token_account_info: &AccountInfo<'a>,
|
||||
accept_payment_info: &AccountInfo<'a>,
|
||||
transfer_authority_info: &AccountInfo<'a>,
|
||||
token_program_info: &AccountInfo<'a>,
|
||||
win_index: Option<usize>,
|
||||
config: &ParticipationConfig,
|
||||
auction_manager_bump: u8,
|
||||
auction_manager: &mut AuctionManager,
|
||||
bidder_token: &Account,
|
||||
bidder_metadata: &BidderMetadata,
|
||||
) -> ProgramResult {
|
||||
let signer_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
auction_manager.auction.as_ref(),
|
||||
&[auction_manager_bump],
|
||||
];
|
||||
|
||||
let mut price: u64 = 0;
|
||||
if win_index.is_none() {
|
||||
if let Some(fixed_price) = config.fixed_price {
|
||||
price = fixed_price;
|
||||
} else if config.non_winning_constraint == NonWinningConstraint::GivenForBidPrice {
|
||||
price = bidder_metadata.last_bid;
|
||||
}
|
||||
}
|
||||
|
||||
if bidder_token.amount.saturating_sub(price) < 0 as u64 {
|
||||
return Err(MetaplexError::NotEnoughBalanceForParticipation.into());
|
||||
}
|
||||
|
||||
if price > 0 {
|
||||
if let Some(state) = &auction_manager.state.participation_state {
|
||||
// Can't really edit something behind an Option reference...
|
||||
// just make new one.
|
||||
auction_manager.state.participation_state = Some(ParticipationState {
|
||||
collected_to_accept_payment: state
|
||||
.collected_to_accept_payment
|
||||
.checked_add(price)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?,
|
||||
primary_sale_happened: state.primary_sale_happened,
|
||||
validated: state.validated,
|
||||
printing_authorization_token_account: state.printing_authorization_token_account,
|
||||
});
|
||||
}
|
||||
|
||||
spl_token_transfer(
|
||||
bidder_token_account_info.clone(),
|
||||
accept_payment_info.clone(),
|
||||
price,
|
||||
transfer_authority_info.clone(),
|
||||
signer_seeds,
|
||||
token_program_info.clone(),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
#[allow(clippy::absurd_extreme_comparisons)]
|
||||
pub fn process_redeem_participation_bid<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
legacy: bool,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let auction_manager_info = next_account_info(account_info_iter)?;
|
||||
|
@ -43,16 +271,36 @@ pub fn process_redeem_participation_bid<'a>(
|
|||
let store_info = next_account_info(account_info_iter)?;
|
||||
let system_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let mut legacy_accounts: Option<LegacyAccounts> = None;
|
||||
let mut v2_accounts: Option<V2Accounts> = None;
|
||||
|
||||
let transfer_authority_info = next_account_info(account_info_iter)?;
|
||||
let accept_payment_info = next_account_info(account_info_iter)?;
|
||||
let bidder_token_account_info = next_account_info(account_info_iter)?;
|
||||
let participation_printing_holding_account_info = next_account_info(account_info_iter)?;
|
||||
|
||||
if legacy {
|
||||
legacy_accounts = Some(LegacyAccounts {
|
||||
participation_printing_holding_account_info: next_account_info(account_info_iter)?,
|
||||
});
|
||||
} else {
|
||||
v2_accounts = Some(V2Accounts {
|
||||
prize_tracking_ticket_info: next_account_info(account_info_iter)?,
|
||||
new_metadata_account_info: next_account_info(account_info_iter)?,
|
||||
new_edition_account_info: next_account_info(account_info_iter)?,
|
||||
master_edition_account_info: next_account_info(account_info_iter)?,
|
||||
mint_info: next_account_info(account_info_iter)?,
|
||||
edition_marker_info: next_account_info(account_info_iter)?,
|
||||
mint_authority_info: next_account_info(account_info_iter)?,
|
||||
metadata_account_info: next_account_info(account_info_iter)?,
|
||||
auction_extended_info: next_account_info(account_info_iter)?,
|
||||
})
|
||||
}
|
||||
|
||||
let CommonRedeemReturn {
|
||||
mut auction_manager,
|
||||
redemption_bump_seed,
|
||||
bidder_metadata,
|
||||
auction,
|
||||
cancelled,
|
||||
rent: _rent,
|
||||
win_index,
|
||||
token_metadata_program: _t,
|
||||
|
@ -73,52 +321,39 @@ pub fn process_redeem_participation_bid<'a>(
|
|||
rent_info,
|
||||
store_info,
|
||||
is_participation: true,
|
||||
user_provided_win_index: Some(None),
|
||||
overwrite_win_index: None,
|
||||
assert_bidder_signer: legacy,
|
||||
ignore_bid_redeemed_item_check: false,
|
||||
})?;
|
||||
|
||||
let bidder_metadata = BidderMetadata::from_account_info(bidder_metadata_info)?;
|
||||
|
||||
let config: ParticipationConfig;
|
||||
if let Some(part_config) = auction_manager.settings.participation_config.clone() {
|
||||
config = part_config
|
||||
} else {
|
||||
return Err(MetaplexError::NotEligibleForParticipation.into());
|
||||
}
|
||||
|
||||
assert_owned_by(accept_payment_info, token_program_info.key)?;
|
||||
assert_owned_by(bidder_token_account_info, token_program_info.key)?;
|
||||
assert_owned_by(
|
||||
participation_printing_holding_account_info,
|
||||
token_program_info.key,
|
||||
)?;
|
||||
|
||||
let participation_printing_account: Account =
|
||||
assert_initialized(participation_printing_holding_account_info)?;
|
||||
|
||||
if participation_printing_account.amount == 0 {
|
||||
return Err(MetaplexError::ParticipationPrintingEmpty.into());
|
||||
}
|
||||
|
||||
if let Some(state) = &auction_manager.state.participation_state {
|
||||
if let Some(token) = state.printing_authorization_token_account {
|
||||
if *participation_printing_holding_account_info.key != token {
|
||||
return Err(MetaplexError::PrintingAuthorizationTokenAccountMismatch.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bidder_token: Account = assert_initialized(bidder_token_account_info)?;
|
||||
|
||||
if bidder_token.mint != auction.token_mint {
|
||||
if bidder_token.mint != AuctionData::get_token_mint(auction_info) {
|
||||
return Err(MetaplexError::AcceptPaymentMintMismatch.into());
|
||||
}
|
||||
|
||||
if *accept_payment_info.key != auction_manager.accept_payment {
|
||||
return Err(MetaplexError::AcceptPaymentMismatch.into());
|
||||
}
|
||||
let config: &ParticipationConfig;
|
||||
if let Some(part_config) = &auction_manager.settings.participation_config {
|
||||
config = part_config
|
||||
} else {
|
||||
return Err(MetaplexError::NotEligibleForParticipation.into());
|
||||
}
|
||||
|
||||
let mut gets_participation =
|
||||
config.non_winning_constraint != NonWinningConstraint::NoParticipationPrize;
|
||||
|
||||
if !bidder_metadata.cancelled {
|
||||
if let Some(winning_index) = auction.is_winner(bidder_info.key) {
|
||||
if !cancelled {
|
||||
if let Some(winning_index) = AuctionData::get_is_winner(auction_info, bidder_info.key) {
|
||||
if winning_index < auction_manager.settings.winning_configs.len() {
|
||||
// Okay, so they placed in the auction winning prizes section!
|
||||
gets_participation =
|
||||
|
@ -127,62 +362,79 @@ pub fn process_redeem_participation_bid<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let bump_seed = assert_derivation(
|
||||
program_id,
|
||||
auction_manager_info,
|
||||
&[PREFIX.as_bytes(), &auction_manager.auction.as_ref()],
|
||||
)?;
|
||||
|
||||
if gets_participation {
|
||||
let seeds = &[PREFIX.as_bytes(), &auction_manager.auction.as_ref()];
|
||||
let (_, bump_seed) = Pubkey::find_program_address(seeds, &program_id);
|
||||
let mint_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
&auction_manager.auction.as_ref(),
|
||||
&[bump_seed],
|
||||
];
|
||||
|
||||
spl_token_transfer(
|
||||
participation_printing_holding_account_info.clone(),
|
||||
destination_info.clone(),
|
||||
1,
|
||||
auction_manager_info.clone(),
|
||||
mint_seeds,
|
||||
token_program_info.clone(),
|
||||
)?;
|
||||
|
||||
let mut price: u64 = 0;
|
||||
if win_index.is_none() {
|
||||
if let Some(fixed_price) = config.fixed_price {
|
||||
price = fixed_price;
|
||||
} else if config.non_winning_constraint == NonWinningConstraint::GivenForBidPrice {
|
||||
price = bidder_metadata.last_bid;
|
||||
}
|
||||
}
|
||||
|
||||
if bidder_token.amount.saturating_sub(price) < 0 as u64 {
|
||||
return Err(MetaplexError::NotEnoughBalanceForParticipation.into());
|
||||
}
|
||||
|
||||
if price > 0 {
|
||||
if let Some(state) = &auction_manager.state.participation_state {
|
||||
// Can't really edit something behind an Option reference...
|
||||
// just make new one.
|
||||
auction_manager.state.participation_state = Some(ParticipationState {
|
||||
collected_to_accept_payment: state
|
||||
.collected_to_accept_payment
|
||||
.checked_add(price)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?,
|
||||
primary_sale_happened: state.primary_sale_happened,
|
||||
validated: state.validated,
|
||||
printing_authorization_token_account: state
|
||||
.printing_authorization_token_account,
|
||||
});
|
||||
}
|
||||
if let Some(accounts) = legacy_accounts {
|
||||
let mint_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
&auction_manager.auction.as_ref(),
|
||||
&[bump_seed],
|
||||
];
|
||||
|
||||
legacy_validation(token_program_info, &auction_manager, &accounts)?;
|
||||
spl_token_transfer(
|
||||
bidder_token_account_info.clone(),
|
||||
accept_payment_info.clone(),
|
||||
price,
|
||||
transfer_authority_info.clone(),
|
||||
&[],
|
||||
accounts.participation_printing_holding_account_info.clone(),
|
||||
destination_info.clone(),
|
||||
1,
|
||||
auction_manager_info.clone(),
|
||||
mint_seeds,
|
||||
token_program_info.clone(),
|
||||
)?;
|
||||
} else if let Some(accounts) = v2_accounts {
|
||||
let me_supply = get_supply_off_master_edition(accounts.master_edition_account_info)?;
|
||||
v2_validation(
|
||||
program_id,
|
||||
auction_manager_info,
|
||||
store_info,
|
||||
vault_info,
|
||||
payer_info,
|
||||
token_program_info,
|
||||
system_info,
|
||||
rent_info,
|
||||
bidder_info,
|
||||
accounts.master_edition_account_info,
|
||||
destination_info,
|
||||
auction_info,
|
||||
&config,
|
||||
&accounts,
|
||||
)?;
|
||||
|
||||
v2_transfer(
|
||||
auction_manager_info,
|
||||
auction_info,
|
||||
vault_info,
|
||||
bidder_info,
|
||||
token_vault_program_info,
|
||||
token_metadata_program_info,
|
||||
token_program_info,
|
||||
payer_info,
|
||||
safety_deposit_info,
|
||||
safety_deposit_token_store_info,
|
||||
system_info,
|
||||
rent_info,
|
||||
bump_seed,
|
||||
me_supply,
|
||||
&accounts,
|
||||
)?;
|
||||
}
|
||||
|
||||
charge_for_participation(
|
||||
bidder_token_account_info,
|
||||
accept_payment_info,
|
||||
transfer_authority_info,
|
||||
token_program_info,
|
||||
win_index,
|
||||
&config,
|
||||
bump_seed,
|
||||
&mut auction_manager,
|
||||
&bidder_token,
|
||||
&bidder_metadata,
|
||||
)?;
|
||||
} else {
|
||||
return Err(MetaplexError::NotEligibleForParticipation.into());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,393 @@
|
|||
use {
|
||||
crate::{
|
||||
error::MetaplexError,
|
||||
state::{
|
||||
Key, WinningConfigItem, WinningConfigType, MAX_PRIZE_TRACKING_TICKET_SIZE, PREFIX,
|
||||
},
|
||||
utils::{
|
||||
assert_derivation, assert_is_ata, assert_owned_by, common_redeem_checks,
|
||||
common_redeem_finish, common_winning_config_checks, create_or_allocate_account_raw,
|
||||
get_amount_from_token_account, CommonRedeemCheckArgs, CommonRedeemFinishArgs,
|
||||
CommonRedeemReturn, CommonWinningConfigCheckReturn,
|
||||
},
|
||||
},
|
||||
arrayref::{array_mut_ref, array_ref, mut_array_refs},
|
||||
solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint::ProgramResult,
|
||||
program::invoke_signed,
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
spl_token_metadata::{
|
||||
instruction::mint_edition_from_master_edition_via_vault_proxy,
|
||||
utils::get_supply_off_master_edition,
|
||||
},
|
||||
spl_token_vault::state::SafetyDepositBox,
|
||||
};
|
||||
|
||||
fn count_item_amount_by_safety_deposit_order(
|
||||
items: &Vec<WinningConfigItem>,
|
||||
safety_deposit_index: u8,
|
||||
) -> u64 {
|
||||
let item = items.iter().find_map(|i| {
|
||||
if i.safety_deposit_box_index == safety_deposit_index {
|
||||
Some(i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
match item {
|
||||
Some(item) => item.amount as u64,
|
||||
None => 0u64,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn mint_edition<'a>(
|
||||
token_metadata_program_info: &AccountInfo<'a>,
|
||||
token_vault_program_info: &AccountInfo<'a>,
|
||||
new_metadata_account_info: &AccountInfo<'a>,
|
||||
new_edition_account_info: &AccountInfo<'a>,
|
||||
master_edition_account_info: &AccountInfo<'a>,
|
||||
edition_marker_info: &AccountInfo<'a>,
|
||||
mint_info: &AccountInfo<'a>,
|
||||
mint_authority_info: &AccountInfo<'a>,
|
||||
payer_info: &AccountInfo<'a>,
|
||||
auction_manager_info: &AccountInfo<'a>,
|
||||
safety_deposit_token_store_info: &AccountInfo<'a>,
|
||||
safety_deposit_box_info: &AccountInfo<'a>,
|
||||
vault_info: &AccountInfo<'a>,
|
||||
bidder_info: &AccountInfo<'a>,
|
||||
metadata_account_info: &AccountInfo<'a>,
|
||||
token_program_info: &AccountInfo<'a>,
|
||||
system_program_info: &AccountInfo<'a>,
|
||||
rent_info: &AccountInfo<'a>,
|
||||
actual_edition: u64,
|
||||
signer_seeds: &[&[u8]],
|
||||
) -> ProgramResult {
|
||||
invoke_signed(
|
||||
&mint_edition_from_master_edition_via_vault_proxy(
|
||||
*token_metadata_program_info.key,
|
||||
*new_metadata_account_info.key,
|
||||
*new_edition_account_info.key,
|
||||
*master_edition_account_info.key,
|
||||
*mint_info.key,
|
||||
*edition_marker_info.key,
|
||||
*mint_authority_info.key,
|
||||
*payer_info.key,
|
||||
*auction_manager_info.key,
|
||||
*safety_deposit_token_store_info.key,
|
||||
*safety_deposit_box_info.key,
|
||||
*vault_info.key,
|
||||
*bidder_info.key,
|
||||
*metadata_account_info.key,
|
||||
*token_program_info.key,
|
||||
*token_vault_program_info.key,
|
||||
actual_edition,
|
||||
),
|
||||
&[
|
||||
token_metadata_program_info.clone(),
|
||||
token_vault_program_info.clone(),
|
||||
new_metadata_account_info.clone(),
|
||||
new_edition_account_info.clone(),
|
||||
master_edition_account_info.clone(),
|
||||
edition_marker_info.clone(),
|
||||
mint_info.clone(),
|
||||
mint_authority_info.clone(),
|
||||
payer_info.clone(),
|
||||
auction_manager_info.clone(),
|
||||
safety_deposit_token_store_info.clone(),
|
||||
safety_deposit_box_info.clone(),
|
||||
vault_info.clone(),
|
||||
bidder_info.clone(),
|
||||
metadata_account_info.clone(),
|
||||
token_program_info.clone(),
|
||||
system_program_info.clone(),
|
||||
rent_info.clone(),
|
||||
],
|
||||
&[&signer_seeds],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_or_update_prize_tracking<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
auction_manager_info: &AccountInfo<'a>,
|
||||
prize_tracking_ticket_info: &AccountInfo<'a>,
|
||||
metadata_account_info: &AccountInfo<'a>,
|
||||
payer_info: &AccountInfo<'a>,
|
||||
rent_info: &AccountInfo<'a>,
|
||||
system_info: &AccountInfo<'a>,
|
||||
master_edition_account_info: &AccountInfo<'a>,
|
||||
expected_redemptions: u64,
|
||||
) -> Result<u64, ProgramError> {
|
||||
let metadata_data = metadata_account_info.data.borrow();
|
||||
let metadata_mint = Pubkey::new_from_array(*array_ref![metadata_data, 33, 32]);
|
||||
|
||||
let bump = assert_derivation(
|
||||
program_id,
|
||||
prize_tracking_ticket_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
auction_manager_info.key.as_ref(),
|
||||
metadata_mint.as_ref(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let supply_snapshot: u64;
|
||||
if prize_tracking_ticket_info.data_is_empty() {
|
||||
create_or_allocate_account_raw(
|
||||
*program_id,
|
||||
prize_tracking_ticket_info,
|
||||
rent_info,
|
||||
system_info,
|
||||
payer_info,
|
||||
MAX_PRIZE_TRACKING_TICKET_SIZE,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
auction_manager_info.key.as_ref(),
|
||||
metadata_mint.as_ref(),
|
||||
&[bump],
|
||||
],
|
||||
)?;
|
||||
let data = &mut prize_tracking_ticket_info.data.borrow_mut();
|
||||
let output = array_mut_ref![data, 0, MAX_PRIZE_TRACKING_TICKET_SIZE];
|
||||
|
||||
let (key, metadata, supply_snapshot_ptr, expected_redemptions_ptr, redemptions, _padding) =
|
||||
mut_array_refs![output, 1, 32, 8, 8, 8, 50];
|
||||
|
||||
*key = [Key::PrizeTrackingTicketV1 as u8];
|
||||
metadata.copy_from_slice(metadata_account_info.key.as_ref());
|
||||
supply_snapshot = get_supply_off_master_edition(master_edition_account_info)?;
|
||||
*supply_snapshot_ptr = supply_snapshot.to_le_bytes();
|
||||
*redemptions = 1u64.to_le_bytes();
|
||||
*expected_redemptions_ptr = expected_redemptions.to_le_bytes();
|
||||
} else {
|
||||
// CPU is very precious in this large action, so we skip borsh's angry CPU usage.
|
||||
let data = &mut prize_tracking_ticket_info.data.borrow_mut();
|
||||
let output = array_mut_ref![data, 0, MAX_PRIZE_TRACKING_TICKET_SIZE];
|
||||
|
||||
let (_key, _metadata, supply_snapshot_ptr, _expected_redemptions, redemptions, _padding) =
|
||||
mut_array_refs![output, 1, 32, 8, 8, 8, 50];
|
||||
supply_snapshot = u64::from_le_bytes(*supply_snapshot_ptr);
|
||||
let next_redemptions = u64::from_le_bytes(*redemptions)
|
||||
.checked_add(1)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
*redemptions = next_redemptions.to_le_bytes();
|
||||
}
|
||||
|
||||
Ok(supply_snapshot)
|
||||
}
|
||||
|
||||
pub fn process_redeem_printing_v2_bid<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
edition_offset: u64,
|
||||
user_provided_win_index: u64,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let auction_manager_info = next_account_info(account_info_iter)?;
|
||||
let safety_deposit_token_store_info = next_account_info(account_info_iter)?;
|
||||
let new_edition_token_account_info = next_account_info(account_info_iter)?;
|
||||
let bid_redemption_info = next_account_info(account_info_iter)?;
|
||||
let safety_deposit_info = next_account_info(account_info_iter)?;
|
||||
let vault_info = next_account_info(account_info_iter)?;
|
||||
let _fraction_mint_info = next_account_info(account_info_iter)?;
|
||||
let auction_info = next_account_info(account_info_iter)?;
|
||||
let bidder_metadata_info = next_account_info(account_info_iter)?;
|
||||
let bidder_info = next_account_info(account_info_iter)?;
|
||||
let payer_info = next_account_info(account_info_iter)?;
|
||||
let token_program_info = next_account_info(account_info_iter)?;
|
||||
let token_vault_program_info = next_account_info(account_info_iter)?;
|
||||
let token_metadata_program_info = next_account_info(account_info_iter)?;
|
||||
let store_info = next_account_info(account_info_iter)?;
|
||||
let system_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let prize_tracking_ticket_info = next_account_info(account_info_iter)?;
|
||||
let new_metadata_account_info = next_account_info(account_info_iter)?;
|
||||
let new_edition_account_info = next_account_info(account_info_iter)?;
|
||||
let master_edition_account_info = next_account_info(account_info_iter)?;
|
||||
let mint_info = next_account_info(account_info_iter)?;
|
||||
let edition_marker_info = next_account_info(account_info_iter)?;
|
||||
let mint_authority_info = next_account_info(account_info_iter)?;
|
||||
let metadata_account_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let new_edition_account_amount = get_amount_from_token_account(new_edition_token_account_info)?;
|
||||
|
||||
assert_is_ata(
|
||||
new_edition_token_account_info,
|
||||
bidder_info.key,
|
||||
token_program_info.key,
|
||||
mint_info.key,
|
||||
)?;
|
||||
|
||||
if new_edition_account_amount != 1 {
|
||||
return Err(MetaplexError::ProvidedAccountDoesNotContainOneToken.into());
|
||||
}
|
||||
|
||||
let CommonRedeemReturn {
|
||||
auction_manager,
|
||||
redemption_bump_seed,
|
||||
cancelled,
|
||||
rent: _rent,
|
||||
win_index,
|
||||
token_metadata_program,
|
||||
} = common_redeem_checks(CommonRedeemCheckArgs {
|
||||
program_id,
|
||||
auction_manager_info,
|
||||
safety_deposit_token_store_info,
|
||||
destination_info: new_edition_token_account_info,
|
||||
bid_redemption_info,
|
||||
safety_deposit_info,
|
||||
vault_info,
|
||||
auction_info,
|
||||
bidder_metadata_info,
|
||||
bidder_info,
|
||||
token_program_info,
|
||||
token_vault_program_info,
|
||||
token_metadata_program_info,
|
||||
store_info,
|
||||
rent_info,
|
||||
is_participation: false,
|
||||
user_provided_win_index: Some(Some(user_provided_win_index as usize)),
|
||||
overwrite_win_index: None,
|
||||
assert_bidder_signer: false,
|
||||
ignore_bid_redeemed_item_check: true,
|
||||
})?;
|
||||
|
||||
assert_owned_by(metadata_account_info, &token_metadata_program)?;
|
||||
|
||||
let mut winning_item_index = None;
|
||||
if !cancelled {
|
||||
if let Some(winning_index) = win_index {
|
||||
if winning_index < auction_manager.settings.winning_configs.len() {
|
||||
let CommonWinningConfigCheckReturn {
|
||||
winning_config_item,
|
||||
winning_item_index: wii,
|
||||
} = common_winning_config_checks(
|
||||
&auction_manager,
|
||||
&safety_deposit_info,
|
||||
winning_index,
|
||||
true,
|
||||
)?;
|
||||
|
||||
winning_item_index = wii;
|
||||
|
||||
if winning_config_item.winning_config_type != WinningConfigType::PrintingV2 {
|
||||
return Err(MetaplexError::WrongBidEndpointForPrize.into());
|
||||
}
|
||||
let auction_manager_bump = assert_derivation(
|
||||
program_id,
|
||||
auction_manager_info,
|
||||
&[PREFIX.as_bytes(), auction_info.key.as_ref()],
|
||||
)?;
|
||||
|
||||
let safety_deposit_box_order = SafetyDepositBox::get_order(safety_deposit_info);
|
||||
|
||||
let mut edition_offset_min: u64 = 1;
|
||||
let mut expected_redemptions: u64 = 0;
|
||||
|
||||
// Given every single winning config item carries a u8, it is impossible to overflow
|
||||
// a u64 with the amount in it given the limited size. Avoid using checked add to save on cpu.
|
||||
for n in 0..auction_manager.settings.winning_configs.len() {
|
||||
let matching = count_item_amount_by_safety_deposit_order(
|
||||
&auction_manager.settings.winning_configs[n].items,
|
||||
safety_deposit_box_order,
|
||||
);
|
||||
|
||||
if n < winning_index {
|
||||
edition_offset_min += matching
|
||||
}
|
||||
if prize_tracking_ticket_info.data_is_empty() {
|
||||
expected_redemptions += matching
|
||||
} else if n >= winning_index {
|
||||
// no need to keep using this loop more than winning_index if we're not
|
||||
// tabulating expected_redemptions
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let edition_offset_max = edition_offset_min
|
||||
+ count_item_amount_by_safety_deposit_order(
|
||||
&auction_manager.settings.winning_configs[winning_index].items,
|
||||
safety_deposit_box_order,
|
||||
);
|
||||
|
||||
if edition_offset < edition_offset_min || edition_offset >= edition_offset_max {
|
||||
return Err(MetaplexError::InvalidEditionNumber.into());
|
||||
}
|
||||
|
||||
let supply_snapshot = create_or_update_prize_tracking(
|
||||
program_id,
|
||||
auction_manager_info,
|
||||
prize_tracking_ticket_info,
|
||||
metadata_account_info,
|
||||
payer_info,
|
||||
rent_info,
|
||||
system_info,
|
||||
master_edition_account_info,
|
||||
expected_redemptions,
|
||||
)?;
|
||||
|
||||
let actual_edition = edition_offset
|
||||
.checked_add(supply_snapshot)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
|
||||
let signer_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
auction_info.key.as_ref(),
|
||||
&[auction_manager_bump],
|
||||
];
|
||||
|
||||
mint_edition(
|
||||
token_metadata_program_info,
|
||||
token_vault_program_info,
|
||||
new_metadata_account_info,
|
||||
new_edition_account_info,
|
||||
master_edition_account_info,
|
||||
edition_marker_info,
|
||||
mint_info,
|
||||
mint_authority_info,
|
||||
payer_info,
|
||||
auction_manager_info,
|
||||
safety_deposit_token_store_info,
|
||||
safety_deposit_info,
|
||||
vault_info,
|
||||
bidder_info,
|
||||
metadata_account_info,
|
||||
token_program_info,
|
||||
system_info,
|
||||
rent_info,
|
||||
actual_edition,
|
||||
signer_seeds,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
common_redeem_finish(CommonRedeemFinishArgs {
|
||||
program_id,
|
||||
auction_manager,
|
||||
auction_manager_info,
|
||||
bidder_metadata_info,
|
||||
rent_info,
|
||||
system_info,
|
||||
payer_info,
|
||||
bid_redemption_info,
|
||||
redemption_bump_seed,
|
||||
winning_index: win_index,
|
||||
bid_redeemed: true,
|
||||
participation_redeemed: false,
|
||||
winning_item_index,
|
||||
overwrite_win_index: None,
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
instruction::RedeemUnusedWinningConfigItemsAsAuctioneerArgs,
|
||||
instruction::{ProxyCallAddress, RedeemUnusedWinningConfigItemsAsAuctioneerArgs},
|
||||
processor::redeem_bid::process_redeem_bid,
|
||||
processor::redeem_full_rights_transfer_bid::process_full_rights_transfer_bid,
|
||||
},
|
||||
|
@ -18,17 +18,15 @@ pub fn process_redeem_unused_winning_config_items_as_auctioneer<'a>(
|
|||
// check that you ARE the auction authority, because nobody else should be claiming this unused prize.
|
||||
// We also still make sure this prize hasnt been claimed more than once.
|
||||
match args.proxy_call {
|
||||
crate::instruction::ProxyCallAddress::RedeemBid => process_redeem_bid(
|
||||
ProxyCallAddress::RedeemBid => process_redeem_bid(
|
||||
program_id,
|
||||
accounts,
|
||||
Some(args.winning_config_item_index as usize),
|
||||
),
|
||||
ProxyCallAddress::RedeemFullRightsTransferBid => process_full_rights_transfer_bid(
|
||||
program_id,
|
||||
accounts,
|
||||
Some(args.winning_config_item_index as usize),
|
||||
),
|
||||
crate::instruction::ProxyCallAddress::RedeemFullRightsTransferBid => {
|
||||
process_full_rights_transfer_bid(
|
||||
program_id,
|
||||
accounts,
|
||||
Some(args.winning_config_item_index as usize),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
error::MetaplexError,
|
||||
state::{
|
||||
AuctionManager, AuctionManagerStatus, Key, OriginalAuthorityLookup,
|
||||
AuctionManager, AuctionManagerStatus, Key, OriginalAuthorityLookup, ParticipationState,
|
||||
SafetyDepositValidationTicket, Store, WinningConfigType, MAX_AUTHORITY_LOOKUP_SIZE,
|
||||
MAX_VALIDATION_TICKET_SIZE, PREFIX,
|
||||
},
|
||||
|
@ -21,7 +21,7 @@ use {
|
|||
},
|
||||
spl_token::state::{Account, Mint},
|
||||
spl_token_metadata::{
|
||||
state::{MasterEdition, Metadata},
|
||||
state::{MasterEditionV1, MasterEditionV2, Metadata},
|
||||
utils::assert_update_authority_is_correct,
|
||||
},
|
||||
spl_token_vault::state::{SafetyDepositBox, Vault},
|
||||
|
@ -195,11 +195,9 @@ pub fn process_validate_safety_deposit_box(
|
|||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
|
||||
// Build array to sum total amount
|
||||
total_amount_requested =
|
||||
match total_amount_requested.checked_add(possible_item.amount.into()) {
|
||||
Some(val) => val,
|
||||
None => return Err(MetaplexError::NumericalOverflowError.into()),
|
||||
};
|
||||
total_amount_requested = total_amount_requested
|
||||
.checked_add(possible_item.amount.into())
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
// Record that primary sale happened at time of validation for later royalties reconcilation
|
||||
auction_manager.state.winning_config_states[i].items[j].primary_sale_happened =
|
||||
metadata.primary_sale_happened;
|
||||
|
@ -207,6 +205,28 @@ pub fn process_validate_safety_deposit_box(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(participation_config) = &auction_manager.settings.participation_config {
|
||||
if participation_config.safety_deposit_box_index == safety_deposit.order {
|
||||
// Really it's unknown how many prints will be made
|
||||
// but we set it to 1 since that's how many master edition tokens are in there.
|
||||
total_amount_requested = total_amount_requested
|
||||
.checked_add(1)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
|
||||
// now that participation configs can be validated through normal safety deposit endpoints, need to flip this boolean
|
||||
// here too, until we can deprecate it later.
|
||||
if let Some(state) = &auction_manager.state.participation_state {
|
||||
auction_manager.state.participation_state = Some(ParticipationState {
|
||||
collected_to_accept_payment: state.collected_to_accept_payment,
|
||||
primary_sale_happened: state.primary_sale_happened,
|
||||
validated: true,
|
||||
printing_authorization_token_account: state
|
||||
.printing_authorization_token_account,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if total_amount_requested == 0 {
|
||||
return Err(MetaplexError::SafetyDepositBoxNotUsedInAuction.into());
|
||||
}
|
||||
|
@ -301,11 +321,11 @@ pub fn process_validate_safety_deposit_box(
|
|||
return Err(MetaplexError::NotEnoughTokensToSupplyWinners.into());
|
||||
}
|
||||
}
|
||||
WinningConfigType::Printing => {
|
||||
WinningConfigType::PrintingV1 => {
|
||||
if edition_key != *edition_info.key {
|
||||
return Err(MetaplexError::InvalidEditionAddress.into());
|
||||
}
|
||||
let master_edition = MasterEdition::from_account_info(edition_info)?;
|
||||
let master_edition = MasterEditionV1::from_account_info(edition_info)?;
|
||||
if safety_deposit.token_mint != master_edition.printing_mint {
|
||||
return Err(MetaplexError::SafetyDepositBoxMasterMintMismatch.into());
|
||||
}
|
||||
|
@ -314,6 +334,28 @@ pub fn process_validate_safety_deposit_box(
|
|||
return Err(MetaplexError::NotEnoughTokensToSupplyWinners.into());
|
||||
}
|
||||
}
|
||||
WinningConfigType::PrintingV2 => {
|
||||
if edition_key != *edition_info.key {
|
||||
return Err(MetaplexError::InvalidEditionAddress.into());
|
||||
}
|
||||
let master_edition = MasterEditionV2::from_account_info(edition_info)?;
|
||||
if safety_deposit.token_mint != metadata.mint {
|
||||
return Err(MetaplexError::SafetyDepositBoxMetadataMismatch.into());
|
||||
}
|
||||
|
||||
if safety_deposit_token_store.amount != 1 {
|
||||
return Err(MetaplexError::NotEnoughTokensToSupplyWinners.into());
|
||||
}
|
||||
|
||||
if let Some(max) = master_edition.max_supply {
|
||||
let amount_available = max
|
||||
.checked_sub(master_edition.supply)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?;
|
||||
if amount_available < total_amount_requested {
|
||||
return Err(MetaplexError::NotEnoughTokensToSupplyWinners.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auction_manager.state.winning_config_items_validated = match auction_manager
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
use {
|
||||
crate::{
|
||||
error::MetaplexError,
|
||||
state::{AuctionManager, PrizeTrackingTicket, Store, WinningConfigType, PREFIX},
|
||||
utils::{
|
||||
assert_derivation, assert_is_ata, assert_owned_by, assert_rent_exempt,
|
||||
assert_store_safety_vault_manager_match, transfer_safety_deposit_box_items,
|
||||
},
|
||||
},
|
||||
solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
sysvar::Sysvar,
|
||||
},
|
||||
spl_auction::processor::{AuctionData, AuctionDataExtended, AuctionState},
|
||||
spl_token_vault::state::SafetyDepositBox,
|
||||
};
|
||||
|
||||
pub fn process_withdraw_master_edition<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let auction_manager_info = next_account_info(account_info_iter)?;
|
||||
let safety_deposit_token_store_info = next_account_info(account_info_iter)?;
|
||||
let destination_info = next_account_info(account_info_iter)?;
|
||||
let safety_deposit_info = next_account_info(account_info_iter)?;
|
||||
let vault_info = next_account_info(account_info_iter)?;
|
||||
let fraction_mint_info = next_account_info(account_info_iter)?;
|
||||
let prize_tracking_ticket_info = next_account_info(account_info_iter)?;
|
||||
let transfer_authority_info = next_account_info(account_info_iter)?;
|
||||
let auction_info = next_account_info(account_info_iter)?;
|
||||
let auction_extended_info = next_account_info(account_info_iter)?;
|
||||
let token_program_info = next_account_info(account_info_iter)?;
|
||||
let token_vault_program_info = next_account_info(account_info_iter)?;
|
||||
let store_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let rent = &Rent::from_account_info(&rent_info)?;
|
||||
|
||||
let auction_manager: AuctionManager = AuctionManager::from_account_info(auction_manager_info)?;
|
||||
let auction = AuctionData::from_account_info(auction_info)?;
|
||||
let auction_data_extended = AuctionDataExtended::from_account_info(auction_extended_info)?;
|
||||
|
||||
let store = Store::from_account_info(store_info)?;
|
||||
let safety_deposit_box = SafetyDepositBox::from_account_info(safety_deposit_info)?;
|
||||
|
||||
assert_owned_by(&destination_info, token_program_info.key)?;
|
||||
assert_owned_by(&auction_manager_info, &program_id)?;
|
||||
assert_owned_by(safety_deposit_token_store_info, token_program_info.key)?;
|
||||
assert_owned_by(safety_deposit_info, token_vault_program_info.key)?;
|
||||
assert_owned_by(vault_info, token_vault_program_info.key)?;
|
||||
assert_owned_by(fraction_mint_info, token_program_info.key)?;
|
||||
assert_owned_by(auction_info, &store.auction_program)?;
|
||||
assert_owned_by(store_info, &program_id)?;
|
||||
|
||||
assert_store_safety_vault_manager_match(
|
||||
&auction_manager,
|
||||
&safety_deposit_info,
|
||||
&vault_info,
|
||||
token_vault_program_info.key,
|
||||
)?;
|
||||
// looking out for you!
|
||||
assert_rent_exempt(rent, &destination_info)?;
|
||||
|
||||
if auction_manager.auction != *auction_info.key {
|
||||
return Err(MetaplexError::AuctionManagerAuctionMismatch.into());
|
||||
}
|
||||
|
||||
assert_derivation(
|
||||
&store.auction_program,
|
||||
auction_extended_info,
|
||||
&[
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
store.auction_program.as_ref(),
|
||||
vault_info.key.as_ref(),
|
||||
spl_auction::EXTENDED.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
if *store_info.key != auction_manager.store {
|
||||
return Err(MetaplexError::AuctionManagerStoreMismatch.into());
|
||||
}
|
||||
|
||||
if auction.state != AuctionState::Ended {
|
||||
return Err(MetaplexError::AuctionHasNotEnded.into());
|
||||
}
|
||||
|
||||
if store.token_vault_program != *token_vault_program_info.key {
|
||||
return Err(MetaplexError::AuctionManagerTokenVaultProgramMismatch.into());
|
||||
}
|
||||
|
||||
if store.token_program != *token_program_info.key {
|
||||
return Err(MetaplexError::AuctionManagerTokenProgramMismatch.into());
|
||||
}
|
||||
|
||||
assert_rent_exempt(rent, destination_info)?;
|
||||
assert_is_ata(
|
||||
destination_info,
|
||||
&auction_manager.authority,
|
||||
token_program_info.key,
|
||||
&safety_deposit_box.token_mint,
|
||||
)?;
|
||||
|
||||
if prize_tracking_ticket_info.data_is_empty() {
|
||||
// Nobody has redeemed yet, we need to figure out if SOMEONE could and if we should
|
||||
// stop a withdrawal.
|
||||
|
||||
let mut minimum_required_bids_to_stop_removal = 0;
|
||||
for n in 0..auction_manager.settings.winning_configs.len() {
|
||||
if auction_manager.settings.winning_configs[n]
|
||||
.items
|
||||
.iter()
|
||||
.find(|i| i.safety_deposit_box_index == safety_deposit_box.order)
|
||||
.is_some()
|
||||
{
|
||||
// This means at least n bids must exist for there to be at least one bidder that will be eligible for this prize.
|
||||
minimum_required_bids_to_stop_removal = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if auction_data_extended.total_uncancelled_bids
|
||||
> minimum_required_bids_to_stop_removal as u64
|
||||
{
|
||||
return Err(MetaplexError::NotAllBidsClaimed.into());
|
||||
}
|
||||
} else {
|
||||
assert_derivation(
|
||||
program_id,
|
||||
prize_tracking_ticket_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
auction_manager_info.key.as_ref(),
|
||||
safety_deposit_box.token_mint.as_ref(),
|
||||
],
|
||||
)?;
|
||||
let prize_tracking_ticket =
|
||||
PrizeTrackingTicket::from_account_info(prize_tracking_ticket_info)?;
|
||||
if prize_tracking_ticket.redemptions < prize_tracking_ticket.expected_redemptions {
|
||||
return Err(MetaplexError::NotAllBidsClaimed.into());
|
||||
}
|
||||
}
|
||||
|
||||
let atleast_one_matching = auction_manager
|
||||
.settings
|
||||
.winning_configs
|
||||
.iter()
|
||||
.find(|c| {
|
||||
c.items
|
||||
.iter()
|
||||
.find(|i| {
|
||||
i.safety_deposit_box_index == safety_deposit_box.order
|
||||
&& i.winning_config_type == WinningConfigType::PrintingV2
|
||||
})
|
||||
.is_some()
|
||||
})
|
||||
.is_some();
|
||||
|
||||
if !atleast_one_matching {
|
||||
if let Some(config) = auction_manager.settings.participation_config {
|
||||
if config.safety_deposit_box_index != safety_deposit_box.order {
|
||||
return Err(MetaplexError::InvalidOperation.into());
|
||||
}
|
||||
} else {
|
||||
// This means there arent any winning configs listed as PrintingV2 so
|
||||
// this isnt a printing v2 type and isnt a master edition.
|
||||
return Err(MetaplexError::InvalidOperation.into());
|
||||
}
|
||||
}
|
||||
|
||||
let auction_bump_seed = assert_derivation(
|
||||
program_id,
|
||||
auction_manager_info,
|
||||
&[PREFIX.as_bytes(), &auction_manager.auction.as_ref()],
|
||||
)?;
|
||||
|
||||
let auction_auth_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
&auction_manager.auction.as_ref(),
|
||||
&[auction_bump_seed],
|
||||
];
|
||||
|
||||
transfer_safety_deposit_box_items(
|
||||
token_vault_program_info.clone(),
|
||||
destination_info.clone(),
|
||||
safety_deposit_info.clone(),
|
||||
safety_deposit_token_store_info.clone(),
|
||||
vault_info.clone(),
|
||||
fraction_mint_info.clone(),
|
||||
auction_manager_info.clone(),
|
||||
transfer_authority_info.clone(),
|
||||
rent_info.clone(),
|
||||
1,
|
||||
auction_auth_seeds,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
use solana_program::{msg};
|
||||
|
||||
use {
|
||||
crate::utils::try_from_slice_checked,
|
||||
arrayref::array_ref,
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey},
|
||||
};
|
||||
|
@ -34,14 +37,18 @@ pub const MAX_AUCTION_MANAGER_SIZE: usize = 1 + // key
|
|||
1 + // participation non winner constraint
|
||||
1 + // u8 participation_config's safety deposit box index
|
||||
9 + // option<u64> participation fixed price in borsh is a u8 for option and actual u64
|
||||
150; // padding;
|
||||
1 +
|
||||
AUCTION_MANAGER_PADDING; // padding;
|
||||
// Add padding for future booleans/enums
|
||||
pub const AUCTION_MANAGER_PADDING: usize = 149;
|
||||
pub const MAX_STORE_SIZE: usize = 2 + 32 + 32 + 32 + 32 + 100;
|
||||
pub const MAX_WHITELISTED_CREATOR_SIZE: usize = 2 + 32 + 10;
|
||||
pub const MAX_PAYOUT_TICKET_SIZE: usize = 1 + 32 + 8;
|
||||
pub const MAX_VALIDATION_TICKET_SIZE: usize = 1 + 32 + 10;
|
||||
pub const MAX_BID_REDEMPTION_TICKET_SIZE: usize = 3;
|
||||
pub const MAX_AUTHORITY_LOOKUP_SIZE: usize = 33;
|
||||
pub const MAX_PRIZE_TRACKING_TICKET_SIZE: usize = 1 + 32 + 8 + 8 + 8 + 50;
|
||||
pub const MAX_WINNING_CONFIG_STATE_ITEM_SIZE: usize = 2;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, BorshSerialize, BorshDeserialize, PartialEq, Debug, Copy)]
|
||||
|
@ -54,6 +61,7 @@ pub enum Key {
|
|||
PayoutTicketV1,
|
||||
SafetyDepositValidationTicketV1,
|
||||
AuctionManagerV1,
|
||||
PrizeTrackingTicketV1,
|
||||
}
|
||||
|
||||
/// An Auction Manager can support an auction that is an English auction and limited edition and open edition
|
||||
|
@ -78,6 +86,9 @@ pub struct AuctionManager {
|
|||
pub state: AuctionManagerState,
|
||||
|
||||
pub settings: AuctionManagerSettings,
|
||||
|
||||
/// True if this is only winning configs of one item each, used for optimization in saving.
|
||||
pub straight_shot_optimization: bool,
|
||||
}
|
||||
|
||||
impl AuctionManager {
|
||||
|
@ -90,6 +101,59 @@ impl AuctionManager {
|
|||
|
||||
Ok(am)
|
||||
}
|
||||
|
||||
// cheap setter to set status and claimed in one go without using expensive borsh save.
|
||||
pub fn set_claimed_and_status(
|
||||
a: &AccountInfo,
|
||||
status: AuctionManagerStatus,
|
||||
winning_config_index: usize,
|
||||
winning_config_item_index: usize,
|
||||
use_straight_shot: bool
|
||||
) {
|
||||
let num_configs = AuctionManager::get_num_configs(a);
|
||||
let mut data = a.data.borrow_mut();
|
||||
data[161] = status as u8; // set status
|
||||
let mut current_config_offset = 167;
|
||||
if use_straight_shot {
|
||||
msg!("Using optimization path");
|
||||
// in this optimization framework we know it's one item per config and we can know exact location.
|
||||
let skip = (4 + MAX_WINNING_CONFIG_STATE_ITEM_SIZE + 1) * winning_config_index;
|
||||
// need to skip ahead by the number of items to the next offset.
|
||||
// Add one byte to cover the boolean at the end of the winning config state.
|
||||
let idx = current_config_offset + skip + 4 + 1;
|
||||
data[idx] = 1;
|
||||
} else {
|
||||
msg!("Using tiered auction save");
|
||||
for i in 0..num_configs {
|
||||
// need to hop along and check each u32 of the items sub array to know how much to hop next.
|
||||
let num_items_data = array_ref![data, current_config_offset, 4];
|
||||
|
||||
let num_items = u32::from_le_bytes(*num_items_data) as usize;
|
||||
|
||||
if winning_config_index == i {
|
||||
// ok we need to target the claimed u8 inside the correct item now.
|
||||
let idx = current_config_offset
|
||||
+ 4
|
||||
+ winning_config_item_index * MAX_WINNING_CONFIG_STATE_ITEM_SIZE
|
||||
+ 1;
|
||||
|
||||
data[idx] = 1;
|
||||
break;
|
||||
} else {
|
||||
let skip = MAX_WINNING_CONFIG_STATE_ITEM_SIZE * num_items;
|
||||
// need to skip ahead by the number of items to the next offset.
|
||||
// Add one byte to cover the boolean at the end of the winning config state.
|
||||
current_config_offset = current_config_offset + 4 + skip + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_num_configs(a: &AccountInfo) -> usize {
|
||||
let data = a.data.borrow();
|
||||
let num_elements_data = array_ref![data, 163, 4];
|
||||
u32::from_le_bytes(*num_elements_data) as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -193,8 +257,11 @@ pub enum WinningConfigType {
|
|||
/// token itself. The other person will be able to mint authorization tokens and make changes to the
|
||||
/// artwork.
|
||||
FullRightsTransfer,
|
||||
/// Means you are using authorization tokens to print off editions during the auction
|
||||
Printing,
|
||||
/// Means you are using authorization tokens to print off editions during the auction using
|
||||
/// from a MasterEditionV1
|
||||
PrintingV1,
|
||||
/// Means you are using the MasterEditionV2 to print off editions
|
||||
PrintingV2,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -359,3 +426,25 @@ impl SafetyDepositValidationTicket {
|
|||
Ok(store)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, BorshSerialize, BorshDeserialize, Copy, Debug)]
|
||||
pub struct PrizeTrackingTicket {
|
||||
pub key: Key,
|
||||
pub metadata: Pubkey,
|
||||
pub supply_snapshot: u64,
|
||||
pub expected_redemptions: u64,
|
||||
pub redemptions: u64,
|
||||
}
|
||||
|
||||
impl PrizeTrackingTicket {
|
||||
pub fn from_account_info(a: &AccountInfo) -> Result<PrizeTrackingTicket, ProgramError> {
|
||||
let store: PrizeTrackingTicket = try_from_slice_checked(
|
||||
&a.data.borrow_mut(),
|
||||
Key::PrizeTrackingTicketV1,
|
||||
MAX_PRIZE_TRACKING_TICKET_SIZE,
|
||||
)?;
|
||||
|
||||
Ok(store)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use solana_program::log::sol_log_compute_units;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
error::MetaplexError,
|
||||
state::{
|
||||
AuctionManager, AuctionManagerStatus, BidRedemptionTicket, Key,
|
||||
OriginalAuthorityLookup, Store, WhitelistedCreator, WinningConfigItem,
|
||||
MAX_BID_REDEMPTION_TICKET_SIZE, PREFIX,
|
||||
AuctionManager, AuctionManagerStatus, Key, OriginalAuthorityLookup, Store,
|
||||
WhitelistedCreator, WinningConfigItem, MAX_BID_REDEMPTION_TICKET_SIZE, PREFIX,
|
||||
},
|
||||
},
|
||||
arrayref::array_ref,
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
arrayref::{array_mut_ref, array_ref, mut_array_refs},
|
||||
borsh::BorshDeserialize,
|
||||
solana_program::{
|
||||
account_info::AccountInfo,
|
||||
borsh::try_from_slice_unchecked,
|
||||
|
@ -23,17 +24,27 @@ use {
|
|||
},
|
||||
spl_auction::{
|
||||
instruction::end_auction_instruction,
|
||||
processor::{end_auction::EndAuctionArgs, AuctionData, AuctionState, BidderMetadata},
|
||||
processor::{end_auction::EndAuctionArgs, AuctionData, AuctionState},
|
||||
},
|
||||
spl_token::instruction::{set_authority, AuthorityType},
|
||||
spl_token_metadata::{
|
||||
instruction::update_metadata_accounts,
|
||||
state::{Metadata, EDITION},
|
||||
},
|
||||
spl_token_vault::instruction::create_withdraw_tokens_instruction,
|
||||
std::convert::TryInto,
|
||||
spl_token_vault::{instruction::create_withdraw_tokens_instruction, state::SafetyDepositBox},
|
||||
std::{convert::TryInto, str::FromStr},
|
||||
};
|
||||
|
||||
/// Cheap method to just grab amount from token account, instead of deserializing entire thing
|
||||
pub fn get_amount_from_token_account(
|
||||
token_account_info: &AccountInfo,
|
||||
) -> Result<u64, ProgramError> {
|
||||
// TokeAccount layout: mint(32), owner(32), ...
|
||||
let data = token_account_info.try_borrow_data()?;
|
||||
let amount_data = array_ref![data, 64, 8];
|
||||
Ok(u64::from_le_bytes(*amount_data))
|
||||
}
|
||||
|
||||
/// assert initialized account
|
||||
pub fn assert_initialized<T: Pack + IsInitialized>(
|
||||
account_info: &AccountInfo,
|
||||
|
@ -195,17 +206,19 @@ pub fn create_or_allocate_account_raw<'a>(
|
|||
)?;
|
||||
}
|
||||
|
||||
let accounts = &[new_account_info.clone(), system_program_info.clone()];
|
||||
|
||||
msg!("Allocate space for the account");
|
||||
invoke_signed(
|
||||
&system_instruction::allocate(new_account_info.key, size.try_into().unwrap()),
|
||||
&[new_account_info.clone(), system_program_info.clone()],
|
||||
accounts,
|
||||
&[&signer_seeds],
|
||||
)?;
|
||||
|
||||
msg!("Assign the account to the owning program");
|
||||
invoke_signed(
|
||||
&system_instruction::assign(new_account_info.key, &program_id),
|
||||
&[new_account_info.clone(), system_program_info.clone()],
|
||||
accounts,
|
||||
&[&signer_seeds],
|
||||
)?;
|
||||
msg!("Completed assignation!");
|
||||
|
@ -337,8 +350,7 @@ pub fn transfer_mint_authority<'a>(
|
|||
pub struct CommonRedeemReturn {
|
||||
pub redemption_bump_seed: u8,
|
||||
pub auction_manager: AuctionManager,
|
||||
pub auction: AuctionData,
|
||||
pub bidder_metadata: BidderMetadata,
|
||||
pub cancelled: bool,
|
||||
pub rent: Rent,
|
||||
pub win_index: Option<usize>,
|
||||
pub token_metadata_program: Pubkey,
|
||||
|
@ -361,7 +373,69 @@ pub struct CommonRedeemCheckArgs<'a> {
|
|||
pub store_info: &'a AccountInfo<'a>,
|
||||
pub rent_info: &'a AccountInfo<'a>,
|
||||
pub is_participation: bool,
|
||||
// If this is being called by the auctioneer to pull prizes out they overwrite the win index
|
||||
// they would normally get if they themselves bid for whatever win index they choose.
|
||||
pub overwrite_win_index: Option<usize>,
|
||||
// In newer endpoints, to conserve CPU and make way for 10,000 person auctions,
|
||||
// client must specify win index and then we simply check if the address matches for O(1) lookup vs O(n)
|
||||
// scan. This is an option so older actions which rely on the O(n) lookup because we can't change their call structure
|
||||
// can continue to work.
|
||||
pub user_provided_win_index: Option<Option<usize>>,
|
||||
pub assert_bidder_signer: bool,
|
||||
// For printing v2, the edition pda is what essentially forms a backstop for bad bidders. We do not need this additional
|
||||
// check which isn't accurate anyway when one winning config item has an amount > 1.
|
||||
pub ignore_bid_redeemed_item_check: bool,
|
||||
}
|
||||
|
||||
fn calculate_win_index(
|
||||
bidder_info: &AccountInfo,
|
||||
auction_info: &AccountInfo,
|
||||
user_provided_win_index: Option<Option<usize>>,
|
||||
overwrite_win_index: Option<usize>,
|
||||
) -> Result<Option<usize>, ProgramError> {
|
||||
let mut win_index: Option<usize>;
|
||||
// User provided us with an option of an option telling us what if anything they won. We need to validate.
|
||||
if let Some(up_win_index) = user_provided_win_index {
|
||||
// check that this person is the winner they say they are. Only if not doing an override of win index,
|
||||
// which we know likely wont match bidder info and is simply checking below that you arent stealing a prize.
|
||||
|
||||
if overwrite_win_index.is_none() {
|
||||
if let Some(up_win_index_unwrapped) = up_win_index {
|
||||
let winner = AuctionData::get_winner_at(auction_info, up_win_index_unwrapped);
|
||||
if let Some(winner_key) = winner {
|
||||
if winner_key != *bidder_info.key {
|
||||
return Err(MetaplexError::WinnerIndexMismatch.into());
|
||||
}
|
||||
} else {
|
||||
return Err(MetaplexError::WinnerIndexMismatch.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notice if overwrite win index is some, this gets wiped anyway in the if statement below.
|
||||
// If not, it becomes the win index going forward as we have validated the user is either
|
||||
// saying they won nothing (Participation redemption) or they won something
|
||||
// and they weren't lying.
|
||||
win_index = up_win_index;
|
||||
} else {
|
||||
// Legacy system where we O(n) scan the bid index to find the winner index. CPU intensive.
|
||||
win_index = AuctionData::get_is_winner(auction_info, bidder_info.key);
|
||||
}
|
||||
|
||||
// This means auctioneer is attempting to pull goods out of the system, and is attempting to set
|
||||
// the win index for themselves. Has a different field because it has different logic - mainly
|
||||
// just checking to make sure you arent claiming from someone who won. Supersedes normal user provided
|
||||
// logic.
|
||||
if let Some(index) = overwrite_win_index {
|
||||
let winner_at = AuctionData::get_winner_at(auction_info, index);
|
||||
if winner_at.is_some() {
|
||||
return Err(MetaplexError::AuctioneerCantClaimWonPrize.into());
|
||||
} else {
|
||||
win_index = overwrite_win_index
|
||||
}
|
||||
}
|
||||
|
||||
Ok(win_index)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -386,15 +460,17 @@ pub fn common_redeem_checks(
|
|||
store_info,
|
||||
is_participation,
|
||||
overwrite_win_index,
|
||||
user_provided_win_index,
|
||||
assert_bidder_signer,
|
||||
ignore_bid_redeemed_item_check,
|
||||
} = args;
|
||||
|
||||
let rent = &Rent::from_account_info(&rent_info)?;
|
||||
|
||||
let mut auction_manager: AuctionManager =
|
||||
AuctionManager::from_account_info(auction_manager_info)?;
|
||||
let auction = AuctionData::from_account_info(auction_info)?;
|
||||
let store_data = store_info.data.borrow();
|
||||
let bidder_metadata: BidderMetadata;
|
||||
let cancelled: bool;
|
||||
|
||||
let auction_program = Pubkey::new_from_array(*array_ref![store_data, 2, 32]);
|
||||
let token_vault_program = Pubkey::new_from_array(*array_ref![store_data, 34, 32]);
|
||||
|
@ -403,20 +479,18 @@ pub fn common_redeem_checks(
|
|||
|
||||
let mut redemption_bump_seed: u8 = 0;
|
||||
if overwrite_win_index.is_some() {
|
||||
// Auctioneer coming through, need to stub bidder metadata since it will not exist.
|
||||
bidder_metadata = BidderMetadata {
|
||||
bidder_pubkey: *bidder_info.key,
|
||||
auction_pubkey: *auction_info.key,
|
||||
last_bid: 0,
|
||||
last_bid_timestamp: 0,
|
||||
cancelled: false,
|
||||
};
|
||||
cancelled = false;
|
||||
|
||||
if *bidder_info.key != auction_manager.authority {
|
||||
return Err(MetaplexError::MustBeAuctioneer.into());
|
||||
}
|
||||
} else {
|
||||
bidder_metadata = BidderMetadata::from_account_info(bidder_metadata_info)?;
|
||||
let bidder_metadata_data = bidder_metadata_info.data.borrow();
|
||||
if bidder_metadata_data[80] == 0 {
|
||||
cancelled = false
|
||||
} else {
|
||||
cancelled = true;
|
||||
}
|
||||
assert_owned_by(bidder_metadata_info, &auction_program)?;
|
||||
assert_derivation(
|
||||
&auction_program,
|
||||
|
@ -430,7 +504,8 @@ pub fn common_redeem_checks(
|
|||
],
|
||||
)?;
|
||||
|
||||
if bidder_metadata.bidder_pubkey != *bidder_info.key {
|
||||
let bidder_pubkey = Pubkey::new_from_array(*array_ref![bidder_metadata_data, 0, 32]);
|
||||
if bidder_pubkey != *bidder_info.key {
|
||||
return Err(MetaplexError::BidderMetadataBidderMismatch.into());
|
||||
}
|
||||
let redemption_path = [
|
||||
|
@ -447,33 +522,47 @@ pub fn common_redeem_checks(
|
|||
}
|
||||
}
|
||||
|
||||
let mut win_index = auction.is_winner(bidder_info.key);
|
||||
|
||||
if let Some(index) = overwrite_win_index {
|
||||
let winner_at = auction.winner_at(index);
|
||||
if winner_at.is_some() {
|
||||
return Err(MetaplexError::AuctioneerCantClaimWonPrize.into());
|
||||
} else {
|
||||
win_index = overwrite_win_index
|
||||
}
|
||||
}
|
||||
let win_index = calculate_win_index(
|
||||
bidder_info,
|
||||
auction_info,
|
||||
user_provided_win_index,
|
||||
overwrite_win_index,
|
||||
)?;
|
||||
|
||||
if !bid_redemption_info.data_is_empty() && overwrite_win_index.is_none() {
|
||||
let bid_redemption: BidRedemptionTicket =
|
||||
BidRedemptionTicket::from_account_info(bid_redemption_info)?;
|
||||
let bid_redemption_data = bid_redemption_info.data.borrow();
|
||||
|
||||
if bid_redemption_data[0] != Key::BidRedemptionTicketV1 as u8 {
|
||||
return Err(MetaplexError::DataTypeMismatch.into());
|
||||
}
|
||||
|
||||
let mut participation_redeemed = false;
|
||||
if bid_redemption_data[1] == 1 {
|
||||
participation_redeemed = true;
|
||||
}
|
||||
let items_redeemed = bid_redemption_data[2];
|
||||
msg!(
|
||||
"Items redeemed is {} and participation redemption is {}",
|
||||
items_redeemed,
|
||||
participation_redeemed
|
||||
);
|
||||
let possible_items_to_redeem = match win_index {
|
||||
Some(val) => auction_manager.settings.winning_configs[val].items.len(),
|
||||
None => 0,
|
||||
};
|
||||
if (is_participation && bid_redemption.participation_redeemed)
|
||||
if (is_participation && participation_redeemed)
|
||||
|| (!is_participation
|
||||
&& bid_redemption.items_redeemed == possible_items_to_redeem as u8)
|
||||
&& !ignore_bid_redeemed_item_check
|
||||
&& items_redeemed == possible_items_to_redeem as u8)
|
||||
{
|
||||
return Err(MetaplexError::BidAlreadyRedeemed.into());
|
||||
}
|
||||
}
|
||||
|
||||
assert_signer(bidder_info)?;
|
||||
if assert_bidder_signer {
|
||||
assert_signer(bidder_info)?;
|
||||
}
|
||||
|
||||
assert_owned_by(&destination_info, token_program_info.key)?;
|
||||
assert_owned_by(&auction_manager_info, &program_id)?;
|
||||
assert_owned_by(safety_deposit_token_store_info, token_program_info.key)?;
|
||||
|
@ -514,7 +603,7 @@ pub fn common_redeem_checks(
|
|||
return Err(MetaplexError::AuctionManagerTokenMetadataProgramMismatch.into());
|
||||
}
|
||||
|
||||
if auction.state != AuctionState::Ended {
|
||||
if AuctionData::get_state(auction_info)? != AuctionState::Ended {
|
||||
return Err(MetaplexError::AuctionHasNotEnded.into());
|
||||
}
|
||||
|
||||
|
@ -524,8 +613,7 @@ pub fn common_redeem_checks(
|
|||
Ok(CommonRedeemReturn {
|
||||
redemption_bump_seed,
|
||||
auction_manager,
|
||||
auction,
|
||||
bidder_metadata,
|
||||
cancelled,
|
||||
rent: *rent,
|
||||
win_index,
|
||||
token_metadata_program,
|
||||
|
@ -552,7 +640,7 @@ pub struct CommonRedeemFinishArgs<'a> {
|
|||
pub fn common_redeem_finish(args: CommonRedeemFinishArgs) -> ProgramResult {
|
||||
let CommonRedeemFinishArgs {
|
||||
program_id,
|
||||
mut auction_manager,
|
||||
auction_manager,
|
||||
auction_manager_info,
|
||||
bidder_metadata_info,
|
||||
rent_info,
|
||||
|
@ -567,14 +655,6 @@ pub fn common_redeem_finish(args: CommonRedeemFinishArgs) -> ProgramResult {
|
|||
overwrite_win_index,
|
||||
} = args;
|
||||
|
||||
if bid_redeemed {
|
||||
if let Some(index) = winning_index {
|
||||
if let Some(item_index) = winning_item_index {
|
||||
auction_manager.state.winning_config_states[index].items[item_index].claimed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bid_redeemed || participation_redeemed) && overwrite_win_index.is_none() {
|
||||
let redemption_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
|
@ -594,34 +674,44 @@ pub fn common_redeem_finish(args: CommonRedeemFinishArgs) -> ProgramResult {
|
|||
redemption_seeds,
|
||||
)?;
|
||||
}
|
||||
let mut bid_redemption = BidRedemptionTicket::from_account_info(bid_redemption_info)?;
|
||||
// Saving on CPU in these large actions by avoiding borsh
|
||||
let data = &mut bid_redemption_info.data.borrow_mut();
|
||||
let output = array_mut_ref![data, 0, MAX_BID_REDEMPTION_TICKET_SIZE];
|
||||
|
||||
bid_redemption.key = Key::BidRedemptionTicketV1;
|
||||
let (key, participation_redeemed_ptr, items_redeemed_ptr) =
|
||||
mut_array_refs![output, 1, 1, 1];
|
||||
|
||||
*key = [Key::BidRedemptionTicketV1 as u8];
|
||||
|
||||
let curr_items_redeemed = u8::from_le_bytes(*items_redeemed_ptr);
|
||||
|
||||
if participation_redeemed {
|
||||
bid_redemption.participation_redeemed = true
|
||||
*participation_redeemed_ptr = [1];
|
||||
} else if bid_redeemed {
|
||||
bid_redemption.items_redeemed += 1;
|
||||
*items_redeemed_ptr = curr_items_redeemed
|
||||
.checked_add(1)
|
||||
.ok_or(MetaplexError::NumericalOverflowError)?
|
||||
.to_le_bytes();
|
||||
}
|
||||
bid_redemption.serialize(&mut *bid_redemption_info.data.borrow_mut())?;
|
||||
}
|
||||
|
||||
let mut open_claims = false;
|
||||
for state in &auction_manager.state.winning_config_states {
|
||||
for item in &state.items {
|
||||
if !item.claimed {
|
||||
open_claims = true;
|
||||
break;
|
||||
msg!("About to pass through the eye of the needle");
|
||||
sol_log_compute_units();
|
||||
|
||||
if bid_redeemed {
|
||||
if let Some(index) = winning_index {
|
||||
if let Some(item_index) = winning_item_index {
|
||||
AuctionManager::set_claimed_and_status(
|
||||
auction_manager_info,
|
||||
auction_manager.state.status,
|
||||
index,
|
||||
item_index,
|
||||
auction_manager.straight_shot_optimization,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !open_claims {
|
||||
auction_manager.state.status = AuctionManagerStatus::Finished
|
||||
}
|
||||
|
||||
auction_manager.serialize(&mut *auction_manager_info.data.borrow_mut())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -634,15 +724,15 @@ pub fn common_winning_config_checks(
|
|||
auction_manager: &AuctionManager,
|
||||
safety_deposit_info: &AccountInfo,
|
||||
winning_index: usize,
|
||||
ignore_claim: bool,
|
||||
) -> Result<CommonWinningConfigCheckReturn, ProgramError> {
|
||||
let winning_config = &auction_manager.settings.winning_configs[winning_index];
|
||||
let winning_config_state = &auction_manager.state.winning_config_states[winning_index];
|
||||
|
||||
let mut winning_item_index = None;
|
||||
for i in 0..winning_config.items.len() {
|
||||
let order: usize = 97;
|
||||
if winning_config.items[i].safety_deposit_box_index
|
||||
== safety_deposit_info.data.borrow()[order]
|
||||
== SafetyDepositBox::get_order(safety_deposit_info)
|
||||
{
|
||||
winning_item_index = Some(i);
|
||||
break;
|
||||
|
@ -659,7 +749,9 @@ pub fn common_winning_config_checks(
|
|||
None => return Err(MetaplexError::SafetyDepositBoxNotUsedInAuction.into()),
|
||||
};
|
||||
|
||||
if winning_config_state_item.claimed {
|
||||
// For printing v2, we may call many times for different editions and the edition PDA check makes sure it cant
|
||||
// be claimed over-much. This would be 1 time, we need n times.
|
||||
if winning_config_state_item.claimed && !ignore_claim {
|
||||
return Err(MetaplexError::PrizeAlreadyClaimed.into());
|
||||
}
|
||||
|
||||
|
@ -833,3 +925,18 @@ pub fn end_auction<'a: 'b, 'b>(
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn assert_is_ata(
|
||||
account: &AccountInfo,
|
||||
wallet: &Pubkey,
|
||||
token_program: &Pubkey,
|
||||
mint: &Pubkey,
|
||||
) -> ProgramResult {
|
||||
assert_derivation(
|
||||
&Pubkey::from_str("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").unwrap(),
|
||||
account,
|
||||
&[wallet.as_ref(), token_program.as_ref(), mint.as_ref()],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,512 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
settings_utils::{parse_settings, JsonAuctionManagerSettings},
|
||||
vault_utils::{activate_vault, add_token_to_vault, combine_vault, initialize_vault},
|
||||
AUCTION_PROGRAM_PUBKEY, PROGRAM_PUBKEY, TOKEN_PROGRAM_PUBKEY, VAULT_PROGRAM_PUBKEY,
|
||||
},
|
||||
clap::ArgMatches,
|
||||
solana_clap_utils::input_parsers::pubkey_of,
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_program::{
|
||||
account_info::AccountInfo, borsh::try_from_slice_unchecked, instruction::Instruction,
|
||||
program_pack::Pack,
|
||||
},
|
||||
solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Keypair, Signer},
|
||||
system_instruction::create_account,
|
||||
transaction::Transaction,
|
||||
},
|
||||
spl_auction::{
|
||||
instruction::create_auction_instruction,
|
||||
processor::{create_auction::CreateAuctionArgs, AuctionData, PriceFloor, WinnerLimit},
|
||||
},
|
||||
spl_metaplex::{
|
||||
instruction::create_init_auction_manager_instruction,
|
||||
instruction::create_set_store_instruction,
|
||||
instruction::create_validate_participation_instruction, state::AuctionManager,
|
||||
},
|
||||
spl_token::{
|
||||
instruction::{initialize_account, initialize_mint},
|
||||
state::{Account, Mint},
|
||||
},
|
||||
spl_token_metadata::state::{MasterEdition, Metadata, EDITION},
|
||||
spl_token_vault::{
|
||||
instruction::create_update_external_price_account_instruction,
|
||||
state::{ExternalPriceAccount, MAX_EXTERNAL_ACCOUNT_SIZE},
|
||||
},
|
||||
std::{convert::TryInto, fs::File, io::Write, str::FromStr},
|
||||
};
|
||||
|
||||
pub fn to_account_info<'a>(
|
||||
key: &'a Pubkey,
|
||||
a: &'a mut solana_sdk::account::Account,
|
||||
lamports: &'a mut u64,
|
||||
) -> AccountInfo<'a> {
|
||||
AccountInfo::new(
|
||||
&key,
|
||||
false,
|
||||
false,
|
||||
lamports,
|
||||
&mut a.data,
|
||||
&a.owner,
|
||||
false,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
fn find_or_initialize_external_account<'a>(
|
||||
app_matches: &ArgMatches,
|
||||
payer: &Keypair,
|
||||
vault_program_key: &Pubkey,
|
||||
token_key: &Pubkey,
|
||||
client: &RpcClient,
|
||||
payer_mint_key: &'a Keypair,
|
||||
external_keypair: &'a Keypair,
|
||||
) -> (Pubkey, ExternalPriceAccount) {
|
||||
let external_key: Pubkey;
|
||||
if !app_matches.is_present("external_price_account") {
|
||||
let mut instructions: Vec<Instruction> = vec![];
|
||||
let mut signers: Vec<&Keypair> = vec![&payer, &external_keypair];
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&payer_mint_key.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Mint::LEN)
|
||||
.unwrap(),
|
||||
Mint::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
instructions.push(
|
||||
initialize_mint(
|
||||
&token_key,
|
||||
&payer_mint_key.pubkey(),
|
||||
&payer.pubkey(),
|
||||
Some(&payer.pubkey()),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&external_keypair.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(MAX_EXTERNAL_ACCOUNT_SIZE)
|
||||
.unwrap(),
|
||||
MAX_EXTERNAL_ACCOUNT_SIZE as u64,
|
||||
&vault_program_key,
|
||||
));
|
||||
instructions.push(create_update_external_price_account_instruction(
|
||||
*vault_program_key,
|
||||
external_keypair.pubkey(),
|
||||
0,
|
||||
payer_mint_key.pubkey(),
|
||||
true,
|
||||
));
|
||||
|
||||
signers.push(&payer_mint_key);
|
||||
signers.push(&external_keypair);
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
external_key = external_keypair.pubkey();
|
||||
} else {
|
||||
external_key = pubkey_of(app_matches, "external_price_account").unwrap();
|
||||
}
|
||||
let mut external_account_data = client.get_account(&external_key).unwrap();
|
||||
|
||||
let external_account: ExternalPriceAccount = ExternalPriceAccount::from_account_info(
|
||||
&to_account_info(&external_key, &mut external_account_data, &mut 0u64),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
(external_key, external_account)
|
||||
}
|
||||
|
||||
fn find_or_initialize_store(
|
||||
app_matches: &ArgMatches,
|
||||
payer: &Keypair,
|
||||
client: &RpcClient,
|
||||
) -> Pubkey {
|
||||
let admin = read_keypair_file(
|
||||
app_matches
|
||||
.value_of("admin")
|
||||
.unwrap_or_else(|| app_matches.value_of("keypair").unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let program_key = Pubkey::from_str(PROGRAM_PUBKEY).unwrap();
|
||||
let admin_key = admin.pubkey();
|
||||
|
||||
let seeds = &[
|
||||
spl_metaplex::state::PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
&admin_key.as_ref(),
|
||||
];
|
||||
let (store_key, _) = Pubkey::find_program_address(seeds, &program_key);
|
||||
|
||||
let instructions = [create_set_store_instruction(
|
||||
program_key,
|
||||
store_key,
|
||||
admin.pubkey(),
|
||||
payer.pubkey(),
|
||||
true,
|
||||
)];
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&[&admin, &payer], recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
println!("Store created {:?}", store_key);
|
||||
store_key
|
||||
}
|
||||
|
||||
fn find_or_initialize_auction(
|
||||
app_matches: &ArgMatches,
|
||||
vault_key: &Pubkey,
|
||||
program_key: &Pubkey,
|
||||
auction_program_key: &Pubkey,
|
||||
payer_mint_key: &Pubkey,
|
||||
payer: &Keypair,
|
||||
client: &RpcClient,
|
||||
) -> (Pubkey, AuctionData) {
|
||||
let auction_key: Pubkey;
|
||||
if !app_matches.is_present("auction") {
|
||||
let signers: Vec<&Keypair> = vec![&payer];
|
||||
|
||||
let winner_limit = app_matches
|
||||
.value_of("winner_limit")
|
||||
.unwrap_or("0")
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
|
||||
let gap_time = app_matches
|
||||
.value_of("gap_time")
|
||||
.unwrap_or("1200")
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
|
||||
let end_time = app_matches
|
||||
.value_of("end_time")
|
||||
.unwrap_or("1200")
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
|
||||
let auction_path = [
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
auction_program_key.as_ref(),
|
||||
&vault_key.to_bytes(),
|
||||
];
|
||||
|
||||
// Derive the address we'll store the auction in, and confirm it matches what we expected the
|
||||
// user to provide.
|
||||
let (actual_auction_key, _) =
|
||||
Pubkey::find_program_address(&auction_path, auction_program_key);
|
||||
|
||||
// You'll notice that the authority IS what will become the auction manager ;)
|
||||
let authority_seeds = &[
|
||||
spl_metaplex::state::PREFIX.as_bytes(),
|
||||
&actual_auction_key.as_ref(),
|
||||
];
|
||||
let (auction_manager_key, _) = Pubkey::find_program_address(authority_seeds, &program_key);
|
||||
|
||||
let instructions = [create_auction_instruction(
|
||||
*auction_program_key,
|
||||
payer.pubkey(),
|
||||
CreateAuctionArgs {
|
||||
resource: *vault_key,
|
||||
authority: auction_manager_key,
|
||||
end_auction_at: Some(end_time.try_into().unwrap()),
|
||||
end_auction_gap: Some(gap_time.try_into().unwrap()),
|
||||
winners: match winner_limit {
|
||||
0 => WinnerLimit::Unlimited(0),
|
||||
val => WinnerLimit::Capped(val.try_into().unwrap()),
|
||||
},
|
||||
token_mint: *payer_mint_key,
|
||||
price_floor: PriceFloor::None([0; 32]),
|
||||
gap_tick_size_percentage: Some(0),
|
||||
tick_size: Some(0),
|
||||
},
|
||||
)];
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
auction_key = actual_auction_key;
|
||||
} else {
|
||||
auction_key = pubkey_of(app_matches, "auction").unwrap();
|
||||
}
|
||||
let mut data = client.get_account(&auction_key).unwrap();
|
||||
|
||||
let account: AuctionData =
|
||||
AuctionData::from_account_info(&to_account_info(&auction_key, &mut data, &mut 0u64))
|
||||
.unwrap();
|
||||
(auction_key, account)
|
||||
}
|
||||
|
||||
fn add_tokens_to_vault_activate_and_return_mints_and_open_edition(
|
||||
app_matches: &ArgMatches,
|
||||
json_settings: &JsonAuctionManagerSettings,
|
||||
vault_key: &Pubkey,
|
||||
payer: &Keypair,
|
||||
auction_manager_key: &Pubkey,
|
||||
client: &RpcClient,
|
||||
) -> (Vec<Pubkey>, Option<Pubkey>, Option<Pubkey>, Option<Pubkey>) {
|
||||
let mut mint_keys: Vec<Pubkey> = vec![];
|
||||
let open_edition_mint_key: Option<Pubkey>;
|
||||
let mut open_edition_safety_deposit: Option<Pubkey> = None;
|
||||
let mut open_edition_safety_deposit_store: Option<Pubkey> = None;
|
||||
if !app_matches.is_present("vault") {
|
||||
for config in &json_settings.winning_configs {
|
||||
for item in &config.items {
|
||||
let (_, actual_mint, _) = add_token_to_vault(
|
||||
&payer,
|
||||
vault_key,
|
||||
&payer,
|
||||
client,
|
||||
item.amount.into(),
|
||||
match &item.mint {
|
||||
Some(val) => Some(Pubkey::from_str(&val).unwrap()),
|
||||
None => None,
|
||||
},
|
||||
match &item.account {
|
||||
Some(val) => Some(Pubkey::from_str(&val).unwrap()),
|
||||
None => None,
|
||||
},
|
||||
!matches!(item.winning_config_type, 0),
|
||||
item.desired_supply,
|
||||
false,
|
||||
);
|
||||
mint_keys.push(actual_mint);
|
||||
}
|
||||
}
|
||||
if let Some(config) = &json_settings.participation_config {
|
||||
let (safety_deposit_box, actual_open_edition_mint, store) = add_token_to_vault(
|
||||
&payer,
|
||||
vault_key,
|
||||
&payer,
|
||||
client,
|
||||
1,
|
||||
match &config.mint {
|
||||
Some(val) => Some(Pubkey::from_str(&val).unwrap()),
|
||||
None => None,
|
||||
},
|
||||
match &config.account {
|
||||
Some(val) => Some(Pubkey::from_str(&val).unwrap()),
|
||||
None => None,
|
||||
},
|
||||
true,
|
||||
None,
|
||||
true,
|
||||
);
|
||||
open_edition_mint_key = Some(actual_open_edition_mint);
|
||||
open_edition_safety_deposit = Some(safety_deposit_box);
|
||||
open_edition_safety_deposit_store = Some(store);
|
||||
} else {
|
||||
open_edition_mint_key = None; // Return nothing, it wont be used
|
||||
}
|
||||
|
||||
activate_vault(&payer, vault_key, &payer, client);
|
||||
|
||||
combine_vault(&payer, auction_manager_key, vault_key, &payer, client);
|
||||
} else {
|
||||
open_edition_mint_key = match &json_settings.participation_config {
|
||||
Some(val) => match &val.mint {
|
||||
Some(mint) => Some(Pubkey::from_str(&mint).unwrap()),
|
||||
None => None, // If a config was provided for existing vault but no mint, cant do anything here.
|
||||
},
|
||||
None => None, // Return nothing, it wont be used
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
mint_keys,
|
||||
open_edition_mint_key,
|
||||
open_edition_safety_deposit,
|
||||
open_edition_safety_deposit_store,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn initialize_auction_manager(
|
||||
app_matches: &ArgMatches,
|
||||
payer: Keypair,
|
||||
client: RpcClient,
|
||||
) -> (Pubkey, AuctionManager) {
|
||||
let program_key = Pubkey::from_str(PROGRAM_PUBKEY).unwrap();
|
||||
let vault_program_key = Pubkey::from_str(VAULT_PROGRAM_PUBKEY).unwrap();
|
||||
let auction_program_key = Pubkey::from_str(AUCTION_PROGRAM_PUBKEY).unwrap();
|
||||
let accept_payment_account_key = Keypair::new();
|
||||
let printing_token_account_key = Keypair::new();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
let authority = pubkey_of(app_matches, "authority").unwrap_or_else(|| payer.pubkey());
|
||||
let store_key = find_or_initialize_store(app_matches, &payer, &client);
|
||||
|
||||
let (settings, json_settings) = parse_settings(app_matches.value_of("settings_file").unwrap());
|
||||
|
||||
let vault_key: Pubkey;
|
||||
let mut instructions: Vec<Instruction> = vec![];
|
||||
let mut signers: Vec<&Keypair> = vec![&payer, &accept_payment_account_key];
|
||||
|
||||
let payer_mint_key = Keypair::new();
|
||||
let external_keypair = Keypair::new();
|
||||
let (external_key, external_price_account) = find_or_initialize_external_account(
|
||||
app_matches,
|
||||
&payer,
|
||||
&vault_program_key,
|
||||
&token_key,
|
||||
&client,
|
||||
&payer_mint_key,
|
||||
&external_keypair,
|
||||
);
|
||||
let mut payer_mint_pubkey = external_price_account.price_mint;
|
||||
|
||||
// Create vault first, so we can use it to make auction, then add stuff to vault.
|
||||
if !app_matches.is_present("vault") {
|
||||
vault_key = initialize_vault(&payer, &external_key, &payer, &client);
|
||||
} else {
|
||||
vault_key = pubkey_of(app_matches, "vault").unwrap();
|
||||
}
|
||||
|
||||
let (auction_key, auction) = find_or_initialize_auction(
|
||||
app_matches,
|
||||
&vault_key,
|
||||
&program_key,
|
||||
&auction_program_key,
|
||||
&payer_mint_pubkey,
|
||||
&payer,
|
||||
&client,
|
||||
);
|
||||
|
||||
// just in case it was changed because pubkey was set from outside
|
||||
payer_mint_pubkey = auction.token_mint;
|
||||
|
||||
let seeds = &[
|
||||
spl_metaplex::state::PREFIX.as_bytes(),
|
||||
&auction_key.as_ref(),
|
||||
];
|
||||
let (auction_manager_key, _) = Pubkey::find_program_address(seeds, &program_key);
|
||||
|
||||
let (actual_mints, open_edition_mint_key, open_edition_safety_deposit, open_edition_store) =
|
||||
add_tokens_to_vault_activate_and_return_mints_and_open_edition(
|
||||
app_matches,
|
||||
&json_settings,
|
||||
&vault_key,
|
||||
&payer,
|
||||
&auction_manager_key,
|
||||
&client,
|
||||
);
|
||||
|
||||
let actual_mints_to_json = serde_json::to_string(&actual_mints).unwrap();
|
||||
let mut file = File::create(auction_manager_key.to_string() + ".json").unwrap();
|
||||
file.write_all(&actual_mints_to_json.as_bytes()).unwrap();
|
||||
println!("Printed mints to file {:?}.json", auction_manager_key);
|
||||
|
||||
let token_metadata = spl_token_metadata::id();
|
||||
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&accept_payment_account_key.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&accept_payment_account_key.pubkey(),
|
||||
&payer_mint_pubkey,
|
||||
&auction_manager_key,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(create_init_auction_manager_instruction(
|
||||
program_key,
|
||||
auction_manager_key,
|
||||
vault_key,
|
||||
auction_key,
|
||||
authority,
|
||||
payer.pubkey(),
|
||||
accept_payment_account_key.pubkey(),
|
||||
store_key,
|
||||
settings,
|
||||
));
|
||||
|
||||
if let Some(mint_key) = open_edition_mint_key {
|
||||
let metadata_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
&token_metadata.as_ref(),
|
||||
&mint_key.as_ref(),
|
||||
];
|
||||
let (metadata_key, _) =
|
||||
Pubkey::find_program_address(metadata_seeds, &spl_token_metadata::id());
|
||||
let metadata_account = client.get_account(&metadata_key).unwrap();
|
||||
let metadata: Metadata = try_from_slice_unchecked(&metadata_account.data).unwrap();
|
||||
|
||||
let metadata_authority = metadata.update_authority;
|
||||
|
||||
let edition_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
token_metadata.as_ref(),
|
||||
mint_key.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
];
|
||||
let (edition_key, _) = Pubkey::find_program_address(edition_seeds, &token_metadata);
|
||||
let master_edition_account = client.get_account(&edition_key).unwrap();
|
||||
let master_edition: MasterEdition =
|
||||
try_from_slice_unchecked(&master_edition_account.data).unwrap();
|
||||
let open_edition_printing_mint = master_edition.printing_mint;
|
||||
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&printing_token_account_key.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&printing_token_account_key.pubkey(),
|
||||
&open_edition_printing_mint,
|
||||
&auction_manager_key,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
signers.push(&printing_token_account_key);
|
||||
|
||||
instructions.push(create_validate_participation_instruction(
|
||||
program_key,
|
||||
auction_manager_key,
|
||||
metadata_key,
|
||||
edition_key,
|
||||
printing_token_account_key.pubkey(),
|
||||
authority,
|
||||
metadata_authority,
|
||||
store_key,
|
||||
open_edition_safety_deposit.unwrap(),
|
||||
open_edition_store.unwrap(),
|
||||
vault_key,
|
||||
));
|
||||
}
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
let account = client.get_account(&auction_manager_key).unwrap();
|
||||
let manager: AuctionManager = try_from_slice_unchecked(&account.data).unwrap();
|
||||
|
||||
(auction_manager_key, manager)
|
||||
}
|
|
@ -1,31 +1,29 @@
|
|||
mod initialize_auction_manager;
|
||||
mod place_bid;
|
||||
mod redeem_bid;
|
||||
mod settings_utils;
|
||||
mod show;
|
||||
mod start_auction;
|
||||
mod validate_safety_deposits;
|
||||
mod vault_utils;
|
||||
|
||||
use {
|
||||
clap::{crate_description, crate_name, crate_version, App, Arg, SubCommand},
|
||||
initialize_auction_manager::initialize_auction_manager,
|
||||
place_bid::make_bid,
|
||||
redeem_bid::redeem_bid_wrapper,
|
||||
show::send_show,
|
||||
solana_clap_utils::input_validators::{is_url, is_valid_pubkey, is_valid_signer},
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_sdk::signature::read_keypair_file,
|
||||
start_auction::send_start_auction,
|
||||
validate_safety_deposits::validate_safety_deposits,
|
||||
solana_program::{account_info::AccountInfo, pubkey::Pubkey},
|
||||
solana_sdk::{account::Account, signature::read_keypair_file},
|
||||
};
|
||||
|
||||
pub const VAULT_PROGRAM_PUBKEY: &str = "vau1zxA2LbssAUEF7Gpw91zMM1LvXrvpzJtmZ58rPsn";
|
||||
pub const AUCTION_PROGRAM_PUBKEY: &str = "auctxRXPeJoc4817jDhf4HbjnhEcr1cCXenosMhK5R8";
|
||||
|
||||
pub const PROGRAM_PUBKEY: &str = "p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98";
|
||||
|
||||
pub const TOKEN_PROGRAM_PUBKEY: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
||||
pub fn make_account_with_data<'a>(
|
||||
key: &'a Pubkey,
|
||||
account: &'a mut Account,
|
||||
lamports: &'a mut u64,
|
||||
) -> AccountInfo<'a> {
|
||||
AccountInfo::new(
|
||||
key,
|
||||
false,
|
||||
false,
|
||||
lamports,
|
||||
&mut account.data,
|
||||
&account.owner,
|
||||
false,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let app_matches = App::new(crate_name!())
|
||||
|
@ -59,114 +57,6 @@ fn main() {
|
|||
.help("Admin of the store you want to use, defaults to your key"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("init")
|
||||
.about("Initialize an Auction Manager")
|
||||
.arg(
|
||||
Arg::with_name("authority")
|
||||
.long("authority")
|
||||
.value_name("AUTHORITY")
|
||||
.required(false)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of authority, defaults to you otherwise"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("external_price_account")
|
||||
.long("external_price_account")
|
||||
.value_name("EXTERNAL_PRICE_ACCOUNT")
|
||||
.required(false)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of external price account, if one not provided, one will be made. Needs to be same as the one on the Vault."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("vault")
|
||||
.long("vault")
|
||||
.value_name("VAULT")
|
||||
.required(false)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of vault. If one not provided, one will be made."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("auction")
|
||||
.long("auction")
|
||||
.value_name("AUCTION")
|
||||
.required(false)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of auction. If one not provided, one will be made."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("winner_limit")
|
||||
.long("winner_limit")
|
||||
.value_name("WINNER_LIMIT")
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.help("Defaults to unlimited (0), ignored if existing auction provided."),
|
||||
).arg(
|
||||
Arg::with_name("gap_time")
|
||||
.long("gap_time")
|
||||
.value_name("GAP_TIME")
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.help("Defaults to 1200 slots, ignored if existing auction provided."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("end_time")
|
||||
.long("end_time")
|
||||
.value_name("END_TIME")
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.help("Defaults to 1200 slots, ignored if existing auction provided."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("settings_file")
|
||||
.long("settings_file")
|
||||
.value_name("SETTINGS_FILE")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("File path or uri to settings file (json) for setting up Auction Managers. See settings_sample.json, and you can follow the JSON structs in settings_utils.rs to customize the AuctionManagerSetting struct that gets created for shipping."),
|
||||
),
|
||||
).subcommand(
|
||||
SubCommand::with_name("validate")
|
||||
.about("Validate one (or all) of the winning configurations of your auction manager by slot.")
|
||||
.arg(
|
||||
Arg::with_name("authority")
|
||||
.long("authority")
|
||||
.value_name("AUTHORITY")
|
||||
.required(false)
|
||||
.validator(is_valid_signer)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of authority, defaults to you otherwise"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("metadata_authority")
|
||||
.long("metadata_authority")
|
||||
.value_name("METADATA_AUTHORITY")
|
||||
.required(false)
|
||||
.validator(is_valid_signer)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of the metadata authority on the given winning configuration(s), defaults to you otherwise"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("auction_manager")
|
||||
.long("auction_manager")
|
||||
.value_name("AUCTION_MANAGER")
|
||||
.required(true)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of auction manager."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("winner_config_slot")
|
||||
.long("winner_config_slot")
|
||||
.value_name("WINNER_CONFIG_SLOT")
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.help("Pass in a specific 0-indexed slot in the array to validate that slot, if not passed, all will be validated."),
|
||||
)
|
||||
).subcommand(
|
||||
SubCommand::with_name("show")
|
||||
.about("Print out the manager data for a given manager address.")
|
||||
.arg(
|
||||
|
@ -177,91 +67,8 @@ fn main() {
|
|||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of auction manager."),
|
||||
)
|
||||
).subcommand(
|
||||
SubCommand::with_name("place_bid")
|
||||
.about("Place a bid on a specific slot, receive a bidder metadata address in return.")
|
||||
.arg(
|
||||
Arg::with_name("auction_manager")
|
||||
.long("auction_manager")
|
||||
.value_name("AUCTION_MANAGER")
|
||||
.required(true)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of auction manager."),
|
||||
).arg(
|
||||
Arg::with_name("wallet")
|
||||
.long("wallet")
|
||||
.value_name("WALLET")
|
||||
.required(false)
|
||||
.validator(is_valid_signer)
|
||||
.takes_value(true)
|
||||
.help("Valid wallet, defaults to you."),
|
||||
).arg(
|
||||
Arg::with_name("mint_it")
|
||||
.long("mint_it")
|
||||
.value_name("MINT_IT")
|
||||
.required(false)
|
||||
.takes_value(false)
|
||||
.help("Attempts to mint the tokens. Useful on devnet and you need to have authority as payer over the token_mint on the auction."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("price")
|
||||
.long("price")
|
||||
.value_name("PRICE")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.help("The price in sol you want to bid"),
|
||||
)
|
||||
).subcommand(
|
||||
SubCommand::with_name("redeem_bid")
|
||||
.about("Redeem a bid")
|
||||
.arg(
|
||||
Arg::with_name("auction_manager")
|
||||
.long("auction_manager")
|
||||
.value_name("AUCTION_MANAGER")
|
||||
.required(true)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of auction manager."),
|
||||
).arg(
|
||||
Arg::with_name("wallet")
|
||||
.long("wallet")
|
||||
.value_name("WALLET")
|
||||
.required(false)
|
||||
.validator(is_valid_signer)
|
||||
.takes_value(true)
|
||||
.help("Wallet that placed the bid, defaults to you."),
|
||||
).arg(
|
||||
Arg::with_name("mint_it")
|
||||
.long("mint_it")
|
||||
.value_name("MINT_IT")
|
||||
.required(false)
|
||||
.takes_value(false)
|
||||
.help("Attempts to mint tokens to pay for the open edition. Useful on devnet and you need to have authority as payer over the token_mint on the auction."),
|
||||
)
|
||||
).subcommand(
|
||||
SubCommand::with_name("start_auction")
|
||||
.about("Starts an auction on an auction manager that has been fully validated")
|
||||
.arg(
|
||||
Arg::with_name("auction_manager")
|
||||
.long("auction_manager")
|
||||
.value_name("AUCTION_MANAGER")
|
||||
.required(true)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of auction manager."),
|
||||
).arg(
|
||||
Arg::with_name("authority")
|
||||
.long("authority")
|
||||
.value_name("AUTHORITY")
|
||||
.required(false)
|
||||
.validator(is_valid_signer)
|
||||
.takes_value(true)
|
||||
.help("Pubkey of authority, defaults to you otherwise"),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
.get_matches();
|
||||
|
||||
let client = RpcClient::new(
|
||||
|
@ -276,26 +83,6 @@ fn main() {
|
|||
let payer = read_keypair_file(app_matches.value_of("keypair").unwrap()).unwrap();
|
||||
|
||||
match (sub_command, sub_matches) {
|
||||
("init", Some(arg_matches)) => {
|
||||
let (key, manager) = initialize_auction_manager(arg_matches, payer, client);
|
||||
println!(
|
||||
"Created auction manager with address {:?} and output {:?}",
|
||||
key, manager
|
||||
);
|
||||
}
|
||||
("validate", Some(arg_matches)) => {
|
||||
validate_safety_deposits(arg_matches, payer, client);
|
||||
println!("Validated all winning configs passed in.",);
|
||||
}
|
||||
("place_bid", Some(arg_matches)) => {
|
||||
make_bid(arg_matches, payer, client);
|
||||
}
|
||||
("redeem_bid", Some(arg_matches)) => {
|
||||
redeem_bid_wrapper(arg_matches, payer, client);
|
||||
}
|
||||
("start_auction", Some(arg_matches)) => {
|
||||
send_start_auction(arg_matches, payer, client);
|
||||
}
|
||||
("show", Some(arg_matches)) => {
|
||||
send_show(arg_matches, payer, client);
|
||||
}
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
use {
|
||||
crate::{AUCTION_PROGRAM_PUBKEY, TOKEN_PROGRAM_PUBKEY},
|
||||
clap::ArgMatches,
|
||||
solana_clap_utils::input_parsers::pubkey_of,
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_program::{
|
||||
borsh::try_from_slice_unchecked, program_pack::Pack, system_instruction::create_account,
|
||||
},
|
||||
solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::write_keypair_file,
|
||||
signature::{read_keypair_file, Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
},
|
||||
spl_auction::{
|
||||
instruction::place_bid_instruction,
|
||||
processor::{place_bid::PlaceBidArgs, AuctionData, BidderMetadata, BidderPot},
|
||||
},
|
||||
spl_metaplex::state::{AuctionManager, Store},
|
||||
spl_token::{
|
||||
instruction::{approve, initialize_account, mint_to},
|
||||
state::Account,
|
||||
},
|
||||
std::str::FromStr,
|
||||
};
|
||||
|
||||
pub fn make_bid(app_matches: &ArgMatches, payer: Keypair, client: RpcClient) {
|
||||
let auction_program_key = Pubkey::from_str(AUCTION_PROGRAM_PUBKEY).unwrap();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
let wallet: Keypair;
|
||||
if !app_matches.is_present("wallet") {
|
||||
wallet = Keypair::new();
|
||||
} else {
|
||||
wallet = read_keypair_file(app_matches.value_of("wallet").unwrap()).unwrap();
|
||||
}
|
||||
|
||||
let amount = app_matches
|
||||
.value_of("price")
|
||||
.unwrap()
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
|
||||
let auction_manager_key = pubkey_of(app_matches, "auction_manager").unwrap();
|
||||
|
||||
let account = client.get_account(&auction_manager_key).unwrap();
|
||||
let manager: AuctionManager = try_from_slice_unchecked(&account.data).unwrap();
|
||||
|
||||
let store_account = client.get_account(&manager.store).unwrap();
|
||||
let store: Store = try_from_slice_unchecked(&store_account.data).unwrap();
|
||||
|
||||
let auction_account = client.get_account(&manager.auction).unwrap();
|
||||
let auction: AuctionData = try_from_slice_unchecked(&auction_account.data).unwrap();
|
||||
let wallet_key = wallet.pubkey();
|
||||
let bidder_pot_seeds = &[
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
&auction_program_key.as_ref(),
|
||||
manager.auction.as_ref(),
|
||||
wallet_key.as_ref(),
|
||||
];
|
||||
let (bidder_pot_pubkey, _) =
|
||||
Pubkey::find_program_address(bidder_pot_seeds, &auction_program_key);
|
||||
let bidder_pot_account = client.get_account(&bidder_pot_pubkey);
|
||||
|
||||
let transfer_authority = Keypair::new();
|
||||
let mut signers = vec![&wallet, &transfer_authority, &payer];
|
||||
let mut instructions = vec![];
|
||||
|
||||
let bidder_pot_token: Pubkey;
|
||||
let new_bidder_pot = Keypair::new();
|
||||
match bidder_pot_account {
|
||||
Ok(val) => {
|
||||
let bidder_pot: BidderPot = try_from_slice_unchecked(&val.data).unwrap();
|
||||
bidder_pot_token = bidder_pot.bidder_pot;
|
||||
}
|
||||
Err(_) => {
|
||||
bidder_pot_token = new_bidder_pot.pubkey();
|
||||
signers.push(&new_bidder_pot);
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&new_bidder_pot.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&new_bidder_pot.pubkey(),
|
||||
&auction.token_mint,
|
||||
&manager.auction,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure you can afford the bid.
|
||||
|
||||
if app_matches.is_present("mint_it") {
|
||||
if !app_matches.is_present("wallet") {
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&wallet.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&wallet.pubkey(),
|
||||
&auction.token_mint,
|
||||
&payer.pubkey(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
instructions.push(
|
||||
mint_to(
|
||||
&token_key,
|
||||
&auction.token_mint,
|
||||
&wallet.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
amount + 2,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
instructions.push(
|
||||
approve(
|
||||
&token_key,
|
||||
&wallet.pubkey(),
|
||||
&transfer_authority.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
amount,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(place_bid_instruction(
|
||||
auction_program_key,
|
||||
// Can use any account as bidder key, so we just reuse spl token account as bidder. Traditionally
|
||||
// this would be your sol wallet.
|
||||
wallet.pubkey(),
|
||||
wallet.pubkey(),
|
||||
bidder_pot_token,
|
||||
auction.token_mint,
|
||||
transfer_authority.pubkey(),
|
||||
payer.pubkey(),
|
||||
PlaceBidArgs {
|
||||
amount,
|
||||
resource: manager.vault,
|
||||
},
|
||||
));
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
|
||||
let wallet_key = wallet.pubkey();
|
||||
let meta_path = [
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
store.auction_program.as_ref(),
|
||||
manager.auction.as_ref(),
|
||||
wallet_key.as_ref(),
|
||||
"metadata".as_bytes(),
|
||||
];
|
||||
let (meta_key, _) = Pubkey::find_program_address(&meta_path, &store.auction_program);
|
||||
let bidding_metadata = client.get_account(&meta_key).unwrap();
|
||||
let _bid: BidderMetadata = try_from_slice_unchecked(&bidding_metadata.data).unwrap();
|
||||
write_keypair_file(&wallet, wallet.pubkey().to_string() + ".json").unwrap();
|
||||
println!(
|
||||
"Because no wallet provided, created new one at {:?}.json, it was used to place the bid. Please use it for redemption as a signer.",
|
||||
wallet.pubkey()
|
||||
);
|
||||
println!("Created bid {:?}", meta_key);
|
||||
}
|
|
@ -1,549 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
settings_utils::parse_metadata_keys, PROGRAM_PUBKEY, TOKEN_PROGRAM_PUBKEY,
|
||||
VAULT_PROGRAM_PUBKEY,
|
||||
},
|
||||
arrayref::array_ref,
|
||||
clap::ArgMatches,
|
||||
solana_clap_utils::input_parsers::pubkey_of,
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_program::{
|
||||
borsh::try_from_slice_unchecked, instruction::Instruction, program_pack::Pack,
|
||||
system_instruction::create_account,
|
||||
},
|
||||
solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
},
|
||||
spl_auction::processor::{AuctionData, BidderMetadata},
|
||||
spl_metaplex::{
|
||||
instruction::{
|
||||
create_redeem_bid_instruction, create_redeem_full_rights_transfer_bid_instruction,
|
||||
create_redeem_participation_bid_instruction,
|
||||
},
|
||||
state::{AuctionManager, Store, WinningConfigItem, WinningConfigType},
|
||||
},
|
||||
spl_token::{
|
||||
instruction::{approve, initialize_account, mint_to},
|
||||
state::Account,
|
||||
},
|
||||
spl_token_metadata::state::{MasterEdition, EDITION},
|
||||
spl_token_vault::state::{Key, SafetyDepositBox, Vault},
|
||||
std::{collections::HashMap, str::FromStr},
|
||||
};
|
||||
|
||||
struct BaseAccountList {
|
||||
auction_manager: Pubkey,
|
||||
store: Pubkey,
|
||||
destination: Pubkey,
|
||||
bid_redemption: Pubkey,
|
||||
safety_deposit_box: Pubkey,
|
||||
fraction_mint: Pubkey,
|
||||
vault: Pubkey,
|
||||
auction: Pubkey,
|
||||
bidder_metadata: Pubkey,
|
||||
bidder: Pubkey,
|
||||
payer: Pubkey,
|
||||
token_vault_program: Pubkey,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn redeem_bid_token_only_type<'a>(
|
||||
base_account_list: BaseAccountList,
|
||||
manager: &AuctionManager,
|
||||
winning_config_item: &WinningConfigItem,
|
||||
safety_deposit: &SafetyDepositBox,
|
||||
program_id: &Pubkey,
|
||||
token_program: &Pubkey,
|
||||
instructions: &'a mut Vec<Instruction>,
|
||||
client: &RpcClient,
|
||||
) -> Vec<Instruction> {
|
||||
println!("You are redeeming a normal token.");
|
||||
|
||||
let BaseAccountList {
|
||||
auction_manager,
|
||||
store,
|
||||
destination,
|
||||
bid_redemption,
|
||||
safety_deposit_box,
|
||||
fraction_mint,
|
||||
vault,
|
||||
auction,
|
||||
bidder_metadata,
|
||||
bidder,
|
||||
payer,
|
||||
token_vault_program,
|
||||
} = base_account_list;
|
||||
let transfer_seeds = [
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
token_vault_program.as_ref(),
|
||||
];
|
||||
let (transfer_authority, _) =
|
||||
Pubkey::find_program_address(&transfer_seeds, &token_vault_program);
|
||||
|
||||
instructions.push(create_account(
|
||||
&payer,
|
||||
&destination,
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_program,
|
||||
));
|
||||
// For limited editions, we need owner to be payer to be used in token metadata
|
||||
let owner_key = match winning_config_item.winning_config_type {
|
||||
spl_metaplex::state::WinningConfigType::TokenOnlyTransfer => &bidder,
|
||||
spl_metaplex::state::WinningConfigType::Printing => &payer,
|
||||
_ => &bidder,
|
||||
};
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_program,
|
||||
&destination,
|
||||
&safety_deposit.token_mint,
|
||||
owner_key,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(
|
||||
approve(
|
||||
token_program,
|
||||
&base_account_list.destination,
|
||||
&transfer_authority,
|
||||
&owner_key,
|
||||
&[owner_key],
|
||||
winning_config_item.amount.into(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(create_redeem_bid_instruction(
|
||||
*program_id,
|
||||
auction_manager,
|
||||
store,
|
||||
destination,
|
||||
bid_redemption,
|
||||
safety_deposit_box,
|
||||
vault,
|
||||
fraction_mint,
|
||||
auction,
|
||||
bidder_metadata,
|
||||
bidder,
|
||||
payer,
|
||||
manager.store,
|
||||
transfer_authority,
|
||||
));
|
||||
|
||||
let mut new_instructions: Vec<Instruction> = vec![];
|
||||
for instr in instructions.iter() {
|
||||
new_instructions.push(instr.clone());
|
||||
}
|
||||
new_instructions
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn redeem_bid_open_edition_type<'a>(
|
||||
base_account_list: BaseAccountList,
|
||||
manager: &AuctionManager,
|
||||
safety_deposit: &SafetyDepositBox,
|
||||
program_id: &Pubkey,
|
||||
token_program: &Pubkey,
|
||||
instructions: &'a mut Vec<Instruction>,
|
||||
token_metadata_key: &Pubkey,
|
||||
transfer_authority: &Keypair,
|
||||
client: &RpcClient,
|
||||
app_matches: &ArgMatches,
|
||||
bidding_metadata_obj: BidderMetadata,
|
||||
) -> Vec<Instruction> {
|
||||
println!("You are redeeming an open edition.");
|
||||
|
||||
let BaseAccountList {
|
||||
auction_manager,
|
||||
store,
|
||||
destination,
|
||||
bid_redemption,
|
||||
safety_deposit_box,
|
||||
fraction_mint,
|
||||
vault,
|
||||
auction,
|
||||
bidder_metadata,
|
||||
bidder,
|
||||
payer,
|
||||
token_vault_program: _t,
|
||||
} = base_account_list;
|
||||
|
||||
let master_edition_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
&token_metadata_key.as_ref(),
|
||||
safety_deposit.token_mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
];
|
||||
let (master_edition_key, _) =
|
||||
Pubkey::find_program_address(master_edition_seeds, &token_metadata_key);
|
||||
let master_edition_account = client.get_account(&master_edition_key).unwrap();
|
||||
let master_edition: MasterEdition =
|
||||
try_from_slice_unchecked(&master_edition_account.data).unwrap();
|
||||
|
||||
let mut price = bidding_metadata_obj.last_bid;
|
||||
if let Some(config) = &manager.settings.participation_config {
|
||||
if let Some(fixed_price) = config.fixed_price {
|
||||
price = fixed_price
|
||||
}
|
||||
}
|
||||
|
||||
if app_matches.is_present("mint_it") {
|
||||
let auction_acct = client.get_account(&auction).unwrap();
|
||||
let auction: AuctionData = try_from_slice_unchecked(&auction_acct.data).unwrap();
|
||||
|
||||
instructions.push(
|
||||
mint_to(
|
||||
token_program,
|
||||
&auction.token_mint,
|
||||
&base_account_list.bidder,
|
||||
&payer,
|
||||
&[&payer],
|
||||
price + 2,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
instructions.push(
|
||||
approve(
|
||||
token_program,
|
||||
&base_account_list.bidder,
|
||||
&transfer_authority.pubkey(),
|
||||
&payer,
|
||||
&[&payer],
|
||||
price,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(create_account(
|
||||
&payer,
|
||||
&destination,
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_program,
|
||||
));
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_program,
|
||||
&destination,
|
||||
&master_edition.printing_mint,
|
||||
&payer,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let state = manager.state.participation_state.clone();
|
||||
|
||||
instructions.push(create_redeem_participation_bid_instruction(
|
||||
*program_id,
|
||||
auction_manager,
|
||||
store,
|
||||
destination,
|
||||
bid_redemption,
|
||||
safety_deposit_box,
|
||||
vault,
|
||||
fraction_mint,
|
||||
auction,
|
||||
bidder_metadata,
|
||||
bidder,
|
||||
payer,
|
||||
manager.store,
|
||||
transfer_authority.pubkey(),
|
||||
manager.accept_payment,
|
||||
bidder,
|
||||
state.unwrap().printing_authorization_token_account.unwrap(),
|
||||
));
|
||||
|
||||
let mut new_instructions: Vec<Instruction> = vec![];
|
||||
for instr in instructions.iter() {
|
||||
new_instructions.push(instr.clone());
|
||||
}
|
||||
|
||||
new_instructions
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn redeem_bid_rights_transfer<'a>(
|
||||
base_account_list: BaseAccountList,
|
||||
manager: &AuctionManager,
|
||||
safety_deposit: &SafetyDepositBox,
|
||||
program_id: &Pubkey,
|
||||
token_program: &Pubkey,
|
||||
instructions: &'a mut Vec<Instruction>,
|
||||
token_metadata_key: &Pubkey,
|
||||
client: &RpcClient,
|
||||
) -> Vec<Instruction> {
|
||||
println!("You are redeeming a master edition.");
|
||||
let BaseAccountList {
|
||||
auction_manager,
|
||||
store,
|
||||
destination,
|
||||
bid_redemption,
|
||||
safety_deposit_box,
|
||||
fraction_mint,
|
||||
vault,
|
||||
auction,
|
||||
bidder_metadata,
|
||||
bidder,
|
||||
payer,
|
||||
token_vault_program,
|
||||
} = base_account_list;
|
||||
|
||||
let master_metadata_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
&token_metadata_key.as_ref(),
|
||||
&safety_deposit.token_mint.as_ref(),
|
||||
];
|
||||
let (master_metadata_key, _) =
|
||||
Pubkey::find_program_address(master_metadata_seeds, &token_metadata_key);
|
||||
|
||||
let transfer_seeds = [
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
token_vault_program.as_ref(),
|
||||
];
|
||||
let (transfer_authority, _) =
|
||||
Pubkey::find_program_address(&transfer_seeds, &token_vault_program);
|
||||
|
||||
instructions.push(create_account(
|
||||
&payer,
|
||||
&destination,
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_program,
|
||||
));
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_program,
|
||||
&destination,
|
||||
&safety_deposit.token_mint,
|
||||
&bidder,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
instructions.push(
|
||||
approve(
|
||||
token_program,
|
||||
&base_account_list.destination,
|
||||
&transfer_authority,
|
||||
&base_account_list.bidder,
|
||||
&[&base_account_list.bidder],
|
||||
1,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(create_redeem_full_rights_transfer_bid_instruction(
|
||||
*program_id,
|
||||
auction_manager,
|
||||
store,
|
||||
destination,
|
||||
bid_redemption,
|
||||
safety_deposit_box,
|
||||
vault,
|
||||
fraction_mint,
|
||||
auction,
|
||||
bidder_metadata,
|
||||
bidder,
|
||||
payer,
|
||||
manager.store,
|
||||
master_metadata_key,
|
||||
bidder,
|
||||
transfer_authority,
|
||||
));
|
||||
|
||||
let mut new_instructions: Vec<Instruction> = vec![];
|
||||
for instr in instructions.iter() {
|
||||
new_instructions.push(instr.clone());
|
||||
}
|
||||
new_instructions
|
||||
}
|
||||
|
||||
pub fn redeem_bid_wrapper(app_matches: &ArgMatches, payer: Keypair, client: RpcClient) {
|
||||
let program_key = Pubkey::from_str(PROGRAM_PUBKEY).unwrap();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
let token_metadata_key = spl_token_metadata::id();
|
||||
|
||||
let token_vault_program = Pubkey::from_str(VAULT_PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
let wallet = read_keypair_file(
|
||||
app_matches
|
||||
.value_of("wallet")
|
||||
.unwrap_or_else(|| app_matches.value_of("keypair").unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let auction_manager_key = pubkey_of(app_matches, "auction_manager").unwrap();
|
||||
let mint_map = parse_metadata_keys(&(auction_manager_key.to_string() + ".json"));
|
||||
|
||||
let account = client.get_account(&auction_manager_key).unwrap();
|
||||
let manager: AuctionManager = try_from_slice_unchecked(&account.data).unwrap();
|
||||
|
||||
let store_account = client.get_account(&manager.store).unwrap();
|
||||
let store: Store = try_from_slice_unchecked(&store_account.data).unwrap();
|
||||
let all_vault_accounts = client.get_program_accounts(&token_vault_program).unwrap();
|
||||
|
||||
let mut safety_deposits = HashMap::new();
|
||||
|
||||
for acc in &all_vault_accounts {
|
||||
let obj = &acc.1;
|
||||
let obj_key = &acc.0;
|
||||
let type_of_obj = obj.data[0];
|
||||
|
||||
if type_of_obj == Key::SafetyDepositBoxV1 as u8 {
|
||||
let pubkey_arr = array_ref![obj.data, 1, 32];
|
||||
let pubkey = Pubkey::new_from_array(*pubkey_arr);
|
||||
if pubkey == manager.vault {
|
||||
let safety_deposit: SafetyDepositBox = try_from_slice_unchecked(&obj.data).unwrap();
|
||||
safety_deposits.insert(safety_deposit.order, (safety_deposit, obj_key));
|
||||
}
|
||||
}
|
||||
}
|
||||
let wallet_key = wallet.pubkey();
|
||||
let meta_path = [
|
||||
spl_auction::PREFIX.as_bytes(),
|
||||
store.auction_program.as_ref(),
|
||||
manager.auction.as_ref(),
|
||||
wallet_key.as_ref(),
|
||||
"metadata".as_bytes(),
|
||||
];
|
||||
|
||||
let (meta_key, _) = Pubkey::find_program_address(&meta_path, &store.auction_program);
|
||||
let bidding_metadata = client.get_account(&meta_key).unwrap();
|
||||
let auction_data = client.get_account(&manager.auction).unwrap();
|
||||
let vault_data = client.get_account(&manager.vault).unwrap();
|
||||
let auction: AuctionData = try_from_slice_unchecked(&auction_data.data).unwrap();
|
||||
let bid: BidderMetadata = try_from_slice_unchecked(&bidding_metadata.data).unwrap();
|
||||
let vault: Vault = try_from_slice_unchecked(&vault_data.data).unwrap();
|
||||
|
||||
let redemption_path = [
|
||||
spl_metaplex::state::PREFIX.as_bytes(),
|
||||
manager.auction.as_ref(),
|
||||
&meta_key.as_ref(),
|
||||
];
|
||||
let (bid_redemption_key, _) = Pubkey::find_program_address(&redemption_path, &program_key);
|
||||
|
||||
if let Some(winning_index) = auction.is_winner(&bid.bidder_pubkey) {
|
||||
let destination = Keypair::new();
|
||||
let winning_config = &manager.settings.winning_configs[winning_index];
|
||||
for item in &winning_config.items {
|
||||
let safety_deposit_result =
|
||||
safety_deposits.get(&item.safety_deposit_box_index).unwrap();
|
||||
let safety_deposit = &safety_deposit_result.0;
|
||||
let safety_deposit_key = safety_deposit_result.1;
|
||||
let signers: Vec<&Keypair> = vec![&wallet, &payer, &destination];
|
||||
let mut instructions: Vec<Instruction> = vec![];
|
||||
|
||||
let base_account_list = BaseAccountList {
|
||||
auction_manager: auction_manager_key,
|
||||
store: safety_deposit.store,
|
||||
destination: destination.pubkey(),
|
||||
bid_redemption: bid_redemption_key,
|
||||
safety_deposit_box: *safety_deposit_key,
|
||||
fraction_mint: vault.fraction_mint,
|
||||
vault: manager.vault,
|
||||
auction: manager.auction,
|
||||
bidder_metadata: meta_key,
|
||||
bidder: wallet.pubkey(),
|
||||
payer: payer.pubkey(),
|
||||
token_vault_program,
|
||||
};
|
||||
|
||||
let instructions = match item.winning_config_type {
|
||||
WinningConfigType::TokenOnlyTransfer | WinningConfigType::Printing => {
|
||||
redeem_bid_token_only_type(
|
||||
base_account_list,
|
||||
&manager,
|
||||
item,
|
||||
safety_deposit,
|
||||
&program_key,
|
||||
&token_key,
|
||||
&mut instructions,
|
||||
&client,
|
||||
)
|
||||
}
|
||||
WinningConfigType::FullRightsTransfer => redeem_bid_rights_transfer(
|
||||
base_account_list,
|
||||
&manager,
|
||||
safety_deposit,
|
||||
&program_key,
|
||||
&token_key,
|
||||
&mut instructions,
|
||||
&token_metadata_key,
|
||||
&client,
|
||||
),
|
||||
};
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
|
||||
println!(
|
||||
"Sent prize to {:?}. If this is a Limited Edition, this is actually an authorization token to receive your prize from token metadata. To get it, you can run the following: Ex: ./target/debug/spl-token-metadata-test-client mint_new_edition_from_master_edition_via_token --mint {:?} --account {:?}. Now let's see if you have an open edition to redeem...",
|
||||
destination.pubkey(), mint_map[safety_deposit.order as usize], destination.pubkey()
|
||||
)
|
||||
}
|
||||
} else {
|
||||
println!("You are not a winner, but lets see if you have open editions to redeem...");
|
||||
}
|
||||
|
||||
if let Some(participation_config) = &manager.settings.participation_config {
|
||||
println!("This auction has an open edition. Submitting!");
|
||||
let safety_deposit_result = safety_deposits
|
||||
.get(&participation_config.safety_deposit_box_index)
|
||||
.unwrap();
|
||||
let destination = Keypair::new();
|
||||
let safety_deposit = &safety_deposit_result.0;
|
||||
let safety_deposit_key = safety_deposit_result.1;
|
||||
let transfer_authority = Keypair::new();
|
||||
let signers = vec![&wallet, &transfer_authority, &payer, &destination];
|
||||
let mut instructions: Vec<Instruction> = vec![];
|
||||
let base_account_list = BaseAccountList {
|
||||
auction_manager: auction_manager_key,
|
||||
store: safety_deposit.store,
|
||||
destination: destination.pubkey(),
|
||||
bid_redemption: bid_redemption_key,
|
||||
safety_deposit_box: *safety_deposit_key,
|
||||
fraction_mint: vault.fraction_mint,
|
||||
vault: manager.vault,
|
||||
auction: manager.auction,
|
||||
bidder_metadata: meta_key,
|
||||
bidder: wallet.pubkey(),
|
||||
payer: payer.pubkey(),
|
||||
token_vault_program,
|
||||
};
|
||||
|
||||
let instructions = redeem_bid_open_edition_type(
|
||||
base_account_list,
|
||||
&manager,
|
||||
safety_deposit,
|
||||
&program_key,
|
||||
&token_key,
|
||||
&mut instructions,
|
||||
&token_metadata_key,
|
||||
&transfer_authority,
|
||||
&client,
|
||||
&app_matches,
|
||||
bid,
|
||||
);
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
println!("Open edition authorization token sent to {:?}. To receive your open edition, you can call token metadata now with it. Ex: ./target/debug/spl-token-metadata-test-client mint_new_edition_from_master_edition_via_token --mint {:?} --account {:?}", destination.pubkey(), safety_deposit.token_mint, destination.pubkey());
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"winning_configs": [
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"safety_deposit_box_index": 0,
|
||||
"amount": 1,
|
||||
"winning_config_type": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"participation_config": null
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
use {
|
||||
serde::{Deserialize, Serialize},
|
||||
solana_program::pubkey::Pubkey,
|
||||
spl_metaplex::state::{
|
||||
AuctionManagerSettings, NonWinningConstraint, ParticipationConfig, WinningConfig,
|
||||
WinningConfigItem, WinningConfigType, WinningConstraint,
|
||||
},
|
||||
std::fs::File,
|
||||
};
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct JsonWinningConfig {
|
||||
pub items: Vec<JsonWinningConfigItem>,
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct JsonWinningConfigItem {
|
||||
pub safety_deposit_box_index: u8,
|
||||
pub amount: u8,
|
||||
pub winning_config_type: u8,
|
||||
pub desired_supply: Option<u64>,
|
||||
pub mint: Option<String>,
|
||||
pub account: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct JsonParticipationConfig {
|
||||
pub safety_deposit_box_index: u8,
|
||||
pub mint: Option<String>,
|
||||
pub account: Option<String>,
|
||||
pub winner_constraint: u8,
|
||||
pub non_winning_constraint: u8,
|
||||
pub fixed_price: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct JsonAuctionManagerSettings {
|
||||
pub winning_configs: Vec<JsonWinningConfig>,
|
||||
|
||||
pub participation_config: Option<JsonParticipationConfig>,
|
||||
}
|
||||
|
||||
pub fn parse_metadata_keys(settings_file: &str) -> Vec<Pubkey> {
|
||||
let file = File::open(settings_file).unwrap();
|
||||
let json: Vec<[u8; 32]> = serde_json::from_reader(file).unwrap();
|
||||
json.iter().map(|x| Pubkey::new(x)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn parse_settings(settings_file: &str) -> (AuctionManagerSettings, JsonAuctionManagerSettings) {
|
||||
let file = File::open(settings_file).unwrap();
|
||||
let json_settings: JsonAuctionManagerSettings = serde_json::from_reader(file).unwrap();
|
||||
let mut parsed_winning_configs: Vec<WinningConfig> = vec![];
|
||||
|
||||
for n in 0..json_settings.winning_configs.len() {
|
||||
let json_box = json_settings.winning_configs[n].clone();
|
||||
let mut items: Vec<WinningConfigItem> = vec![];
|
||||
for item in &json_box.items {
|
||||
items.push(WinningConfigItem {
|
||||
safety_deposit_box_index: item.safety_deposit_box_index,
|
||||
amount: item.amount,
|
||||
winning_config_type: match item.winning_config_type {
|
||||
0 => WinningConfigType::TokenOnlyTransfer,
|
||||
1 => WinningConfigType::FullRightsTransfer,
|
||||
2 => WinningConfigType::Printing,
|
||||
_ => WinningConfigType::TokenOnlyTransfer,
|
||||
},
|
||||
})
|
||||
}
|
||||
parsed_winning_configs.push(WinningConfig { items })
|
||||
}
|
||||
|
||||
let settings = AuctionManagerSettings {
|
||||
winning_configs: parsed_winning_configs,
|
||||
participation_config: match &json_settings.participation_config {
|
||||
Some(val) => Some(ParticipationConfig {
|
||||
winner_constraint: match val.winner_constraint {
|
||||
0 => WinningConstraint::NoParticipationPrize,
|
||||
1 => WinningConstraint::ParticipationPrizeGiven,
|
||||
_ => WinningConstraint::NoParticipationPrize,
|
||||
},
|
||||
non_winning_constraint: match val.non_winning_constraint {
|
||||
0 => NonWinningConstraint::NoParticipationPrize,
|
||||
1 => NonWinningConstraint::GivenForFixedPrice,
|
||||
2 => NonWinningConstraint::GivenForBidPrice,
|
||||
_ => NonWinningConstraint::NoParticipationPrize,
|
||||
},
|
||||
safety_deposit_box_index: val.safety_deposit_box_index,
|
||||
fixed_price: val.fixed_price,
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
};
|
||||
|
||||
(settings, json_settings)
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
use {
|
||||
crate::PROGRAM_PUBKEY,
|
||||
clap::ArgMatches,
|
||||
solana_clap_utils::input_parsers::pubkey_of,
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_program::borsh::try_from_slice_unchecked,
|
||||
solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
},
|
||||
spl_metaplex::instruction::create_start_auction_instruction,
|
||||
spl_metaplex::state::AuctionManager,
|
||||
std::str::FromStr,
|
||||
};
|
||||
|
||||
pub fn send_start_auction(app_matches: &ArgMatches, payer: Keypair, client: RpcClient) {
|
||||
let program_key = Pubkey::from_str(PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
let authority = read_keypair_file(
|
||||
app_matches
|
||||
.value_of("authority")
|
||||
.unwrap_or_else(|| app_matches.value_of("keypair").unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let auction_manager_key = pubkey_of(app_matches, "auction_manager").unwrap();
|
||||
|
||||
let account = client.get_account(&auction_manager_key).unwrap();
|
||||
let manager: AuctionManager = try_from_slice_unchecked(&account.data).unwrap();
|
||||
let instructions = [create_start_auction_instruction(
|
||||
program_key,
|
||||
auction_manager_key,
|
||||
manager.auction,
|
||||
authority.pubkey(),
|
||||
manager.store,
|
||||
)];
|
||||
|
||||
let signers = [&payer];
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
|
||||
println!("Started auction.");
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
use {
|
||||
crate::{settings_utils::parse_metadata_keys, PROGRAM_PUBKEY, VAULT_PROGRAM_PUBKEY},
|
||||
arrayref::array_ref,
|
||||
clap::ArgMatches,
|
||||
solana_clap_utils::input_parsers::pubkey_of,
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_program::borsh::try_from_slice_unchecked,
|
||||
solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
},
|
||||
spl_metaplex::{
|
||||
instruction::create_validate_safety_deposit_box_instruction,
|
||||
state::{AuctionManager, WinningConfig},
|
||||
},
|
||||
spl_token_metadata::state::{Key, MasterEdition, EDITION},
|
||||
spl_token_vault::state::{Key as VaultKey, SafetyDepositBox},
|
||||
std::{collections::HashMap, str::FromStr},
|
||||
};
|
||||
|
||||
pub fn validate_safety_deposits(app_matches: &ArgMatches, payer: Keypair, client: RpcClient) {
|
||||
let program_key = Pubkey::from_str(PROGRAM_PUBKEY).unwrap();
|
||||
let vault_program_key = Pubkey::from_str(VAULT_PROGRAM_PUBKEY).unwrap();
|
||||
let token_metadata_key = spl_token_metadata::id();
|
||||
let admin = read_keypair_file(
|
||||
app_matches
|
||||
.value_of("admin")
|
||||
.unwrap_or_else(|| app_matches.value_of("keypair").unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let admin_key = admin.pubkey();
|
||||
let store_seeds = &[
|
||||
spl_metaplex::state::PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
&admin_key.as_ref(),
|
||||
];
|
||||
let (store_key, _) = Pubkey::find_program_address(store_seeds, &program_key);
|
||||
|
||||
let authority = read_keypair_file(
|
||||
app_matches
|
||||
.value_of("authority")
|
||||
.unwrap_or_else(|| app_matches.value_of("keypair").unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
let metadata_authority = read_keypair_file(
|
||||
app_matches
|
||||
.value_of("metadata_authority")
|
||||
.unwrap_or_else(|| app_matches.value_of("keypair").unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
let auction_manager_key = pubkey_of(app_matches, "auction_manager").unwrap();
|
||||
let mint_map = parse_metadata_keys(&(auction_manager_key.to_string() + ".json"));
|
||||
|
||||
let account = client.get_account(&auction_manager_key).unwrap();
|
||||
let manager: AuctionManager = try_from_slice_unchecked(&account.data).unwrap();
|
||||
let all_vault_accounts = client.get_program_accounts(&vault_program_key).unwrap();
|
||||
|
||||
let mut safety_deposits = HashMap::new();
|
||||
|
||||
for acc in &all_vault_accounts {
|
||||
let obj = &acc.1;
|
||||
let obj_key = &acc.0;
|
||||
let type_of_obj = obj.data[0];
|
||||
|
||||
if type_of_obj == VaultKey::SafetyDepositBoxV1 as u8 {
|
||||
let pubkey_arr = array_ref![obj.data, 1, 32];
|
||||
let pubkey = Pubkey::new_from_array(*pubkey_arr);
|
||||
if pubkey == manager.vault {
|
||||
let safety_deposit: SafetyDepositBox = try_from_slice_unchecked(&obj.data).unwrap();
|
||||
safety_deposits.insert(safety_deposit.order, (safety_deposit, *obj_key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let winner_config_slot = app_matches
|
||||
.value_of("winner_config_slot")
|
||||
.unwrap_or("-1")
|
||||
.parse::<i64>()
|
||||
.unwrap();
|
||||
|
||||
let mut configs_to_validate: Vec<&WinningConfig> = vec![];
|
||||
|
||||
if winner_config_slot == -1 {
|
||||
for config in &manager.settings.winning_configs {
|
||||
configs_to_validate.push(config);
|
||||
}
|
||||
} else {
|
||||
configs_to_validate.push(&manager.settings.winning_configs[winner_config_slot as usize]);
|
||||
}
|
||||
|
||||
for n in 0..configs_to_validate.len() {
|
||||
let config = &configs_to_validate[n];
|
||||
for item in &config.items {
|
||||
let (config_box, box_key) =
|
||||
safety_deposits.get(&item.safety_deposit_box_index).unwrap();
|
||||
|
||||
let metadata_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
&token_metadata_key.as_ref(),
|
||||
&mint_map[n].as_ref(),
|
||||
];
|
||||
let (metadata_key, _) =
|
||||
Pubkey::find_program_address(metadata_seeds, &token_metadata_key);
|
||||
|
||||
let edition_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
&token_metadata_key.as_ref(),
|
||||
mint_map[n].as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
];
|
||||
let (edition_key, _) = Pubkey::find_program_address(edition_seeds, &token_metadata_key);
|
||||
|
||||
let original_authority_seeds = &[
|
||||
spl_metaplex::state::PREFIX.as_bytes(),
|
||||
manager.auction.as_ref(),
|
||||
metadata_key.as_ref(),
|
||||
];
|
||||
let (original_authority_key, _) =
|
||||
Pubkey::find_program_address(original_authority_seeds, &program_key);
|
||||
|
||||
let master_edition_account = client.get_account(&edition_key);
|
||||
let edition_printing_mint: Option<Pubkey>;
|
||||
let edition_printing_mint_authority: Option<Pubkey>;
|
||||
match master_edition_account {
|
||||
Ok(acct) => {
|
||||
if acct.data[0] == Key::MasterEditionV1 as u8 {
|
||||
let master_edition: MasterEdition =
|
||||
try_from_slice_unchecked(&acct.data).unwrap();
|
||||
edition_printing_mint = Some(master_edition.printing_mint);
|
||||
edition_printing_mint_authority = Some(payer.pubkey());
|
||||
} else {
|
||||
edition_printing_mint = None;
|
||||
edition_printing_mint_authority = None;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
edition_printing_mint = None;
|
||||
edition_printing_mint_authority = None;
|
||||
}
|
||||
}
|
||||
|
||||
let instructions = [create_validate_safety_deposit_box_instruction(
|
||||
program_key,
|
||||
auction_manager_key,
|
||||
metadata_key,
|
||||
original_authority_key,
|
||||
solana_program::system_program::id(),
|
||||
store_key,
|
||||
*box_key,
|
||||
config_box.store,
|
||||
config_box.token_mint,
|
||||
edition_key,
|
||||
manager.vault,
|
||||
authority.pubkey(),
|
||||
metadata_authority.pubkey(),
|
||||
payer.pubkey(),
|
||||
edition_printing_mint,
|
||||
edition_printing_mint_authority,
|
||||
)];
|
||||
|
||||
let signers = [&payer, &authority, &metadata_authority];
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
|
||||
println!("Validated safety deposit box {:?} which contained token account {:?} in winning slot {:?}", box_key, config_box.store, n);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,644 +0,0 @@
|
|||
use {
|
||||
crate::{TOKEN_PROGRAM_PUBKEY, VAULT_PROGRAM_PUBKEY},
|
||||
solana_client::rpc_client::RpcClient,
|
||||
solana_program::{borsh::try_from_slice_unchecked, program_pack::Pack},
|
||||
solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
system_instruction::create_account,
|
||||
transaction::Transaction,
|
||||
},
|
||||
spl_token::{
|
||||
instruction::{approve, initialize_account, initialize_mint, mint_to},
|
||||
state::{Account, Mint},
|
||||
},
|
||||
spl_token_metadata::{
|
||||
instruction::{create_master_edition, create_metadata_accounts},
|
||||
state::EDITION,
|
||||
},
|
||||
spl_token_vault::{
|
||||
instruction::{
|
||||
create_activate_vault_instruction, create_add_token_to_inactive_vault_instruction,
|
||||
create_combine_vault_instruction, create_init_vault_instruction,
|
||||
},
|
||||
state::{ExternalPriceAccount, Vault, VaultState, MAX_VAULT_SIZE},
|
||||
},
|
||||
std::str::FromStr,
|
||||
};
|
||||
|
||||
#[allow(clippy::clone_on_copy)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn add_token_to_vault(
|
||||
vault_authority: &Keypair,
|
||||
vault_key: &Pubkey,
|
||||
payer: &Keypair,
|
||||
client: &RpcClient,
|
||||
amount: u64,
|
||||
existing_mint: Option<Pubkey>,
|
||||
existing_account: Option<Pubkey>,
|
||||
is_master_edition: bool,
|
||||
token_supply: Option<u64>,
|
||||
is_participation: bool,
|
||||
) -> (Pubkey, Pubkey, Pubkey) {
|
||||
let program_key = Pubkey::from_str(VAULT_PROGRAM_PUBKEY).unwrap();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
let store = Keypair::new();
|
||||
let mut instructions = vec![];
|
||||
let signers = vec![payer, &store];
|
||||
let token_mint = Keypair::new();
|
||||
|
||||
let mint_key = match existing_mint {
|
||||
None => {
|
||||
// Due to txn size limits, need to do this in a separate one.
|
||||
let create_signers = [&payer, &token_mint];
|
||||
let create_mint_instructions = [
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&token_mint.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Mint::LEN)
|
||||
.unwrap(),
|
||||
Mint::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
initialize_mint(
|
||||
&token_key,
|
||||
&token_mint.pubkey(),
|
||||
&payer.pubkey(),
|
||||
Some(&payer.pubkey()),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
];
|
||||
let mut transaction =
|
||||
Transaction::new_with_payer(&create_mint_instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
transaction.sign(&create_signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
token_mint.pubkey()
|
||||
}
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
// The Printing mint needs to be the store type if we're doing limited editions since we're actually
|
||||
// handing out authorization tokens
|
||||
let printing_mint = Keypair::new();
|
||||
let one_time_printing_authorization_mint = Keypair::new();
|
||||
let store_mint_key = match token_supply {
|
||||
Some(_) => printing_mint.pubkey(),
|
||||
None => mint_key,
|
||||
};
|
||||
|
||||
let seeds = &[
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
&vault_key.as_ref(),
|
||||
&store_mint_key.as_ref(),
|
||||
];
|
||||
let (safety_deposit_box, _) = Pubkey::find_program_address(seeds, &program_key);
|
||||
let seeds = &[
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
];
|
||||
let (authority, _) = Pubkey::find_program_address(seeds, &program_key);
|
||||
let token_metadata = spl_token_metadata::id();
|
||||
let metadata_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
&token_metadata.as_ref(),
|
||||
&mint_key.as_ref(),
|
||||
];
|
||||
let (metadata_key, _) = Pubkey::find_program_address(metadata_seeds, &spl_token_metadata::id());
|
||||
|
||||
let edition_seeds = &[
|
||||
spl_token_metadata::state::PREFIX.as_bytes(),
|
||||
&token_metadata.as_ref(),
|
||||
mint_key.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
];
|
||||
let (edition_key, _) = Pubkey::find_program_address(edition_seeds, &spl_token_metadata::id());
|
||||
|
||||
let token_account = Keypair::new();
|
||||
|
||||
let token_account_key = match existing_account {
|
||||
None => {
|
||||
instructions.push(create_metadata_accounts(
|
||||
spl_token_metadata::id(),
|
||||
metadata_key,
|
||||
mint_key,
|
||||
payer.pubkey(),
|
||||
payer.pubkey(),
|
||||
payer.pubkey(),
|
||||
"no".to_owned(),
|
||||
"name".to_owned(),
|
||||
"www.none.com".to_owned(),
|
||||
None,
|
||||
0,
|
||||
true,
|
||||
false,
|
||||
));
|
||||
if is_master_edition {
|
||||
let master_signers = [
|
||||
&payer,
|
||||
&printing_mint,
|
||||
&one_time_printing_authorization_mint,
|
||||
];
|
||||
let master_account_instructions = [
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&printing_mint.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Mint::LEN)
|
||||
.unwrap(),
|
||||
Mint::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
initialize_mint(
|
||||
&token_key,
|
||||
&printing_mint.pubkey(),
|
||||
&payer.pubkey(),
|
||||
Some(&payer.pubkey()),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&one_time_printing_authorization_mint.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Mint::LEN)
|
||||
.unwrap(),
|
||||
Mint::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
initialize_mint(
|
||||
&token_key,
|
||||
&one_time_printing_authorization_mint.pubkey(),
|
||||
&payer.pubkey(),
|
||||
Some(&payer.pubkey()),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
];
|
||||
|
||||
let mut master_transaction = Transaction::new_with_payer(
|
||||
&master_account_instructions,
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
master_transaction.sign(&master_signers, recent_blockhash);
|
||||
client
|
||||
.send_and_confirm_transaction(&master_transaction)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let token_account_mint = match token_supply {
|
||||
Some(_) => {
|
||||
if is_participation {
|
||||
one_time_printing_authorization_mint.pubkey()
|
||||
} else {
|
||||
printing_mint.pubkey()
|
||||
}
|
||||
}
|
||||
None => mint_key,
|
||||
};
|
||||
|
||||
// Due to txn size limits, need to do this in a separate one.
|
||||
let mut create_signers = vec![payer, &token_account];
|
||||
let mut create_account_instructions = vec![
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&token_account.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&token_account.pubkey(),
|
||||
&token_account_mint,
|
||||
&payer.pubkey(),
|
||||
)
|
||||
.unwrap(),
|
||||
];
|
||||
|
||||
let extra_real_token_acct = Keypair::new();
|
||||
if token_supply.is_some() {
|
||||
create_signers.push(&extra_real_token_acct);
|
||||
// means the token account above is actually a Printing mint account, we need a separate account to have
|
||||
// at least one of the main token type in it.
|
||||
create_account_instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&extra_real_token_acct.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
create_account_instructions.push(
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&extra_real_token_acct.pubkey(),
|
||||
&mint_key,
|
||||
&payer.pubkey(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
create_account_instructions.push(
|
||||
mint_to(
|
||||
&token_key,
|
||||
&mint_key,
|
||||
&extra_real_token_acct.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
1,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
} else {
|
||||
// we just need to mint the tokens to this account because we're going to transfer tokens
|
||||
// out of it.
|
||||
create_account_instructions.push(
|
||||
mint_to(
|
||||
&token_key,
|
||||
&mint_key,
|
||||
&token_account.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
amount,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
let mut transaction =
|
||||
Transaction::new_with_payer(&create_account_instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
transaction.sign(&create_signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
if is_master_edition {
|
||||
let one_time_printing_authorization_mint_authority: Option<Pubkey> =
|
||||
match token_supply {
|
||||
Some(_) => Some(payer.pubkey()),
|
||||
None => None,
|
||||
};
|
||||
instructions.push(create_master_edition(
|
||||
spl_token_metadata::id(),
|
||||
edition_key,
|
||||
mint_key,
|
||||
printing_mint.pubkey(),
|
||||
one_time_printing_authorization_mint.pubkey(),
|
||||
payer.pubkey(),
|
||||
payer.pubkey(),
|
||||
payer.pubkey(),
|
||||
metadata_key,
|
||||
payer.pubkey(),
|
||||
token_supply,
|
||||
one_time_printing_authorization_mint_authority,
|
||||
));
|
||||
}
|
||||
token_account.pubkey()
|
||||
}
|
||||
Some(val) => val,
|
||||
};
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&store.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
|
||||
instructions.push(
|
||||
initialize_account(&token_key, &store.pubkey(), &store_mint_key, &authority).unwrap(),
|
||||
);
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
let transfer_authority = Keypair::new();
|
||||
let token_instructions = vec![
|
||||
approve(
|
||||
&token_key,
|
||||
&token_account_key,
|
||||
&transfer_authority.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
amount,
|
||||
)
|
||||
.unwrap(),
|
||||
create_add_token_to_inactive_vault_instruction(
|
||||
program_key,
|
||||
safety_deposit_box,
|
||||
token_account_key,
|
||||
store.pubkey(),
|
||||
vault_key.clone(),
|
||||
vault_authority.pubkey(),
|
||||
payer.pubkey(),
|
||||
transfer_authority.pubkey(),
|
||||
amount,
|
||||
),
|
||||
];
|
||||
|
||||
let token_signers = vec![payer, &transfer_authority];
|
||||
|
||||
let mut token_transaction =
|
||||
Transaction::new_with_payer(&token_instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
token_transaction.sign(&token_signers, recent_blockhash);
|
||||
client
|
||||
.send_and_confirm_transaction(&token_transaction)
|
||||
.unwrap();
|
||||
let _account = client.get_account(&safety_deposit_box).unwrap();
|
||||
(safety_deposit_box, mint_key, store.pubkey())
|
||||
}
|
||||
|
||||
pub fn activate_vault(
|
||||
vault_authority: &Keypair,
|
||||
vault_key: &Pubkey,
|
||||
payer: &Keypair,
|
||||
client: &RpcClient,
|
||||
) -> Option<Pubkey> {
|
||||
let program_key = Pubkey::from_str(VAULT_PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
let number_of_shares: u64 = 0;
|
||||
let vault_account = client.get_account(&vault_key).unwrap();
|
||||
let vault: Vault = try_from_slice_unchecked(&vault_account.data).unwrap();
|
||||
|
||||
let seeds = &[
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
];
|
||||
let (mint_authority, _) = Pubkey::find_program_address(seeds, &program_key);
|
||||
|
||||
let instructions = [create_activate_vault_instruction(
|
||||
program_key,
|
||||
*vault_key,
|
||||
vault.fraction_mint,
|
||||
vault.fraction_treasury,
|
||||
mint_authority,
|
||||
vault_authority.pubkey(),
|
||||
number_of_shares,
|
||||
)];
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
let signers = vec![payer, &vault_authority];
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
let updated_vault_data = client.get_account(&vault_key).unwrap();
|
||||
let updated_vault: Vault = try_from_slice_unchecked(&updated_vault_data.data).unwrap();
|
||||
if updated_vault.state == VaultState::Active {
|
||||
Some(*vault_key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn combine_vault(
|
||||
vault_authority: &Keypair,
|
||||
new_vault_authority: &Pubkey,
|
||||
vault_key: &Pubkey,
|
||||
payer: &Keypair,
|
||||
client: &RpcClient,
|
||||
) -> Option<Pubkey> {
|
||||
let program_key = Pubkey::from_str(VAULT_PROGRAM_PUBKEY).unwrap();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
let amount_of_money = 0;
|
||||
let vault_account = client.get_account(&vault_key).unwrap();
|
||||
let vault: Vault = try_from_slice_unchecked(&vault_account.data).unwrap();
|
||||
let external_price_account = client.get_account(&vault.pricing_lookup_address).unwrap();
|
||||
let external: ExternalPriceAccount =
|
||||
try_from_slice_unchecked(&external_price_account.data).unwrap();
|
||||
let payment_account = Keypair::new();
|
||||
|
||||
let seeds = &[
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
];
|
||||
let (uncirculated_burn_authority, _) = Pubkey::find_program_address(seeds, &program_key);
|
||||
|
||||
let transfer_authority = Keypair::new();
|
||||
let mut signers = vec![
|
||||
payer,
|
||||
&vault_authority,
|
||||
&payment_account,
|
||||
&transfer_authority,
|
||||
];
|
||||
|
||||
let mut instructions = vec![
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&payment_account.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&payment_account.pubkey(),
|
||||
&external.price_mint,
|
||||
&payer.pubkey(),
|
||||
)
|
||||
.unwrap(),
|
||||
mint_to(
|
||||
&token_key,
|
||||
&external.price_mint,
|
||||
&payment_account.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
amount_of_money,
|
||||
)
|
||||
.unwrap(),
|
||||
approve(
|
||||
&token_key,
|
||||
&payment_account.pubkey(),
|
||||
&transfer_authority.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
amount_of_money,
|
||||
)
|
||||
.unwrap(),
|
||||
];
|
||||
|
||||
let shares_outstanding: u64 = 0;
|
||||
let outstanding_shares_account = Keypair::new();
|
||||
|
||||
// We make an empty oustanding share account if one is not provided.
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&outstanding_shares_account.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&outstanding_shares_account.pubkey(),
|
||||
&vault.fraction_mint,
|
||||
&payer.pubkey(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
signers.push(&outstanding_shares_account);
|
||||
|
||||
instructions.push(
|
||||
approve(
|
||||
&token_key,
|
||||
&outstanding_shares_account.pubkey(),
|
||||
&transfer_authority.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
shares_outstanding,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(create_combine_vault_instruction(
|
||||
program_key,
|
||||
*vault_key,
|
||||
outstanding_shares_account.pubkey(),
|
||||
payment_account.pubkey(),
|
||||
vault.fraction_mint,
|
||||
vault.fraction_treasury,
|
||||
vault.redeem_treasury,
|
||||
*new_vault_authority,
|
||||
vault_authority.pubkey(),
|
||||
transfer_authority.pubkey(),
|
||||
uncirculated_burn_authority,
|
||||
vault.pricing_lookup_address,
|
||||
));
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
let updated_vault_data = client.get_account(&vault_key).unwrap();
|
||||
let updated_vault: Vault = try_from_slice_unchecked(&updated_vault_data.data).unwrap();
|
||||
if updated_vault.state == VaultState::Combined {
|
||||
Some(*vault_key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_vault(
|
||||
vault_authority: &Keypair,
|
||||
external_key: &Pubkey,
|
||||
payer: &Keypair,
|
||||
client: &RpcClient,
|
||||
) -> Pubkey {
|
||||
let program_key = Pubkey::from_str(VAULT_PROGRAM_PUBKEY).unwrap();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
let external_account = client.get_account(&external_key).unwrap();
|
||||
let external: ExternalPriceAccount = try_from_slice_unchecked(&external_account.data).unwrap();
|
||||
let fraction_mint = Keypair::new();
|
||||
let redeem_mint = external.price_mint;
|
||||
let redeem_treasury = Keypair::new();
|
||||
let fraction_treasury = Keypair::new();
|
||||
let vault = Keypair::new();
|
||||
let allow_further_share_creation = false;
|
||||
|
||||
let seeds = &[
|
||||
spl_token_vault::state::PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
];
|
||||
let (authority, _) = Pubkey::find_program_address(seeds, &program_key);
|
||||
|
||||
let instructions = [
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&fraction_mint.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Mint::LEN)
|
||||
.unwrap(),
|
||||
Mint::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&redeem_treasury.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&fraction_treasury.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
),
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
&vault.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(MAX_VAULT_SIZE)
|
||||
.unwrap(),
|
||||
MAX_VAULT_SIZE as u64,
|
||||
&program_key,
|
||||
),
|
||||
initialize_mint(
|
||||
&token_key,
|
||||
&fraction_mint.pubkey(),
|
||||
&authority,
|
||||
Some(&authority),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&redeem_treasury.pubkey(),
|
||||
&redeem_mint,
|
||||
&authority,
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&fraction_treasury.pubkey(),
|
||||
&fraction_mint.pubkey(),
|
||||
&authority,
|
||||
)
|
||||
.unwrap(),
|
||||
create_init_vault_instruction(
|
||||
program_key,
|
||||
fraction_mint.pubkey(),
|
||||
redeem_treasury.pubkey(),
|
||||
fraction_treasury.pubkey(),
|
||||
vault.pubkey(),
|
||||
vault_authority.pubkey(),
|
||||
*external_key,
|
||||
allow_further_share_creation,
|
||||
),
|
||||
];
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
let signers = vec![
|
||||
payer,
|
||||
&redeem_treasury,
|
||||
&fraction_treasury,
|
||||
&fraction_mint,
|
||||
&vault,
|
||||
];
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
let _account = client.get_account(&vault.pubkey()).unwrap();
|
||||
vault.pubkey()
|
||||
}
|
|
@ -14,8 +14,10 @@ test-bpf = []
|
|||
|
||||
[dependencies]
|
||||
num-derive = "0.3"
|
||||
arrayref = "0.3.6"
|
||||
num-traits = "0.2"
|
||||
solana-program = "1.6.10"
|
||||
spl-token-vault = { path = "../../token-vault/program", features = [ "no-entrypoint" ] }
|
||||
spl-token = { version="3.1.1", features = [ "no-entrypoint" ] }
|
||||
thiserror = "1.0"
|
||||
borsh = "0.8.2"
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
use {
|
||||
crate::{
|
||||
instruction::{CreateMasterEditionArgs, MetadataInstruction},
|
||||
state::Reservation,
|
||||
},
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
solana_program::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
pub struct MintPrintingTokensViaTokenArgs {
|
||||
pub supply: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
pub struct SetReservationListArgs {
|
||||
/// If set, means that no more than this number of editions can ever be minted. This is immutable.
|
||||
pub reservations: Vec<Reservation>,
|
||||
/// should only be present on the very first call to set reservation list.
|
||||
pub total_reservation_spots: Option<u64>,
|
||||
/// Where in the reservation list you want to insert this slice of reservations
|
||||
pub offset: u64,
|
||||
/// What the total spot offset is in the reservation list from the beginning to your slice of reservations.
|
||||
/// So if is going to be 4 total editions eventually reserved between your slice and the beginning of the array,
|
||||
/// split between 2 reservation entries, the offset variable above would be "2" since you start at entry 2 in 0 indexed array
|
||||
/// (first 2 taking 0 and 1) and because they each have 2 spots taken, this variable would be 4.
|
||||
pub total_spot_offset: u64,
|
||||
}
|
||||
|
||||
/// creates a create_master_edition instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn deprecated_create_master_edition(
|
||||
program_id: Pubkey,
|
||||
edition: Pubkey,
|
||||
mint: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
one_time_printing_authorization_mint: Pubkey,
|
||||
update_authority: Pubkey,
|
||||
printing_mint_authority: Pubkey,
|
||||
mint_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
payer: Pubkey,
|
||||
max_supply: Option<u64>,
|
||||
one_time_printing_authorization_mint_authority: Option<Pubkey>,
|
||||
) -> Instruction {
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new(edition, false),
|
||||
AccountMeta::new(mint, false),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new(one_time_printing_authorization_mint, false),
|
||||
AccountMeta::new_readonly(update_authority, true),
|
||||
AccountMeta::new_readonly(printing_mint_authority, true),
|
||||
AccountMeta::new_readonly(mint_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(payer, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
];
|
||||
|
||||
if let Some(auth) = one_time_printing_authorization_mint_authority {
|
||||
accounts.push(AccountMeta::new_readonly(auth, true));
|
||||
}
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetadataInstruction::DeprecatedCreateMasterEdition(CreateMasterEditionArgs {
|
||||
max_supply,
|
||||
})
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates a mint_new_edition_from_master_edition instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn deprecated_mint_new_edition_from_master_edition_via_printing_token(
|
||||
program_id: Pubkey,
|
||||
metadata: Pubkey,
|
||||
edition: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
mint: Pubkey,
|
||||
mint_authority: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
master_token_account: Pubkey,
|
||||
burn_authority: Pubkey,
|
||||
payer: Pubkey,
|
||||
master_update_authority: Pubkey,
|
||||
master_metadata: Pubkey,
|
||||
reservation_list: Option<Pubkey>,
|
||||
) -> Instruction {
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new(metadata, false),
|
||||
AccountMeta::new(edition, false),
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(mint, false),
|
||||
AccountMeta::new_readonly(mint_authority, true),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new(master_token_account, false),
|
||||
AccountMeta::new_readonly(burn_authority, true),
|
||||
AccountMeta::new(payer, true),
|
||||
AccountMeta::new_readonly(master_update_authority, true),
|
||||
AccountMeta::new_readonly(master_metadata, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
];
|
||||
|
||||
if let Some(list) = reservation_list {
|
||||
accounts.push(AccountMeta::new_readonly(list, false))
|
||||
}
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetadataInstruction::DeprecatedMintNewEditionFromMasterEditionViaPrintingToken
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates an set_reservation_list instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn deprecated_set_reservation_list(
|
||||
program_id: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
reservation_list: Pubkey,
|
||||
resource: Pubkey,
|
||||
reservations: Vec<Reservation>,
|
||||
total_reservation_spots: Option<u64>,
|
||||
offset: u64,
|
||||
total_spot_offset: u64,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(reservation_list, false),
|
||||
AccountMeta::new_readonly(resource, true),
|
||||
],
|
||||
data: MetadataInstruction::DeprecatedSetReservationList(SetReservationListArgs {
|
||||
reservations,
|
||||
total_reservation_spots,
|
||||
offset,
|
||||
total_spot_offset,
|
||||
})
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates an create_reservation_list instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn deprecated_create_reservation_list(
|
||||
program_id: Pubkey,
|
||||
reservation_list: Pubkey,
|
||||
payer: Pubkey,
|
||||
update_authority: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
resource: Pubkey,
|
||||
metadata: Pubkey,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(reservation_list, false),
|
||||
AccountMeta::new_readonly(payer, true),
|
||||
AccountMeta::new_readonly(update_authority, true),
|
||||
AccountMeta::new_readonly(master_edition, false),
|
||||
AccountMeta::new_readonly(resource, false),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetadataInstruction::DeprecatedCreateReservationList
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates an mint_printing_tokens_via_token instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn deprecated_mint_printing_tokens_via_token(
|
||||
program_id: Pubkey,
|
||||
destination: Pubkey,
|
||||
token: Pubkey,
|
||||
one_time_printing_authorization_mint: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
burn_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
supply: u64,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(destination, false),
|
||||
AccountMeta::new(token, false),
|
||||
AccountMeta::new(one_time_printing_authorization_mint, false),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new_readonly(burn_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(master_edition, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetadataInstruction::DeprecatedMintPrintingTokensViaToken(
|
||||
MintPrintingTokensViaTokenArgs { supply },
|
||||
)
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates an mint_printing_tokens instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn deprecated_mint_printing_tokens(
|
||||
program_id: Pubkey,
|
||||
destination: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
update_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
supply: u64,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(destination, false),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new_readonly(update_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(master_edition, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetadataInstruction::DeprecatedMintPrintingTokens(MintPrintingTokensViaTokenArgs {
|
||||
supply,
|
||||
})
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,588 @@
|
|||
use solana_program::msg;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
error::MetadataError,
|
||||
state::{
|
||||
get_reservation_list, Key, MasterEditionV1, Metadata, Reservation, ReservationListV2,
|
||||
EDITION, MAX_MASTER_EDITION_LEN, MAX_RESERVATIONS, MAX_RESERVATION_LIST_SIZE, PREFIX,
|
||||
RESERVATION,
|
||||
},
|
||||
utils::{
|
||||
assert_derivation, assert_initialized, assert_mint_authority_matches_mint,
|
||||
assert_owned_by, assert_rent_exempt, assert_signer, assert_supply_invariance,
|
||||
assert_token_program_matches_package, assert_update_authority_is_correct,
|
||||
create_or_allocate_account_raw, mint_limited_edition, spl_token_burn,
|
||||
spl_token_mint_to, transfer_mint_authority, TokenBurnParams, TokenMintToParams,
|
||||
},
|
||||
},
|
||||
borsh::BorshSerialize,
|
||||
solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
sysvar::Sysvar,
|
||||
},
|
||||
spl_token::state::{Account, Mint},
|
||||
};
|
||||
|
||||
/// Create master edition
|
||||
pub fn process_deprecated_create_master_edition(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
max_supply: Option<u64>,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let edition_account_info = next_account_info(account_info_iter)?;
|
||||
let mint_info = next_account_info(account_info_iter)?;
|
||||
let printing_mint_info = next_account_info(account_info_iter)?;
|
||||
let one_time_printing_authorization_mint_info = next_account_info(account_info_iter)?;
|
||||
let update_authority_info = next_account_info(account_info_iter)?;
|
||||
let printing_mint_authority_info = next_account_info(account_info_iter)?;
|
||||
let mint_authority_info = next_account_info(account_info_iter)?;
|
||||
let metadata_account_info = next_account_info(account_info_iter)?;
|
||||
let payer_account_info = next_account_info(account_info_iter)?;
|
||||
let token_program_info = next_account_info(account_info_iter)?;
|
||||
let system_account_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let metadata = Metadata::from_account_info(metadata_account_info)?;
|
||||
let mint: Mint = assert_initialized(mint_info)?;
|
||||
let printing_mint: Mint = assert_initialized(printing_mint_info)?;
|
||||
let one_time_printing_authorization_mint: Mint =
|
||||
assert_initialized(one_time_printing_authorization_mint_info)?;
|
||||
|
||||
let bump_seed = assert_derivation(
|
||||
program_id,
|
||||
edition_account_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
&mint_info.key.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
assert_token_program_matches_package(token_program_info)?;
|
||||
assert_mint_authority_matches_mint(&mint.mint_authority, mint_authority_info)?;
|
||||
assert_mint_authority_matches_mint(
|
||||
&printing_mint.mint_authority,
|
||||
printing_mint_authority_info,
|
||||
)?;
|
||||
assert_mint_authority_matches_mint(
|
||||
&one_time_printing_authorization_mint.mint_authority,
|
||||
mint_authority_info,
|
||||
)?;
|
||||
assert_owned_by(metadata_account_info, program_id)?;
|
||||
assert_owned_by(mint_info, &spl_token::id())?;
|
||||
assert_owned_by(printing_mint_info, &spl_token::id())?;
|
||||
assert_owned_by(one_time_printing_authorization_mint_info, &spl_token::id())?;
|
||||
|
||||
if metadata.mint != *mint_info.key {
|
||||
return Err(MetadataError::MintMismatch.into());
|
||||
}
|
||||
|
||||
if printing_mint.decimals != 0 {
|
||||
return Err(MetadataError::PrintingMintDecimalsShouldBeZero.into());
|
||||
}
|
||||
|
||||
if one_time_printing_authorization_mint.decimals != 0 {
|
||||
return Err(MetadataError::OneTimePrintingAuthorizationMintDecimalsShouldBeZero.into());
|
||||
}
|
||||
|
||||
if mint.decimals != 0 {
|
||||
return Err(MetadataError::EditionMintDecimalsShouldBeZero.into());
|
||||
}
|
||||
|
||||
assert_update_authority_is_correct(&metadata, update_authority_info)?;
|
||||
|
||||
if mint.supply != 1 {
|
||||
return Err(MetadataError::EditionsMustHaveExactlyOneToken.into());
|
||||
}
|
||||
|
||||
let edition_authority_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
&mint_info.key.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
&[bump_seed],
|
||||
];
|
||||
|
||||
create_or_allocate_account_raw(
|
||||
*program_id,
|
||||
edition_account_info,
|
||||
rent_info,
|
||||
system_account_info,
|
||||
payer_account_info,
|
||||
MAX_MASTER_EDITION_LEN,
|
||||
edition_authority_seeds,
|
||||
)?;
|
||||
|
||||
let mut edition = MasterEditionV1::from_account_info(edition_account_info)?;
|
||||
|
||||
edition.key = Key::MasterEditionV1;
|
||||
edition.supply = 0;
|
||||
edition.max_supply = max_supply;
|
||||
edition.printing_mint = *printing_mint_info.key;
|
||||
edition.one_time_printing_authorization_mint = *one_time_printing_authorization_mint_info.key;
|
||||
edition.serialize(&mut *edition_account_info.data.borrow_mut())?;
|
||||
|
||||
// While you can't mint any more of your master record, you can
|
||||
// mint as many limited editions as you like, and coins to permission others
|
||||
// to mint one of them in the future.
|
||||
transfer_mint_authority(
|
||||
edition_account_info.key,
|
||||
edition_account_info,
|
||||
mint_info,
|
||||
mint_authority_info,
|
||||
token_program_info,
|
||||
)?;
|
||||
|
||||
// The program needs to own the printing mint to be able to print tokens via the one time printing auth
|
||||
// you can get tokens out of it as update authority via another call.
|
||||
transfer_mint_authority(
|
||||
edition_account_info.key,
|
||||
edition_account_info,
|
||||
printing_mint_info,
|
||||
printing_mint_authority_info,
|
||||
token_program_info,
|
||||
)?;
|
||||
|
||||
if max_supply.is_some() {
|
||||
// We need to enact limited supply protocol, take away one time printing too.
|
||||
let one_time_printing_authorization_mint_authority_info =
|
||||
next_account_info(account_info_iter)?;
|
||||
|
||||
transfer_mint_authority(
|
||||
&edition_account_info.key,
|
||||
edition_account_info,
|
||||
one_time_printing_authorization_mint_info,
|
||||
one_time_printing_authorization_mint_authority_info,
|
||||
token_program_info,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_deprecated_mint_new_edition_from_master_edition_via_printing_token<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let new_metadata_account_info = next_account_info(account_info_iter)?;
|
||||
let new_edition_account_info = next_account_info(account_info_iter)?;
|
||||
let master_edition_account_info = next_account_info(account_info_iter)?;
|
||||
let mint_info = next_account_info(account_info_iter)?;
|
||||
let mint_authority_info = next_account_info(account_info_iter)?;
|
||||
let printing_mint_info = next_account_info(account_info_iter)?;
|
||||
let master_token_account_info = next_account_info(account_info_iter)?;
|
||||
let burn_authority = next_account_info(account_info_iter)?;
|
||||
let payer_account_info = next_account_info(account_info_iter)?;
|
||||
let update_authority_info = next_account_info(account_info_iter)?;
|
||||
let master_metadata_account_info = next_account_info(account_info_iter)?;
|
||||
let token_program_account_info = next_account_info(account_info_iter)?;
|
||||
let system_account_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
let reservation_list_info = match next_account_info(account_info_iter) {
|
||||
Ok(account) => Some(account),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
assert_token_program_matches_package(token_program_account_info)?;
|
||||
assert_owned_by(mint_info, &spl_token::id())?;
|
||||
assert_owned_by(printing_mint_info, &spl_token::id())?;
|
||||
assert_owned_by(master_token_account_info, &spl_token::id())?;
|
||||
|
||||
if !new_metadata_account_info.data_is_empty() {
|
||||
return Err(MetadataError::AlreadyInitialized.into());
|
||||
}
|
||||
|
||||
if !new_edition_account_info.data_is_empty() {
|
||||
return Err(MetadataError::AlreadyInitialized.into());
|
||||
}
|
||||
|
||||
assert_owned_by(master_edition_account_info, program_id)?;
|
||||
assert_owned_by(master_metadata_account_info, program_id)?;
|
||||
if let Some(acct) = reservation_list_info {
|
||||
assert_owned_by(acct, program_id)?;
|
||||
}
|
||||
|
||||
let token_account: Account = assert_initialized(master_token_account_info)?;
|
||||
let master_edition = MasterEditionV1::from_account_info(master_edition_account_info)?;
|
||||
let master_metadata = Metadata::from_account_info(master_metadata_account_info)?;
|
||||
|
||||
if master_edition.printing_mint != *printing_mint_info.key {
|
||||
return Err(MetadataError::PrintingMintMismatch.into());
|
||||
}
|
||||
|
||||
if token_account.mint != *printing_mint_info.key {
|
||||
return Err(MetadataError::TokenAccountMintMismatch.into());
|
||||
}
|
||||
|
||||
if token_account.amount < 1 {
|
||||
return Err(MetadataError::NotEnoughTokens.into());
|
||||
}
|
||||
|
||||
spl_token_burn(TokenBurnParams {
|
||||
mint: printing_mint_info.clone(),
|
||||
source: master_token_account_info.clone(),
|
||||
amount: 1,
|
||||
authority: burn_authority.clone(),
|
||||
authority_signer_seeds: None,
|
||||
token_program: token_program_account_info.clone(),
|
||||
})?;
|
||||
|
||||
mint_limited_edition(
|
||||
program_id,
|
||||
master_metadata,
|
||||
new_metadata_account_info,
|
||||
new_edition_account_info,
|
||||
master_edition_account_info,
|
||||
mint_info,
|
||||
mint_authority_info,
|
||||
payer_account_info,
|
||||
update_authority_info,
|
||||
token_program_account_info,
|
||||
system_account_info,
|
||||
rent_info,
|
||||
reservation_list_info,
|
||||
None,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_deprecated_create_reservation_list(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let reservation_list_info = next_account_info(account_info_iter)?;
|
||||
let payer_info = next_account_info(account_info_iter)?;
|
||||
let update_authority_info = next_account_info(account_info_iter)?;
|
||||
let master_edition_info = next_account_info(account_info_iter)?;
|
||||
let resource_info = next_account_info(account_info_iter)?;
|
||||
let metadata_info = next_account_info(account_info_iter)?;
|
||||
let system_program_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
|
||||
assert_owned_by(master_edition_info, program_id)?;
|
||||
assert_owned_by(metadata_info, program_id)?;
|
||||
|
||||
let metadata = Metadata::from_account_info(metadata_info)?;
|
||||
assert_update_authority_is_correct(&metadata, update_authority_info)?;
|
||||
|
||||
if !reservation_list_info.data_is_empty() {
|
||||
return Err(MetadataError::ReservationExists.into());
|
||||
}
|
||||
|
||||
let bump = assert_derivation(
|
||||
program_id,
|
||||
reservation_list_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
master_edition_info.key.as_ref(),
|
||||
RESERVATION.as_bytes(),
|
||||
resource_info.key.as_ref(),
|
||||
],
|
||||
)?;
|
||||
|
||||
assert_derivation(
|
||||
program_id,
|
||||
master_edition_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
metadata.mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
master_edition_info.key.as_ref(),
|
||||
RESERVATION.as_bytes(),
|
||||
resource_info.key.as_ref(),
|
||||
&[bump],
|
||||
];
|
||||
|
||||
create_or_allocate_account_raw(
|
||||
*program_id,
|
||||
reservation_list_info,
|
||||
rent_info,
|
||||
system_program_info,
|
||||
payer_info,
|
||||
MAX_RESERVATION_LIST_SIZE,
|
||||
seeds,
|
||||
)?;
|
||||
let mut reservation = ReservationListV2::from_account_info(reservation_list_info)?;
|
||||
|
||||
reservation.key = Key::ReservationListV2;
|
||||
reservation.master_edition = *master_edition_info.key;
|
||||
reservation.supply_snapshot = None;
|
||||
reservation.reservations = vec![];
|
||||
|
||||
reservation.serialize(&mut *reservation_list_info.data.borrow_mut())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_deprecated_set_reservation_list(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
reservations: Vec<Reservation>,
|
||||
total_reservation_spots: Option<u64>,
|
||||
offset: u64,
|
||||
total_spot_offset: u64,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let master_edition_info = next_account_info(account_info_iter)?;
|
||||
let reservation_list_info = next_account_info(account_info_iter)?;
|
||||
let resource_info = next_account_info(account_info_iter)?;
|
||||
|
||||
assert_signer(resource_info)?;
|
||||
assert_owned_by(master_edition_info, program_id)?;
|
||||
assert_owned_by(reservation_list_info, program_id)?;
|
||||
|
||||
let mut master_edition = MasterEditionV1::from_account_info(master_edition_info)?;
|
||||
|
||||
if reservation_list_info.data_is_empty() {
|
||||
return Err(MetadataError::ReservationDoesNotExist.into());
|
||||
}
|
||||
|
||||
if reservations.len() > 1 || reservations.len() == 0 {
|
||||
return Err(MetadataError::ReservationArrayShouldBeSizeOne.into());
|
||||
}
|
||||
|
||||
let my_reservation = &reservations[0];
|
||||
|
||||
assert_derivation(
|
||||
program_id,
|
||||
reservation_list_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
master_edition_info.key.as_ref(),
|
||||
RESERVATION.as_bytes(),
|
||||
resource_info.key.as_ref(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let mut reservation_list = get_reservation_list(reservation_list_info)?;
|
||||
|
||||
if reservation_list.supply_snapshot().is_some() && total_reservation_spots.is_some() {
|
||||
return Err(MetadataError::ReservationAlreadyMade.into());
|
||||
}
|
||||
|
||||
if my_reservation.spots_remaining != my_reservation.total_spots {
|
||||
return Err(MetadataError::ReservationSpotsRemainingShouldMatchTotalSpotsAtStart.into());
|
||||
}
|
||||
|
||||
reservation_list.set_current_reservation_spots(
|
||||
reservation_list
|
||||
.current_reservation_spots()
|
||||
.checked_add(my_reservation.total_spots)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?,
|
||||
);
|
||||
|
||||
reservation_list.add_reservation(my_reservation.clone(), offset, total_spot_offset)?;
|
||||
|
||||
if let Some(total) = total_reservation_spots {
|
||||
reservation_list.set_supply_snapshot(Some(master_edition.supply));
|
||||
reservation_list.set_total_reservation_spots(total);
|
||||
master_edition.supply = master_edition
|
||||
.supply
|
||||
.checked_add(total as u64)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?;
|
||||
|
||||
if let Some(max_supply) = master_edition.max_supply {
|
||||
if master_edition.supply > max_supply {
|
||||
return Err(MetadataError::ReservationBreachesMaximumSupply.into());
|
||||
}
|
||||
}
|
||||
master_edition.serialize(&mut *master_edition_info.data.borrow_mut())?;
|
||||
}
|
||||
|
||||
if reservation_list.current_reservation_spots() > reservation_list.total_reservation_spots() {
|
||||
msg!("Beyond alotted address size but we're moratoriuming this due to some bad data that's been saved. Cant screw over users for 2 weeks.")
|
||||
//return Err(MetadataError::BeyondAlottedAddressSize.into());
|
||||
};
|
||||
|
||||
if reservation_list.reservations().len() > MAX_RESERVATIONS {
|
||||
return Err(MetadataError::BeyondMaxAddressSize.into());
|
||||
}
|
||||
|
||||
reservation_list.save(reservation_list_info)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_deprecated_mint_printing_tokens_via_token(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
supply: u64,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
||||
let destination_info = next_account_info(account_info_iter)?;
|
||||
let one_time_token_account_info = next_account_info(account_info_iter)?;
|
||||
let one_time_printing_authorization_mint_info = next_account_info(account_info_iter)?;
|
||||
let printing_mint_info = next_account_info(account_info_iter)?;
|
||||
let burn_authority_info = next_account_info(account_info_iter)?;
|
||||
let metadata_info = next_account_info(account_info_iter)?;
|
||||
let master_edition_info = next_account_info(account_info_iter)?;
|
||||
let token_program_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
let rent = &Rent::from_account_info(rent_info)?;
|
||||
|
||||
let destination: Account = assert_initialized(destination_info)?;
|
||||
let one_time_token_account: Account = assert_initialized(one_time_token_account_info)?;
|
||||
let master_edition = MasterEditionV1::from_account_info(master_edition_info)?;
|
||||
let metadata = Metadata::from_account_info(metadata_info)?;
|
||||
|
||||
let printing_mint: Mint = assert_initialized(printing_mint_info)?;
|
||||
|
||||
assert_supply_invariance(&master_edition, &printing_mint, supply)?;
|
||||
assert_token_program_matches_package(token_program_info)?;
|
||||
assert_rent_exempt(rent, destination_info)?;
|
||||
assert_owned_by(destination_info, &spl_token::id())?;
|
||||
assert_owned_by(one_time_token_account_info, &spl_token::id())?;
|
||||
assert_owned_by(one_time_printing_authorization_mint_info, &spl_token::id())?;
|
||||
assert_owned_by(printing_mint_info, &spl_token::id())?;
|
||||
assert_owned_by(metadata_info, program_id)?;
|
||||
assert_owned_by(master_edition_info, program_id)?;
|
||||
|
||||
if destination.mint != master_edition.printing_mint {
|
||||
return Err(MetadataError::DestinationMintMismatch.into());
|
||||
}
|
||||
|
||||
if one_time_token_account.mint != master_edition.one_time_printing_authorization_mint {
|
||||
return Err(MetadataError::TokenAccountOneTimeAuthMintMismatch.into());
|
||||
}
|
||||
|
||||
if one_time_token_account.amount == 0 {
|
||||
return Err(MetadataError::NoBalanceInAccountForAuthorization.into());
|
||||
}
|
||||
|
||||
if *printing_mint_info.key != master_edition.printing_mint {
|
||||
return Err(MetadataError::PrintingMintMismatch.into());
|
||||
}
|
||||
|
||||
if *one_time_printing_authorization_mint_info.key
|
||||
!= master_edition.one_time_printing_authorization_mint
|
||||
{
|
||||
return Err(MetadataError::OneTimePrintingAuthMintMismatch.into());
|
||||
}
|
||||
|
||||
spl_token_burn(TokenBurnParams {
|
||||
mint: one_time_printing_authorization_mint_info.clone(),
|
||||
source: one_time_token_account_info.clone(),
|
||||
amount: 1,
|
||||
authority: burn_authority_info.clone(),
|
||||
authority_signer_seeds: None,
|
||||
token_program: token_program_info.clone(),
|
||||
})?;
|
||||
|
||||
let bump = assert_derivation(
|
||||
program_id,
|
||||
master_edition_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
metadata.mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let authority_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
metadata.mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
&[bump],
|
||||
];
|
||||
spl_token_mint_to(TokenMintToParams {
|
||||
mint: printing_mint_info.clone(),
|
||||
destination: destination_info.clone(),
|
||||
amount: supply,
|
||||
authority: master_edition_info.clone(),
|
||||
authority_signer_seeds: Some(authority_seeds),
|
||||
token_program: token_program_info.clone(),
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_deprecated_mint_printing_tokens(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
supply: u64,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let destination_info = next_account_info(account_info_iter)?;
|
||||
let printing_mint_info = next_account_info(account_info_iter)?;
|
||||
let update_authority_info = next_account_info(account_info_iter)?;
|
||||
let metadata_info = next_account_info(account_info_iter)?;
|
||||
let master_edition_info = next_account_info(account_info_iter)?;
|
||||
let token_program_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
let rent = &Rent::from_account_info(rent_info)?;
|
||||
|
||||
let destination: Account = assert_initialized(destination_info)?;
|
||||
let master_edition = MasterEditionV1::from_account_info(master_edition_info)?;
|
||||
let metadata = Metadata::from_account_info(metadata_info)?;
|
||||
let printing_mint: Mint = assert_initialized(printing_mint_info)?;
|
||||
assert_token_program_matches_package(token_program_info)?;
|
||||
assert_rent_exempt(rent, destination_info)?;
|
||||
assert_owned_by(destination_info, &spl_token::id())?;
|
||||
assert_update_authority_is_correct(&metadata, update_authority_info)?;
|
||||
assert_supply_invariance(&master_edition, &printing_mint, supply)?;
|
||||
assert_owned_by(printing_mint_info, &spl_token::id())?;
|
||||
assert_owned_by(metadata_info, program_id)?;
|
||||
assert_owned_by(master_edition_info, program_id)?;
|
||||
|
||||
let bump = assert_derivation(
|
||||
program_id,
|
||||
master_edition_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
metadata.mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let authority_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
metadata.mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
&[bump],
|
||||
];
|
||||
|
||||
if destination.mint != master_edition.printing_mint {
|
||||
return Err(MetadataError::DestinationMintMismatch.into());
|
||||
}
|
||||
|
||||
if *printing_mint_info.key != master_edition.printing_mint {
|
||||
return Err(MetadataError::PrintingMintMismatch.into());
|
||||
}
|
||||
|
||||
spl_token_mint_to(TokenMintToParams {
|
||||
mint: printing_mint_info.clone(),
|
||||
destination: destination_info.clone(),
|
||||
amount: supply,
|
||||
authority: master_edition_info.clone(),
|
||||
authority_signer_seeds: Some(authority_seeds),
|
||||
token_program: token_program_info.clone(),
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -11,9 +11,9 @@ use {
|
|||
};
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
fn process_instruction<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
if let Err(error) = processor::process_instruction(program_id, accounts, instruction_data) {
|
||||
|
|
|
@ -137,6 +137,10 @@ pub enum MetadataError {
|
|||
#[error("The mint of the token account does not match the Printing mint!")]
|
||||
TokenAccountMintMismatch,
|
||||
|
||||
/// The mint of the token account does not match the master metadata mint!
|
||||
#[error("The mint of the token account does not match the master metadata mint!")]
|
||||
TokenAccountMintMismatchV2,
|
||||
|
||||
/// Not enough tokens to mint a limited edition
|
||||
#[error("Not enough tokens to mint a limited edition")]
|
||||
NotEnoughTokens,
|
||||
|
@ -278,6 +282,30 @@ pub enum MetadataError {
|
|||
/// You cannot splice over an existing reservation!
|
||||
#[error("You cannot splice over an existing reservation!")]
|
||||
TriedToReplaceAnExistingReservation,
|
||||
|
||||
/// Invalid operation
|
||||
#[error("Invalid operation")]
|
||||
InvalidOperation,
|
||||
|
||||
/// Invalid owner
|
||||
#[error("Invalid Owner")]
|
||||
InvalidOwner,
|
||||
|
||||
/// Printing mint supply must be zero for conversion
|
||||
#[error("Printing mint supply must be zero for conversion")]
|
||||
PrintingMintSupplyMustBeZeroForConversion,
|
||||
|
||||
/// One Time Auth mint supply must be zero for conversion
|
||||
#[error("One Time Auth mint supply must be zero for conversion")]
|
||||
OneTimeAuthMintSupplyMustBeZeroForConversion,
|
||||
|
||||
/// You tried to insert one edition too many into an edition mark pda
|
||||
#[error("You tried to insert one edition too many into an edition mark pda")]
|
||||
InvalidEditionIndex,
|
||||
|
||||
// In the legacy system the reservation needs to be of size one for cpu limit reasons
|
||||
#[error("In the legacy system the reservation needs to be of size one for cpu limit reasons")]
|
||||
ReservationArrayShouldBeSizeOne,
|
||||
}
|
||||
|
||||
impl PrintProgramError for MetadataError {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use {
|
||||
crate::state::{Creator, Data, Reservation},
|
||||
crate::{
|
||||
deprecated_instruction::{MintPrintingTokensViaTokenArgs, SetReservationListArgs},
|
||||
state::{Creator, Data, EDITION, EDITION_MARKER_BIT_SIZE, PREFIX},
|
||||
},
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
solana_program::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
|
@ -36,24 +39,8 @@ pub struct CreateMasterEditionArgs {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
pub struct MintPrintingTokensViaTokenArgs {
|
||||
pub supply: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
pub struct SetReservationListArgs {
|
||||
/// If set, means that no more than this number of editions can ever be minted. This is immutable.
|
||||
pub reservations: Vec<Reservation>,
|
||||
/// should only be present on the very first call to set reservation list.
|
||||
pub total_reservation_spots: Option<u64>,
|
||||
/// Where in the reservation list you want to insert this slice of reservations
|
||||
pub offset: u64,
|
||||
/// What the total spot offset is in the reservation list from the beginning to your slice of reservations.
|
||||
/// So if is going to be 4 total editions eventually reserved between your slice and the beginning of the array,
|
||||
/// split between 2 reservation entries, the offset variable above would be "2" since you start at entry 2 in 0 indexed array
|
||||
/// (first 2 taking 0 and 1) and because they each have 2 spots taken, this variable would be 4.
|
||||
pub total_spot_offset: u64,
|
||||
pub struct MintNewEditionFromMasterEditionViaTokenArgs {
|
||||
pub edition: u64,
|
||||
}
|
||||
|
||||
/// Instructions supported by the Metadata program.
|
||||
|
@ -74,16 +61,16 @@ pub enum MetadataInstruction {
|
|||
/// 1. `[signer]` Update authority key
|
||||
UpdateMetadataAccount(UpdateMetadataAccountArgs),
|
||||
|
||||
/// Register a Metadata as a Master Edition, which means Editions can be minted.
|
||||
/// Register a Metadata as a Master Edition V1, which means Editions can be minted.
|
||||
/// Henceforth, no further tokens will be mintable from this primary mint. Will throw an error if more than one
|
||||
/// token exists, and will throw an error if less than one token exists in this primary mint.
|
||||
/// 0. `[writable]` Unallocated edition account with address as pda of ['metadata', program id, mint, 'edition']
|
||||
/// 0. `[writable]` Unallocated edition V1 account with address as pda of ['metadata', program id, mint, 'edition']
|
||||
/// 1. `[writable]` Metadata mint
|
||||
/// 2. `[writable]` Printing mint - A mint you control that can mint tokens that can be exchanged for limited editions of your
|
||||
/// master edition via the MintNewEditionFromMasterEditionViaToken endpoint
|
||||
/// 3. `[writable]` One time authorization printing mint - A mint you control that prints tokens that gives the bearer permission to mint any
|
||||
/// number of tokens from the printing mint one time via an endpoint with the token-metadata program for your metadata. Also burns the token.
|
||||
/// 4. `[signer]` Current Update authority key on metadata
|
||||
/// 4. `[signer]` Current Update authority key
|
||||
/// 5. `[signer]` Printing mint authority - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY.
|
||||
/// 6. `[signer]` Mint authority on the metadata's mint - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY
|
||||
/// 7. `[]` Metadata account
|
||||
|
@ -92,27 +79,28 @@ pub enum MetadataInstruction {
|
|||
/// 10. `[]` System program
|
||||
/// 11. `[]` Rent info
|
||||
/// 13. `[signer]` One time authorization printing mint authority - must be provided if using max supply. THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY.
|
||||
CreateMasterEdition(CreateMasterEditionArgs),
|
||||
DeprecatedCreateMasterEdition(CreateMasterEditionArgs),
|
||||
|
||||
/// Given an authority token minted by the Printing mint of a master edition, and a brand new non-metadata-ed mint with one token
|
||||
/// make a new Metadata + Edition that is a child of the master edition denoted by this authority token.
|
||||
/// 0. `[writable]` New Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 1. `[writable]` New Edition (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 2. `[writable]` Master Record Edition (pda of ['metadata', program id, Printing mint id, 'edition'])
|
||||
/// 1. `[writable]` New Edition V1 (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 2. `[writable]` Master Record Edition V1 (pda of ['metadata', program id, master metadata mint id, 'edition'])
|
||||
/// 3. `[writable]` Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY
|
||||
/// 4. `[signer]` Mint authority of new mint
|
||||
/// 5. `[writable]` Printing Mint of master record edition
|
||||
/// 6. `[writable]` Token account containing Printing mint token to be transferred
|
||||
/// 7. `[signer]` Burn authority for this token
|
||||
/// 8. `[signer]` payer
|
||||
/// 9. `[signer]` update authority info of master metadata account
|
||||
/// 10. `[]` Master record metadata account
|
||||
/// 11. `[]` Token program
|
||||
/// 12. `[]` System program
|
||||
/// 13. `[]` Rent info
|
||||
/// 14. `[optional/writable]` Reservation List - If present, and you are on this list, you can get
|
||||
/// 7. `[writable]` Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master mint id, edition_number])
|
||||
/// 8. `[signer]` Burn authority for this token
|
||||
/// 9. `[signer]` payer
|
||||
/// 10. `[]` update authority info for new metadata account
|
||||
/// 11. `[]` Master record metadata account
|
||||
/// 12. `[]` Token program
|
||||
/// 13. `[]` System program
|
||||
/// 14. `[]` Rent info
|
||||
/// 15. `[optional/writable]` Reservation List - If present, and you are on this list, you can get
|
||||
/// an edition number given by your position on the list.
|
||||
MintNewEditionFromMasterEditionViaToken,
|
||||
DeprecatedMintNewEditionFromMasterEditionViaPrintingToken,
|
||||
|
||||
/// Allows updating the primary sale boolean on Metadata solely through owning an account
|
||||
/// containing a token from the metadata's mint and being a signer on this transaction.
|
||||
|
@ -137,10 +125,10 @@ pub enum MetadataInstruction {
|
|||
/// otherwise, it simply wont fit in one transaction. Only provide a total_reservation argument on the first call, which will
|
||||
/// allocate the edition space, and in follow up calls this will specifically be unnecessary (and indeed will error.)
|
||||
///
|
||||
/// 0. `[writable]` Master Edition key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 0. `[writable]` Master Edition V1 key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 1. `[writable]` PDA for ReservationList of ['metadata', program id, master edition key, 'reservation', resource-key]
|
||||
/// 2. `[signer]` The resource you tied the reservation list too
|
||||
SetReservationList(SetReservationListArgs),
|
||||
DeprecatedSetReservationList(SetReservationListArgs),
|
||||
|
||||
/// Create an empty reservation list for a resource who can come back later as a signer and fill the reservation list
|
||||
/// with reservations to ensure that people who come to get editions get the number they expect. See SetReservationList for more.
|
||||
|
@ -148,13 +136,13 @@ pub enum MetadataInstruction {
|
|||
/// 0. `[writable]` PDA for ReservationList of ['metadata', program id, master edition key, 'reservation', resource-key]
|
||||
/// 1. `[signer]` Payer
|
||||
/// 2. `[signer]` Update authority
|
||||
/// 3. `[]` Master Edition key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 3. `[]` Master Edition V1 key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 4. `[]` A resource you wish to tie the reservation list to. This is so your later visitors who come to
|
||||
/// redeem can derive your reservation list PDA with something they can easily get at. You choose what this should be.
|
||||
/// 5. `[]` Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 6. `[]` System program
|
||||
/// 7. `[]` Rent info
|
||||
CreateReservationList,
|
||||
DeprecatedCreateReservationList,
|
||||
|
||||
// Sign a piece of metadata that has you as an unverified creator so that it is now verified.
|
||||
//
|
||||
|
@ -162,7 +150,7 @@ pub enum MetadataInstruction {
|
|||
/// 1. `[signer]` Creator
|
||||
SignMetadata,
|
||||
|
||||
/// Using a one time authorization token from a master edition, print any number of printing tokens from the printing_mint
|
||||
/// Using a one time authorization token from a master edition v1, print any number of printing tokens from the printing_mint
|
||||
/// one time, burning the one time authorization token.
|
||||
///
|
||||
/// 0. `[writable]` Destination account
|
||||
|
@ -171,10 +159,10 @@ pub enum MetadataInstruction {
|
|||
/// 3. `[writable]` Printing mint
|
||||
/// 4. `[signer]` Burn authority
|
||||
/// 5. `[]` Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 6. `[]` Master Edition key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 6. `[]` Master Edition V1 key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 7. `[]` Token program
|
||||
/// 8. `[]` Rent
|
||||
MintPrintingTokensViaToken(MintPrintingTokensViaTokenArgs),
|
||||
DeprecatedMintPrintingTokensViaToken(MintPrintingTokensViaTokenArgs),
|
||||
|
||||
/// Using your update authority, mint printing tokens for your master edition.
|
||||
///
|
||||
|
@ -182,10 +170,74 @@ pub enum MetadataInstruction {
|
|||
/// 1. `[writable]` Printing mint
|
||||
/// 2. `[signer]` Update authority
|
||||
/// 3. `[]` Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 4. `[]` Master Edition key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 4. `[]` Master Edition V1 key (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 5. `[]` Token program
|
||||
/// 6. `[]` Rent
|
||||
MintPrintingTokens(MintPrintingTokensViaTokenArgs),
|
||||
DeprecatedMintPrintingTokens(MintPrintingTokensViaTokenArgs),
|
||||
|
||||
/// Register a Metadata as a Master Edition V2, which means Edition V2s can be minted.
|
||||
/// Henceforth, no further tokens will be mintable from this primary mint. Will throw an error if more than one
|
||||
/// token exists, and will throw an error if less than one token exists in this primary mint.
|
||||
/// 0. `[writable]` Unallocated edition V2 account with address as pda of ['metadata', program id, mint, 'edition']
|
||||
/// 1. `[writable]` Metadata mint
|
||||
/// 2. `[signer]` Update authority
|
||||
/// 3. `[signer]` Mint authority on the metadata's mint - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY
|
||||
/// 4. `[signer]` payer
|
||||
/// 5. `[]` Metadata account
|
||||
/// 6. `[]` Token program
|
||||
/// 7. `[]` System program
|
||||
/// 8. `[]` Rent info
|
||||
CreateMasterEdition(CreateMasterEditionArgs),
|
||||
|
||||
/// Given a token account containing the master edition token to prove authority, and a brand new non-metadata-ed mint with one token
|
||||
/// make a new Metadata + Edition that is a child of the master edition denoted by this authority token.
|
||||
/// 0. `[writable]` New Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 1. `[writable]` New Edition (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 2. `[writable]` Master Record Edition V2 (pda of ['metadata', program id, master metadata mint id, 'edition'])
|
||||
/// 3. `[writable]` Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY
|
||||
/// 4. `[writable]` Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number])
|
||||
/// where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE).
|
||||
/// 5. `[signer]` Mint authority of new mint
|
||||
/// 6. `[signer]` payer
|
||||
/// 7. `[signer]` owner of token account containing master token (#8)
|
||||
/// 8. `[]` token account containing token from master metadata mint
|
||||
/// 9. `[]` Update authority info for new metadata
|
||||
/// 10. `[]` Master record metadata account
|
||||
/// 11. `[]` Token program
|
||||
/// 12. `[]` System program
|
||||
/// 13. `[]` Rent info
|
||||
MintNewEditionFromMasterEditionViaToken(MintNewEditionFromMasterEditionViaTokenArgs),
|
||||
|
||||
/// Converts the Master Edition V1 to a Master Edition V2, draining lamports from the two printing mints
|
||||
/// to the owner of the token account holding the master edition token. Permissionless.
|
||||
/// Can only be called if there are currenly no printing tokens or one time authorization tokens in circulation.
|
||||
///
|
||||
/// 0. `[writable]` Master Record Edition V1 (pda of ['metadata', program id, master metadata mint id, 'edition'])
|
||||
/// 1. `[writable]` One time authorization mint
|
||||
/// 2. `[writable]` Printing mint
|
||||
ConvertMasterEditionV1ToV2,
|
||||
|
||||
/// Proxy Call to Mint Edition using a Store Token Account as a Vault Authority.
|
||||
///
|
||||
/// 0. `[writable]` New Metadata key (pda of ['metadata', program id, mint id])
|
||||
/// 1. `[writable]` New Edition (pda of ['metadata', program id, mint id, 'edition'])
|
||||
/// 2. `[writable]` Master Record Edition V2 (pda of ['metadata', program id, master metadata mint id, 'edition']
|
||||
/// 3. `[writable]` Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY
|
||||
/// 4. `[writable]` Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number])
|
||||
/// where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE).
|
||||
/// 5. `[signer]` Mint authority of new mint
|
||||
/// 6. `[signer]` payer
|
||||
/// 7. `[signer]` Vault authority
|
||||
/// 8. `[]` Safety deposit token store account
|
||||
/// 9. `[]` Safety deposit box
|
||||
/// 10. `[]` Vault
|
||||
/// 11. `[]` Update authority info for new metadata
|
||||
/// 12. `[]` Master record metadata account
|
||||
/// 13. `[]` Token program
|
||||
/// 14. `[]` Token vault program
|
||||
/// 15. `[]` System program
|
||||
/// 16. `[]` Rent info
|
||||
MintNewEditionFromMasterEditionViaVaultProxy(MintNewEditionFromMasterEditionViaTokenArgs),
|
||||
}
|
||||
|
||||
/// Creates an CreateMetadataAccounts instruction
|
||||
|
@ -256,97 +308,6 @@ pub fn update_metadata_accounts(
|
|||
}
|
||||
}
|
||||
|
||||
/// creates a create_master_edition instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_master_edition(
|
||||
program_id: Pubkey,
|
||||
edition: Pubkey,
|
||||
mint: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
one_time_printing_authorization_mint: Pubkey,
|
||||
update_authority: Pubkey,
|
||||
printing_mint_authority: Pubkey,
|
||||
mint_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
payer: Pubkey,
|
||||
max_supply: Option<u64>,
|
||||
one_time_printing_authorization_mint_authority: Option<Pubkey>,
|
||||
) -> Instruction {
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new(edition, false),
|
||||
AccountMeta::new(mint, false),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new(one_time_printing_authorization_mint, false),
|
||||
AccountMeta::new_readonly(update_authority, true),
|
||||
AccountMeta::new_readonly(printing_mint_authority, true),
|
||||
AccountMeta::new_readonly(mint_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(payer, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
];
|
||||
|
||||
if let Some(auth) = one_time_printing_authorization_mint_authority {
|
||||
accounts.push(AccountMeta::new_readonly(auth, true));
|
||||
}
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetadataInstruction::CreateMasterEdition(CreateMasterEditionArgs { max_supply })
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates a mint_new_edition_from_master_edition instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn mint_new_edition_from_master_edition_via_token(
|
||||
program_id: Pubkey,
|
||||
metadata: Pubkey,
|
||||
edition: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
mint: Pubkey,
|
||||
mint_authority: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
master_token_account: Pubkey,
|
||||
burn_authority: Pubkey,
|
||||
payer: Pubkey,
|
||||
master_update_authority: Pubkey,
|
||||
master_metadata: Pubkey,
|
||||
reservation_list: Option<Pubkey>,
|
||||
) -> Instruction {
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new(metadata, false),
|
||||
AccountMeta::new(edition, false),
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(mint, false),
|
||||
AccountMeta::new_readonly(mint_authority, true),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new(master_token_account, false),
|
||||
AccountMeta::new_readonly(burn_authority, true),
|
||||
AccountMeta::new(payer, true),
|
||||
AccountMeta::new_readonly(master_update_authority, true),
|
||||
AccountMeta::new_readonly(master_metadata, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
];
|
||||
|
||||
if let Some(list) = reservation_list {
|
||||
accounts.push(AccountMeta::new_readonly(list, false))
|
||||
}
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetadataInstruction::MintNewEditionFromMasterEditionViaToken
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates a update_primary_sale_happened_via_token instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn update_primary_sale_happened_via_token(
|
||||
|
@ -368,123 +329,166 @@ pub fn update_primary_sale_happened_via_token(
|
|||
}
|
||||
}
|
||||
|
||||
/// creates an set_reservation_list instruction
|
||||
/// creates a create_master_edition instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn set_reservation_list(
|
||||
pub fn create_master_edition(
|
||||
program_id: Pubkey,
|
||||
edition: Pubkey,
|
||||
mint: Pubkey,
|
||||
update_authority: Pubkey,
|
||||
mint_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
payer: Pubkey,
|
||||
max_supply: Option<u64>,
|
||||
) -> Instruction {
|
||||
let accounts = vec![
|
||||
AccountMeta::new(edition, false),
|
||||
AccountMeta::new(mint, false),
|
||||
AccountMeta::new_readonly(update_authority, true),
|
||||
AccountMeta::new_readonly(mint_authority, true),
|
||||
AccountMeta::new_readonly(payer, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
];
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetadataInstruction::CreateMasterEdition(CreateMasterEditionArgs { max_supply })
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates a mint_new_edition_from_master_edition instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn mint_new_edition_from_master_edition_via_token(
|
||||
program_id: Pubkey,
|
||||
new_metadata: Pubkey,
|
||||
new_edition: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
new_mint: Pubkey,
|
||||
new_mint_authority: Pubkey,
|
||||
payer: Pubkey,
|
||||
token_account_owner: Pubkey,
|
||||
token_account: Pubkey,
|
||||
new_metadata_update_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
metadata_mint: Pubkey,
|
||||
edition: u64,
|
||||
) -> Instruction {
|
||||
let edition_number = edition.checked_div(EDITION_MARKER_BIT_SIZE).unwrap();
|
||||
let as_string = edition_number.to_string();
|
||||
let (edition_mark_pda, _) = Pubkey::find_program_address(
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
metadata_mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
as_string.as_bytes(),
|
||||
],
|
||||
&program_id,
|
||||
);
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new(new_metadata, false),
|
||||
AccountMeta::new(new_edition, false),
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(new_mint, false),
|
||||
AccountMeta::new(edition_mark_pda, false),
|
||||
AccountMeta::new_readonly(new_mint_authority, true),
|
||||
AccountMeta::new(payer, true),
|
||||
AccountMeta::new_readonly(token_account_owner, true),
|
||||
AccountMeta::new_readonly(token_account, false),
|
||||
AccountMeta::new_readonly(new_metadata_update_authority, false),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
];
|
||||
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts,
|
||||
data: MetadataInstruction::MintNewEditionFromMasterEditionViaToken(
|
||||
MintNewEditionFromMasterEditionViaTokenArgs { edition },
|
||||
)
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a master edition v1 to v2
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn convert_master_edition_v1_to_v2(
|
||||
program_id: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
reservation_list: Pubkey,
|
||||
resource: Pubkey,
|
||||
reservations: Vec<Reservation>,
|
||||
total_reservation_spots: Option<u64>,
|
||||
offset: u64,
|
||||
total_spot_offset: u64,
|
||||
one_time_auth: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(reservation_list, false),
|
||||
AccountMeta::new_readonly(resource, true),
|
||||
AccountMeta::new(one_time_auth, false),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
],
|
||||
data: MetadataInstruction::SetReservationList(SetReservationListArgs {
|
||||
reservations,
|
||||
total_reservation_spots,
|
||||
offset,
|
||||
total_spot_offset,
|
||||
})
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
data: MetadataInstruction::ConvertMasterEditionV1ToV2
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates an create_reservation_list instruction
|
||||
/// creates a mint_edition_proxy instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_reservation_list(
|
||||
pub fn mint_edition_from_master_edition_via_vault_proxy(
|
||||
program_id: Pubkey,
|
||||
reservation_list: Pubkey,
|
||||
new_metadata: Pubkey,
|
||||
new_edition: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
new_mint: Pubkey,
|
||||
edition_mark_pda: Pubkey,
|
||||
new_mint_authority: Pubkey,
|
||||
payer: Pubkey,
|
||||
update_authority: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
resource: Pubkey,
|
||||
vault_authority: Pubkey,
|
||||
safety_deposit_store: Pubkey,
|
||||
safety_deposit_box: Pubkey,
|
||||
vault: Pubkey,
|
||||
new_metadata_update_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
token_program: Pubkey,
|
||||
token_vault_program_info: Pubkey,
|
||||
edition: u64,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(reservation_list, false),
|
||||
AccountMeta::new_readonly(payer, true),
|
||||
AccountMeta::new_readonly(update_authority, true),
|
||||
AccountMeta::new_readonly(master_edition, false),
|
||||
AccountMeta::new_readonly(resource, false),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetadataInstruction::CreateReservationList
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
let accounts = vec![
|
||||
AccountMeta::new(new_metadata, false),
|
||||
AccountMeta::new(new_edition, false),
|
||||
AccountMeta::new(master_edition, false),
|
||||
AccountMeta::new(new_mint, false),
|
||||
AccountMeta::new(edition_mark_pda, false),
|
||||
AccountMeta::new_readonly(new_mint_authority, true),
|
||||
AccountMeta::new(payer, true),
|
||||
AccountMeta::new_readonly(vault_authority, true),
|
||||
AccountMeta::new_readonly(safety_deposit_store, false),
|
||||
AccountMeta::new_readonly(safety_deposit_box, false),
|
||||
AccountMeta::new_readonly(vault, false),
|
||||
AccountMeta::new_readonly(new_metadata_update_authority, false),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(token_program, false),
|
||||
AccountMeta::new_readonly(token_vault_program_info, false),
|
||||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
];
|
||||
|
||||
/// creates an mint_printing_tokens_via_token instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn mint_printing_tokens_via_token(
|
||||
program_id: Pubkey,
|
||||
destination: Pubkey,
|
||||
token: Pubkey,
|
||||
one_time_printing_authorization_mint: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
burn_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
supply: u64,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(destination, false),
|
||||
AccountMeta::new(token, false),
|
||||
AccountMeta::new(one_time_printing_authorization_mint, false),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new_readonly(burn_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(master_edition, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetadataInstruction::MintPrintingTokensViaToken(MintPrintingTokensViaTokenArgs {
|
||||
supply,
|
||||
})
|
||||
accounts,
|
||||
data: MetadataInstruction::MintNewEditionFromMasterEditionViaVaultProxy(
|
||||
MintNewEditionFromMasterEditionViaTokenArgs { edition },
|
||||
)
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// creates an mint_printing_tokens instruction
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn mint_printing_tokens(
|
||||
program_id: Pubkey,
|
||||
destination: Pubkey,
|
||||
printing_mint: Pubkey,
|
||||
update_authority: Pubkey,
|
||||
metadata: Pubkey,
|
||||
master_edition: Pubkey,
|
||||
supply: u64,
|
||||
) -> Instruction {
|
||||
Instruction {
|
||||
program_id,
|
||||
accounts: vec![
|
||||
AccountMeta::new(destination, false),
|
||||
AccountMeta::new(printing_mint, false),
|
||||
AccountMeta::new_readonly(update_authority, true),
|
||||
AccountMeta::new_readonly(metadata, false),
|
||||
AccountMeta::new_readonly(master_edition, false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: MetadataInstruction::MintPrintingTokens(MintPrintingTokensViaTokenArgs { supply })
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! A Token Metadata program for the Solana blockchain.
|
||||
|
||||
pub mod deprecated_instruction;
|
||||
pub mod deprecated_processor;
|
||||
pub mod entrypoint;
|
||||
pub mod error;
|
||||
pub mod instruction;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,7 +34,10 @@ pub const MAX_METADATA_LEN: usize = 1
|
|||
|
||||
pub const MAX_EDITION_LEN: usize = 1 + 32 + 8 + 200;
|
||||
|
||||
pub const MAX_MASTER_EDITION_LEN: usize = 1 + 9 + 8 + 32 + 32 + 200;
|
||||
// Large buffer because the older master editions have two pubkeys in them,
|
||||
// need to keep two versions same size because the conversion process actually changes the same account
|
||||
// by rewriting it.
|
||||
pub const MAX_MASTER_EDITION_LEN: usize = 1 + 9 + 8 + 264;
|
||||
|
||||
pub const MAX_CREATOR_LIMIT: usize = 5;
|
||||
|
||||
|
@ -48,8 +51,12 @@ pub const MAX_RESERVATION_LIST_V1_SIZE: usize = 1 + 32 + 8 + 8 + MAX_RESERVATION
|
|||
// can hold up to 200 keys per reservation, note: the extra 8 is for number of elements in the vec
|
||||
pub const MAX_RESERVATION_LIST_SIZE: usize = 1 + 32 + 8 + 8 + MAX_RESERVATIONS * 48 + 8 + 8 + 84;
|
||||
|
||||
pub const MAX_EDITION_MARKER_SIZE: usize = 32;
|
||||
|
||||
pub const EDITION_MARKER_BIT_SIZE: u64 = 248;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone, Copy)]
|
||||
pub enum Key {
|
||||
Uninitialized,
|
||||
EditionV1,
|
||||
|
@ -57,6 +64,8 @@ pub enum Key {
|
|||
ReservationListV1,
|
||||
MetadataV1,
|
||||
ReservationListV2,
|
||||
MasterEditionV2,
|
||||
EditionMarker,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
|
@ -95,9 +104,73 @@ impl Metadata {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MasterEdition {
|
||||
fn key(&self) -> Key;
|
||||
fn supply(&self) -> u64;
|
||||
fn set_supply(&mut self, supply: u64);
|
||||
fn max_supply(&self) -> Option<u64>;
|
||||
fn save(&self, account: &AccountInfo) -> ProgramResult;
|
||||
}
|
||||
|
||||
pub fn get_master_edition(account: &AccountInfo) -> Result<Box<dyn MasterEdition>, ProgramError> {
|
||||
let version = account.data.borrow()[0];
|
||||
|
||||
// For some reason when converting Key to u8 here, it becomes unreachable. Use direct constant instead.
|
||||
match version {
|
||||
2 => return Ok(Box::new(MasterEditionV1::from_account_info(account)?)),
|
||||
6 => return Ok(Box::new(MasterEditionV2::from_account_info(account)?)),
|
||||
_ => return Err(MetadataError::DataTypeMismatch.into()),
|
||||
};
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct MasterEdition {
|
||||
pub struct MasterEditionV2 {
|
||||
pub key: Key,
|
||||
|
||||
pub supply: u64,
|
||||
|
||||
pub max_supply: Option<u64>,
|
||||
}
|
||||
|
||||
impl MasterEdition for MasterEditionV2 {
|
||||
fn key(&self) -> Key {
|
||||
self.key
|
||||
}
|
||||
|
||||
fn supply(&self) -> u64 {
|
||||
self.supply
|
||||
}
|
||||
|
||||
fn set_supply(&mut self, supply: u64) {
|
||||
self.supply = supply;
|
||||
}
|
||||
|
||||
fn max_supply(&self) -> Option<u64> {
|
||||
self.max_supply
|
||||
}
|
||||
|
||||
fn save(&self, account: &AccountInfo) -> ProgramResult {
|
||||
self.serialize(&mut *account.data.borrow_mut())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MasterEditionV2 {
|
||||
pub fn from_account_info(a: &AccountInfo) -> Result<MasterEditionV2, ProgramError> {
|
||||
let me: MasterEditionV2 = try_from_slice_checked(
|
||||
&a.data.borrow_mut(),
|
||||
Key::MasterEditionV2,
|
||||
MAX_MASTER_EDITION_LEN,
|
||||
)?;
|
||||
|
||||
Ok(me)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct MasterEditionV1 {
|
||||
pub key: Key,
|
||||
|
||||
pub supply: u64,
|
||||
|
@ -120,9 +193,32 @@ pub struct MasterEdition {
|
|||
pub one_time_printing_authorization_mint: Pubkey,
|
||||
}
|
||||
|
||||
impl MasterEdition {
|
||||
pub fn from_account_info(a: &AccountInfo) -> Result<MasterEdition, ProgramError> {
|
||||
let me: MasterEdition = try_from_slice_checked(
|
||||
impl MasterEdition for MasterEditionV1 {
|
||||
fn key(&self) -> Key {
|
||||
self.key
|
||||
}
|
||||
|
||||
fn supply(&self) -> u64 {
|
||||
self.supply
|
||||
}
|
||||
|
||||
fn max_supply(&self) -> Option<u64> {
|
||||
self.max_supply
|
||||
}
|
||||
|
||||
fn set_supply(&mut self, supply: u64) {
|
||||
self.supply = supply;
|
||||
}
|
||||
|
||||
fn save(&self, account: &AccountInfo) -> ProgramResult {
|
||||
self.serialize(&mut *account.data.borrow_mut())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MasterEditionV1 {
|
||||
pub fn from_account_info(a: &AccountInfo) -> Result<MasterEditionV1, ProgramError> {
|
||||
let me: MasterEditionV1 = try_from_slice_checked(
|
||||
&a.data.borrow_mut(),
|
||||
Key::MasterEditionV1,
|
||||
MAX_MASTER_EDITION_LEN,
|
||||
|
@ -175,9 +271,9 @@ pub trait ReservationList {
|
|||
fn set_master_edition(&mut self, key: Pubkey);
|
||||
fn set_supply_snapshot(&mut self, supply: Option<u64>);
|
||||
fn set_reservations(&mut self, reservations: Vec<Reservation>) -> ProgramResult;
|
||||
fn add_reservations(
|
||||
fn add_reservation(
|
||||
&mut self,
|
||||
reservations: Vec<Reservation>,
|
||||
reservation: Reservation,
|
||||
offset: u64,
|
||||
total_spot_offset: u64,
|
||||
) -> ProgramResult;
|
||||
|
@ -236,9 +332,9 @@ impl ReservationList for ReservationListV2 {
|
|||
self.supply_snapshot = supply;
|
||||
}
|
||||
|
||||
fn add_reservations(
|
||||
fn add_reservation(
|
||||
&mut self,
|
||||
mut reservations: Vec<Reservation>,
|
||||
reservation: Reservation,
|
||||
offset: u64,
|
||||
total_spot_offset: u64,
|
||||
) -> ProgramResult {
|
||||
|
@ -251,36 +347,23 @@ impl ReservationList for ReservationListV2 {
|
|||
})
|
||||
}
|
||||
if self.reservations.len() > usize_offset {
|
||||
let reservation_length = reservations.len();
|
||||
let replaced_addr = self.reservations[usize_offset].address;
|
||||
let replaced_spots = self.reservations[usize_offset].total_spots;
|
||||
|
||||
let removed_elements: Vec<Reservation> = self
|
||||
.reservations
|
||||
.splice(
|
||||
usize_offset..usize_offset + reservations.len(),
|
||||
reservations,
|
||||
)
|
||||
.collect();
|
||||
let existing_res = removed_elements
|
||||
.iter()
|
||||
.find(|r| r.address != solana_program::system_program::id());
|
||||
if let Some(replaced) = existing_res {
|
||||
// If you overwrite yourself and only yourself, allow it.
|
||||
let allowable_edgecase = reservation_length == 1
|
||||
&& self.reservations[usize_offset].address == replaced.address;
|
||||
if !allowable_edgecase {
|
||||
return Err(MetadataError::TriedToReplaceAnExistingReservation.into());
|
||||
} else {
|
||||
// Since we will have incremented, decrease in advance so we dont blow the spot check.
|
||||
// Super hacky but this code is to be deprecated.
|
||||
self.set_current_reservation_spots(
|
||||
self.current_reservation_spots
|
||||
.checked_sub(replaced.total_spots)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?,
|
||||
);
|
||||
}
|
||||
if replaced_addr == reservation.address {
|
||||
// Since we will have incremented, decrease in advance so we dont blow the spot check.
|
||||
// Super hacky but this code is to be deprecated.
|
||||
self.set_current_reservation_spots(
|
||||
self.current_reservation_spots()
|
||||
.checked_sub(replaced_spots)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?,
|
||||
);
|
||||
} else if replaced_addr != solana_program::system_program::id() {
|
||||
return Err(MetadataError::TriedToReplaceAnExistingReservation.into());
|
||||
}
|
||||
self.reservations[usize_offset] = reservation;
|
||||
} else {
|
||||
self.reservations.append(&mut reservations)
|
||||
self.reservations.push(reservation)
|
||||
}
|
||||
|
||||
if usize_offset != 0
|
||||
|
@ -382,12 +465,17 @@ impl ReservationList for ReservationListV1 {
|
|||
self.supply_snapshot = supply;
|
||||
}
|
||||
|
||||
fn add_reservations(
|
||||
&mut self,
|
||||
reservations: Vec<Reservation>,
|
||||
_: u64,
|
||||
_: u64,
|
||||
) -> ProgramResult {
|
||||
fn add_reservation(&mut self, reservation: Reservation, _: u64, _: u64) -> ProgramResult {
|
||||
self.reservations = vec![ReservationV1 {
|
||||
address: reservation.address,
|
||||
spots_remaining: reservation.spots_remaining as u8,
|
||||
total_spots: reservation.total_spots as u8,
|
||||
}];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_reservations(&mut self, reservations: Vec<Reservation>) -> ProgramResult {
|
||||
self.reservations = reservations
|
||||
.iter()
|
||||
.map(|r| ReservationV1 {
|
||||
|
@ -396,12 +484,6 @@ impl ReservationList for ReservationListV1 {
|
|||
total_spots: r.total_spots as u8,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_reservations(&mut self, reservations: Vec<Reservation>) -> ProgramResult {
|
||||
self.add_reservations(reservations, 0, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -442,3 +524,85 @@ pub struct ReservationV1 {
|
|||
pub spots_remaining: u8,
|
||||
pub total_spots: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
pub struct EditionMarker {
|
||||
pub key: Key,
|
||||
pub ledger: [u8; 31],
|
||||
}
|
||||
|
||||
impl EditionMarker {
|
||||
pub fn from_account_info(a: &AccountInfo) -> Result<EditionMarker, ProgramError> {
|
||||
let res: EditionMarker = try_from_slice_checked(
|
||||
&a.data.borrow_mut(),
|
||||
Key::EditionMarker,
|
||||
MAX_EDITION_MARKER_SIZE,
|
||||
)?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_edition_offset_from_starting_index(edition: u64) -> Result<usize, ProgramError> {
|
||||
Ok(edition
|
||||
.checked_rem(EDITION_MARKER_BIT_SIZE)
|
||||
.ok_or(MetadataError::NumericalOverflowError)? as usize)
|
||||
}
|
||||
|
||||
fn get_index(offset_from_start: usize) -> Result<usize, ProgramError> {
|
||||
let index = offset_from_start
|
||||
.checked_div(8)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?;
|
||||
|
||||
// With only EDITION_MARKER_BIT_SIZE bits, or 31 bytes, we have a max constraint here.
|
||||
if index > 30 {
|
||||
return Err(MetadataError::InvalidEditionIndex.into());
|
||||
}
|
||||
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
fn get_offset_from_right(offset_from_start: usize) -> Result<u32, ProgramError> {
|
||||
// We're saying the left hand side of a u8 is the 0th index so to get a 1 in that 0th index
|
||||
// you need to shift a 1 over 8 spots from the right hand side. To do that you actually
|
||||
// need not 00000001 but 10000000 which you can get by simply multiplying 1 by 2^7, 128 and then ORing
|
||||
// it with the current value.
|
||||
Ok(7 - offset_from_start
|
||||
.checked_rem(8)
|
||||
.ok_or(MetadataError::NumericalOverflowError)? as u32)
|
||||
}
|
||||
|
||||
fn get_index_and_mask(edition: u64) -> Result<(usize, u8), ProgramError> {
|
||||
// How many editions off we are from edition at 0th index
|
||||
let offset_from_start = EditionMarker::get_edition_offset_from_starting_index(edition)?;
|
||||
|
||||
// How many whole u8s we are from the u8 at the 0th index, which basically dividing by 8
|
||||
let index = EditionMarker::get_index(offset_from_start)?;
|
||||
|
||||
// what position in the given u8 bitset are we (remainder math)
|
||||
let my_position_in_index_starting_from_right =
|
||||
EditionMarker::get_offset_from_right(offset_from_start)?;
|
||||
|
||||
Ok((
|
||||
index,
|
||||
u8::pow(2, my_position_in_index_starting_from_right as u32),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn edition_taken(&self, edition: u64) -> Result<bool, ProgramError> {
|
||||
let (index, mask) = EditionMarker::get_index_and_mask(edition)?;
|
||||
|
||||
// apply mask with bitwise and with a 1 to determine if it is set or not
|
||||
let applied_mask = self.ledger[index] & mask;
|
||||
|
||||
// What remains should not equal 0.
|
||||
Ok(applied_mask != 0)
|
||||
}
|
||||
|
||||
pub fn insert_edition(&mut self, edition: u64) -> ProgramResult {
|
||||
let (index, mask) = EditionMarker::get_index_and_mask(edition)?;
|
||||
// bitwise or a 1 into our position in that position
|
||||
self.ledger[index] = self.ledger[index] | mask;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use {
|
||||
crate::{
|
||||
error::MetadataError,
|
||||
processor::process_create_metadata_accounts,
|
||||
state::{
|
||||
get_reservation_list, Data, Edition, Key, MasterEdition, Metadata, EDITION,
|
||||
MAX_CREATOR_LIMIT, MAX_EDITION_LEN, MAX_NAME_LENGTH, MAX_SYMBOL_LENGTH, MAX_URI_LENGTH,
|
||||
PREFIX,
|
||||
get_reservation_list, Data, EditionMarker, Key, MasterEditionV1, Metadata, EDITION,
|
||||
EDITION_MARKER_BIT_SIZE, MAX_CREATOR_LIMIT, MAX_EDITION_LEN, MAX_EDITION_MARKER_SIZE,
|
||||
MAX_MASTER_EDITION_LEN, MAX_METADATA_LEN, MAX_NAME_LENGTH, MAX_SYMBOL_LENGTH,
|
||||
MAX_URI_LENGTH, PREFIX,
|
||||
},
|
||||
},
|
||||
arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs},
|
||||
borsh::{BorshDeserialize, BorshSerialize},
|
||||
solana_program::{
|
||||
account_info::AccountInfo,
|
||||
|
@ -16,6 +17,7 @@ use {
|
|||
msg,
|
||||
program::{invoke, invoke_signed},
|
||||
program_error::ProgramError,
|
||||
program_option::COption,
|
||||
program_pack::{IsInitialized, Pack},
|
||||
pubkey::Pubkey,
|
||||
system_instruction,
|
||||
|
@ -23,7 +25,7 @@ use {
|
|||
},
|
||||
spl_token::{
|
||||
instruction::{set_authority, AuthorityType},
|
||||
state::Mint,
|
||||
state::{Account, Mint},
|
||||
},
|
||||
std::convert::TryInto,
|
||||
};
|
||||
|
@ -169,17 +171,19 @@ pub fn create_or_allocate_account_raw<'a>(
|
|||
)?;
|
||||
}
|
||||
|
||||
let accounts = &[new_account_info.clone(), system_program_info.clone()];
|
||||
|
||||
msg!("Allocate space for the account");
|
||||
invoke_signed(
|
||||
&system_instruction::allocate(new_account_info.key, size.try_into().unwrap()),
|
||||
&[new_account_info.clone(), system_program_info.clone()],
|
||||
accounts,
|
||||
&[&signer_seeds],
|
||||
)?;
|
||||
|
||||
msg!("Assign the account to the owning program");
|
||||
invoke_signed(
|
||||
&system_instruction::assign(new_account_info.key, &program_id),
|
||||
&[new_account_info.clone(), system_program_info.clone()],
|
||||
accounts,
|
||||
&[&signer_seeds],
|
||||
)?;
|
||||
|
||||
|
@ -201,16 +205,64 @@ pub fn assert_update_authority_is_correct(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Unpacks COption from a slice, taken from token program
|
||||
fn unpack_coption_key(src: &[u8; 36]) -> Result<COption<Pubkey>, ProgramError> {
|
||||
let (tag, body) = array_refs![src, 4, 32];
|
||||
match *tag {
|
||||
[0, 0, 0, 0] => Ok(COption::None),
|
||||
[1, 0, 0, 0] => Ok(COption::Some(Pubkey::new_from_array(*body))),
|
||||
_ => Err(ProgramError::InvalidAccountData),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cheap method to just grab owner Pubkey from token account, instead of deserializing entire thing
|
||||
pub fn get_owner_from_token_account(
|
||||
token_account_info: &AccountInfo,
|
||||
) -> Result<Pubkey, ProgramError> {
|
||||
// TokeAccount layout: mint(32), owner(32), ...
|
||||
let data = token_account_info.try_borrow_data()?;
|
||||
let owner_data = array_ref![data, 32, 32];
|
||||
Ok(Pubkey::new_from_array(*owner_data))
|
||||
}
|
||||
|
||||
pub fn get_mint_authority(account_info: &AccountInfo) -> Result<COption<Pubkey>, ProgramError> {
|
||||
// In token program, 36, 8, 1, 1 is the layout, where the first 36 is mint_authority
|
||||
// so we start at 0.
|
||||
let data = account_info.try_borrow_data().unwrap();
|
||||
let authority_bytes = array_ref![data, 0, 36];
|
||||
|
||||
Ok(unpack_coption_key(&authority_bytes)?)
|
||||
}
|
||||
|
||||
pub fn get_mint_freeze_authority(
|
||||
account_info: &AccountInfo,
|
||||
) -> Result<COption<Pubkey>, ProgramError> {
|
||||
let data = account_info.try_borrow_data().unwrap();
|
||||
let authority_bytes = array_ref![data, 36 + 8 + 1 + 1, 36];
|
||||
|
||||
Ok(unpack_coption_key(&authority_bytes)?)
|
||||
}
|
||||
|
||||
/// cheap method to just get supply off a mint without unpacking whole object
|
||||
pub fn get_mint_supply(account_info: &AccountInfo) -> Result<u64, ProgramError> {
|
||||
// In token program, 36, 8, 1, 1 is the layout, where the first 8 is supply u64.
|
||||
// so we start at 36.
|
||||
let data = account_info.try_borrow_data().unwrap();
|
||||
let bytes = array_ref![data, 36, 8];
|
||||
|
||||
Ok(u64::from_le_bytes(*bytes))
|
||||
}
|
||||
|
||||
pub fn assert_mint_authority_matches_mint(
|
||||
mint: &Mint,
|
||||
mint_authority: &COption<Pubkey>,
|
||||
mint_authority_info: &AccountInfo,
|
||||
) -> ProgramResult {
|
||||
match mint.mint_authority {
|
||||
solana_program::program_option::COption::None => {
|
||||
match mint_authority {
|
||||
COption::None => {
|
||||
return Err(MetadataError::InvalidMintAuthority.into());
|
||||
}
|
||||
solana_program::program_option::COption::Some(key) => {
|
||||
if *mint_authority_info.key != key {
|
||||
COption::Some(key) => {
|
||||
if mint_authority_info.key != key {
|
||||
return Err(MetadataError::InvalidMintAuthority.into());
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +276,7 @@ pub fn assert_mint_authority_matches_mint(
|
|||
}
|
||||
|
||||
pub fn assert_supply_invariance(
|
||||
master_edition: &MasterEdition,
|
||||
master_edition: &MasterEditionV1,
|
||||
printing_mint: &Mint,
|
||||
new_supply: u64,
|
||||
) -> ProgramResult {
|
||||
|
@ -253,6 +305,12 @@ pub fn transfer_mint_authority<'a>(
|
|||
token_program_info: &AccountInfo<'a>,
|
||||
) -> ProgramResult {
|
||||
msg!("Setting mint authority");
|
||||
let accounts = &[
|
||||
mint_authority_info.clone(),
|
||||
mint_info.clone(),
|
||||
token_program_info.clone(),
|
||||
edition_account_info.clone(),
|
||||
];
|
||||
invoke_signed(
|
||||
&set_authority(
|
||||
token_program_info.key,
|
||||
|
@ -263,33 +321,30 @@ pub fn transfer_mint_authority<'a>(
|
|||
&[&mint_authority_info.key],
|
||||
)
|
||||
.unwrap(),
|
||||
&[
|
||||
mint_authority_info.clone(),
|
||||
mint_info.clone(),
|
||||
token_program_info.clone(),
|
||||
edition_account_info.clone(),
|
||||
],
|
||||
accounts,
|
||||
&[],
|
||||
)?;
|
||||
msg!("Setting freeze authority");
|
||||
invoke_signed(
|
||||
&set_authority(
|
||||
token_program_info.key,
|
||||
mint_info.key,
|
||||
Some(&edition_key),
|
||||
AuthorityType::FreezeAccount,
|
||||
mint_authority_info.key,
|
||||
&[&mint_authority_info.key],
|
||||
)
|
||||
.unwrap(),
|
||||
&[
|
||||
mint_authority_info.clone(),
|
||||
mint_info.clone(),
|
||||
token_program_info.clone(),
|
||||
edition_account_info.clone(),
|
||||
],
|
||||
&[],
|
||||
)?;
|
||||
let freeze_authority = get_mint_freeze_authority(mint_info)?;
|
||||
if freeze_authority.is_some() {
|
||||
invoke_signed(
|
||||
&set_authority(
|
||||
token_program_info.key,
|
||||
mint_info.key,
|
||||
Some(&edition_key),
|
||||
AuthorityType::FreezeAccount,
|
||||
mint_authority_info.key,
|
||||
&[&mint_authority_info.key],
|
||||
)
|
||||
.unwrap(),
|
||||
accounts,
|
||||
&[],
|
||||
)?;
|
||||
msg!("Finished setting freeze authority");
|
||||
} else {
|
||||
msg!("Skipping freeze authority because this mint has none")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -321,27 +376,170 @@ pub fn assert_edition_valid(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extract_edition_number_from_deprecated_reservation_list(
|
||||
account: &AccountInfo,
|
||||
mint_authority_info: &AccountInfo,
|
||||
) -> Result<u64, ProgramError> {
|
||||
let mut reservation_list = get_reservation_list(account)?;
|
||||
|
||||
if let Some(supply_snapshot) = reservation_list.supply_snapshot() {
|
||||
let mut prev_total_offsets: u64 = 0;
|
||||
let mut offset: Option<u64> = None;
|
||||
let mut reservations = reservation_list.reservations();
|
||||
for i in 0..reservations.len() {
|
||||
let mut reservation = &mut reservations[i];
|
||||
|
||||
if reservation.address == *mint_authority_info.key {
|
||||
offset = Some(
|
||||
prev_total_offsets
|
||||
.checked_add(reservation.spots_remaining)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?,
|
||||
);
|
||||
// You get your editions in reverse order but who cares, saves a byte
|
||||
reservation.spots_remaining = reservation
|
||||
.spots_remaining
|
||||
.checked_sub(1)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?;
|
||||
|
||||
reservation_list.set_reservations(reservations)?;
|
||||
reservation_list.save(account)?;
|
||||
break;
|
||||
}
|
||||
|
||||
if reservation.address == solana_program::system_program::id() {
|
||||
// This is an anchor point in the array...it means we reset our math to
|
||||
// this offset because we may be missing information in between this point and
|
||||
// the points before it.
|
||||
prev_total_offsets = reservation.total_spots;
|
||||
} else {
|
||||
prev_total_offsets = prev_total_offsets
|
||||
.checked_add(reservation.total_spots)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?;
|
||||
}
|
||||
}
|
||||
|
||||
match offset {
|
||||
Some(val) => Ok(supply_snapshot
|
||||
.checked_add(val)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?),
|
||||
None => {
|
||||
return Err(MetadataError::AddressNotInReservation.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(MetadataError::ReservationNotSet.into());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_edition_number(
|
||||
mint_authority_info: &AccountInfo,
|
||||
reservation_list_info: Option<&AccountInfo>,
|
||||
edition_override: Option<u64>,
|
||||
me_supply: u64,
|
||||
) -> Result<u64, ProgramError> {
|
||||
let edition = match reservation_list_info {
|
||||
Some(account) => {
|
||||
extract_edition_number_from_deprecated_reservation_list(account, mint_authority_info)?
|
||||
}
|
||||
None => {
|
||||
if let Some(edit) = edition_override {
|
||||
edit
|
||||
} else {
|
||||
me_supply
|
||||
.checked_add(1)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(edition)
|
||||
}
|
||||
|
||||
fn get_max_supply_off_master_edition(
|
||||
master_edition_account_info: &AccountInfo,
|
||||
) -> Result<Option<u64>, ProgramError> {
|
||||
let data = master_edition_account_info.try_borrow_data()?;
|
||||
// this is an option, 9 bytes, first is 0 means is none
|
||||
if data[9] == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
let amount_data = array_ref![data, 10, 8];
|
||||
Ok(Some(u64::from_le_bytes(*amount_data)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_supply_off_master_edition(
|
||||
master_edition_account_info: &AccountInfo,
|
||||
) -> Result<u64, ProgramError> {
|
||||
let data = master_edition_account_info.try_borrow_data()?;
|
||||
// this is an option, 9 bytes, first is 0 means is none
|
||||
|
||||
let amount_data = array_ref![data, 1, 8];
|
||||
Ok(u64::from_le_bytes(*amount_data))
|
||||
}
|
||||
|
||||
pub fn calculate_supply_change<'a>(
|
||||
master_edition_account_info: &AccountInfo<'a>,
|
||||
reservation_list_info: Option<&AccountInfo<'a>>,
|
||||
edition_override: Option<u64>,
|
||||
me_supply: u64,
|
||||
) -> ProgramResult {
|
||||
if reservation_list_info.is_none() {
|
||||
let new_supply: u64;
|
||||
if let Some(edition) = edition_override {
|
||||
if edition > me_supply {
|
||||
new_supply = edition;
|
||||
} else {
|
||||
new_supply = me_supply
|
||||
}
|
||||
} else {
|
||||
new_supply = me_supply
|
||||
.checked_add(1)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?;
|
||||
}
|
||||
|
||||
if let Some(max) = get_max_supply_off_master_edition(master_edition_account_info)? {
|
||||
if new_supply > max {
|
||||
return Err(MetadataError::MaxEditionsMintedAlready.into());
|
||||
}
|
||||
}
|
||||
// Doing old school serialization to protect CPU credits.
|
||||
let edition_data = &mut master_edition_account_info.data.borrow_mut();
|
||||
let output = array_mut_ref![edition_data, 0, MAX_MASTER_EDITION_LEN];
|
||||
|
||||
let (_key, supply, _the_rest) =
|
||||
mut_array_refs![output, 1, 8, MAX_MASTER_EDITION_LEN - 8 - 1];
|
||||
*supply = new_supply.to_le_bytes();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn mint_limited_edition<'a>(
|
||||
program_id: &Pubkey,
|
||||
new_metadata_account_info: &AccountInfo<'a>,
|
||||
new_edition_account_info: &AccountInfo<'a>,
|
||||
master_edition_account_info: &AccountInfo<'a>,
|
||||
mint_info: &AccountInfo<'a>,
|
||||
mint_authority_info: &AccountInfo<'a>,
|
||||
payer_account_info: &AccountInfo<'a>,
|
||||
update_authority_info: &AccountInfo<'a>,
|
||||
master_metadata_account_info: &AccountInfo<'a>,
|
||||
token_program_account_info: &AccountInfo<'a>,
|
||||
system_account_info: &AccountInfo<'a>,
|
||||
rent_info: &AccountInfo<'a>,
|
||||
reservation_list_info: Option<&AccountInfo<'a>>,
|
||||
program_id: &'a Pubkey,
|
||||
master_metadata: Metadata,
|
||||
new_metadata_account_info: &'a AccountInfo<'a>,
|
||||
new_edition_account_info: &'a AccountInfo<'a>,
|
||||
master_edition_account_info: &'a AccountInfo<'a>,
|
||||
mint_info: &'a AccountInfo<'a>,
|
||||
mint_authority_info: &'a AccountInfo<'a>,
|
||||
payer_account_info: &'a AccountInfo<'a>,
|
||||
update_authority_info: &'a AccountInfo<'a>,
|
||||
token_program_account_info: &'a AccountInfo<'a>,
|
||||
system_account_info: &'a AccountInfo<'a>,
|
||||
rent_info: &'a AccountInfo<'a>,
|
||||
// Only present with MasterEditionV1 calls, if present, use edition based off address in res list,
|
||||
// otherwise, pull off the top
|
||||
reservation_list_info: Option<&'a AccountInfo<'a>>,
|
||||
// Only present with MasterEditionV2 calls, if present, means
|
||||
// directing to a specific version, otherwise just pull off the top
|
||||
edition_override: Option<u64>,
|
||||
) -> ProgramResult {
|
||||
let master_metadata = Metadata::from_account_info(master_metadata_account_info)?;
|
||||
let mut master_edition = MasterEdition::from_account_info(master_edition_account_info)?;
|
||||
let mint: Mint = assert_initialized(mint_info)?;
|
||||
|
||||
assert_mint_authority_matches_mint(&mint, mint_authority_info)?;
|
||||
let me_supply = get_supply_off_master_edition(master_edition_account_info)?;
|
||||
let mint_authority = get_mint_authority(mint_info)?;
|
||||
let mint_supply = get_mint_supply(mint_info)?;
|
||||
assert_mint_authority_matches_mint(&mint_authority, mint_authority_info)?;
|
||||
|
||||
assert_edition_valid(
|
||||
program_id,
|
||||
|
@ -360,38 +558,37 @@ pub fn mint_limited_edition<'a>(
|
|||
return Err(MetadataError::InvalidEditionKey.into());
|
||||
}
|
||||
|
||||
if reservation_list_info.is_none() {
|
||||
if let Some(max) = master_edition.max_supply {
|
||||
if master_edition.supply >= max {
|
||||
return Err(MetadataError::MaxEditionsMintedAlready.into());
|
||||
}
|
||||
}
|
||||
|
||||
master_edition.supply += 1;
|
||||
master_edition.serialize(&mut *master_edition_account_info.data.borrow_mut())?;
|
||||
if reservation_list_info.is_some() && edition_override.is_some() {
|
||||
return Err(MetadataError::InvalidOperation.into());
|
||||
}
|
||||
|
||||
if mint.supply != 1 {
|
||||
calculate_supply_change(
|
||||
master_edition_account_info,
|
||||
reservation_list_info,
|
||||
edition_override,
|
||||
me_supply,
|
||||
)?;
|
||||
|
||||
if mint_supply != 1 {
|
||||
return Err(MetadataError::EditionsMustHaveExactlyOneToken.into());
|
||||
}
|
||||
|
||||
// create the metadata the normal way...
|
||||
process_create_metadata_accounts(
|
||||
program_id,
|
||||
&[
|
||||
new_metadata_account_info.clone(),
|
||||
mint_info.clone(),
|
||||
mint_authority_info.clone(),
|
||||
payer_account_info.clone(),
|
||||
update_authority_info.clone(),
|
||||
system_account_info.clone(),
|
||||
rent_info.clone(),
|
||||
],
|
||||
process_create_metadata_accounts_logic(
|
||||
&program_id,
|
||||
CreateMetadataAccountsLogicArgs {
|
||||
metadata_account_info: new_metadata_account_info,
|
||||
mint_info,
|
||||
mint_authority_info,
|
||||
payer_account_info,
|
||||
update_authority_info,
|
||||
system_account_info,
|
||||
rent_info,
|
||||
},
|
||||
master_metadata.data,
|
||||
true,
|
||||
false,
|
||||
)?;
|
||||
|
||||
let edition_authority_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
|
@ -410,66 +607,22 @@ pub fn mint_limited_edition<'a>(
|
|||
edition_authority_seeds,
|
||||
)?;
|
||||
|
||||
let mut new_edition = Edition::from_account_info(new_edition_account_info)?;
|
||||
new_edition.key = Key::EditionV1;
|
||||
new_edition.parent = *master_edition_account_info.key;
|
||||
// Doing old school serialization to protect CPU credits.
|
||||
let edition_data = &mut new_edition_account_info.data.borrow_mut();
|
||||
let output = array_mut_ref![edition_data, 0, MAX_EDITION_LEN];
|
||||
|
||||
new_edition.edition = match reservation_list_info {
|
||||
Some(account) => {
|
||||
let mut reservation_list = get_reservation_list(account)?;
|
||||
let (key, parent, edition, _padding) = mut_array_refs![output, 1, 32, 8, 200];
|
||||
|
||||
if let Some(supply_snapshot) = reservation_list.supply_snapshot() {
|
||||
let mut prev_total_offsets: u64 = 0;
|
||||
let mut offset: Option<u64> = None;
|
||||
let mut reservations = reservation_list.reservations();
|
||||
for i in 0..reservations.len() {
|
||||
let mut reservation = &mut reservations[i];
|
||||
*key = [Key::EditionV1 as u8];
|
||||
parent.copy_from_slice(master_edition_account_info.key.as_ref());
|
||||
|
||||
if reservation.address == *mint_authority_info.key {
|
||||
offset = Some(
|
||||
prev_total_offsets
|
||||
.checked_add(reservation.spots_remaining)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?,
|
||||
);
|
||||
// You get your editions in reverse order but who cares, saves a byte
|
||||
reservation.spots_remaining = reservation
|
||||
.spots_remaining
|
||||
.checked_sub(1)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?;
|
||||
|
||||
reservation_list.set_reservations(reservations)?;
|
||||
reservation_list.save(account)?;
|
||||
break;
|
||||
}
|
||||
|
||||
if reservation.address == solana_program::system_program::id() {
|
||||
// This is an anchor point in the array...it means we reset our math to
|
||||
// this offset because we may be missing information in between this point and
|
||||
// the points before it.
|
||||
prev_total_offsets = reservation.total_spots;
|
||||
} else {
|
||||
prev_total_offsets = prev_total_offsets
|
||||
.checked_add(reservation.total_spots)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?;
|
||||
}
|
||||
}
|
||||
|
||||
match offset {
|
||||
Some(val) => supply_snapshot
|
||||
.checked_add(val)
|
||||
.ok_or(MetadataError::NumericalOverflowError)?,
|
||||
None => {
|
||||
return Err(MetadataError::AddressNotInReservation.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(MetadataError::ReservationNotSet.into());
|
||||
}
|
||||
}
|
||||
None => master_edition.supply,
|
||||
};
|
||||
|
||||
new_edition.serialize(&mut *new_edition_account_info.data.borrow_mut())?;
|
||||
*edition = calculate_edition_number(
|
||||
mint_authority_info,
|
||||
reservation_list_info,
|
||||
edition_override,
|
||||
me_supply,
|
||||
)?
|
||||
.to_le_bytes();
|
||||
|
||||
// Now make sure this mint can never be used by anybody else.
|
||||
transfer_mint_authority(
|
||||
|
@ -622,3 +775,218 @@ pub fn try_from_slice_checked<T: BorshDeserialize>(
|
|||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub struct CreateMetadataAccountsLogicArgs<'a> {
|
||||
pub metadata_account_info: &'a AccountInfo<'a>,
|
||||
pub mint_info: &'a AccountInfo<'a>,
|
||||
pub mint_authority_info: &'a AccountInfo<'a>,
|
||||
pub payer_account_info: &'a AccountInfo<'a>,
|
||||
pub update_authority_info: &'a AccountInfo<'a>,
|
||||
pub system_account_info: &'a AccountInfo<'a>,
|
||||
pub rent_info: &'a AccountInfo<'a>,
|
||||
}
|
||||
|
||||
/// Create a new account instruction
|
||||
pub fn process_create_metadata_accounts_logic(
|
||||
program_id: &Pubkey,
|
||||
accounts: CreateMetadataAccountsLogicArgs,
|
||||
data: Data,
|
||||
allow_direct_creator_writes: bool,
|
||||
is_mutable: bool,
|
||||
) -> ProgramResult {
|
||||
let CreateMetadataAccountsLogicArgs {
|
||||
metadata_account_info,
|
||||
mint_info,
|
||||
mint_authority_info,
|
||||
payer_account_info,
|
||||
update_authority_info,
|
||||
system_account_info,
|
||||
rent_info,
|
||||
} = accounts;
|
||||
|
||||
let mint_authority = get_mint_authority(mint_info)?;
|
||||
assert_mint_authority_matches_mint(&mint_authority, mint_authority_info)?;
|
||||
assert_owned_by(mint_info, &spl_token::id())?;
|
||||
|
||||
let metadata_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
mint_info.key.as_ref(),
|
||||
];
|
||||
let (metadata_key, metadata_bump_seed) =
|
||||
Pubkey::find_program_address(metadata_seeds, program_id);
|
||||
let metadata_authority_signer_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
mint_info.key.as_ref(),
|
||||
&[metadata_bump_seed],
|
||||
];
|
||||
|
||||
if metadata_account_info.key != &metadata_key {
|
||||
return Err(MetadataError::InvalidMetadataKey.into());
|
||||
}
|
||||
|
||||
create_or_allocate_account_raw(
|
||||
*program_id,
|
||||
metadata_account_info,
|
||||
rent_info,
|
||||
system_account_info,
|
||||
payer_account_info,
|
||||
MAX_METADATA_LEN,
|
||||
metadata_authority_signer_seeds,
|
||||
)?;
|
||||
|
||||
let mut metadata = Metadata::from_account_info(metadata_account_info)?;
|
||||
assert_data_valid(
|
||||
&data,
|
||||
update_authority_info.key,
|
||||
&metadata,
|
||||
allow_direct_creator_writes,
|
||||
)?;
|
||||
|
||||
metadata.mint = *mint_info.key;
|
||||
metadata.key = Key::MetadataV1;
|
||||
metadata.data = data;
|
||||
metadata.is_mutable = is_mutable;
|
||||
metadata.update_authority = *update_authority_info.key;
|
||||
|
||||
metadata.serialize(&mut *metadata_account_info.data.borrow_mut())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub struct MintNewEditionFromMasterEditionViaTokenLogicArgs<'a> {
|
||||
pub new_metadata_account_info: &'a AccountInfo<'a>,
|
||||
pub new_edition_account_info: &'a AccountInfo<'a>,
|
||||
pub master_edition_account_info: &'a AccountInfo<'a>,
|
||||
pub mint_info: &'a AccountInfo<'a>,
|
||||
pub edition_marker_info: &'a AccountInfo<'a>,
|
||||
pub mint_authority_info: &'a AccountInfo<'a>,
|
||||
pub payer_account_info: &'a AccountInfo<'a>,
|
||||
pub owner_account_info: &'a AccountInfo<'a>,
|
||||
pub token_account_info: &'a AccountInfo<'a>,
|
||||
pub update_authority_info: &'a AccountInfo<'a>,
|
||||
pub master_metadata_account_info: &'a AccountInfo<'a>,
|
||||
pub token_program_account_info: &'a AccountInfo<'a>,
|
||||
pub system_account_info: &'a AccountInfo<'a>,
|
||||
pub rent_info: &'a AccountInfo<'a>,
|
||||
}
|
||||
|
||||
pub fn process_mint_new_edition_from_master_edition_via_token_logic<'a>(
|
||||
program_id: &'a Pubkey,
|
||||
accounts: MintNewEditionFromMasterEditionViaTokenLogicArgs<'a>,
|
||||
edition: u64,
|
||||
ignore_owner_signer: bool,
|
||||
) -> ProgramResult {
|
||||
let MintNewEditionFromMasterEditionViaTokenLogicArgs {
|
||||
new_metadata_account_info,
|
||||
new_edition_account_info,
|
||||
master_edition_account_info,
|
||||
mint_info,
|
||||
edition_marker_info,
|
||||
mint_authority_info,
|
||||
payer_account_info,
|
||||
owner_account_info,
|
||||
token_account_info,
|
||||
update_authority_info,
|
||||
master_metadata_account_info,
|
||||
token_program_account_info,
|
||||
system_account_info,
|
||||
rent_info,
|
||||
} = accounts;
|
||||
|
||||
assert_token_program_matches_package(token_program_account_info)?;
|
||||
assert_owned_by(mint_info, &spl_token::id())?;
|
||||
assert_owned_by(token_account_info, &spl_token::id())?;
|
||||
assert_owned_by(master_edition_account_info, program_id)?;
|
||||
assert_owned_by(master_metadata_account_info, program_id)?;
|
||||
|
||||
let master_metadata = Metadata::from_account_info(master_metadata_account_info)?;
|
||||
let token_account: Account = assert_initialized(token_account_info)?;
|
||||
|
||||
if !ignore_owner_signer {
|
||||
assert_signer(owner_account_info)?;
|
||||
|
||||
if token_account.owner != *owner_account_info.key {
|
||||
return Err(MetadataError::InvalidOwner.into());
|
||||
}
|
||||
}
|
||||
|
||||
if token_account.mint != master_metadata.mint {
|
||||
return Err(MetadataError::TokenAccountMintMismatchV2.into());
|
||||
}
|
||||
|
||||
if token_account.amount < 1 {
|
||||
return Err(MetadataError::NotEnoughTokens.into());
|
||||
}
|
||||
|
||||
if !new_metadata_account_info.data_is_empty() {
|
||||
return Err(MetadataError::AlreadyInitialized.into());
|
||||
}
|
||||
|
||||
if !new_edition_account_info.data_is_empty() {
|
||||
return Err(MetadataError::AlreadyInitialized.into());
|
||||
}
|
||||
|
||||
let edition_number = edition.checked_div(EDITION_MARKER_BIT_SIZE).unwrap();
|
||||
let as_string = edition_number.to_string();
|
||||
|
||||
let bump = assert_derivation(
|
||||
program_id,
|
||||
edition_marker_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
master_metadata.mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
as_string.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
if edition_marker_info.data_is_empty() {
|
||||
let seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
program_id.as_ref(),
|
||||
master_metadata.mint.as_ref(),
|
||||
EDITION.as_bytes(),
|
||||
as_string.as_bytes(),
|
||||
&[bump],
|
||||
];
|
||||
|
||||
create_or_allocate_account_raw(
|
||||
*program_id,
|
||||
edition_marker_info,
|
||||
rent_info,
|
||||
system_account_info,
|
||||
payer_account_info,
|
||||
MAX_EDITION_MARKER_SIZE,
|
||||
seeds,
|
||||
)?;
|
||||
}
|
||||
|
||||
let mut edition_marker = EditionMarker::from_account_info(edition_marker_info)?;
|
||||
edition_marker.key = Key::EditionMarker;
|
||||
if edition_marker.edition_taken(edition)? {
|
||||
return Err(MetadataError::AlreadyInitialized.into());
|
||||
} else {
|
||||
edition_marker.insert_edition(edition)?
|
||||
}
|
||||
edition_marker.serialize(&mut *edition_marker_info.data.borrow_mut())?;
|
||||
|
||||
mint_limited_edition(
|
||||
program_id,
|
||||
master_metadata,
|
||||
new_metadata_account_info,
|
||||
new_edition_account_info,
|
||||
master_edition_account_info,
|
||||
mint_info,
|
||||
mint_authority_info,
|
||||
payer_account_info,
|
||||
update_authority_info,
|
||||
token_program_account_info,
|
||||
system_account_info,
|
||||
rent_info,
|
||||
None,
|
||||
Some(edition),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use solana_client::rpc_request::TokenAccountsFilter;
|
||||
|
||||
use {
|
||||
clap::{crate_description, crate_name, crate_version, App, Arg, ArgMatches, SubCommand},
|
||||
solana_clap_utils::{
|
||||
|
@ -15,17 +17,17 @@ use {
|
|||
transaction::Transaction,
|
||||
},
|
||||
spl_token::{
|
||||
instruction::{approve, initialize_account, initialize_mint, mint_to},
|
||||
instruction::{initialize_account, initialize_mint, mint_to},
|
||||
state::{Account, Mint},
|
||||
},
|
||||
spl_token_metadata::{
|
||||
instruction::{
|
||||
create_master_edition, create_metadata_accounts,
|
||||
mint_new_edition_from_master_edition_via_token, mint_printing_tokens,
|
||||
update_metadata_accounts,
|
||||
mint_new_edition_from_master_edition_via_token, update_metadata_accounts,
|
||||
},
|
||||
state::{
|
||||
get_reservation_list, Data, Edition, Key, MasterEdition, Metadata, EDITION, PREFIX,
|
||||
get_reservation_list, Data, Edition, Key, MasterEditionV1, MasterEditionV2, Metadata,
|
||||
EDITION, PREFIX,
|
||||
},
|
||||
},
|
||||
std::str::FromStr,
|
||||
|
@ -139,7 +141,11 @@ fn show(app_matches: &ArgMatches, _payer: Keypair, client: RpcClient) {
|
|||
println!("Metadata: {:#?}", master_metadata);
|
||||
println!("Update authority: {:?}", update_authority);
|
||||
if master_edition_account.data[0] == Key::MasterEditionV1 as u8 {
|
||||
let master_edition: MasterEdition =
|
||||
let master_edition: MasterEditionV1 =
|
||||
try_from_slice_unchecked(&master_edition_account.data).unwrap();
|
||||
println!("Deprecated Master edition {:#?}", master_edition);
|
||||
} else if master_edition_account.data[0] == Key::MasterEditionV2 as u8 {
|
||||
let master_edition: MasterEditionV2 =
|
||||
try_from_slice_unchecked(&master_edition_account.data).unwrap();
|
||||
println!("Master edition {:#?}", master_edition);
|
||||
} else {
|
||||
|
@ -163,9 +169,29 @@ fn mint_edition_via_token_call(
|
|||
let program_key = spl_token_metadata::id();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
let mint_key = pubkey_of(app_matches, "mint").unwrap();
|
||||
let existing_token_account = Pubkey::from_str(
|
||||
&client
|
||||
.get_token_accounts_by_owner(
|
||||
&account_authority.pubkey(),
|
||||
TokenAccountsFilter::Mint(mint_key),
|
||||
)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|x| {
|
||||
client
|
||||
.get_token_account_balance(&Pubkey::from_str(&x.pubkey).unwrap())
|
||||
.unwrap()
|
||||
.amount
|
||||
!= "0"
|
||||
})
|
||||
.unwrap()
|
||||
.pubkey,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let new_mint_key = Keypair::new();
|
||||
let added_token_account = Keypair::new();
|
||||
let burn_authority = Keypair::new();
|
||||
let new_mint_pub = new_mint_key.pubkey();
|
||||
let metadata_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
|
@ -182,12 +208,7 @@ fn mint_edition_via_token_call(
|
|||
];
|
||||
let (edition_key, _) = Pubkey::find_program_address(edition_seeds, &program_key);
|
||||
|
||||
let printing_mint_key = pubkey_of(app_matches, "mint").unwrap();
|
||||
let master_metadata_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
printing_mint_key.as_ref(),
|
||||
];
|
||||
let master_metadata_seeds = &[PREFIX.as_bytes(), &program_key.as_ref(), mint_key.as_ref()];
|
||||
let (master_metadata_key, _) =
|
||||
Pubkey::find_program_address(master_metadata_seeds, &program_key);
|
||||
|
||||
|
@ -195,7 +216,6 @@ fn mint_edition_via_token_call(
|
|||
let master_metadata: Metadata =
|
||||
try_from_slice_unchecked(&master_metadata_account.data).unwrap();
|
||||
|
||||
let update_authority = master_metadata.update_authority;
|
||||
let master_edition_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
&program_key.as_ref(),
|
||||
|
@ -204,14 +224,9 @@ fn mint_edition_via_token_call(
|
|||
];
|
||||
let (master_edition_key, _) = Pubkey::find_program_address(master_edition_seeds, &program_key);
|
||||
let master_edition_account = client.get_account(&master_edition_key).unwrap();
|
||||
let master_edition: MasterEdition =
|
||||
let master_edition: MasterEditionV2 =
|
||||
try_from_slice_unchecked(&master_edition_account.data).unwrap();
|
||||
let mut signers = vec![
|
||||
&account_authority,
|
||||
&new_mint_key,
|
||||
&burn_authority,
|
||||
&added_token_account,
|
||||
];
|
||||
let signers = vec![&account_authority, &new_mint_key, &added_token_account];
|
||||
let mut instructions = vec![
|
||||
create_account(
|
||||
&payer.pubkey(),
|
||||
|
@ -257,72 +272,22 @@ fn mint_edition_via_token_call(
|
|||
.unwrap(),
|
||||
];
|
||||
|
||||
let new_master_key: Pubkey;
|
||||
let new_master_account = Keypair::new();
|
||||
if app_matches.is_present("account") {
|
||||
new_master_key = pubkey_of(app_matches, "account").unwrap();
|
||||
} else {
|
||||
signers.push(&new_master_account);
|
||||
new_master_key = new_master_account.pubkey();
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&new_master_account.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Account::LEN)
|
||||
.unwrap(),
|
||||
Account::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
instructions.push(
|
||||
initialize_account(
|
||||
&token_key,
|
||||
&new_master_account.pubkey(),
|
||||
&master_edition.printing_mint,
|
||||
&payer.pubkey(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(mint_printing_tokens(
|
||||
program_key,
|
||||
new_master_account.pubkey(),
|
||||
master_edition.printing_mint,
|
||||
update_authority,
|
||||
master_metadata_key,
|
||||
master_edition_key,
|
||||
1,
|
||||
));
|
||||
}
|
||||
|
||||
instructions.push(
|
||||
approve(
|
||||
&token_key,
|
||||
&new_master_key,
|
||||
&burn_authority.pubkey(),
|
||||
&payer.pubkey(),
|
||||
&[&payer.pubkey()],
|
||||
1,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(mint_new_edition_from_master_edition_via_token(
|
||||
program_key,
|
||||
metadata_key,
|
||||
edition_key,
|
||||
master_edition_key,
|
||||
new_mint_key.pubkey(),
|
||||
account_authority.pubkey(),
|
||||
payer.pubkey(),
|
||||
master_edition.printing_mint,
|
||||
new_master_key,
|
||||
burn_authority.pubkey(),
|
||||
payer.pubkey(),
|
||||
update_authority,
|
||||
account_authority.pubkey(),
|
||||
existing_token_account,
|
||||
account_authority.pubkey(),
|
||||
master_metadata_key,
|
||||
None,
|
||||
master_metadata.mint,
|
||||
master_edition.supply + 1,
|
||||
));
|
||||
|
||||
println!("Instructions, {:?},", instructions);
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
|
@ -337,7 +302,7 @@ fn master_edition_call(
|
|||
app_matches: &ArgMatches,
|
||||
payer: Keypair,
|
||||
client: RpcClient,
|
||||
) -> (MasterEdition, Pubkey) {
|
||||
) -> (MasterEditionV2, Pubkey) {
|
||||
let update_authority = read_keypair_file(
|
||||
app_matches
|
||||
.value_of("update_authority")
|
||||
|
@ -351,8 +316,6 @@ fn master_edition_call(
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let printing_mint = Keypair::new();
|
||||
let one_time_printing_authorization_mint = Keypair::new();
|
||||
let program_key = spl_token_metadata::id();
|
||||
let token_key = Pubkey::from_str(TOKEN_PROGRAM_PUBKEY).unwrap();
|
||||
|
||||
|
@ -379,14 +342,11 @@ fn master_edition_call(
|
|||
let added_token_account = Keypair::new();
|
||||
|
||||
let needs_a_token = app_matches.is_present("add_one_token");
|
||||
let mut signers = vec![
|
||||
&update_authority,
|
||||
&printing_mint,
|
||||
&one_time_printing_authorization_mint,
|
||||
];
|
||||
let mut signers = vec![&update_authority, &mint_authority];
|
||||
let mut instructions = vec![];
|
||||
|
||||
if needs_a_token {
|
||||
signers.push(&added_token_account);
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&added_token_account.pubkey(),
|
||||
|
@ -418,80 +378,24 @@ fn master_edition_call(
|
|||
)
|
||||
}
|
||||
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&printing_mint.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Mint::LEN)
|
||||
.unwrap(),
|
||||
Mint::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
|
||||
instructions.push(
|
||||
initialize_mint(
|
||||
&token_key,
|
||||
&printing_mint.pubkey(),
|
||||
&payer.pubkey(),
|
||||
Some(&payer.pubkey()),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
instructions.push(create_account(
|
||||
&payer.pubkey(),
|
||||
&one_time_printing_authorization_mint.pubkey(),
|
||||
client
|
||||
.get_minimum_balance_for_rent_exemption(Mint::LEN)
|
||||
.unwrap(),
|
||||
Mint::LEN as u64,
|
||||
&token_key,
|
||||
));
|
||||
|
||||
instructions.push(
|
||||
initialize_mint(
|
||||
&token_key,
|
||||
&one_time_printing_authorization_mint.pubkey(),
|
||||
&payer.pubkey(),
|
||||
Some(&payer.pubkey()),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let printing_mint_authority = payer.pubkey();
|
||||
let mut one_time_printing_authorization_mint_authority = None;
|
||||
if max_supply.is_some() {
|
||||
one_time_printing_authorization_mint_authority = Some(payer.pubkey());
|
||||
}
|
||||
|
||||
instructions.push(create_master_edition(
|
||||
program_key,
|
||||
master_edition_key,
|
||||
mint_key,
|
||||
printing_mint.pubkey(),
|
||||
one_time_printing_authorization_mint.pubkey(),
|
||||
update_authority.pubkey(),
|
||||
printing_mint_authority,
|
||||
mint_authority.pubkey(),
|
||||
metadata_key,
|
||||
payer.pubkey(),
|
||||
max_supply,
|
||||
one_time_printing_authorization_mint_authority,
|
||||
));
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(&instructions, Some(&payer.pubkey()));
|
||||
let recent_blockhash = client.get_recent_blockhash().unwrap().0;
|
||||
|
||||
if needs_a_token {
|
||||
signers.push(&added_token_account);
|
||||
}
|
||||
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
client.send_and_confirm_transaction(&transaction).unwrap();
|
||||
let account = client.get_account(&master_edition_key).unwrap();
|
||||
let master_edition: MasterEdition = try_from_slice_unchecked(&account.data).unwrap();
|
||||
let master_edition: MasterEditionV2 = try_from_slice_unchecked(&account.data).unwrap();
|
||||
(master_edition, master_edition_key)
|
||||
}
|
||||
|
||||
|
@ -820,7 +724,7 @@ fn main() {
|
|||
.required(true)
|
||||
.validator(is_valid_pubkey)
|
||||
.takes_value(true)
|
||||
.help("Printing mint from which to mint this new edition"),
|
||||
.help("Metadata Mint from which to mint this new edition"),
|
||||
).arg(
|
||||
Arg::with_name("account")
|
||||
.long("account")
|
||||
|
|
|
@ -228,6 +228,10 @@ pub enum VaultError {
|
|||
/// Accept payment close authority should be none
|
||||
#[error("Accept payment close authority should be none")]
|
||||
CloseAuthorityShouldBeNone,
|
||||
|
||||
/// Derived key invalid
|
||||
#[error("Derived key invalid")]
|
||||
DerivedKeyInvalid,
|
||||
}
|
||||
|
||||
impl PrintProgramError for VaultError {
|
||||
|
|
|
@ -26,6 +26,12 @@ pub struct NumberOfShareArgs {
|
|||
pub number_of_shares: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
|
||||
pub struct MintEditionProxyArgs {
|
||||
pub edition: u64,
|
||||
}
|
||||
|
||||
/// Instructions supported by the Fraction program.
|
||||
#[derive(BorshSerialize, BorshDeserialize, Clone)]
|
||||
pub enum VaultInstruction {
|
||||
|
|
|
@ -95,6 +95,10 @@ impl SafetyDepositBox {
|
|||
|
||||
Ok(sd)
|
||||
}
|
||||
|
||||
pub fn get_order(a: &AccountInfo) -> u8 {
|
||||
a.data.borrow()[97]
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
|
@ -262,3 +262,15 @@ pub fn try_from_slice_checked<T: BorshDeserialize>(
|
|||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn assert_derivation(
|
||||
program_id: &Pubkey,
|
||||
account: &AccountInfo,
|
||||
path: &[&[u8]],
|
||||
) -> Result<u8, ProgramError> {
|
||||
let (key, bump) = Pubkey::find_program_address(&path, program_id);
|
||||
if key != *account.key {
|
||||
return Err(VaultError::DerivedKeyInvalid.into());
|
||||
}
|
||||
Ok(bump)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue