mirror of https://github.com/certusone/oyster.git
Intermediate commit, working through auction manager super create
This commit is contained in:
parent
85be78d001
commit
87bb0870c6
|
@ -1,2 +1,3 @@
|
|||
export * from './account';
|
||||
export * from './metadata';
|
||||
export * from './vault';
|
||||
|
|
|
@ -21,7 +21,7 @@ export const MAX_METADATA_LEN =
|
|||
export const MAX_NAME_SYMBOL_LEN = 1 + 32 + 8;
|
||||
export const MAX_MASTER_EDITION_KEN = 1 + 9 + 8 + 32;
|
||||
|
||||
export enum Key {
|
||||
export enum MetadataKey {
|
||||
MetadataV1 = 0,
|
||||
NameSymbolTupleV1 = 1,
|
||||
EditionV1 = 2,
|
||||
|
@ -48,27 +48,27 @@ export interface IMetadataExtension {
|
|||
}
|
||||
|
||||
export class MasterEdition {
|
||||
key: Key;
|
||||
key: MetadataKey;
|
||||
supply: BN;
|
||||
maxSupply?: BN;
|
||||
/// Can be used to mint tokens that give one-time permission to mint a single limited edition.
|
||||
masterMint: PublicKey;
|
||||
|
||||
constructor(args: {
|
||||
key: Key;
|
||||
key: MetadataKey;
|
||||
supply: BN;
|
||||
maxSupply?: BN;
|
||||
/// Can be used to mint tokens that give one-time permission to mint a single limited edition.
|
||||
masterMint: PublicKey;
|
||||
}) {
|
||||
this.key = Key.MasterEditionV1;
|
||||
this.key = MetadataKey.MasterEditionV1;
|
||||
this.supply = args.supply;
|
||||
this.maxSupply = args.maxSupply;
|
||||
this.masterMint = args.masterMint;
|
||||
}
|
||||
}
|
||||
export class Metadata {
|
||||
key: Key;
|
||||
key: MetadataKey;
|
||||
nonUniqueSpecificUpdateAuthority?: PublicKey;
|
||||
|
||||
mint: PublicKey;
|
||||
|
@ -85,7 +85,7 @@ export class Metadata {
|
|||
symbol: string;
|
||||
uri: string;
|
||||
}) {
|
||||
this.key = Key.MetadataV1;
|
||||
this.key = MetadataKey.MetadataV1;
|
||||
this.nonUniqueSpecificUpdateAuthority =
|
||||
args.nonUniqueSpecificUpdateAuthority;
|
||||
this.mint = args.mint;
|
||||
|
@ -96,12 +96,12 @@ export class Metadata {
|
|||
}
|
||||
|
||||
export class NameSymbolTuple {
|
||||
key: Key;
|
||||
key: MetadataKey;
|
||||
updateAuthority: PublicKey;
|
||||
metadata: PublicKey;
|
||||
|
||||
constructor(args: { updateAuthority: Buffer; metadata: Buffer }) {
|
||||
this.key = Key.NameSymbolTupleV1;
|
||||
this.key = MetadataKey.NameSymbolTupleV1;
|
||||
this.updateAuthority = new PublicKey(args.updateAuthority);
|
||||
this.metadata = new PublicKey(args.metadata);
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ class CreateMasterEditionArgs {
|
|||
}
|
||||
}
|
||||
|
||||
export const SCHEMA = new Map<any, any>([
|
||||
export const METADATA_SCHEMA = new Map<any, any>([
|
||||
[
|
||||
CreateMetadataArgs,
|
||||
{
|
||||
|
@ -244,7 +244,7 @@ export const SCHEMA = new Map<any, any>([
|
|||
]);
|
||||
|
||||
export const decodeMetadata = (buffer: Buffer) => {
|
||||
return deserializeBorsh(SCHEMA, Metadata, buffer) as Metadata;
|
||||
return deserializeBorsh(METADATA_SCHEMA, Metadata, buffer) as Metadata;
|
||||
};
|
||||
|
||||
export async function transferUpdateAuthority(
|
||||
|
@ -256,7 +256,7 @@ export async function transferUpdateAuthority(
|
|||
const metadataProgramId = programIds().metadata;
|
||||
|
||||
const data = Buffer.from(
|
||||
serialize(SCHEMA, new TransferUpdateAuthorityArgs()),
|
||||
serialize(METADATA_SCHEMA, new TransferUpdateAuthorityArgs()),
|
||||
);
|
||||
|
||||
const keys = [
|
||||
|
@ -331,7 +331,7 @@ export async function updateMetadata(
|
|||
? undefined
|
||||
: newNonUniqueSpecificUpdateAuthority,
|
||||
});
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const data = Buffer.from(serialize(METADATA_SCHEMA, value));
|
||||
const keys = [
|
||||
{
|
||||
pubkey: metadataAccount,
|
||||
|
@ -397,7 +397,7 @@ export async function createMetadata(
|
|||
)[0];
|
||||
|
||||
const value = new CreateMetadataArgs({ name, symbol, uri, allowDuplicates });
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const data = Buffer.from(serialize(METADATA_SCHEMA, value));
|
||||
|
||||
const keys = [
|
||||
{
|
||||
|
@ -501,7 +501,7 @@ export async function createMasterEdition(
|
|||
)[0];
|
||||
|
||||
const value = new CreateMasterEditionArgs({ maxSupply });
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const data = Buffer.from(serialize(METADATA_SCHEMA, value));
|
||||
|
||||
const keys = [
|
||||
{
|
||||
|
|
|
@ -9,8 +9,8 @@ import { deserializeBorsh } from './../utils/borsh';
|
|||
import { serialize } from 'borsh';
|
||||
import BN from 'bn.js';
|
||||
|
||||
const PREFIX = 'vault';
|
||||
export enum Key {
|
||||
export const VAULT_PREFIX = 'vault';
|
||||
export enum VaultKey {
|
||||
VaultV1 = 0,
|
||||
SafetyDepositBoxV1 = 1,
|
||||
ExternalPriceAccountV1 = 2,
|
||||
|
@ -23,8 +23,12 @@ export enum VaultState {
|
|||
Deactivated = 3,
|
||||
}
|
||||
|
||||
export const MAX_VAULT_SIZE =
|
||||
1 + 32 + 32 + 32 + 32 + 1 + 32 + 1 + 32 + 1 + 1 + 8;
|
||||
|
||||
export const MAX_EXTERNAL_ACCOUNT_SIZE = 1 + 8 + 32 + 1;
|
||||
export class Vault {
|
||||
key: Key;
|
||||
key: VaultKey;
|
||||
/// Store token program used
|
||||
tokenProgram: PublicKey;
|
||||
/// Mint that produces the fractional shares
|
||||
|
@ -65,7 +69,7 @@ export class Vault {
|
|||
state: VaultState;
|
||||
lockedPricePerShare: BN;
|
||||
}) {
|
||||
this.key = Key.VaultV1;
|
||||
this.key = VaultKey.VaultV1;
|
||||
this.tokenProgram = args.tokenProgram;
|
||||
this.fractionMint = args.fractionMint;
|
||||
this.authority = args.authority;
|
||||
|
@ -80,8 +84,8 @@ export class Vault {
|
|||
}
|
||||
export class SafetyDepositBox {
|
||||
/// Each token type in a vault has it's own box that contains it's mint and a look-back
|
||||
key: Key;
|
||||
/// Key pointing to the parent vault
|
||||
key: VaultKey;
|
||||
/// VaultKey pointing to the parent vault
|
||||
vault: PublicKey;
|
||||
/// This particular token's mint
|
||||
tokenMint: PublicKey;
|
||||
|
@ -96,7 +100,7 @@ export class SafetyDepositBox {
|
|||
store: PublicKey;
|
||||
order: number;
|
||||
}) {
|
||||
this.key = Key.SafetyDepositBoxV1;
|
||||
this.key = VaultKey.SafetyDepositBoxV1;
|
||||
this.vault = args.vault;
|
||||
this.tokenMint = args.tokenMint;
|
||||
this.store = args.store;
|
||||
|
@ -105,7 +109,7 @@ export class SafetyDepositBox {
|
|||
}
|
||||
|
||||
export class ExternalPriceAccount {
|
||||
key: Key;
|
||||
key: VaultKey;
|
||||
pricePerShare: BN;
|
||||
/// Mint of the currency we are pricing the shares against, should be same as redeem_treasury.
|
||||
/// Most likely will be USDC mint most of the time.
|
||||
|
@ -118,7 +122,7 @@ export class ExternalPriceAccount {
|
|||
priceMint: PublicKey;
|
||||
allowedToCombine: boolean;
|
||||
}) {
|
||||
this.key = Key.ExternalPriceAccountV1;
|
||||
this.key = VaultKey.ExternalPriceAccountV1;
|
||||
this.pricePerShare = args.pricePerShare;
|
||||
this.priceMint = args.priceMint;
|
||||
this.allowedToCombine = args.allowedToCombine;
|
||||
|
@ -163,7 +167,7 @@ class UpdateExternalPriceAccountArgs {
|
|||
}
|
||||
}
|
||||
|
||||
export const SCHEMA = new Map<any, any>([
|
||||
export const VAULT_SCHEMA = new Map<any, any>([
|
||||
[
|
||||
InitVaultArgs,
|
||||
{
|
||||
|
@ -254,7 +258,7 @@ export const SCHEMA = new Map<any, any>([
|
|||
]);
|
||||
|
||||
export const decodeVault = (buffer: Buffer) => {
|
||||
return deserializeBorsh(SCHEMA, Vault, buffer) as Vault;
|
||||
return deserializeBorsh(VAULT_SCHEMA, Vault, buffer) as Vault;
|
||||
};
|
||||
|
||||
export async function initVault(
|
||||
|
@ -270,7 +274,7 @@ export async function initVault(
|
|||
const vaultProgramId = programIds().vault;
|
||||
|
||||
const data = Buffer.from(
|
||||
serialize(SCHEMA, new InitVaultArgs({ allowFurtherShareCreation })),
|
||||
serialize(VAULT_SCHEMA, new InitVaultArgs({ allowFurtherShareCreation })),
|
||||
);
|
||||
|
||||
const keys = [
|
||||
|
@ -340,7 +344,7 @@ export async function addTokenToInactiveVault(
|
|||
|
||||
const safetyDepositBox: PublicKey = (
|
||||
await PublicKey.findProgramAddress(
|
||||
[Buffer.from(PREFIX), vault.toBuffer(), tokenMint.toBuffer()],
|
||||
[Buffer.from(VAULT_PREFIX), vault.toBuffer(), tokenMint.toBuffer()],
|
||||
vaultProgramId,
|
||||
)
|
||||
)[0];
|
||||
|
@ -350,7 +354,7 @@ export async function addTokenToInactiveVault(
|
|||
amount,
|
||||
});
|
||||
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const data = Buffer.from(serialize(VAULT_SCHEMA, value));
|
||||
const keys = [
|
||||
{
|
||||
pubkey: safetyDepositBox,
|
||||
|
@ -424,13 +428,13 @@ export async function activateVault(
|
|||
|
||||
const fractionMintAuthority = (
|
||||
await PublicKey.findProgramAddress(
|
||||
[Buffer.from(PREFIX), vaultProgramId.toBuffer()],
|
||||
[Buffer.from(VAULT_PREFIX), vaultProgramId.toBuffer()],
|
||||
vaultProgramId,
|
||||
)
|
||||
)[0];
|
||||
|
||||
const value = new NumberOfShareArgs({ instruction: 2, numberOfShares });
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const data = Buffer.from(serialize(VAULT_SCHEMA, value));
|
||||
|
||||
const keys = [
|
||||
{
|
||||
|
@ -490,7 +494,7 @@ export async function combineVault(
|
|||
|
||||
const burnAuthority = (
|
||||
await PublicKey.findProgramAddress(
|
||||
[Buffer.from(PREFIX), vaultProgramId.toBuffer()],
|
||||
[Buffer.from(VAULT_PREFIX), vaultProgramId.toBuffer()],
|
||||
vaultProgramId,
|
||||
)
|
||||
)[0];
|
||||
|
@ -582,13 +586,13 @@ export async function withdrawTokenFromSafetyDepositBox(
|
|||
|
||||
const transferAuthority = (
|
||||
await PublicKey.findProgramAddress(
|
||||
[Buffer.from(PREFIX), vaultProgramId.toBuffer()],
|
||||
[Buffer.from(VAULT_PREFIX), vaultProgramId.toBuffer()],
|
||||
vaultProgramId,
|
||||
)
|
||||
)[0];
|
||||
|
||||
const value = new AmountArgs({ instruction: 5, amount });
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const data = Buffer.from(serialize(VAULT_SCHEMA, value));
|
||||
|
||||
const keys = [
|
||||
{
|
||||
|
@ -654,7 +658,7 @@ export async function updateExternalPriceAccount(
|
|||
const vaultProgramId = programIds().vault;
|
||||
|
||||
const value = new UpdateExternalPriceAccountArgs({ externalPriceAccount });
|
||||
const data = Buffer.from(serialize(SCHEMA, value));
|
||||
const data = Buffer.from(serialize(VAULT_SCHEMA, value));
|
||||
|
||||
const keys = [
|
||||
{
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
import {
|
||||
Account,
|
||||
Connection,
|
||||
PublicKey,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import { contexts, utils, actions, models } from '@oyster/common';
|
||||
|
||||
import { AccountLayout } from '@solana/spl-token';
|
||||
import BN from 'bn.js';
|
||||
const {
|
||||
createTokenAccount,
|
||||
activateVault,
|
||||
addTokenToInactiveVault,
|
||||
VAULT_PREFIX,
|
||||
} = actions;
|
||||
const { approve } = models;
|
||||
|
||||
const BATCH_SIZE = 4;
|
||||
// This command batches out adding tokens to a vault using a prefilled payer account, and then activates
|
||||
// the vault for use. It issues a series of transaction instructions and signers for the sendTransactions batch.
|
||||
export async function addTokensToVault(
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
vault: PublicKey,
|
||||
fractionMint: PublicKey,
|
||||
fractionTreasury: PublicKey,
|
||||
nfts: { tokenAccount: PublicKey; tokenMint: PublicKey; amount: BN }[],
|
||||
): Promise<{
|
||||
instructions: Array<TransactionInstruction[]>;
|
||||
signers: Array<Account[]>;
|
||||
}> {
|
||||
const PROGRAM_IDS = utils.programIds();
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
AccountLayout.span,
|
||||
);
|
||||
|
||||
const vaultAuthority = (
|
||||
await PublicKey.findProgramAddress(
|
||||
[Buffer.from(VAULT_PREFIX), PROGRAM_IDS.vault.toBuffer()],
|
||||
PROGRAM_IDS.vault,
|
||||
)
|
||||
)[0];
|
||||
|
||||
let batchCounter = 0;
|
||||
|
||||
let signers: Array<Account[]> = [];
|
||||
let instructions: Array<TransactionInstruction[]> = [];
|
||||
|
||||
let currSigners: Account[] = [];
|
||||
let currInstructions: TransactionInstruction[] = [];
|
||||
nfts.forEach(nft => {
|
||||
const newStoreAccount = createTokenAccount(
|
||||
currInstructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
nft.tokenMint,
|
||||
vaultAuthority,
|
||||
currSigners,
|
||||
);
|
||||
|
||||
const transferAuthority = approve(
|
||||
currInstructions,
|
||||
[],
|
||||
nft.tokenAccount,
|
||||
wallet.publicKey,
|
||||
nft.amount.toNumber(),
|
||||
);
|
||||
|
||||
currSigners.push(transferAuthority);
|
||||
|
||||
addTokenToInactiveVault(
|
||||
nft.amount,
|
||||
nft.tokenMint,
|
||||
nft.tokenAccount,
|
||||
newStoreAccount,
|
||||
vault,
|
||||
vaultAuthority,
|
||||
wallet.publicKey,
|
||||
transferAuthority.publicKey,
|
||||
currInstructions,
|
||||
);
|
||||
|
||||
if (batchCounter == BATCH_SIZE) {
|
||||
signers.push(currSigners);
|
||||
instructions.push(currInstructions);
|
||||
batchCounter = 0;
|
||||
currSigners = [];
|
||||
currInstructions = [];
|
||||
}
|
||||
});
|
||||
|
||||
currSigners = [];
|
||||
currInstructions = [];
|
||||
|
||||
activateVault(
|
||||
new BN(0),
|
||||
vault,
|
||||
fractionMint,
|
||||
fractionTreasury,
|
||||
vaultAuthority,
|
||||
currInstructions,
|
||||
);
|
||||
|
||||
signers.push(currSigners);
|
||||
instructions.push(currInstructions);
|
||||
|
||||
return { signers, instructions };
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
import {
|
||||
Account,
|
||||
Connection,
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import { contexts, utils, actions, createMint } from '@oyster/common';
|
||||
|
||||
import { AccountLayout, MintLayout } from '@solana/spl-token';
|
||||
import BN from 'bn.js';
|
||||
const {
|
||||
createTokenAccount,
|
||||
initVault,
|
||||
updateExternalPriceAccount,
|
||||
ExternalPriceAccount,
|
||||
MAX_VAULT_SIZE,
|
||||
VAULT_PREFIX,
|
||||
MAX_EXTERNAL_ACCOUNT_SIZE,
|
||||
} = actions;
|
||||
|
||||
// This command creates the external pricing oracle a vault
|
||||
// This gets the vault ready for adding the tokens.
|
||||
export async function createVault(
|
||||
connection: Connection,
|
||||
wallet: any,
|
||||
): Promise<{
|
||||
vault: PublicKey;
|
||||
externalPriceAccount: PublicKey;
|
||||
fractionalMint: PublicKey;
|
||||
redeemTreasury: PublicKey;
|
||||
fractionTreasury: PublicKey;
|
||||
priceMint: PublicKey;
|
||||
instructions: TransactionInstruction[];
|
||||
signers: Account[];
|
||||
}> {
|
||||
const PROGRAM_IDS = utils.programIds();
|
||||
|
||||
let signers: Account[] = [];
|
||||
let instructions: TransactionInstruction[] = [];
|
||||
|
||||
const accountRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
AccountLayout.span,
|
||||
);
|
||||
|
||||
const mintRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
MintLayout.span,
|
||||
);
|
||||
|
||||
const vaultRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
MAX_VAULT_SIZE,
|
||||
);
|
||||
|
||||
const epaRentExempt = await connection.getMinimumBalanceForRentExemption(
|
||||
MAX_EXTERNAL_ACCOUNT_SIZE,
|
||||
);
|
||||
|
||||
let vault = new Account();
|
||||
let externalPriceAccount = new Account();
|
||||
|
||||
const vaultAuthority = (
|
||||
await PublicKey.findProgramAddress(
|
||||
[Buffer.from(VAULT_PREFIX), PROGRAM_IDS.vault.toBuffer()],
|
||||
PROGRAM_IDS.vault,
|
||||
)
|
||||
)[0];
|
||||
|
||||
const fractionalMint = createMint(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
mintRentExempt,
|
||||
0,
|
||||
vaultAuthority,
|
||||
vaultAuthority,
|
||||
signers,
|
||||
);
|
||||
const priceMint = createMint(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
mintRentExempt,
|
||||
0,
|
||||
vaultAuthority,
|
||||
vaultAuthority,
|
||||
signers,
|
||||
);
|
||||
|
||||
let epaStruct = new ExternalPriceAccount({
|
||||
pricePerShare: new BN(0),
|
||||
priceMint: priceMint,
|
||||
allowedToCombine: true,
|
||||
});
|
||||
|
||||
const redeemTreasury = createTokenAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
priceMint,
|
||||
vaultAuthority,
|
||||
signers,
|
||||
);
|
||||
|
||||
const fractionTreasury = createTokenAccount(
|
||||
instructions,
|
||||
wallet.publicKey,
|
||||
accountRentExempt,
|
||||
fractionalMint,
|
||||
vaultAuthority,
|
||||
signers,
|
||||
);
|
||||
|
||||
const uninitializedVault = SystemProgram.createAccount({
|
||||
fromPubkey: wallet.publicKey,
|
||||
newAccountPubkey: vault.publicKey,
|
||||
lamports: vaultRentExempt,
|
||||
space: MAX_VAULT_SIZE,
|
||||
programId: PROGRAM_IDS.vault,
|
||||
});
|
||||
const uninitializedEPA = SystemProgram.createAccount({
|
||||
fromPubkey: wallet.publicKey,
|
||||
newAccountPubkey: vault.publicKey,
|
||||
lamports: epaRentExempt,
|
||||
space: MAX_EXTERNAL_ACCOUNT_SIZE,
|
||||
programId: PROGRAM_IDS.vault,
|
||||
});
|
||||
instructions.push(uninitializedVault);
|
||||
instructions.push(uninitializedEPA);
|
||||
signers.push(vault);
|
||||
signers.push(externalPriceAccount);
|
||||
|
||||
await updateExternalPriceAccount(
|
||||
externalPriceAccount.publicKey,
|
||||
epaStruct,
|
||||
instructions,
|
||||
);
|
||||
|
||||
await initVault(
|
||||
true,
|
||||
fractionalMint,
|
||||
redeemTreasury,
|
||||
fractionTreasury,
|
||||
vault.publicKey,
|
||||
wallet.publicKey,
|
||||
externalPriceAccount.publicKey,
|
||||
instructions,
|
||||
);
|
||||
|
||||
return {
|
||||
vault: vault.publicKey,
|
||||
externalPriceAccount: externalPriceAccount.publicKey,
|
||||
fractionalMint,
|
||||
redeemTreasury,
|
||||
fractionTreasury,
|
||||
priceMint,
|
||||
signers,
|
||||
instructions,
|
||||
};
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
export * from './nft';
|
||||
export * from './vault';
|
||||
export * from './createVault';
|
||||
export * from './auction';
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
export const createVault = () => {
|
||||
// TODO:
|
||||
};
|
Loading…
Reference in New Issue