proflupin
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Metaplex Auction House ## Introduction Auction house is a transaction protocol for marketplaces to implement a decentralised, escrow-less, stateless sales contract. Key features of the Auction House contract are the following: * No more escrowing NFTs - the NFTs remain in your wallet till the time the sale goes through * No more making an offer on an NFT and having to return to the site to execute the final sale - it just happens * Secondaries can now do price matching on your behalf - easier to find potential matches for your NFTs and hence makes NFTs more liquid than before * Secondaries can pay your fees for you - sell NFTs with 0 SOL in your wallet ## Escrow-less The community aspect, of auctioning NFTs without the NFTs actually leaving the wallets till the time the sale goes through, is immensely important: 1. This enables you to auction your NFT in multiple (escrow-less) marketplaces that are powered by the Auction House contract 2. Proof of Ownership: don’t miss out on free airdrops and staking rewards or give up access to permissioned discord servers 3. Safety: you don’t have to rely on the marketplaces’ escrow contracts to safely hold your NFTs. ## How to follow this guide? This guide aims at explaining all the concepts regarding the Auction House protocol and how it works, while also giving the readers easy-to-read code-snippets to jump-start their own Auction House powered marketplaces / DEXs. We would recommend following each section in detail to understand the inner mechanisms. This will make it easier to understand the code snippets as well, as they use the Accounts, PDAs and Instructions explained in the guide. There are some code snippets which are repetitive. To avoid having a very lengthy guide, we will show these snippets once and mention these snippets with a mnemonic wherever they are to be re-used. ## Installation Install the required packages to start interacting with Auction House ``` yarn add @metaplex-foundation/js @solana/web3.js npm i @metaplex-foundation/js @solana/web3.js ``` ## Setup After installing the required package lets import the Metaplex Class and some functions from the solana web3 library inorder to interact with the Solana Blockchain. ```tsx import { Metaplex } from "@metaplex-foundation/js"; import { Connection, clusterApiUrl } from "@solana/web3.js"; const connection = new Connection('https://api.devnet.solana.com'); const metaplex = new Metaplex(connection); ``` A wallet or storage can also be passed to the metaplex instance by using a slightly modified version of the API. ```tsx const metaplex = Metaplex.make(connection) .use(keypairIdentity(wallet)) .use(bundlrStorage()); ``` If everything goes well, we can start looking more into how to interact with the Auction house module of the JS SDK. # How to create an Auction House ? The JS SDK provides us with a function called `createAuctionHouse` which is used to create an Auction House instance you can provide all the data that are defined in the `AuctionHouse` Struct to create one. Lets look into how we can do that. The JS SDK allows us to create an auction house with minimum configuration. With this it sets the authority of the auction house instance to the signer of the transaction and by default it sets the treasury mint to SOL. This is done in case of minimum configuration. ```json const {auctionHouse} = await mx .auctions() .createAuctionHouse({ sellerFeeBasisPoints: 200, }) .run(); ``` To configure the Auction House without minimum configuration you can pass all the values yourself in this way: ```tsx // USDC Mint Address in Devnet const treasuryMint = new PublicKey( '3dLdxAs35CXmgi2DfQvgHQdS742JRsvNqSVi8MYsVrv8' ); // The Auction House Authority Address const authority = mx.identity(); // The Address from which the fees are going to be paid when a sale is executed const feeWithdrawalDestination = new PublicKey( 'DqBqTZsffE22kNMpZactpuiqHMp9bLGzcuxhRTfSbnsk' ); // The Address in which the Auction House fees gets collected const treasuryWithdrawalDestinationOwner = new PublicKey( '7EgtopgaQngfAqLmrRzJjBHVcfWZE8vm8tZ3rKTCdYZR' ); const {auctionHouse} = await mx .auctions() .createAuctionHouse({ sellerFeeBasisPoints: 200, requiresSignOff: true, canChangeSalePrice: true, treasuryMint: treasuryMint, payer: authority, authority: authority.publicKey, feeWithdrawalDestination: feeWithdrawalDestination, treasuryWithdrawalDestinationOwner: treasuryWithdrawalDestinationOwner, }) .run(); ``` ## How does Auction House work? We'll first dive deep into how the Auction House protocol works, and then we'll proceed into the additional features which supercharges this protocol. To dive deep into the mechanisms, lets first see all the accounts that are involved / created during the auction process. ## Accounts ![](https://i.imgur.com/Ojm96Wt.png) The Auction House protocol comprises of 5 main Accounts: 1. Auction House Instance 2. Seller Trade State 3. Buyer Trade State 4. Auction House Buyer Escrow 5. Auction House Treasury Account There are other accounts as well but they play a supporting role to the above accounts. ### Auction House Instance ![](https://i.imgur.com/2HPpM9g.png =300x) * This is a program derived address (PDA) * These instances are in the keyspace of the AH program, ie, are public keys owned by the AH program * This Instance is owned by the Authority, which can update the AH instance and create Access Control All this data can be fetched using the JS SDK. Lets look into how we can do that: ```tsx // This is a dummy auction house on Devnet use this or any other auction house address const auction_house_address = "Gr31akcY9wb7Gsnu4ej39MydBfxcT8mehZtKxFTsCAai" (async() => { const ahData = await mx .auctions() .findAuctionHouseByAddress(auction_house_address) .run(); console.log(JSON.stringfy(ahData)) })() ``` While Logging it out you are going to get all the data defined in the above struct i.e: ```json { "model": "auctionHouse", "address": "Gr31akcY9wb7Gsnu4ej39MydBfxcT8mehZtKxFTsCAai", "creatorAddress": "Eqp8mRhQpjk2nDYtZJjkyshJBc5EZudPDcMNhaXGuyJN", "authorityAddress": "Eqp8mRhQpjk2nDYtZJjkyshJBc5EZudPDcMNhaXGuyJN", "treasuryMint": { "model": "mint", "address": "So11111111111111111111111111111111111111112", "mintAuthorityAddress": null, "freezeAuthorityAddress": null, "decimals": 9, "supply": { "basisPoints": "00", "currency": { "symbol": "SOL", "decimals": 9, "namespace": "spl-token" } }, "isWrappedSol": true, "currency": { "symbol": "SOL", "decimals": 9, "namespace": "spl-token" } }, "feeAccountAddress": "AnUxX7EmyRZegQtv4xYaBBWMaYG5uoLdJdMHfWXu4CLo", "treasuryAccountAddress": "FxaGuPmq9qNDX1qWAMrGUfwGp3cqahW1T5eViPDG7VR2", "feeWithdrawalDestinationAddress": "Eqp8mRhQpjk2nDYtZJjkyshJBc5EZudPDcMNhaXGuyJN", "treasuryWithdrawalDestinationAddress": "Eqp8mRhQpjk2nDYtZJjkyshJBc5EZudPDcMNhaXGuyJN", "sellerFeeBasisPoints": 500, "requiresSignOff": false, "canChangeSalePrice": false, "isNative": true } ``` #### Important parameters of Instance * **Treasury Withdraw Destination**: The wallet that receives the AuctionHouse fees. * **Fee Withdraw Destination**: In AH, the marketplace needs to pay the fees for selling and buying, and not the user. This points to the account from which the fees is withdrawn in case of a sale goes through * **Seller Fee Basis Points**: The share of the sale the auction house takes on all NFTs. * **Treasury Mint**: The SPL token you accept as the purchase currency #### requireSignOff This allows the centralised MPs to gate which NFT can be listed, bought and sold! For every action: list, bid, sale, the instance authority needs to sign the tx. This also allows the MPs to implement their own order matching algorithms (see next slide). Decentralised MPs should keep requireSignOff as False, and they can use other means like Allow Lists using Merkele Trees and UI gating to gate which NFTs get listed. This allows for an easy way for MPs to index data required to keep track of all offers/bids/sales/change in token accounts etc (more info on why this is required later). #### canChangeSalePrice `canChangeSalePrice` is only intended to be used with AuctionHouses that Requires Sign Off. If the buyer intentionally lists their NFT for a price of 0, a new `FreeSellerTradeState` is made. The Auction House can then change the sale price to match a matching Bid that is greater than 0. This allows the Auction house to do complicated order matching to find the best price for the seller. The Auction House can only sell it for 0 if you sign the transaction with your key, but currently it can sell it for an arbitarily low price, e.g. 1 lamport. ### Trade States ![](https://i.imgur.com/ki27Ds8.png) Trade States are PDAs that represent, what are effectively a bid or an offer for an NFT. There are two main trade states: Seller Trade State and Buyer Trade State for an offer and a bid respectively. There is also a third trade state: Free Seller Trade State. * remember canChangeSalePrice and user selling an NFT for 0 SOL? * when the user auctions an NFT for 0 SOL, AH builds the Free Seller Trade State using which it creates new sales at different prices. Trade states only have 1 byte of data, and only store 1 thing: bump (because its a PDA, it has to store a bump) It's a pattern to show that this account is real: since it's a PDA and the address is owned by AH contract, no one can make fake bids and listings. They are a hash of the ordered data: type of NFT, mint address, token amount which can be x for a fungible asset/tokens, offer price. All this information, in that order, is hashed into the seeds of the PDA This is primarily done to cut down the costs: trade states are very cheap. There is one major issue here: How do you figure out the list of bids / offers / sales / changes in token accounts if nothing is stored in the Trade States? We'll talk about this in later sections. ### Program As Signer Account ![](https://i.imgur.com/3jTMRTI.png) `programAsSigner` account is the program derived address which the Auction House assigns as the Delegate to `executeSale` once an Offer and a Bid (trade states) match. We will talk about Delegates and `executeSale` in much greater detail in the coming sections. ### Buyer Escrow Account ![](https://i.imgur.com/o4ITCY5.png) When a trade is executed, the amount of the sale is debited from the buyer's escrow account. This has a slight manual step associated to it: this account needs to be topped off (manually) if the user is buying multiple NFTs. There are Deposit and Withdraw instructions to deposit and withdraw tokens (native or SPL) from buyer escrow accounts. ## Auction in action Now that we know about all the (major) accounts that are involved in a Auction, lets dive deep into how the Auction actually works. The Auction is divided into three main Instructions: 1. Sell 2. Buy 3. ExecuteSale There are other supporting instructions as well like withdrawFee, withdrawTreasury that I'll talk about later. ## Sell Order The seller posts an offer to "sell" an NFT. When this happens, the Auction House creates the Seller trade state PDA. Auction House then assigns the programAsSigner PDA as the "Delegate" * Delegates are a feature of the Solana SPL-token program: https://spl.solana.com/token#authority-delegation. * Delegates are assigned by the authority using the "Approve" instruction This allows a key signer or authority to take a quantity of tokens out of a token account while the delegate is valid. A token account can only have 1 delegate. As an NFT comprises of 1 token, Auction House pulls the entire asset from the seller when the sale goes through (at a later point) Here is how you can make the create a Sell Order using JS: ```tsx export const createSell = async (connection: anchor.web3.Connection) => { try { // Accounts/Publickeys const mint = new anchor.web3.PublicKey(''); const auctionHousePubKey = new anchor.web3.PublicKey(''); const feeAccountPubkey = new anchor.web3.PublicKey(''); const metadataPubkey = new anchor.web3.PublicKey(''); const freeSellerTradeState = new anchor.web3.PublicKey(''); const tokenAccountPubkey = (await getAtaForMint(mint, wallet.publicKey))[0]; const [programAsSigner, programAsSignerBump] = await getAuctionHouseProgramAsSigner(); const accounts: SellInstructionAccounts = { auctionHouse: auctionHousePubKey, auctionHouseFeeAccount: feeAccountPubkey, authority: wallet.publicKey, metadata: metadataPubkey, wallet: wallet.publicKey, freeSellerTradeState: freeSellerTradeState, programAsSigner: programAsSigner, tokenAccount: tokenAccountPubkey, sellerTradeState: programAsSigner }; // const args: SellInstructionArgs = {}; } catch (error) { console.log('SELL ERROR', error); } }; ``` ## Buy Order Similar to the sell order, when a buyer places a bid, Auction House creates the buyer trade state PDA representing the bid. The buy order instruction then transfers tokens (native, or SPL tokens) to the aforementioned Buyer Escrow Account. In case of an SPL token, an associated token account gets created first at the buyer escrow account's location before transferring the SPL tokens. The beauty of separate buy and sell orders is that one can post a bid for a non-listed NFT one prefers. This allows for the non-sellers to allure attractive bids for their NFTs, and vice-versa allows buyers to attract otherwise non-interested sellers. I call that a win-win. This is how you can make a Buy Order using JS: ```tsx export const buy = async (connection: anchor.web3.Connection) => { try { const mint = new anchor.web3.PublicKey(''); const tokenAccount = new anchor.web3.PublicKey(''); const NFTMintData = await getMint(connection, mint); const tokenSizeAdjusted = new anchor.BN( await getPriceWithMantissa(1, NFTMintData.decimals) ); const TreasuryMintData = await getMint( connection, new anchor.web3.PublicKey(AuctionHouse.mint) ); const buyPriceAdjusted = new anchor.BN( await getPriceWithMantissa(1, TreasuryMintData.decimals) ); const [escrowPaymentAccount, escrowBump] = await getAuctionHouseBuyerEscrow( new anchor.web3.PublicKey(AuctionHouse.address), wallet.publicKey ); const [BuyertradeState, BuyertradeBump] = await getAuctionHouseTradeState( new anchor.web3.PublicKey(AuctionHouse.address), wallet.publicKey, tokenAccount, new anchor.web3.PublicKey(AuctionHouse.mint), mint, tokenSizeAdjusted, buyPriceAdjusted ); const accounts: BuyInstructionAccounts = { auctionHouse: new anchor.web3.PublicKey(AuctionHouse.address), auctionHouseFeeAccount: new anchor.web3.PublicKey( AuctionHouse.feeAccount ), authority: new anchor.web3.PublicKey(AuctionHouse.authority), metadata: await getMetadata(mint), wallet: wallet.publicKey, // Token Account of the Token to purchase tokenAccount: tokenAccount, treasuryMint: new anchor.web3.PublicKey(AuctionHouse.mint), buyerTradeState: BuyertradeState, escrowPaymentAccount: escrowPaymentAccount, paymentAccount: wallet.publicKey, transferAuthority: wallet.publicKey }; const args: BuyInstructionArgs = { buyerPrice: buyPriceAdjusted, escrowPaymentBump: escrowBump, tokenSize: tokenSizeAdjusted, tradeStateBump: BuyertradeBump }; const instruction = createBuyInstruction(accounts, args); const { blockhash } = await connection.getLatestBlockhash(); const transaction = new anchor.web3.Transaction({ recentBlockhash: blockhash }); transaction.add(instruction); wallet.signTransaction(transaction); const rawTx = transaction.serialize(); const sig = await connection.sendRawTransaction(rawTx); await connection.confirmTransaction(sig, 'confirmed'); return sig; } catch (error) { console.log('ERROR In Buy', error); } }; ``` ## Execute Sale As soon as the buyer and the seller have both posted their bids and offers respectively, and there is a price-match, a Partial or a Complete Order Fulfilment takes place. Partial or Complete Order fulfilment takes place by calling the `executeSale` instruction. Its meant to be called by a permission-less crank by `programAsSigner` PDA account that monitors bids and offers on auction house accounts. The buyer's escrow account will transfer the tokens to the seller (minus auction house fees). The seller's token account will send the NFT to the buyer via a delegate transfer, completing a trade This is how you can Execute Sale using JS: ```tsx export const executeSale = async ( connection: anchor.web3.Connection, buyer: anchor.Wallet, mint: anchor.web3.PublicKey ) => { try { const [programAsSigner, programAsSignerBump] = await getAuctionHouseProgramAsSigner(); const [escrowPaymentAccount, escrowBump] = await getAuctionHouseBuyerEscrow( new anchor.web3.PublicKey(AuctionHouse.address), buyer.publicKey ); const tokenAccountPubkey = (await getAtaForMint(mint, wallet.publicKey))[0]; const buyerATA = await getOrCreateAssociatedTokenAccount( connection, buyer.payer, mint, buyer.publicKey ); const NFTMintData = await getMint(connection, mint); const tokenSizeAdjusted = new anchor.BN( await getPriceWithMantissa(1, NFTMintData.decimals) ); const [freeTradeState, freeTradeBump] = await getAuctionHouseTradeState( new anchor.web3.PublicKey(AuctionHouse.address), wallet.publicKey, tokenAccountPubkey, new anchor.web3.PublicKey(AuctionHouse.mint), mint, tokenSizeAdjusted, new anchor.BN(0) ); const TreasuryMintData = await getMint( connection, new anchor.web3.PublicKey(AuctionHouse.mint) ); const buyPriceAdjusted = new anchor.BN( await getPriceWithMantissa(1, TreasuryMintData.decimals) ); const [SellertradeState, SellertradeBump] = await getAuctionHouseTradeState( new anchor.web3.PublicKey(AuctionHouse.address), wallet.publicKey, tokenAccountPubkey, new anchor.web3.PublicKey(AuctionHouse.mint), mint, tokenSizeAdjusted, buyPriceAdjusted ); const [BuyertradeState, BuyertradeBump] = await getAuctionHouseTradeState( new anchor.web3.PublicKey(AuctionHouse.address), buyer.publicKey, tokenAccountPubkey, new anchor.web3.PublicKey(AuctionHouse.mint), mint, tokenSizeAdjusted, buyPriceAdjusted ); const accounts: ExecuteSaleInstructionAccounts = { treasuryMint: new anchor.web3.PublicKey(AuctionHouse.mint), auctionHouse: new anchor.web3.PublicKey(AuctionHouse.address), auctionHouseFeeAccount: new anchor.web3.PublicKey( AuctionHouse.feeAccount ), authority: new anchor.web3.PublicKey(AuctionHouse.authority), programAsSigner: programAsSigner, auctionHouseTreasury: new anchor.web3.PublicKey( AuctionHouse.treasuryAccount ), seller: wallet.publicKey, metadata: await getMetadata(mint), tokenMint: mint, buyer: buyer.publicKey, escrowPaymentAccount: escrowPaymentAccount, sellerPaymentReceiptAccount: wallet.publicKey, tokenAccount: tokenAccountPubkey, buyerReceiptTokenAccount: buyerATA.address, freeTradeState: freeTradeState, sellerTradeState: SellertradeState, buyerTradeState: BuyertradeState }; const args: ExecuteSaleInstructionArgs = { buyerPrice: buyPriceAdjusted, escrowPaymentBump: escrowBump, tokenSize: tokenSizeAdjusted, freeTradeStateBump: freeTradeBump, programAsSignerBump: programAsSignerBump }; const instruction = createExecuteSaleInstruction(accounts, args); const { blockhash } = await connection.getLatestBlockhash(); const transaction = new anchor.web3.Transaction({ recentBlockhash: blockhash }); transaction.add(instruction); wallet.signTransaction(transaction); const rawTx = transaction.serialize(); const sig = await connection.sendRawTransaction(rawTx); await connection.confirmTransaction(sig, 'confirmed'); return sig; } catch (error) { console.log('ERROR In Execute Sale', error); } }; ``` ## Other Instructions * Cancel - Potential buyer revokes their offer. * Show Escrow - Print out the balance of an auction house escrow account for a given wallet. * Withdraw - Transfer funds from user's buyer escrow account for the auction house to their wallet. * Deposit - Add funds to user's buyer escrow account for the auction house. * Withdraw from Fee - Transfer funds from auction house fee wallet to the auction house authority. * Widthraw from Treasury - Transfer funds from the auction house treasury wallet to the auction house authority. * Update Auction House - Update any of the auction house settings including it's authority or seller fee. ## Auction House Receipts To aid transaction tracking, Auction House supports the generation of receipts for listings, bids, and sales. To generate these receipts, the receipt printing function should be called immediately after the corresponding transaction: `PrintListingReceipt`, `PrintBidReceipt`, and `PrintPurchaseReceipt` Additionally, the `CancelListingReceipt` and `CancelBidReceipt` instructions should be called in the case of canceled listing add bids. Calling these two instructions will fill the `canceled_at` fields of the `ListingReceipt` and `BidReceipt` accounts. # How to update an Auction House? The Auction house program has a function to update the attributes value of an Auction House instance that has been already created. Let’s look into how can be update an already existing auction house instance. Firstly, let’s find the Auction house instance ```tsx const auction_house_address = new PublicKey( 'Gr31akcY9wb7Gsnu4ej39MydBfxcT8mehZtKxFTsCAai' ); const ah = await mx .auctions() .findAuctionHouseByAddress(auction_house_address) .run(); ``` Now let’s update the authority and the `sellerFeeBasisPoints` points for this auction house instance. ```tsx const {auctionHouse: updateAuctionHouse} = await mx .auctions() .updateAuctionHouse(ah, { sellerFeeBasisPoints: 300, newAuthority: newAhAuthority, }) .run(); ``` ## What info do MPs need to track? Specifically Marketplaces should currently store: * Trade State Account Keys * Trade State Token Size and Price parts of the seed * Token Account Keys that are stored in the trade state * Auction House Receipts (Listing Receipts, Bid Receipts, and Purchase Receipts) Specifically Marketplaces need to track these two events on Token Accounts: * Ownership has changed from the original Seller of the NFT * Token Account Amount has changed to 0 ## An important corner case: What happens if the user makes any change to the token account of the NFT / SPL-tokens (what? spl-tokens can also be auctioned? More on that later) after making the sell order but before executeSale goes through? Well, quite simply the sale is cancelled (temporarily). So no subsequent call to `executeSale` will be successful until the required amount of tokens are back in the associated token account (ATA). The AH program doesn't do anything other than make the executeSale instruction fail until this happens. To cancel the sale completely: one needs to manually invoke the `Cancel` instruction to revoke programAsSigner account as the Delegate and wipe the Sell trade state. ## Auctioning Fungible Assets Auction House can be used not only to create NFT marketplaces but also to create Decentralised Exchanges (DEX). Auction House has no restrictions on the token type and size that can be auctioned using it. So in practice any SPL-token, fungible, and semi-fungible assets can be auctioned off using the Auction House protocol. A sell order for a token with `tokenSize` > 1 can be made for SPL-tokens or any other fungible assets. In case of DEXs, with the help of Partial Order Fulfillment, Auction House protocol can be used to replicate the order of actions in traditional DEXs where a user can make a buy order for less than equal to the quantity of tokens offered by other users. Important to note here is that, as the Auction house does not have or create a central orderbook, the marketplaces or the DEXs will have to keep track of listings, offers and sales going through the given Auction House using receipts. ## Partial Order Fulfilment Once the seller creates a sell order for a fungible asset with `tokenSize` > 1, the buyer can create a buy order for the said assets with `tokenSize` <= to the `tokenSize` in the sell order. In order for `ExecuteSale` to succeed, the buy order must have been created with both a `partial_order_size` and a `partial_order_price`. `partial_order_size` must not be greater than the total amount of tokens in the original sell order. If there is no partial order needing to take place, `partital_order_price` and `partial_order_size` can be passed in as `None`. ## Auction House Public Bids A standard bid, also called a private bid, refers to a bid made that's specific to an auction. When the auction is complete, the bid can be canceled and the funds in escrow returned to the bidder. However, Auction House also supports public bids which are specific to the token itself and not to any specific auction. This means that a bid can stay active beyond the end of an auction and be resolved if it meets the criteria for subsequent auctions of that token. For a fungible asset, thus, there can be multiple partial order fulfillments for a single sell order. While for NFTs, the same asset can be bid upon AND sold even after subsequent sales go through. ## Auctioneer The current AH implementation is designed with instant sales in mind and currently has no features that enable the various auction types that have become popular in the Solana ecosystem (ex. Timed auctions). Auctioneer is a customized contract type, written by the user, that uses the composability pattern of AH to control an individual Auction House instance. To fully enable Auctioneer to use an Auction House instance's instructions, it must be explicitly delegated. The `DelegateAuctioneer` command is used to tell the Auction House instance which program will be using the `auctioneer_\<method>` instructions. ## Auctioneer Scope By default, the Auctioneer contract has control over the following Auction House methods via the `auctioneer_\<method>` instructions. * Buy * Public Buy * Sell * Execute Sale * Cancel * Deposit * Withdraw ## References * Metaplex docs: https://docs.metaplex.com/auction-house/definition * Prof Lupin's Auction House guide: https://proflupin.xyz/metaplex-auction-house * Jordan's twitter thread: https://twitter.com/redacted_j/status/1453926144248623104 * 0xRohan's twitter thread: https://twitter.com/0xrohan/status/1458364632888844288 * Armani's twitter thread: https://twitter.com/armaniferrante/status/1460760940454965248 * arcticmatt's blog: https://github.com/arcticmatt/blog/tree/wip/solana/auction-house * Metaplex documentation: https://docs.metaplex.com/guides/auction-house/auctioneer Visit: https://twitter.com/0xprof_lupin

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully