Full Code of solana-labs/chatgpt-plugin for AI

master 6b7c56e757c0 cached
77 files
225.9 KB
58.7k tokens
143 symbols
1 requests
Download .txt
Showing preview only (249K chars total). Download the full file or copy to clipboard to get everything.
Repository: solana-labs/chatgpt-plugin
Branch: master
Commit: 6b7c56e757c0
Files: 77
Total size: 225.9 KB

Directory structure:
gitextract_4oy13ijj/

├── .gitignore
├── DISCLAIMER.md
├── LICENSE
├── README.md
├── chatgpt-plugin/
│   ├── .gitignore
│   ├── .prettierrc
│   ├── README.md
│   ├── next.config.js
│   ├── postcss.config.js
│   ├── public/
│   │   └── openapi.yaml
│   ├── src/
│   │   ├── app/
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── lib/
│   │   │   ├── address.ts
│   │   │   ├── features.tsx
│   │   │   ├── helloMoon/
│   │   │   │   └── index.ts
│   │   │   ├── hyperspace/
│   │   │   │   ├── account.ts
│   │   │   │   ├── constants.ts
│   │   │   │   └── idl/
│   │   │   │       └── hyperspace.ts
│   │   │   ├── middleware.ts
│   │   │   └── on-chain-metadata/
│   │   │       └── index.ts
│   │   └── pages/
│   │       └── api/
│   │           ├── constants.ts
│   │           ├── handlers/
│   │           │   ├── getAccountInfo/
│   │           │   │   └── index.ts
│   │           │   ├── getAssetsByOwner/
│   │           │   │   └── index.ts
│   │           │   ├── getBalance/
│   │           │   │   └── index.ts
│   │           │   ├── getCollectionsByFloorPrice/
│   │           │   │   └── index.ts
│   │           │   ├── getCollectionsByName/
│   │           │   │   └── index.ts
│   │           │   ├── getListedCollectionNFTs/
│   │           │   │   └── index.ts
│   │           │   ├── getSignaturesForAddress/
│   │           │   │   └── index.ts
│   │           │   ├── getTokenAccounts/
│   │           │   │   └── index.ts
│   │           │   ├── getTotalValue/
│   │           │   │   └── index.ts
│   │           │   ├── getTransaction/
│   │           │   │   └── index.ts
│   │           │   ├── solana-pay/
│   │           │   │   ├── page/
│   │           │   │   │   └── [methodName].ts
│   │           │   │   ├── qr/
│   │           │   │   │   └── [methodName].ts
│   │           │   │   ├── sign/
│   │           │   │   │   ├── createBurnAsset.ts
│   │           │   │   │   ├── createBuyNFT.ts
│   │           │   │   │   ├── createCloseNFTMetadata.ts
│   │           │   │   │   ├── createListNFT.ts
│   │           │   │   │   ├── createMerkleTree.ts
│   │           │   │   │   ├── createMintCNFT.ts
│   │           │   │   │   ├── createMintNFT.ts
│   │           │   │   │   ├── createSetProfilePic.ts
│   │           │   │   │   ├── createTransferAsset.ts
│   │           │   │   │   ├── createTransferSol.ts
│   │           │   │   │   ├── createTransferToken.ts
│   │           │   │   │   ├── createWriteNFTMetadata.ts
│   │           │   │   │   └── index.ts
│   │           │   │   └── utils/
│   │           │   │       └── helpers.ts
│   │           │   ├── tokenName/
│   │           │   │   └── index.ts
│   │           │   ├── tx-link/
│   │           │   │   └── [txSlug].ts
│   │           │   └── walletName/
│   │           │       └── index.ts
│   │           ├── helloMoon/
│   │           │   ├── defi/
│   │           │   │   ├── defi.yaml
│   │           │   │   ├── programNewUsers.ts
│   │           │   │   ├── programOverlap.ts
│   │           │   │   ├── tokenStats.ts
│   │           │   │   └── tokenUsers.ts
│   │           │   ├── jupiter/
│   │           │   │   ├── README.md
│   │           │   │   ├── historical.ts
│   │           │   │   ├── pairs.ts
│   │           │   │   ├── summary.ts
│   │           │   │   └── swaps.ts
│   │           │   └── jupiter.yaml
│   │           ├── metaplex/
│   │           │   ├── getCNFTRent/
│   │           │   │   └── index.ts
│   │           │   ├── getPublicTree/
│   │           │   │   └── index.ts
│   │           │   └── metaplex.yaml
│   │           ├── solflare-pfp/
│   │           │   └── getProfilePic.ts
│   │           └── tiplink/
│   │               └── makeLink.ts
│   └── tailwind.config.js
├── langchain_examples/
│   ├── README.md
│   └── python/
│       └── main.py
├── pyproject.toml
└── scripts/
    ├── createNFTCollection.ts
    ├── createTree.ts
    ├── helper.ts
    ├── runCreateCollection.ts
    ├── send.ts
    └── uploadMetadata.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
.env
node_modules/
yarn*
tmp*

# Debugging tools
scripts/collection.ts
scripts/sharp.ts

langchain_examples/python/__pycache__
*json

================================================
FILE: DISCLAIMER.md
================================================
# Disclaimer

All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the good faith efforts Solana Labs, Inc. and its affiliates ("SL"). It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment.
Any content produced by SL or developer resources that SL provides have not been subject to audit and are for educational and inspiration purposes only. SL does not encourage, induce or sanction the deployment, integration or use of any such applications (including the code comprising the Solana blockchain protocol) in violation of applicable laws or regulations and hereby prohibits any such deployment, integration or use. This includes use of any such applications by the reader (a) in violation of export control or sanctions laws of the United States or any other applicable jurisdiction, (b) if the reader is located in or ordinarily resident in a country or territory subject to comprehensive sanctions administered by the U.S. Office of Foreign Assets Control (OFAC), or (c) if the reader is or is working on behalf of a Specially Designated National (SDN) or a person subject to similar blocking or denied party prohibitions.
The reader should be aware that U.S. export control and sanctions laws prohibit U.S. persons (and other persons that are subject to such laws) from transacting with persons in certain countries and territories or that are on the SDN list. As a project based primarily on open-source software, it is possible that such sanctioned persons may nevertheless bypass prohibitions, obtain the code comprising the Solana blockchain protocol (or other project code or applications) and deploy, integrate, or otherwise use it. Accordingly, there is a risk to individuals that other persons using the Solana blockchain protocol may be sanctioned persons and that transactions with such persons would be a violation of U.S. export controls and sanctions law. This risk applies to individuals, organizations, and other ecosystem participants that deploy, integrate, or use the Solana blockchain protocol code directly (e.g., as a node operator), and individuals that transact on the Solana blockchain through light clients, third party interfaces, and/or wallet software.


================================================
FILE: LICENSE
================================================
Copyright 2023 Solana Labs, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: README.md
================================================
# Solana ChatGPT Plugin
A ChatGPT plugin for Solana. Install as an unverified plugin with url `https://chatgpt.solanalabs.com`.

<div>
<img width="350" alt="Search NFTs in ChatGPT" src="https://user-images.githubusercontent.com/7481857/231182274-40b42f0e-5e5d-4050-9e31-2f75375481c1.png">
</div>

## Endpoints

ChatGPT can POST to the following resources, as described by `.well-known/openapi.yaml`.


<details>
<summary>
/getAccountInfo { address }
</summary>

Returns the output of `getAccountInfo` method from the RPC with buffer data, and if it can be deserialized by its program IDL, then the response payload has additional field called `extended` that has a JSON serialized string of the anchor data. Chat GPT's plugin model seems to be able to read this pretty well.

```json
{
  ...,
  "extended": "{\"authority\":\"8fbqVvpK3Dj7fdP2c8JJhtD7Zy3n9qtwAeGfbkgPu625\",\"numMinted\":50}"
}
```
</details>

<details>
<summary>/getBalance { address }</summary>

Returns
```json
{
  "sol": 0.40296
}
```
</details>

<details>
<summary>/getAssetsByOwner { address }</summary>

Returns the assets returned by the [Metaplex Read API spec](https://github.com/metaplex-foundation/api-specifications/blob/main/specifications/read_api/openrpc_spec.json)
</details>

<details>
<summary>/getTransaction { signature } </summary>

Accepts
```json
{
  "signature": "h51pjmFcn8LkxejofUQoDYkyubUKaB7bNtyMMSCCamSEYRutS2G2vm2w1ERShko8boRqdaaTAs4MR6sGYkTByNF"
}
```

Returns human-readable transaction information, parsed from the `getTransaction` method of the Solana RPC.
</details>

<details>
<summary>/getTokenAccounts { address }</summary>

Returns the token accounts owned by a user with an amount > 0. Derived from the `getTokenAccountsByOwner` method on the Solana RPC.

</details>

<details>
<summary>/getSignaturesForAddress { address } </summary>

Returns the transaction signatures returned in `getSignaturesForAddress` method from the Solana RPC.

</details>


<details>
<summary>
/getTotalValue { address }
</summary>

Returns the total value of the assets owned by `address`, broken down by NFTs and tokens. Token prices and NFT price estimates are provided by HelloMoon. An example output is provided below

```json
{
  "total": "50.00",
  "nftTotal": "25.00",
  "tokenTotal": "25.00"
}
```
</details>

### Endpoints for NFT discovery 
These endpoints are under development and subject to rapid change. These currently use the [Hyperspace API](https://docs.hyperspace.xyz).

<details>
<summary>/getCollectionsByFloorPrice { maxFloorPrice, minFloorPrice, orderBy, pageSize } </summary>

Returns
```json
{
  "projects": [
    {
      "id": "<hyperspace-collection-id or pubkey>",
      "desc": "collection description",
      "img": "collection image url",
      "website": "collection website url",
      "floor_price": 0.1
    }
  ],
  "hasMore": true,
  "currentPage'": 1
}
```
</details>

<details>
<summary>/getListedCollectionNFTs { projectId, pageSize, priceOrder }</summary>

Returns LLM friendly response of available NFTs:
```json
{ 
  "listings": [
    {
      "price": 0.1,
      "token": "<token-address-pubkey>",
      "marketplace": "<marketplace-pubkey>"
    }
  ],
  "hasMore": true,
  "currentPage": 1
} 
```
</details>


## Private endpoints (not LLM accessible)

### Endpoints for Sending Transactions

Note: these endpoints are currently disabled in the production version of the ChatGPT plugin

<details>
<summary> /createBuyTransaction { token, price }</summary>

Right now we are trusting Hyperspace to craft a valid transaction for us. 
In the future we will setup a write interface for programs on Solana to adhere to in order to 
be a target of LLM transaction composition.

Returns
```json
{
  "linkToSign": "<url-to-sign-transaction>" 
}
```
</details>

<details>
<summary> /createTransferSol { destination, amount }</summary>

Creates a transaction to transfer an amount in Sol.

Returns
```json
{
  "linkToSign": "<url-to-sign-transaction>" 
}
```
</details>

<details>
<summary> /createTransferToken { destination, mint, amount }</summary>

Creates a transaction to transfer an amount of token (from the mint).

Returns
```json
{
  "linkToSign": "<url-to-sign-transaction>" 
}
```
</details>

### Endpoints for Transaction Composition

These are also subject to change, and we may create actual webpages to inspect
the transaction before signing. However for now, these are simply redirect links 
to ensure that SolanaPay QR codes show up in the ChatGPT link previews.

<details>
<summary>/page/:methodName</summary>

Returns a webpage with [OpenGraph](https://ogp.me/) metadata that will be rendered in the ChatGPT 
rich link preview. All ChatGPT links should be proxied through this sort of pipeline to maximize
user engagement of links. The `og:image` tag is to `/qr/:methodName` to show a SolanaPay QR code in link previews.

This is currently a blank page, but we may show a preview of the transaction in the future.
</details>

<details>
<summary>/qr/:methodName</summary>

Returns a PNG QR code that has been optimized to show in the particular aspect ratio of ChatGPT plugins. 
This just encodes a SolanaPay link that redirects to `/sign/:methodName`. 
</details>

<details>
<summary>/sign/:methodName</summary>

This is the final redirect link that actually returns transaction bytes in a SolanaPay compatible format
so users can sign transactions that are recommended by ChatGPT.

```json
{
  "transaction": "<base64-encoded-transaction-bytes>"
}
```
</details>

## Development

To install dependencies, just execute `yarn`. This project uses `node` with version `>=16.17.0`.

To start a development server, execute `yarn dev`. This will start the plugin available from `localhost:3333` with its own configuration settings in `.well-known-dev/`.

# License

This codebase is released under [Apache License 2.0](LICENSE.md).

# Disclaimer

By accessing or using this codebase or any of its components, you accept and agree with the [Disclaimer](DISCLAIMER.md).


================================================
FILE: chatgpt-plugin/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts


================================================
FILE: chatgpt-plugin/.prettierrc
================================================
{
  "tabWidth": 2,
  "useTabs": false,
  "singleQuote": false,
  "printWidth": 100,
  "trailingComma": "all",
  "arrowParens": "avoid",
  "endOfLine": "auto",
  "proseWrap": "always"
}


================================================
FILE: chatgpt-plugin/README.md
================================================
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.


================================================
FILE: chatgpt-plugin/next.config.js
================================================
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      // temporary until Sidekick has plugin autoselect
      {
        source: "/api/helloMoon/defi/tokenName",
        destination: "/api/handlers/tokenName",
      },
    ];
  },
};

module.exports = nextConfig;


================================================
FILE: chatgpt-plugin/postcss.config.js
================================================
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}


================================================
FILE: chatgpt-plugin/public/openapi.yaml
================================================
openapi: 3.0.2
info:
  title: Solana Labs API
  description: An API for retrieving human-readable information about the Solana blockchain.
  version: 1.0.0
paths:
  /api/handlers/getAssetsByOwner:
    post:
      summary: getAssetsByOwner
      description: Accepts Solana publicKey address. Returns Metaplex NFTs owned by the address
      operationId: query_assets_by_owner
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getAccountInfoRequest"
        required: true
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getAccountInfo:
    post:
      summary: getAccountInfo
      description:
        Returns information about the data stored by that account in a human-readable format.
        Human-readable formatting is only possible when the account's corresponding program owner
        has published an Anchor IDL on the Solana blockchain.
      operationId: query_account_info
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getAccountInfoRequest"
        required: true
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getTokenAccounts:
    post:
      summary: getTokenAccounts
      description:
        Returns the fungible and non-fungible tokens and amounts owned by the address. May show
        tokens not listed in get_assets_by_owner.
      operationId: query_token_accounts
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getBalanceRequest"
        required: true
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getBalance:
    post:
      summary: getBalance
      description:
        Accepts Solana publicKey address. Returns the amount of lamports that the account has
        available.
      operationId: query_balance
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getBalanceRequest"
        required: true
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getTransaction:
    post:
      summary: getTransaction
      description:
        Accepts a transaction signature. Returns the publicly available transaction information and
        metadata. Only high level summaries based on instruction data should be provided to users
        unless otherwise specified. Logs, compute units, and fees are available in devMode.
      operationId: query_transaction
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getTransactionRequest"
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getSignaturesForAddress:
    post:
      summary: getSignaturesForAddress
      description:
        Accepts Solana publicKey address. Returns the latest transaction signatures that involve
        that address.
      operationId: query_signatures_for_address
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getSignaturesForAddressRequest"
        required: true
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getCollectionsByFloorPrice:
    post:
      summary: Search through Solana NFT collections by floor price
      operationId: query_nft_collections_by_fp
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getCollectionsByFloorPriceRequest"
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getListedCollectionNFTs:
    post:
      summary: Returns the listed NFTs in a collection available to purchase
      operationId: query_listed_nfts_for_collection
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getListedCollectionNFTsRequest"
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getCollectionsByName:
    post:
      summary: Searches for NFT collections based on project name
      operationId: query_nfts_collections_by_name
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getCollectionsByNameRequest"
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/getTotalValue:
    post:
      summary:
        Calculates the total value of a the address's holdings in USD, with breakdown by NFTs and
        tokens.
      operationId: query_total_value
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/getTotalValueRequest"
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/walletName:
    post:
      summary:
        Resolves wallet names to the actual solana address, or if it is already a Solana address, it
        looks up all the wallet names associated with that publickey. This works especially well for
        .sol, .glow, .backpack, or .poor domains.
      operationId: query_wallet_name
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                walletName:
                  type: string
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
  /api/handlers/tokenName:
    post:
      summary:
        Searches tokens by name, and returns the mint address, logo, name and symbol for up to 10
        relevant, verified tokens.
      operationId: search_token_name
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                tokenName:
                  type: string
      responses:
        "200":
          description: Successful Response
        "500":
          description: Validation Error
      security:
        - HTTPBearer: []
components:
  schemas:
    getAccountInfoRequest:
      type: object
      required:
        - address
      properties:
        address:
          type: string
          description: Base58 encoded PublicKey
    getSignaturesForAddressRequest:
      title: GetSignaturesForAddressRequest
      type: object
      required:
        - address
      properties:
        address:
          type: string
          description: Base58 encoded PublicKey
        beforeSignature:
          type: string
        untilSignature:
          type: string
    getBalanceRequest:
      title: GetBalanceRequest
      type: object
      required:
        - address
      properties:
        address:
          title: Address
          type: string
          description: Base58 encoded PublicKey
    getTransactionRequest:
      type: object
      required:
        - signature
      properties:
        signature:
          type: string
        devMode:
          type: boolean
    getCollectionsByFloorPriceRequest:
      type: object
      properties:
        maxFloorPrice:
          type: number
          nullable: true
        minFloorPrice:
          type: number
          nullable: true
        orderBy:
          type: string
          enum:
            - ASC
            - DESC
          nullable: true
    getCollectionsByNameRequest:
      type: object
      properties:
        projectName:
          type: string
    getListedCollectionNFTsRequest:
      type: object
      properties:
        projectId:
          type: string
        priceOrder:
          type: string
          nullable: true
        pageSize:
          type: number
          nullable: true
    getTotalValueRequest:
      type: object
      properties:
        address:
          type: string
          description: Base58 encoded PublicKey
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer


================================================
FILE: chatgpt-plugin/src/app/globals.css
================================================
@tailwind base;
@tailwind components;

:root {
  --foreground-rgb: 255, 255, 255;
  --background-start-rgb: 0, 0, 0;
  --background-end-rgb: 0, 0, 0;
}


body {
  color: rgb(var(--foreground-rgb));
  background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb)))
    rgb(var(--background-start-rgb));
}

.ms-6 {
  margin-left: 2rem !important;
}
img,
svg {
  vertical-align: middle;
}
@media (min-width: 768px) {
  .AiHero_hero__title__ZatKJ {
    font-size: 6rem;
    line-height: 6rem;
    margin-bottom: 32px !important;
  }
}
.AiHero_hero__title__ZatKJ {
  font-weight: 700;
  font-size: 3.5rem;
  margin-bottom: 24px !important;
}
h2 {
  font-size: 2.425rem;
  line-height: 3.15rem;
  font-weight: 400;
}
.czAcYK.btn {
  font-family: DSemi, monospace;
  font-weight: normal;
  text-transform: uppercase;
  line-height: 1.25rem;
  font-size: 0.95rem;
  width: fit-content;
  background-color: rgb(153, 69, 255);
  border-radius: 2.25rem;
  padding: 0.875rem 1.5rem;
  color: white;
  border: 1px solid transparent;
}

.lift {
  transition: box-shadow 0.25s ease, transform 0.25s ease;
}

.btn {
  background-color: rgb(153, 69, 255);
  @apply flex items-center gap-3 px-5 py-3 text-lg transition transform whitespace-nowrap rounded-3xl;
  @apply hover:bg-white hover:text-black;
  @apply hover:-translate-y-1;
}
.btn svg {
  @apply w-5 h-5;
}

.disclosure {
  @apply flex items-center justify-between w-full px-4 py-2 rounded-xl;
  @apply text-white bg-gray-800;
  @apply hover:bg-opacity-80;
  @apply border border-gray-700;
}
.disclosure-open {
  @apply font-semibold;
  @apply bg-gray-800 border-gray-600 hover:bg-opacity-100;
}

.disclosure svg {
  @apply w-5 h-5;
}

/* utilities at the end to make the inline classes a priority */
@tailwind utilities;

.legal {
  text-decoration: underline;
  color: #00ffbd;
}

================================================
FILE: chatgpt-plugin/src/app/layout.tsx
================================================
import Link from "next/link";
import "./globals.css";
import { Inter } from "next/font/google";
import Image from "next/image";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Solana Labs - ChatGPT Plugin",
  description: "Get a taste of Solana",
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <nav className="flex items-center p-4">
          <Link href={"/"}>
            <Image src="/solana-image.svg" width="149" height="22" alt="Solana" />
          </Link>

          <section className="">{/* add header links in here, if desired */}</section>
        </nav>

        {children}

        <footer className="my-8 text-center text-gray-400">
          &copy;
          {new Date().getFullYear()}{" "}
          <Link href="https://solanalabs.com" className="hover:underline hover:text-white">
            Solana Labs
          </Link>
          {" | "}
          <Link href="https://solanapay.com/tos" className="hover:underline hover:text-white">
            Terms of Service
          </Link>
        </footer>
      </body>
    </html>
  );
}


================================================
FILE: chatgpt-plugin/src/app/page.tsx
================================================
"use client";

import Head from "next/head";
import Link from "next/link";

import { features } from "@/lib/features";
import { Disclosure } from "@headlessui/react";
import { ArrowRightIcon, ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline";

export default function Home() {
  return (
    <>
      <Head>
        <title>Solana Labs - ChatGPT Plugin</title>
      </Head>

      <main className="block max-w-2xl p-4 mx-auto ">
        <section className="space-y-1 text-center">
          <h1 className="text-6xl font-semibold ">
            <Link href="/">Solana Labs</Link>
          </h1>
          <h2 className="text-2xl font-normal">ChatGPT Plugin</h2>
        </section>

        <p className="my-10 text-center">
          The Solana Labs ChatGPT Plugin helps you query information on the Solana blockchain. Solana Labs has provided the code as a reference implementation with permissive
          licensing on Github. A list of features and example queries is provided below.
        </p>

        <div className="flex items-center justify-center gap-5 my-3">
          <Link
            target="_blank"
            href={"https://github.com/solana-labs/chatgpt-plugin"}
            className="btn"
          >
            GitHub Repo
            <ArrowRightIcon />
          </Link>

          <Link target="_blank" href={"https://solana.com/ai"} className="btn">
            AI Grants
            <ArrowRightIcon />
          </Link>
        </div>

        <section className="my-10 space-y-6">
          <h2 className="text-3xl ml-3">Features</h2>
          {features.map((endpoint, id) => (
            <Disclosure key={id}>
              {({ open }) => (
                <div className="">
                  <Disclosure.Button className={`disclosure ${open ? "disclosure-open" : ""}`}>
                    {endpoint.label}
                    <span className="">{open ? <ChevronUpIcon /> : <ChevronDownIcon />}</span>
                  </Disclosure.Button>
                  <Disclosure.Panel className="px-3 py-2 text-white">
                    {endpoint.description}
                  </Disclosure.Panel>
                </div>
              )}
            </Disclosure>
          ))}
        </section>
      </main>
    </>
  );
}


================================================
FILE: chatgpt-plugin/src/lib/address.ts
================================================
import {
  walletAddressToDotAnything,
  walletAddressToDotGlow,
  walletAddressToDotBackpack,
  walletNameToAddressAndProfilePicture,
} from "@portal-payments/solana-wallet-names";
import { Connection, PublicKey } from "@solana/web3.js";
import { Client } from "@solflare-wallet/utl-sdk";
import configConstants, { CONNECTION } from "../pages/api/constants";
configConstants();

export interface WalletNames {
  walletNames: string[];
}

export const walletAddressToDotSolCustom = async (
  connection: Connection,
  wallet: PublicKey,
): Promise<WalletNames> => {
  try {
    const result = await fetch(
      // See https://github.com/Bonfida/sns-sdk#sdk-proxy
      // There's a 'favorite-domain' endpoint butmost SNS users haven't set up a
      // favorite domain, as the UI to do so is complex
      // `https://sns-sdk-proxy.bonfida.workers.dev/favorite-domain/${wallet.toBase58()}`
      `https://sns-sdk-proxy.bonfida.workers.dev/domains/${wallet.toBase58()}`,
      {
        method: "GET",
      },
    );

    const body = await result.json();
    let walletNames: string[] = body.result.map((info: any) => `${info.domain}.sol`);
    return {
      walletNames,
    };
  } catch (thrownObject) {
    const error = thrownObject as Error;
    if (error.message === "Invalid wallet account provided") {
      return {
        walletNames: [],
      };
    }
    throw error;
  }
};

export const walletAddressToNameAndProfilePictureCustom = async (
  connection: Connection,
  wallet: PublicKey,
  backpackJWT: string | null = null,
): Promise<WalletNames> => {
  let walletNames: string[] = [];
  const dotAnything = await walletAddressToDotAnything(connection, wallet);
  if (dotAnything.walletName) {
    walletNames.push(dotAnything.walletName);
  }

  const dotSol = await walletAddressToDotSolCustom(connection, wallet);
  walletNames = walletNames.concat(dotSol.walletNames);

  const dotGlow = await walletAddressToDotGlow(wallet);
  if (dotGlow?.walletName && dotGlow.walletName !== "null.glow") {
    walletNames.push(dotGlow.walletName);
  }

  if (backpackJWT) {
    const dotBackpack = await walletAddressToDotBackpack(wallet, backpackJWT);
    if (dotBackpack?.walletName) {
      walletNames.push(dotBackpack.walletName);
    }
  }

  return {
    walletNames,
  };
};

export async function resolveAddress(address: string): Promise<PublicKey> {
  if (!address) {
    throw new Error(`No address provided for: ${address}`);
  }

  if (address.search(/\./g) !== -1) {
    let info: { walletAddress: string | null };
    try {
      info = await walletNameToAddressAndProfilePicture(CONNECTION, address);
    } catch (e) {
      throw new Error(`Wallet name ${address} does not exist or cannot be resolved.`);
    }

    if (info.walletAddress === null) {
      throw new Error(`Wallet name does not exist: ${address}`);
    }
    return new PublicKey(info.walletAddress);
  }

  try {
    return new PublicKey(address);
  } catch (_e) {
    throw new Error(`Provided address is invalid base58 Solana address: ${address}`);
  }
}

export async function resolveToken(tokenName: string): Promise<PublicKey> {
  if (!tokenName) {
    throw new Error(`No token name provided for: ${tokenName}`);
  }

  const utl = new Client();
  try {
    let results = (await utl.searchMints(tokenName))
      .filter((res: any) => {
        return res["verified"] && res["holders"] > 0 && res["chainId"] === 101;
      })
      .map((res: any) => {
        return {
          mintAddress: res["address"],
          tokenName: res["name"],
          tokenSymbol: res["symbol"],
          holders: res["holders"],
          verified: res["verified"],
          chainId: res["chainId"],
          logoURI: res["logoURI"],
        };
      });
    return new PublicKey(results[0].mintAddress);
  } catch (_e) {
    throw new Error(
      `Provided token address does not have any relevant token addresses: ${tokenName}`,
    );
  }
}


================================================
FILE: chatgpt-plugin/src/lib/features.tsx
================================================
import Link from "next/link";

export type Endpoint = {
  label: string;
  description: React.ReactNode;
};

export const features: Array<Endpoint> = [
  {
    label: "Fetch account balance",
    description: (
      <p>
        {`Example: "What is the balance of `}
        <i>MY-WALLET-ADDRESS</i>
        {` ?"`}
        <br /> <br />
        {`Returns the amount of Sol that the wallet address owns.`}
      </p>
    ),
  },
  {
    label: "Interpret Solana accounts",
    description: (
      <p>
        {`Example: "What data is in `}
        <i>ACCOUNT-ADDRESS</i>
        {` ?"`}
        <br /> <br />
        {`Returns data about the account, including the owner, the amount of Sol, and the potentially human-readable data stored in the account, if it's owner program has an Anchor IDL.`}
      </p>
    ),
  },
  {
    label: "Interpret Solana transactions",
    description: (
      <p>
        {`Example: "What happened in transaction `}
        <i>TRANSACTION-ID</i>
        {` ?"`}
        <br /> <br />
        {`Returns information about the transaction, and potentially human readable information about program instructions, if the programs have Anchor IDLs.`}
      </p>
    ),
  },
  {
    label: "Find NFTs for a wallet",
    description: (
      <p>
        {`Example: "What NFTs does `}
        <i>MY-WALLET-ADDRESS</i>
        {` own?"`}
        <br /> <br />
        {`The plugin can list your NFTs and their metadata. If you have a lot of NFTs, you can ask it to list all of your NFTs 5 at a time.`}
      </p>
    ),
  },
  {
    label: "Inspect wallet activity",
    description: (
      <p>
        {`Example: "What are the latest transactions for `}
        <i>WALLET-ADDRESS</i>
        {` ?"`}
        <br /> <br />
        {`The plugin can help you go through wallet transactions and explore on-chain activity.`}
      </p>
    ),
  },
  {
    label: "Search NFT collections by name or floor price",
    description: (
      <p>
        {`Example: "Can you find me the cheapest Mad Lads NFT for sale?"`}
        <br /> <br />
        {`NFTs are searched by name and sorted by floor price, you can ask the model to search explicitly by either target floor price name or by name.
        NFTs within a collection can also be sorted by floor price.`}
        <br />
        <br />
        <u>
          <b>Note:</b>
        </u>
        {` If you cannot find your NFT Collection, please see if it exists on `}
        <u>
          <Link href="https://hyperspace.xyz">hyperspace.xyz</Link>
        </u>
        {`. We
        use Hyperspace's API to support this plugin`}
      </p>
    ),
  },
  {
    label: "Calculate wallet value",
    description: (
      <p>
        {`Example: "What is the value of `}
        <i>MY-ADDRESS</i>
        {` ?"`}
        <br /> <br />
        {`Wallet value is calculated by estimating the value of all tokens and NFTs owned by the wallet. Please note that these values are in USD and are subject to change due to market fluctuations. Price estimates are provided by `}
        <u>
          <Link href="https://hyperspace.xyz">{`HelloMoon's`}</Link>
        </u>
        {` API.`}
      </p>
    ),
  },
  // {
  //   label: "Buy an NFT (SolanaPay)",
  //   description: (
  //     <p>
  //       {`Example: "Can you help me transfer 1 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v to `}
  //       <i>DESTINATION</i>
  //       {` ?"`}
  //       <br />
  //       <br />
  //       This will generate a QR code that you can scan from within your mobile wallet to send 1 USDC
  //       (mint address EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) from your wallet to a
  //       destination wallet. See the{" "}
  //       <Link
  //         href={
  //           "https://github.com/solana-labs/chatgpt-plugin/blob/examples-langchain/DISCLAIMER.md"
  //         }
  //         className="legal"
  //       >
  //         Disclaimer
  //       </Link>
  //       {" and "}
  //       <Link href="https://solanapay.com/tos" className="legal">
  //         Terms of Service
  //       </Link>
  //       {"."}
  //     </p>
  //   ),
  // },
  // {
  //   label: "Transfer Sol (SolanaPay)",
  //   description: (
  //     <p>
  //       {`Example: "Can you help me transfer 1 SOL to `}
  //       <i>DESTINATION</i>
  //       {` ?"`}
  //       <br />
  //       <br />
  //       This will generate a QR code that you can scan from within your mobile wallet to send 1 Sol
  //       from your wallet to a destination wallet address. See the{" "}
  //       <Link
  //         href={
  //           "https://github.com/solana-labs/chatgpt-plugin/blob/examples-langchain/DISCLAIMER.md"
  //         }
  //         className="legal"
  //       >
  //         Disclaimer
  //       </Link>
  //       {" and "}
  //       <Link href="https://solanapay.com/tos" className="legal">
  //         Terms of Service
  //       </Link>
  //       {"."}
  //     </p>
  //   ),
  // },
  // {
  //   label: "Transfer a token (SolanaPay)",
  //   description: (
  //     <p>
  //       {`Example: "Can you help me transfer 1 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v to `}
  //       <i>DESTINATION</i>
  //       {` ?"`}
  //       <br />
  //       <br />
  //       This will generate a QR code that you can scan from within your mobile wallet to send 1 USDC
  //       (mint address EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) from your wallet to a
  //       destination wallet. See the{" "}
  //       <Link
  //         href={
  //           "https://github.com/solana-labs/chatgpt-plugin/blob/examples-langchain/DISCLAIMER.md"
  //         }
  //         className="legal"
  //       >
  //         Disclaimer
  //       </Link>
  //       {" and "}
  //       <Link href="https://solanapay.com/tos" className="legal">
  //         Terms of Service
  //       </Link>
  //       {"."}
  //     </p>
  //   ),
  // },
];


================================================
FILE: chatgpt-plugin/src/lib/helloMoon/index.ts
================================================
export const VALID_OPERATORS = ["=", "!=", ">", "<", ">="];
export type Comparison =
  | {
      operator: "=" | "!=" | ">" | "<" | ">=";
      value: number;
    }
  | undefined;

export function buildComparison(
  operator: string | undefined,
  value: number | undefined,
): Comparison {
  if (operator && !VALID_OPERATORS.includes(operator)) {
    throw new Error(
      "Invalid operator: " +
        operator +
        ". Valid operators are: " +
        VALID_OPERATORS.join(", ") +
        ".",
    );
  }

  const comparison =
    operator && value !== undefined
      ? {
          operator,
          value: new Number(value).valueOf(),
        }
      : undefined;

  return comparison as Comparison;
}

/**
 * Rewrites a "B - A" pair to "A-B" pair
 * @param pair
 */
export function cleanSwapPair(pair: string) {
  let cleaned = pair.replaceAll(" ", "");
  let split = cleaned.split("-");
  let pairA = split[0];
  let pairB = split[1];
  if (pairA < pairB) {
    return `${pairA} - ${pairB}`;
  }
  return `${pairB} - ${pairA}`;
}


================================================
FILE: chatgpt-plugin/src/lib/hyperspace/account.ts
================================================
import { Keypair, PublicKey } from "@solana/web3.js";
import * as anchor from "@coral-xyz/anchor";
import {
  HYPERSPACE,
  FEE_PAYER,
  HYPERSPACE_ID as MARKETPLACE_PROGRAM_ID,
} from "./constants";
import { hyperspaceIdl } from "./idl/hyperspace";
import { AnchorProvider } from "@coral-xyz/anchor";
import {
  TOKEN_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID as SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
} from "@solana/spl-token";
import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";

export async function loadHyperspaceProgram(
  anchorWallet: any,
  connection: anchor.web3.Connection
) {
  const provider = new AnchorProvider(connection, anchorWallet, {
    preflightCommitment: "recent",
  });
  return new anchor.Program(hyperspaceIdl, MARKETPLACE_PROGRAM_ID, provider);
}

export const getHyperspaceBuyerEscrow = async (
  auctionHouse: anchor.web3.PublicKey,
  wallet: anchor.web3.PublicKey
): Promise<[PublicKey, number]> => {
  return await anchor.web3.PublicKey.findProgramAddress(
    [Buffer.from(HYPERSPACE), auctionHouse.toBuffer(), wallet.toBuffer()],
    MARKETPLACE_PROGRAM_ID
  );
};

export const getHyperspaceTradeState = async (
  is_buy: boolean,
  wallet: anchor.web3.PublicKey,
  tokenAccount: anchor.web3.PublicKey,
  tokenMint: anchor.web3.PublicKey,
  tokenSize: anchor.BN
): Promise<[PublicKey, number]> => {
  return await anchor.web3.PublicKey.findProgramAddress(
    [
      Buffer.from(HYPERSPACE),
      is_buy
        ? new anchor.BN(1).toArrayLike(Buffer, "le", 1)
        : new anchor.BN(0).toArrayLike(Buffer, "le", 1),
      wallet.toBuffer(),
      tokenAccount.toBuffer(),
      tokenMint.toBuffer(),
      tokenSize.toArrayLike(Buffer, "le", 8),
    ],
    MARKETPLACE_PROGRAM_ID
  );
};

export const getMetadata = async (
  mint: anchor.web3.PublicKey
): Promise<anchor.web3.PublicKey> => {
  return (
    await anchor.web3.PublicKey.findProgramAddress(
      [
        Buffer.from("metadata"),
        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
        mint.toBuffer(),
      ],
      TOKEN_METADATA_PROGRAM_ID
    )
  )[0];
};

export const getHyperspace = async (
  creator: anchor.web3.PublicKey
): Promise<[PublicKey, number]> => {
  return await anchor.web3.PublicKey.findProgramAddress(
    [Buffer.from(HYPERSPACE), creator.toBuffer()],
    MARKETPLACE_PROGRAM_ID
  );
};

export const getHyperspaceFeeAcct = async (
  auctionHouse: anchor.web3.PublicKey
): Promise<[PublicKey, number]> => {
  return await anchor.web3.PublicKey.findProgramAddress(
    [Buffer.from(HYPERSPACE), auctionHouse.toBuffer(), Buffer.from(FEE_PAYER)],
    MARKETPLACE_PROGRAM_ID
  );
};

export const getAtaForMint = async (
  mint: anchor.web3.PublicKey,
  buyer: anchor.web3.PublicKey
): Promise<[anchor.web3.PublicKey, number]> => {
  return await anchor.web3.PublicKey.findProgramAddress(
    [buyer.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()],
    SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
  );
};

export const getEditionDataAccount = async (
  mint: anchor.web3.PublicKey
): Promise<[anchor.web3.PublicKey, number]> => {
  return await anchor.web3.PublicKey.findProgramAddress(
    [
      Buffer.from("metadata"),
      TOKEN_METADATA_PROGRAM_ID.toBuffer(),
      mint.toBuffer(),
      Buffer.from("edition"),
    ],
    TOKEN_METADATA_PROGRAM_ID
  );
};

export const getHyperspaceProgramAsSigner = async (): Promise<
  [PublicKey, number]
> => {
  return await anchor.web3.PublicKey.findProgramAddress(
    [Buffer.from(HYPERSPACE), Buffer.from("signer")],
    MARKETPLACE_PROGRAM_ID
  );
};

export const findTokenRecordPda = (
  mint: PublicKey,
  token: PublicKey
): PublicKey => {
  return PublicKey.findProgramAddressSync(
    [
      Buffer.from("metadata"),
      TOKEN_METADATA_PROGRAM_ID.toBuffer(),
      mint.toBuffer(),
      Buffer.from("token_record"),
      token.toBuffer(),
    ],
    TOKEN_METADATA_PROGRAM_ID
  )[0];
};


================================================
FILE: chatgpt-plugin/src/lib/hyperspace/constants.ts
================================================
import { PublicKey } from "@solana/web3.js";

export const FEE_PAYER = "fee_payer";
export const HYPERSPACE = "hyperspace";

export const HYPERSPACE_ID = new PublicKey(
  "HYPERfwdTjyJ2SCaKHmpF2MtrXqWxrsotYDsTrshHWq8"
);

export const HYPERSPACE_MARKETPLACE_INSTANCE_ID_STRING =
  "5pdaXth4ijgDCeYDKgSx3jAbN7m8h4gy1LRCErAAN1LM";
export const HYPERSPACE_MARKETPLACE_INSTANCE = new PublicKey(
  "5pdaXth4ijgDCeYDKgSx3jAbN7m8h4gy1LRCErAAN1LM"
);


================================================
FILE: chatgpt-plugin/src/lib/hyperspace/idl/hyperspace.ts
================================================
export type Hyperspace = {
  version: "0.1.0";
  name: "hyperspace";
  instructions: [
    {
      name: "initProgramAsSigner";
      accounts: [
        {
          name: "wallet";
          isMut: true;
          isSigner: true;
        },
        {
          name: "programAsSigner";
          isMut: true;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "programAsSignerBump";
          type: "u8";
        }
      ];
    },
    {
      name: "updateHyperspace";
      accounts: [
        {
          name: "payer";
          isMut: false;
          isSigner: true;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: true;
        },
        {
          name: "newAuthority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "feeWithdrawalDestination";
          isMut: true;
          isSigner: false;
        },
        {
          name: "treasuryWithdrawalDestination";
          isMut: true;
          isSigner: false;
        },
        {
          name: "treasuryWithdrawalDestinationOwner";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "ataProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "rent";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "sellerFeeBasisPoints";
          type: {
            option: "u16";
          };
        },
        {
          name: "requiresSignOff";
          type: {
            option: "bool";
          };
        },
        {
          name: "canChangeSalePrice";
          type: {
            option: "bool";
          };
        }
      ];
    },
    {
      name: "withdraw";
      accounts: [
        {
          name: "wallet";
          isMut: false;
          isSigner: false;
        },
        {
          name: "receiptAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "escrowPaymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "rent";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "escrowPaymentBump";
          type: "u8";
        },
        {
          name: "amount";
          type: "u64";
        }
      ];
    },
    {
      name: "deposit";
      accounts: [
        {
          name: "wallet";
          isMut: false;
          isSigner: true;
        },
        {
          name: "paymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "transferAuthority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "escrowPaymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspaceFeeAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "rent";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "escrowPaymentBump";
          type: "u8";
        },
        {
          name: "amount";
          type: "u64";
        }
      ];
    },
    {
      name: "permissionlessCancel";
      accounts: [
        {
          name: "wallet";
          isMut: false;
          isSigner: true;
        },
        {
          name: "tokenMint";
          isMut: false;
          isSigner: false;
        },
        {
          name: "seller";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenAccount";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "programAsSigner";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "programAsSignerBump";
          type: "u8";
        },
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "tokenSize";
          type: "u64";
        }
      ];
    },
    {
      name: "collectionCancelBuy";
      accounts: [
        {
          name: "wallet";
          isMut: true;
          isSigner: false;
        },
        {
          name: "identifierPubkey";
          isMut: false;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: true;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "collectionBuyerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "programAsSigner";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "buyerPrice";
          type: "u64";
        },
        {
          name: "programAsSignerBump";
          type: "u8";
        },
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "collectionTradeStateType";
          type: "u8";
        },
        {
          name: "identifierIndex";
          type: "u8";
        }
      ];
    },
    {
      name: "cancel";
      accounts: [
        {
          name: "wallet";
          isMut: true;
          isSigner: false;
          docs: ["CHECK OWNER OF TRADE_STATE TODO"];
        },
        {
          name: "tokenMint";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "metadata";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "metadataProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "programAsSigner";
          isMut: false;
          isSigner: false;
        },
        {
          name: "instructions";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenRecord";
          isMut: true;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "editionAccount";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "authorizationRules";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "mplTokenAuthRulesProgram";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        }
      ];
      args: [
        {
          name: "isBuy";
          type: "u8";
        },
        {
          name: "programAsSignerBump";
          type: "u8";
        },
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "tokenSize";
          type: "u64";
        }
      ];
    },
    {
      name: "collectionExecuteSale";
      accounts: [
        {
          name: "buyer";
          isMut: true;
          isSigner: false;
        },
        {
          name: "buyerBrokerWallet";
          isMut: true;
          isSigner: false;
        },
        {
          name: "seller";
          isMut: true;
          isSigner: false;
        },
        {
          name: "sellerBrokerWallet";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenMint";
          isMut: false;
          isSigner: false;
        },
        {
          name: "metadata";
          isMut: true;
          isSigner: false;
        },
        {
          name: "editionData";
          isMut: false;
          isSigner: false;
        },
        {
          name: "escrowPaymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "buyerReceiptTokenAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspaceTreasury";
          isMut: true;
          isSigner: false;
        },
        {
          name: "identifierPubkey";
          isMut: false;
          isSigner: false;
        },
        {
          name: "collectionBuyerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "sellerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "ataProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "metadataProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "mplTokenAuthRulesProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "programAsSigner";
          isMut: false;
          isSigner: false;
        },
        {
          name: "rent";
          isMut: false;
          isSigner: false;
        },
        {
          name: "instructions";
          isMut: false;
          isSigner: false;
        },
        {
          name: "ownerTokenRecord";
          isMut: true;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "destinationTokenRecord";
          isMut: true;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "authorizationRules";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        }
      ];
      args: [
        {
          name: "escrowPaymentBump";
          type: "u8";
        },
        {
          name: "programAsSignerBump";
          type: "u8";
        },
        {
          name: "buyerTradeStateBump";
          type: "u8";
        },
        {
          name: "sellerTradeStateBump";
          type: "u8";
        },
        {
          name: "maxAmountToPay";
          type: "u64";
        },
        {
          name: "buyerBrokerBasisPoints";
          type: "u16";
        },
        {
          name: "sellerBrokerBasisPoints";
          type: "u16";
        },
        {
          name: "tokenSize";
          type: "u64";
        },
        {
          name: "collectionTradeStateType";
          type: "u8";
        },
        {
          name: "identifierIndex";
          type: "u8";
        },
        {
          name: "royaltyBasisPoints";
          type: "u16";
        }
      ];
    },
    {
      name: "executeSale";
      accounts: [
        {
          name: "buyer";
          isMut: true;
          isSigner: false;
        },
        {
          name: "buyerBrokerWallet";
          isMut: true;
          isSigner: false;
        },
        {
          name: "seller";
          isMut: true;
          isSigner: false;
        },
        {
          name: "sellerBrokerWallet";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenMint";
          isMut: false;
          isSigner: false;
        },
        {
          name: "metadata";
          isMut: true;
          isSigner: false;
        },
        {
          name: "escrowPaymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "buyerReceiptTokenAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspaceTreasury";
          isMut: true;
          isSigner: false;
        },
        {
          name: "buyerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "sellerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "ataProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "metadataProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "mplTokenAuthRulesProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "programAsSigner";
          isMut: false;
          isSigner: false;
        },
        {
          name: "rent";
          isMut: false;
          isSigner: false;
        },
        {
          name: "instructions";
          isMut: false;
          isSigner: false;
        },
        {
          name: "editionAccount";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "ownerTokenRecord";
          isMut: true;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "destinationTokenRecord";
          isMut: true;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "authorizationRules";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        }
      ];
      args: [
        {
          name: "escrowPaymentBump";
          type: "u8";
        },
        {
          name: "programAsSignerBump";
          type: "u8";
        },
        {
          name: "buyerTradeStateBump";
          type: "u8";
        },
        {
          name: "sellerTradeStateBump";
          type: "u8";
        },
        {
          name: "maxAmountToPay";
          type: "u64";
        },
        {
          name: "buyerBrokerBasisPoints";
          type: "u16";
        },
        {
          name: "sellerBrokerBasisPoints";
          type: "u16";
        },
        {
          name: "tokenSize";
          type: "u64";
        },
        {
          name: "royaltyBasisPoints";
          type: "u16";
        }
      ];
    },
    {
      name: "sell";
      accounts: [
        {
          name: "wallet";
          isMut: false;
          isSigner: true;
        },
        {
          name: "sellerBrokerWallet";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenMint";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "metadata";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspaceFeeAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "sellerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "metadataProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "programAsSigner";
          isMut: false;
          isSigner: false;
        },
        {
          name: "instructions";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenRecord";
          isMut: true;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "editionAccount";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "authorizationRules";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "mplTokenAuthRulesProgram";
          isMut: false;
          isSigner: false;
          docs: ["CHECK no check needed"];
        },
        {
          name: "clock";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "programAsSignerBump";
          type: "u8";
        },
        {
          name: "minAmountToReceive";
          type: "u64";
        },
        {
          name: "brokerBasisPoints";
          type: "u16";
        },
        {
          name: "tokenSize";
          type: "u64";
        },
        {
          name: "royaltyBasisPoints";
          type: "u16";
        }
      ];
    },
    {
      name: "buy";
      accounts: [
        {
          name: "wallet";
          isMut: false;
          isSigner: true;
        },
        {
          name: "buyerBrokerWallet";
          isMut: false;
          isSigner: false;
        },
        {
          name: "paymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "transferAuthority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenAccount";
          isMut: false;
          isSigner: false;
        },
        {
          name: "buyerReceiptTokenAccount";
          isMut: false;
          isSigner: false;
        },
        {
          name: "metadata";
          isMut: false;
          isSigner: false;
        },
        {
          name: "escrowPaymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspaceFeeAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "buyerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "rent";
          isMut: false;
          isSigner: false;
        },
        {
          name: "clock";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "escrowPaymentBump";
          type: "u8";
        },
        {
          name: "maxAmountToPay";
          type: "u64";
        },
        {
          name: "brokerBasisPoints";
          type: "u16";
        },
        {
          name: "tokenSize";
          type: "u64";
        },
        {
          name: "royaltyBasisPoints";
          type: "u16";
        }
      ];
    },
    {
      name: "collectionBuy";
      accounts: [
        {
          name: "wallet";
          isMut: true;
          isSigner: true;
        },
        {
          name: "buyerBrokerWallet";
          isMut: false;
          isSigner: false;
        },
        {
          name: "identifierPubkey";
          isMut: false;
          isSigner: false;
        },
        {
          name: "escrowPaymentAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "authority";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspace";
          isMut: false;
          isSigner: false;
        },
        {
          name: "hyperspaceFeeAccount";
          isMut: true;
          isSigner: false;
        },
        {
          name: "collectionBuyerTradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "tokenProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "rent";
          isMut: false;
          isSigner: false;
        },
        {
          name: "clock";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "escrowPaymentBump";
          type: "u8";
        },
        {
          name: "buyerPrice";
          type: "u64";
        },
        {
          name: "brokerBasisPoints";
          type: "u16";
        },
        {
          name: "collectionTradeStateType";
          type: "u8";
        },
        {
          name: "identifierIndex";
          type: "u8";
        },
        {
          name: "royaltyBasisPoints";
          type: "u16";
        }
      ];
    },
    {
      name: "createCollectionBuyTradeState";
      accounts: [
        {
          name: "wallet";
          isMut: true;
          isSigner: true;
        },
        {
          name: "identifierPubkey";
          isMut: false;
          isSigner: false;
        },
        {
          name: "brokerWallet";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "clock";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "buyPrice";
          type: "u64";
        },
        {
          name: "brokerBasisPoints";
          type: "u16";
        },
        {
          name: "collectionTradeStateType";
          type: "u8";
        },
        {
          name: "identifierIndex";
          type: "u8";
        },
        {
          name: "royaltyBasisPoints";
          type: "u16";
        }
      ];
    },
    {
      name: "createTradeState";
      accounts: [
        {
          name: "wallet";
          isMut: true;
          isSigner: true;
        },
        {
          name: "collection";
          isMut: false;
          isSigner: false;
        },
        {
          name: "brokerWallet";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenAccount";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tokenMint";
          isMut: false;
          isSigner: false;
        },
        {
          name: "tradeState";
          isMut: true;
          isSigner: false;
        },
        {
          name: "systemProgram";
          isMut: false;
          isSigner: false;
        },
        {
          name: "clock";
          isMut: false;
          isSigner: false;
        }
      ];
      args: [
        {
          name: "isBuy";
          type: "u8";
        },
        {
          name: "tradeStateBump";
          type: "u8";
        },
        {
          name: "buyPrice";
          type: "u64";
        },
        {
          name: "brokerBasisPoints";
          type: "u16";
        },
        {
          name: "tokenSize";
          type: "u64";
        },
        {
          name: "royaltyBasisPoints";
          type: "u16";
        }
      ];
    }
  ];
  accounts: [
    {
      name: "hyperspace";
      type: {
        kind: "struct";
        fields: [
          {
            name: "hyperspaceFeeAccount";
            type: "publicKey";
          },
          {
            name: "hyperspaceTreasury";
            type: "publicKey";
          },
          {
            name: "treasuryWithdrawalDestination";
            type: "publicKey";
          },
          {
            name: "feeWithdrawalDestination";
            type: "publicKey";
          },
          {
            name: "authority";
            type: "publicKey";
          },
          {
            name: "creator";
            type: "publicKey";
          },
          {
            name: "bump";
            type: "u8";
          },
          {
            name: "treasuryBump";
            type: "u8";
          },
          {
            name: "feePayerBump";
            type: "u8";
          },
          {
            name: "sellerFeeBasisPoints";
            type: "u16";
          },
          {
            name: "requiresSignOff";
            type: "bool";
          },
          {
            name: "canChangeSalePrice";
            type: "bool";
          }
        ];
      };
    },
    {
      name: "programAsSigner";
      type: {
        kind: "struct";
        fields: [
          {
            name: "firstByte";
            type: "u8";
          }
        ];
      };
    },
    {
      name: "tradeState";
      type: {
        kind: "struct";
        fields: [
          {
            name: "buyPrice";
            type: "u64";
          },
          {
            name: "userWallet";
            type: "publicKey";
          },
          {
            name: "isBuy";
            type: "u8";
          },
          {
            name: "collection";
            type: "publicKey";
          },
          {
            name: "brokerWallet";
            type: "publicKey";
          },
          {
            name: "brokerBasisPoints";
            type: "u16";
          },
          {
            name: "tokenMint";
            type: "publicKey";
          },
          {
            name: "royaltyBasisPoints";
            type: "u16";
          },
          {
            name: "timestamp";
            type: "i64";
          }
        ];
      };
    },
    {
      name: "collectionBuyTradeState";
      type: {
        kind: "struct";
        fields: [
          {
            name: "userWallet";
            type: "publicKey";
          },
          {
            name: "collectionTradeStateType";
            type: "u8";
          },
          {
            name: "identifierIndex";
            type: "u8";
          },
          {
            name: "identifierPubkey";
            type: "publicKey";
          },
          {
            name: "brokerWallet";
            type: "publicKey";
          },
          {
            name: "brokerBasisPoints";
            type: "u16";
          },
          {
            name: "royaltyBasisPoints";
            type: "u16";
          },
          {
            name: "timestamp";
            type: "i64";
          }
        ];
      };
    }
  ];
  types: [
    {
      name: "AuthorizationDataLocal";
      type: {
        kind: "struct";
        fields: [
          {
            name: "payload";
            type: {
              vec: {
                defined: "TaggedPayload";
              };
            };
          }
        ];
      };
    },
    {
      name: "TaggedPayload";
      type: {
        kind: "struct";
        fields: [
          {
            name: "name";
            type: "string";
          },
          {
            name: "payload";
            type: {
              defined: "PayloadTypeLocal";
            };
          }
        ];
      };
    },
    {
      name: "SeedsVecLocal";
      type: {
        kind: "struct";
        fields: [
          {
            name: "seeds";
            docs: ["The vector of derivation seeds."];
            type: {
              vec: "bytes";
            };
          }
        ];
      };
    },
    {
      name: "ProofInfoLocal";
      type: {
        kind: "struct";
        fields: [
          {
            name: "proof";
            docs: ["The merkle proof."];
            type: {
              vec: {
                array: ["u8", 32];
              };
            };
          }
        ];
      };
    },
    {
      name: "PayloadTypeLocal";
      type: {
        kind: "enum";
        variants: [
          {
            name: "Pubkey";
            fields: ["publicKey"];
          },
          {
            name: "Seeds";
            fields: [
              {
                defined: "SeedsVecLocal";
              }
            ];
          },
          {
            name: "MerkleProof";
            fields: [
              {
                defined: "ProofInfoLocal";
              }
            ];
          },
          {
            name: "Number";
            fields: ["u64"];
          }
        ];
      };
    }
  ];
  errors: [
    {
      code: 6000;
      name: "PublicKeyMismatch";
      msg: "PublicKeyMismatch";
    },
    {
      code: 6001;
      name: "InvalidMintAuthority";
      msg: "InvalidMintAuthority";
    },
    {
      code: 6002;
      name: "UninitializedAccount";
      msg: "UninitializedAccount";
    },
    {
      code: 6003;
      name: "IncorrectOwner";
      msg: "IncorrectOwner";
    },
    {
      code: 6004;
      name: "PublicKeysShouldBeUnique";
      msg: "PublicKeysShouldBeUnique";
    },
    {
      code: 6005;
      name: "StatementFalse";
      msg: "StatementFalse";
    },
    {
      code: 6006;
      name: "NotRentExempt";
      msg: "NotRentExempt";
    },
    {
      code: 6007;
      name: "NumericalOverflow";
      msg: "NumericalOverflow";
    },
    {
      code: 6008;
      name: "ExpectedSolAccount";
      msg: "Expected a sol account but got an spl token account instead";
    },
    {
      code: 6009;
      name: "CannotExchangeSOLForSol";
      msg: "Cannot exchange sol for sol";
    },
    {
      code: 6010;
      name: "SOLWalletMustSign";
      msg: "If paying with sol, sol wallet must be signer";
    },
    {
      code: 6011;
      name: "CannotTakeThisActionWithoutHyperspaceSignOff";
      msg: "Cannot take this action without hyperspace signing too";
    },
    {
      code: 6012;
      name: "NoPayerPresent";
      msg: "No payer present on this txn";
    },
    {
      code: 6013;
      name: "DerivedKeyInvalid";
      msg: "Derived key invalid";
    },
    {
      code: 6014;
      name: "MetadataDoesntExist";
      msg: "Metadata doesn't exist";
    },
    {
      code: 6015;
      name: "InvalidTokenAmount";
      msg: "Invalid token amount";
    },
    {
      code: 6016;
      name: "BothPartiesNeedToAgreeToSale";
      msg: "Both parties need to agree to this sale";
    },
    {
      code: 6017;
      name: "CannotMatchFreeSalesWithoutHyperspaceOrSellerSignoff";
      msg: "Cannot match free sales unless the hyperspace or seller signs off";
    },
    {
      code: 6018;
      name: "SaleRequiresSigner";
      msg: "This sale requires a signer";
    },
    {
      code: 6019;
      name: "OldSellerNotInitialized";
      msg: "Old seller not initialized";
    },
    {
      code: 6020;
      name: "SellerATACannotHaveDelegate";
      msg: "Seller ata cannot have a delegate set";
    },
    {
      code: 6021;
      name: "BuyerATACannotHaveDelegate";
      msg: "Buyer ata cannot have a delegate set";
    },
    {
      code: 6022;
      name: "NoValidSignerPresent";
      msg: "No valid signer present";
    },
    {
      code: 6023;
      name: "InvalidBasisPoints";
      msg: "BP must be less than or equal to 10000";
    },
    {
      code: 6024;
      name: "InvalidBrokerInformation";
      msg: "Broker information must match";
    },
    {
      code: 6025;
      name: "InvalidTokenAccount";
      msg: "Token Account holding selling token must be owned by seller";
    },
    {
      code: 6026;
      name: "InvalidPermissionlessCancel";
      msg: "Cannot permissionless cancel this trade state";
    },
    {
      code: 6027;
      name: "InvalidCollectionTradeStateType";
      msg: "Invalid Collection Trade State Type";
    },
    {
      code: 6028;
      name: "InvalidCollectionTradeStateIdentifier";
      msg: "Invalid Collection Trade State Identifier";
    },
    {
      code: 6029;
      name: "BumpSeedNotInHashMap";
      msg: "Bump seed not in hash map.";
    },
    {
      code: 6030;
      name: "MetaplexTransferFailed";
      msg: "Failed to transfer NFT using metaplex";
    },
    {
      code: 6031;
      name: "MetaplexDelegateFailed";
      msg: "Failed to set Sale delegate on NFT using metaplex";
    },
    {
      code: 6032;
      name: "MetaplexRevokeFailed";
      msg: "Failed to revoke Sale delegate on NFT using metaplex";
    },
    {
      code: 6033;
      name: "IncorrectTokenStandard";
      msg: "Token standard must be Programmable NFT or Standard NFT";
    },
    {
      code: 6034;
      name: "PNFTDelegateSetAlready";
      msg: "PNFT Delegate set already";
    },
    {
      code: 6035;
      name: "RoyaltyBPMismatch";
      msg: "Royalty basis points mismatch";
    }
  ];
};

export const hyperspaceIdl: Hyperspace = {
  version: "0.1.0",
  name: "hyperspace",
  instructions: [
    {
      name: "initProgramAsSigner",
      accounts: [
        {
          name: "wallet",
          isMut: true,
          isSigner: true,
        },
        {
          name: "programAsSigner",
          isMut: true,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "programAsSignerBump",
          type: "u8",
        },
      ],
    },
    {
      name: "updateHyperspace",
      accounts: [
        {
          name: "payer",
          isMut: false,
          isSigner: true,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: true,
        },
        {
          name: "newAuthority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "feeWithdrawalDestination",
          isMut: true,
          isSigner: false,
        },
        {
          name: "treasuryWithdrawalDestination",
          isMut: true,
          isSigner: false,
        },
        {
          name: "treasuryWithdrawalDestinationOwner",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "ataProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "rent",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "sellerFeeBasisPoints",
          type: {
            option: "u16",
          },
        },
        {
          name: "requiresSignOff",
          type: {
            option: "bool",
          },
        },
        {
          name: "canChangeSalePrice",
          type: {
            option: "bool",
          },
        },
      ],
    },
    {
      name: "withdraw",
      accounts: [
        {
          name: "wallet",
          isMut: false,
          isSigner: false,
        },
        {
          name: "receiptAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "escrowPaymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "rent",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "escrowPaymentBump",
          type: "u8",
        },
        {
          name: "amount",
          type: "u64",
        },
      ],
    },
    {
      name: "deposit",
      accounts: [
        {
          name: "wallet",
          isMut: false,
          isSigner: true,
        },
        {
          name: "paymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "transferAuthority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "escrowPaymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspaceFeeAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "rent",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "escrowPaymentBump",
          type: "u8",
        },
        {
          name: "amount",
          type: "u64",
        },
      ],
    },
    {
      name: "permissionlessCancel",
      accounts: [
        {
          name: "wallet",
          isMut: false,
          isSigner: true,
        },
        {
          name: "tokenMint",
          isMut: false,
          isSigner: false,
        },
        {
          name: "seller",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenAccount",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "programAsSigner",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "programAsSignerBump",
          type: "u8",
        },
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "tokenSize",
          type: "u64",
        },
      ],
    },
    {
      name: "collectionCancelBuy",
      accounts: [
        {
          name: "wallet",
          isMut: true,
          isSigner: false,
        },
        {
          name: "identifierPubkey",
          isMut: false,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: true,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "collectionBuyerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "programAsSigner",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "buyerPrice",
          type: "u64",
        },
        {
          name: "programAsSignerBump",
          type: "u8",
        },
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "collectionTradeStateType",
          type: "u8",
        },
        {
          name: "identifierIndex",
          type: "u8",
        },
      ],
    },
    {
      name: "cancel",
      accounts: [
        {
          name: "wallet",
          isMut: true,
          isSigner: false,
          docs: ["CHECK OWNER OF TRADE_STATE TODO"],
        },
        {
          name: "tokenMint",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "metadata",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "metadataProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "programAsSigner",
          isMut: false,
          isSigner: false,
        },
        {
          name: "instructions",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenRecord",
          isMut: true,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "editionAccount",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "authorizationRules",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "mplTokenAuthRulesProgram",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
      ],
      args: [
        {
          name: "isBuy",
          type: "u8",
        },
        {
          name: "programAsSignerBump",
          type: "u8",
        },
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "tokenSize",
          type: "u64",
        },
      ],
    },
    {
      name: "collectionExecuteSale",
      accounts: [
        {
          name: "buyer",
          isMut: true,
          isSigner: false,
        },
        {
          name: "buyerBrokerWallet",
          isMut: true,
          isSigner: false,
        },
        {
          name: "seller",
          isMut: true,
          isSigner: false,
        },
        {
          name: "sellerBrokerWallet",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenMint",
          isMut: false,
          isSigner: false,
        },
        {
          name: "metadata",
          isMut: true,
          isSigner: false,
        },
        {
          name: "editionData",
          isMut: false,
          isSigner: false,
        },
        {
          name: "escrowPaymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "buyerReceiptTokenAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspaceTreasury",
          isMut: true,
          isSigner: false,
        },
        {
          name: "identifierPubkey",
          isMut: false,
          isSigner: false,
        },
        {
          name: "collectionBuyerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "sellerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "ataProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "metadataProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "mplTokenAuthRulesProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "programAsSigner",
          isMut: false,
          isSigner: false,
        },
        {
          name: "rent",
          isMut: false,
          isSigner: false,
        },
        {
          name: "instructions",
          isMut: false,
          isSigner: false,
        },
        {
          name: "ownerTokenRecord",
          isMut: true,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "destinationTokenRecord",
          isMut: true,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "authorizationRules",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
      ],
      args: [
        {
          name: "escrowPaymentBump",
          type: "u8",
        },
        {
          name: "programAsSignerBump",
          type: "u8",
        },
        {
          name: "buyerTradeStateBump",
          type: "u8",
        },
        {
          name: "sellerTradeStateBump",
          type: "u8",
        },
        {
          name: "maxAmountToPay",
          type: "u64",
        },
        {
          name: "buyerBrokerBasisPoints",
          type: "u16",
        },
        {
          name: "sellerBrokerBasisPoints",
          type: "u16",
        },
        {
          name: "tokenSize",
          type: "u64",
        },
        {
          name: "collectionTradeStateType",
          type: "u8",
        },
        {
          name: "identifierIndex",
          type: "u8",
        },
        {
          name: "royaltyBasisPoints",
          type: "u16",
        },
      ],
    },
    {
      name: "executeSale",
      accounts: [
        {
          name: "buyer",
          isMut: true,
          isSigner: false,
        },
        {
          name: "buyerBrokerWallet",
          isMut: true,
          isSigner: false,
        },
        {
          name: "seller",
          isMut: true,
          isSigner: false,
        },
        {
          name: "sellerBrokerWallet",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenMint",
          isMut: false,
          isSigner: false,
        },
        {
          name: "metadata",
          isMut: true,
          isSigner: false,
        },
        {
          name: "escrowPaymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "buyerReceiptTokenAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspaceTreasury",
          isMut: true,
          isSigner: false,
        },
        {
          name: "buyerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "sellerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "ataProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "metadataProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "mplTokenAuthRulesProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "programAsSigner",
          isMut: false,
          isSigner: false,
        },
        {
          name: "rent",
          isMut: false,
          isSigner: false,
        },
        {
          name: "instructions",
          isMut: false,
          isSigner: false,
        },
        {
          name: "editionAccount",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "ownerTokenRecord",
          isMut: true,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "destinationTokenRecord",
          isMut: true,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "authorizationRules",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
      ],
      args: [
        {
          name: "escrowPaymentBump",
          type: "u8",
        },
        {
          name: "programAsSignerBump",
          type: "u8",
        },
        {
          name: "buyerTradeStateBump",
          type: "u8",
        },
        {
          name: "sellerTradeStateBump",
          type: "u8",
        },
        {
          name: "maxAmountToPay",
          type: "u64",
        },
        {
          name: "buyerBrokerBasisPoints",
          type: "u16",
        },
        {
          name: "sellerBrokerBasisPoints",
          type: "u16",
        },
        {
          name: "tokenSize",
          type: "u64",
        },
        {
          name: "royaltyBasisPoints",
          type: "u16",
        },
      ],
    },
    {
      name: "sell",
      accounts: [
        {
          name: "wallet",
          isMut: false,
          isSigner: true,
        },
        {
          name: "sellerBrokerWallet",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenMint",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "metadata",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspaceFeeAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "sellerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "metadataProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "programAsSigner",
          isMut: false,
          isSigner: false,
        },
        {
          name: "instructions",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenRecord",
          isMut: true,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "editionAccount",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "authorizationRules",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "mplTokenAuthRulesProgram",
          isMut: false,
          isSigner: false,
          docs: ["CHECK no check needed"],
        },
        {
          name: "clock",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "programAsSignerBump",
          type: "u8",
        },
        {
          name: "minAmountToReceive",
          type: "u64",
        },
        {
          name: "brokerBasisPoints",
          type: "u16",
        },
        {
          name: "tokenSize",
          type: "u64",
        },
        {
          name: "royaltyBasisPoints",
          type: "u16",
        },
      ],
    },
    {
      name: "buy",
      accounts: [
        {
          name: "wallet",
          isMut: false,
          isSigner: true,
        },
        {
          name: "buyerBrokerWallet",
          isMut: false,
          isSigner: false,
        },
        {
          name: "paymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "transferAuthority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenAccount",
          isMut: false,
          isSigner: false,
        },
        {
          name: "buyerReceiptTokenAccount",
          isMut: false,
          isSigner: false,
        },
        {
          name: "metadata",
          isMut: false,
          isSigner: false,
        },
        {
          name: "escrowPaymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspaceFeeAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "buyerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "rent",
          isMut: false,
          isSigner: false,
        },
        {
          name: "clock",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "escrowPaymentBump",
          type: "u8",
        },
        {
          name: "maxAmountToPay",
          type: "u64",
        },
        {
          name: "brokerBasisPoints",
          type: "u16",
        },
        {
          name: "tokenSize",
          type: "u64",
        },
        {
          name: "royaltyBasisPoints",
          type: "u16",
        },
      ],
    },
    {
      name: "collectionBuy",
      accounts: [
        {
          name: "wallet",
          isMut: true,
          isSigner: true,
        },
        {
          name: "buyerBrokerWallet",
          isMut: false,
          isSigner: false,
        },
        {
          name: "identifierPubkey",
          isMut: false,
          isSigner: false,
        },
        {
          name: "escrowPaymentAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "authority",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspace",
          isMut: false,
          isSigner: false,
        },
        {
          name: "hyperspaceFeeAccount",
          isMut: true,
          isSigner: false,
        },
        {
          name: "collectionBuyerTradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "tokenProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "rent",
          isMut: false,
          isSigner: false,
        },
        {
          name: "clock",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "escrowPaymentBump",
          type: "u8",
        },
        {
          name: "buyerPrice",
          type: "u64",
        },
        {
          name: "brokerBasisPoints",
          type: "u16",
        },
        {
          name: "collectionTradeStateType",
          type: "u8",
        },
        {
          name: "identifierIndex",
          type: "u8",
        },
        {
          name: "royaltyBasisPoints",
          type: "u16",
        },
      ],
    },
    {
      name: "createCollectionBuyTradeState",
      accounts: [
        {
          name: "wallet",
          isMut: true,
          isSigner: true,
        },
        {
          name: "identifierPubkey",
          isMut: false,
          isSigner: false,
        },
        {
          name: "brokerWallet",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "clock",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "buyPrice",
          type: "u64",
        },
        {
          name: "brokerBasisPoints",
          type: "u16",
        },
        {
          name: "collectionTradeStateType",
          type: "u8",
        },
        {
          name: "identifierIndex",
          type: "u8",
        },
        {
          name: "royaltyBasisPoints",
          type: "u16",
        },
      ],
    },
    {
      name: "createTradeState",
      accounts: [
        {
          name: "wallet",
          isMut: true,
          isSigner: true,
        },
        {
          name: "collection",
          isMut: false,
          isSigner: false,
        },
        {
          name: "brokerWallet",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenAccount",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tokenMint",
          isMut: false,
          isSigner: false,
        },
        {
          name: "tradeState",
          isMut: true,
          isSigner: false,
        },
        {
          name: "systemProgram",
          isMut: false,
          isSigner: false,
        },
        {
          name: "clock",
          isMut: false,
          isSigner: false,
        },
      ],
      args: [
        {
          name: "isBuy",
          type: "u8",
        },
        {
          name: "tradeStateBump",
          type: "u8",
        },
        {
          name: "buyPrice",
          type: "u64",
        },
        {
          name: "brokerBasisPoints",
          type: "u16",
        },
        {
          name: "tokenSize",
          type: "u64",
        },
        {
          name: "royaltyBasisPoints",
          type: "u16",
        },
      ],
    },
  ],
  accounts: [
    {
      name: "hyperspace",
      type: {
        kind: "struct",
        fields: [
          {
            name: "hyperspaceFeeAccount",
            type: "publicKey",
          },
          {
            name: "hyperspaceTreasury",
            type: "publicKey",
          },
          {
            name: "treasuryWithdrawalDestination",
            type: "publicKey",
          },
          {
            name: "feeWithdrawalDestination",
            type: "publicKey",
          },
          {
            name: "authority",
            type: "publicKey",
          },
          {
            name: "creator",
            type: "publicKey",
          },
          {
            name: "bump",
            type: "u8",
          },
          {
            name: "treasuryBump",
            type: "u8",
          },
          {
            name: "feePayerBump",
            type: "u8",
          },
          {
            name: "sellerFeeBasisPoints",
            type: "u16",
          },
          {
            name: "requiresSignOff",
            type: "bool",
          },
          {
            name: "canChangeSalePrice",
            type: "bool",
          },
        ],
      },
    },
    {
      name: "programAsSigner",
      type: {
        kind: "struct",
        fields: [
          {
            name: "firstByte",
            type: "u8",
          },
        ],
      },
    },
    {
      name: "tradeState",
      type: {
        kind: "struct",
        fields: [
          {
            name: "buyPrice",
            type: "u64",
          },
          {
            name: "userWallet",
            type: "publicKey",
          },
          {
            name: "isBuy",
            type: "u8",
          },
          {
            name: "collection",
            type: "publicKey",
          },
          {
            name: "brokerWallet",
            type: "publicKey",
          },
          {
            name: "brokerBasisPoints",
            type: "u16",
          },
          {
            name: "tokenMint",
            type: "publicKey",
          },
          {
            name: "royaltyBasisPoints",
            type: "u16",
          },
          {
            name: "timestamp",
            type: "i64",
          },
        ],
      },
    },
    {
      name: "collectionBuyTradeState",
      type: {
        kind: "struct",
        fields: [
          {
            name: "userWallet",
            type: "publicKey",
          },
          {
            name: "collectionTradeStateType",
            type: "u8",
          },
          {
            name: "identifierIndex",
            type: "u8",
          },
          {
            name: "identifierPubkey",
            type: "publicKey",
          },
          {
            name: "brokerWallet",
            type: "publicKey",
          },
          {
            name: "brokerBasisPoints",
            type: "u16",
          },
          {
            name: "royaltyBasisPoints",
            type: "u16",
          },
          {
            name: "timestamp",
            type: "i64",
          },
        ],
      },
    },
  ],
  types: [
    {
      name: "AuthorizationDataLocal",
      type: {
        kind: "struct",
        fields: [
          {
            name: "payload",
            type: {
              vec: {
                defined: "TaggedPayload",
              },
            },
          },
        ],
      },
    },
    {
      name: "TaggedPayload",
      type: {
        kind: "struct",
        fields: [
          {
            name: "name",
            type: "string",
          },
          {
            name: "payload",
            type: {
              defined: "PayloadTypeLocal",
            },
          },
        ],
      },
    },
    {
      name: "SeedsVecLocal",
      type: {
        kind: "struct",
        fields: [
          {
            name: "seeds",
            docs: ["The vector of derivation seeds."],
            type: {
              vec: "bytes",
            },
          },
        ],
      },
    },
    {
      name: "ProofInfoLocal",
      type: {
        kind: "struct",
        fields: [
          {
            name: "proof",
            docs: ["The merkle proof."],
            type: {
              vec: {
                array: ["u8", 32],
              },
            },
          },
        ],
      },
    },
    {
      name: "PayloadTypeLocal",
      type: {
        kind: "enum",
        variants: [
          {
            name: "Pubkey",
            fields: ["publicKey"],
          },
          {
            name: "Seeds",
            fields: [
              {
                defined: "SeedsVecLocal",
              },
            ],
          },
          {
            name: "MerkleProof",
            fields: [
              {
                defined: "ProofInfoLocal",
              },
            ],
          },
          {
            name: "Number",
            fields: ["u64"],
          },
        ],
      },
    },
  ],
  errors: [
    {
      code: 6000,
      name: "PublicKeyMismatch",
      msg: "PublicKeyMismatch",
    },
    {
      code: 6001,
      name: "InvalidMintAuthority",
      msg: "InvalidMintAuthority",
    },
    {
      code: 6002,
      name: "UninitializedAccount",
      msg: "UninitializedAccount",
    },
    {
      code: 6003,
      name: "IncorrectOwner",
      msg: "IncorrectOwner",
    },
    {
      code: 6004,
      name: "PublicKeysShouldBeUnique",
      msg: "PublicKeysShouldBeUnique",
    },
    {
      code: 6005,
      name: "StatementFalse",
      msg: "StatementFalse",
    },
    {
      code: 6006,
      name: "NotRentExempt",
      msg: "NotRentExempt",
    },
    {
      code: 6007,
      name: "NumericalOverflow",
      msg: "NumericalOverflow",
    },
    {
      code: 6008,
      name: "ExpectedSolAccount",
      msg: "Expected a sol account but got an spl token account instead",
    },
    {
      code: 6009,
      name: "CannotExchangeSOLForSol",
      msg: "Cannot exchange sol for sol",
    },
    {
      code: 6010,
      name: "SOLWalletMustSign",
      msg: "If paying with sol, sol wallet must be signer",
    },
    {
      code: 6011,
      name: "CannotTakeThisActionWithoutHyperspaceSignOff",
      msg: "Cannot take this action without hyperspace signing too",
    },
    {
      code: 6012,
      name: "NoPayerPresent",
      msg: "No payer present on this txn",
    },
    {
      code: 6013,
      name: "DerivedKeyInvalid",
      msg: "Derived key invalid",
    },
    {
      code: 6014,
      name: "MetadataDoesntExist",
      msg: "Metadata doesn't exist",
    },
    {
      code: 6015,
      name: "InvalidTokenAmount",
      msg: "Invalid token amount",
    },
    {
      code: 6016,
      name: "BothPartiesNeedToAgreeToSale",
      msg: "Both parties need to agree to this sale",
    },
    {
      code: 6017,
      name: "CannotMatchFreeSalesWithoutHyperspaceOrSellerSignoff",
      msg: "Cannot match free sales unless the hyperspace or seller signs off",
    },
    {
      code: 6018,
      name: "SaleRequiresSigner",
      msg: "This sale requires a signer",
    },
    {
      code: 6019,
      name: "OldSellerNotInitialized",
      msg: "Old seller not initialized",
    },
    {
      code: 6020,
      name: "SellerATACannotHaveDelegate",
      msg: "Seller ata cannot have a delegate set",
    },
    {
      code: 6021,
      name: "BuyerATACannotHaveDelegate",
      msg: "Buyer ata cannot have a delegate set",
    },
    {
      code: 6022,
      name: "NoValidSignerPresent",
      msg: "No valid signer present",
    },
    {
      code: 6023,
      name: "InvalidBasisPoints",
      msg: "BP must be less than or equal to 10000",
    },
    {
      code: 6024,
      name: "InvalidBrokerInformation",
      msg: "Broker information must match",
    },
    {
      code: 6025,
      name: "InvalidTokenAccount",
      msg: "Token Account holding selling token must be owned by seller",
    },
    {
      code: 6026,
      name: "InvalidPermissionlessCancel",
      msg: "Cannot permissionless cancel this trade state",
    },
    {
      code: 6027,
      name: "InvalidCollectionTradeStateType",
      msg: "Invalid Collection Trade State Type",
    },
    {
      code: 6028,
      name: "InvalidCollectionTradeStateIdentifier",
      msg: "Invalid Collection Trade State Identifier",
    },
    {
      code: 6029,
      name: "BumpSeedNotInHashMap",
      msg: "Bump seed not in hash map.",
    },
    {
      code: 6030,
      name: "MetaplexTransferFailed",
      msg: "Failed to transfer NFT using metaplex",
    },
    {
      code: 6031,
      name: "MetaplexDelegateFailed",
      msg: "Failed to set Sale delegate on NFT using metaplex",
    },
    {
      code: 6032,
      name: "MetaplexRevokeFailed",
      msg: "Failed to revoke Sale delegate on NFT using metaplex",
    },
    {
      code: 6033,
      name: "IncorrectTokenStandard",
      msg: "Token standard must be Programmable NFT or Standard NFT",
    },
    {
      code: 6034,
      name: "PNFTDelegateSetAlready",
      msg: "PNFT Delegate set already",
    },
    {
      code: 6035,
      name: "RoyaltyBPMismatch",
      msg: "Royalty basis points mismatch",
    },
  ],
};


================================================
FILE: chatgpt-plugin/src/lib/middleware.ts
================================================
import { NextApiRequest, NextApiResponse, NextApiHandler } from "next";
import { resolveAddress, resolveToken } from "./address";

export type Options = {
  addresses?: string[];
  tokens?: string[];
  rewriteQuery?: boolean;
};

export function makeApiPostRequest(handler: NextApiHandler, options?: Options): NextApiHandler {
  return async (req: NextApiRequest, res: NextApiResponse) => {
    const rewriteQuery = options ? options.rewriteQuery : false;

    if (req.method != "POST") {
      res.status(405).send({ message: "Only POST requests allowed" });
      return;
    }

    const target = rewriteQuery ? req.query : req.body;
    try {
      if (options && options.addresses) {
        for (const addr of options.addresses) {
          const publicKey = await resolveAddress(target[addr]);
          target[addr] = publicKey;
        }
      }
      if (options && options.tokens) {
        for (const token of options.tokens) {
          const publicKey = await resolveToken(target[token]);
          target[token] = publicKey;
        }
      }
    } catch (e) {
      res.status(400).send({ message: (e as Error).toString() });
      return;
    }

    await handler(req, res);
  };
}


================================================
FILE: chatgpt-plugin/src/lib/on-chain-metadata/index.ts
================================================
import * as anchor from "@coral-xyz/anchor";
import { Connection } from "@solana/web3.js";

type SolanaPayTx = {
  transaction: string;
  message?: string;
};

/**
 * Need this to fake a wallet with only a publicKey for the anchor provider
 */
class FakeWallet {
  publicKey: anchor.web3.PublicKey;
  constructor(publicKey: anchor.web3.PublicKey) {
    this.publicKey = publicKey;
  }

  async signTransaction<
    T extends anchor.web3.Transaction | anchor.web3.VersionedTransaction
  >(tx: T): Promise<T> {
    return tx;
  }

  async signAllTransactions<
    T extends anchor.web3.Transaction | anchor.web3.VersionedTransaction
  >(txs: T[]): Promise<T[]> {
    return txs;
  }
}

export async function createWriteNFTMetadataTx(
  connection: Connection,
  owner: string,
  metadata: Object
): Promise<SolanaPayTx> {
  const program = await anchor.Program.at(
    process.env.ON_CHAIN_METADATA_PROGRAM as string,
    new anchor.AnchorProvider(
      connection,
      new FakeWallet(new anchor.web3.PublicKey(owner)),
      {}
    )
  );

  let metadataBytes = JSON.stringify(metadata);
  console.log(metadataBytes.length);
  if (metadataBytes.length > 500) {
    throw new Error("Metadata too large: " + metadataBytes.length);
  }

  const metadataKp = anchor.web3.Keypair.generate();

  // Create metadata
  let initIx = await program.methods
    .initialize(new anchor.BN(metadataBytes.length))
    .accounts({
      owner,
      metadata: metadataKp.publicKey,
    })
    .signers([metadataKp])
    .instruction();

  // Write metadata
  let writeIx = await program.methods
    .write(new anchor.BN(0), Buffer.from(metadataBytes))
    .accounts({
      metadata: metadataKp.publicKey,
      owner,
    })
    .instruction();

  // Validate metadata
  let validateIx = await program.methods
    .validate()
    .accounts({ metadata: metadataKp.publicKey })
    .instruction();

  let tx = new anchor.web3.Transaction();
  tx = tx.add(initIx).add(writeIx).add(validateIx);
  tx.recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
  tx.feePayer = new anchor.web3.PublicKey(owner);
  tx.partialSign(metadataKp);

  return {
    transaction: tx
      .serialize({ requireAllSignatures: false })
      .toString("base64"),
  };
}

export async function createCloseNFTMetadataTx(
  connection: Connection,
  owner: string,
  account: string
): Promise<SolanaPayTx> {
  const program = await anchor.Program.at(
    process.env.ON_CHAIN_METADATA_PROGRAM as string,
    new anchor.AnchorProvider(
      connection,
      new FakeWallet(new anchor.web3.PublicKey(owner)),
      {}
    )
  );
  let tx = await program.methods
    .close()
    .accounts({
      metadata: account,
      recipient: owner,
      owner,
    })
    .transaction();

  tx.recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
  tx.feePayer = new anchor.web3.PublicKey(owner);

  return {
    transaction: tx
      .serialize({ requireAllSignatures: false })
      .toString("base64"),
  };
}


================================================
FILE: chatgpt-plugin/src/pages/api/constants.ts
================================================
import express from "express";

import { RestClient } from "@hellomoon/api";
import { Connection } from "@solana/web3.js";
import { HyperspaceClient } from "hyperspace-client-js";

export const APP = express();
export const PORT = process.env.PORT || 3333;

import dotenv from "dotenv";
dotenv.config();

// Internal Solana Pay constants
export const SOLANA_PAY_LABEL = "Solana Labs ChatGPT Plugin";
export const TRANSACTION_ENDPOINTS = [
  "createBuyNFT",
  "createWriteNFTMetadata",
  "createCloseNFTMetadata",
];
export type TransactionEndpoints = (typeof TRANSACTION_ENDPOINTS)[number];
export const TX_DESCRIPTIONS: Record<TransactionEndpoints, string> = {
  createBuyNFT: "Sign to Buy NFT",
  createWriteNFTMetadata: "Sign to Write NFT Metadata",
  createCloseNFTMetadata: "Sign to Close NFT Metadata",
  createTransferToken: "Sign to Transfer Token",
  createTransferSol: "Sign to Transfer Sol",
};

// Inferred Constants
export let HELIUS_URL: string;
export let SELF_URL: string;
export let HYPERSPACE_CLIENT: HyperspaceClient;
export let HELLOMOON_CLIENT: RestClient;
export let CONNECTION: Connection;

export default function index() {
  HELIUS_URL = `https://rpc.helius.xyz/?api-key=${process.env.HELIUS_API_KEY}`;
  CONNECTION = new Connection(HELIUS_URL);
  SELF_URL = process.env.SELF_URL as string;

  HYPERSPACE_CLIENT = new HyperspaceClient(process.env.HYPERSPACE_API_KEY as string);

  HELLOMOON_CLIENT = new RestClient(process.env.HELLOMOON_API_KEY as string);
}


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getAccountInfo/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { PublicKey, Connection, Keypair } from "@solana/web3.js";
import { Program, AnchorProvider, BorshAccountsCoder, BN } from "@coral-xyz/anchor";
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";

import configConstants, { CONNECTION } from "../../constants";
import { makeApiPostRequest } from "@/lib/middleware";
configConstants();

/**
 * Replace Anchor data (BNs, PublicKeys) with stringified data
 * @param obj
 * @returns
 */
export function stringifyAnchorObject(obj: any): any {
  if (obj === true || obj === false) {
    return obj;
  } else if (!obj) {
    return {};
  } else if (obj instanceof BN) {
    return obj.toString();
  } else if (obj instanceof PublicKey) {
    return obj.toString();
  } else if (typeof obj === "bigint") {
    let bigInt = obj as BigInt;
    return bigInt.toString();
  }

  if (typeof obj === "object" && obj !== null) {
    return Object.keys(obj).reduce((acc: Record<string, any>, key: string) => {
      acc[key] = stringifyAnchorObject(obj[key]);
      return acc;
    }, {});
  }

  return obj;
}

/**
 * Returns accountInfo or extends it with deserialized account data if the account is a program account of an Anchor program
 * @param accountAddress
 * @returns
 */
async function getParsedAccountInfo(connection: Connection, accountAddress: PublicKey) {
  // TODO: copy the explorer code here that manually deserializes a bunch of stuff, like Mango & Pyth

  const accountInfo = (await connection.getAccountInfo(accountAddress)) as any;
  // If acccount is not a program, check for Anchor IDL
  if (accountInfo?.owner && !accountInfo.executable) {
    try {
      const program = await Program.at(
        accountInfo.owner,
        new AnchorProvider(connection, new NodeWallet(Keypair.generate()), {
          commitment: "confirmed",
        }),
      );

      // Search through Anchor IDL for the account type
      const rawData = accountInfo.data;
      const coder = new BorshAccountsCoder(program.idl);
      const accountDefTmp = program.idl.accounts?.find((accountType: any) =>
        (rawData as Buffer)
          .slice(0, 8)
          .equals(BorshAccountsCoder.accountDiscriminator(accountType.name)),
      );

      // If we found the Anchor IDL type, decode the account state
      if (accountDefTmp) {
        const accountDef = accountDefTmp;

        // Decode the anchor data & stringify the data
        const decodedAccountData = stringifyAnchorObject(coder.decode(accountDef.name, rawData));

        let payload = {
          ...accountInfo,
          extended: decodedAccountData,
        };
        delete payload["data"];
        return payload;
      }
    } catch (err) {
      console.log(err);
    }
  }
  return accountInfo || {};
}

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const accountInfo = await getParsedAccountInfo(CONNECTION, req.body["address"]);
  res.status(200).json(accountInfo);
}

export default makeApiPostRequest(handler, { addresses: ["address"] });


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getAssetsByOwner/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import configConstants, { HELIUS_URL } from "../../constants";
configConstants();

import axios from "axios";
import { makeApiPostRequest } from "@/lib/middleware";

/**
 * Returns the data from the Metaplex Read API
 * @param address
 * @param page (optional) page number
 * @param limit (optional) set to 5 to prevent overflowing GPT context window
 * @returns
 */
export const readApiGetAssetsByOwner = async (
  address: string,
  page: number = 1,
  limit: number = 5,
) => {
  const sortBy = {
    sortBy: "created",
    sortDirection: "asc",
  };
  const before = "";
  const after = "";
  const { data } = await axios.post(HELIUS_URL, {
    jsonrpc: "2.0",
    id: "my-id",
    method: "getAssetsByOwner",
    params: [address, sortBy, limit, page, before, after],
  });
  return data.result;
};

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const assets = await readApiGetAssetsByOwner(req.body["address"].toString());
  res.status(200).send(assets);
}

export default makeApiPostRequest(handler, { addresses: ["address"] });


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getBalance/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
import configConstants, { CONNECTION } from "../../constants";
configConstants();
import { makeApiPostRequest } from "@/lib/middleware";

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { address } = req.body;
  const balance = await CONNECTION.getBalance(new PublicKey(address));
  res.status(200).send({ sol: balance / LAMPORTS_PER_SOL });
}

export default makeApiPostRequest(handler, { addresses: ["address"] });


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getCollectionsByFloorPrice/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
import configConstants, { HYPERSPACE_CLIENT } from "../../constants";
import { makeApiPostRequest } from "@/lib/middleware";
configConstants();

type CollectionStats = {
  id: string;
  desc: string;
  img: string;
  website: string;
  floor_price: number;
};

/**
 * Provides a feed of NFT collections that the user can afford.
 */
async function hyperspaceGetCollectionsByFloorPrice(
  maxFloorPrice: number | undefined,
  minFloorPrice: number | undefined,
  pageSize: number = 5,
  orderBy: string = "DESC",
  humanReadableSlugs: boolean = false,
) {
  let pageNumber = 1;
  let results: CollectionStats[] = [];
  let hasMore = true;

  const PAGE_SCRAPE_LIMIT = 10;
  while (results.length < pageSize && pageNumber < PAGE_SCRAPE_LIMIT && hasMore) {
    let projects = await HYPERSPACE_CLIENT.getProjects({
      condition: {
        floorPriceFilter: {
          min: minFloorPrice ?? null,
          max: maxFloorPrice ?? null,
        },
      },
      orderBy: {
        field_name: "floor_price",
        sort_order: orderBy.toLocaleUpperCase() as any,
      },
      paginationInfo: {
        page_size: 512,
        page_number: pageNumber,
      },
    });

    let stats: CollectionStats[] =
      projects.getProjectStats.project_stats
        ?.filter(project => {
          return (project.volume_7day ?? 0 > 0) && (project.floor_price ?? 0 > 0);
        })
        .map(project => {
          return {
            id: project.project_id,
            desc: project.project?.display_name ?? "",
            img: project.project?.img_url ?? "",
            website: project.project?.website ?? "",
            floor_price: project.floor_price ?? 0,
          };
        }) ?? [];

    if (humanReadableSlugs) {
      stats = stats?.filter(stat => {
        try {
          bs58.decode(stat.id!);
          return false;
        } catch (err) {
          return true;
        }
      });
    }
    pageNumber += 1;
    console.log("\tFetching collection info... ", stats.length, pageNumber);
    results = results.concat(stats!);
    hasMore = projects.getProjectStats.pagination_info.has_next_page;
  }

  return {
    projects: results.slice(0, pageSize),
    hasMore: hasMore,
  };
}

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { maxFloorPrice, minFloorPrice, orderBy, pageSize, humanReadable } = req.body;
  const result = await hyperspaceGetCollectionsByFloorPrice(
    maxFloorPrice,
    minFloorPrice,
    pageSize,
    orderBy,
    humanReadable,
  );
  res.status(200).send(JSON.stringify(result));
}

export default makeApiPostRequest(handler);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getCollectionsByName/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import configConstants, { HYPERSPACE_CLIENT } from "../../constants";
configConstants();
import { makeApiPostRequest } from "@/lib/middleware";

async function getCollectionsByName(req: NextApiRequest, res: NextApiResponse) {
  const { projectName } = req.body;
  const projects = await HYPERSPACE_CLIENT.searchProjectByName({
    condition: {
      // In practice, it was harder to find projects based on this condition
      //   matchName: {
      //     operation: "FUZZY" as StringInputOperationEnum.Fuzzy,
      //     value: projectName as string,
      //   },
      name: projectName as string,
    },
  });
  const paredResponse =
    projects.getProjectStatByName.project_stats
      ?.map(project => {
        return {
          id: project.project_id,
          verified: project.project?.is_verified ?? false,
          name: project.project?.display_name ?? "",
          img: project.project?.img_url ?? "",
          website: project.project?.website ?? "",
          floorPrice: project.floor_price ?? 0,
          twitterFollowers: project.twitter_followers ?? 0,
          twitter: project.project?.twitter ?? "",
        };
      })
      .filter(project => project.verified) ?? [];
  const result = {
    projects: paredResponse,
  };

  res.status(200).send(JSON.stringify(result));
}

export default makeApiPostRequest(getCollectionsByName);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getListedCollectionNFTs/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import configConstants, { HYPERSPACE_CLIENT } from "../../constants";
import { makeApiPostRequest } from "@/lib/middleware";
configConstants();

type NFTListing = {
  price: number;
  image: string;
  token: string;
};

type ListedNFTResponse = {
  listings: NFTListing[];
  hasMore: boolean;
};

async function hyperspaceGetListedCollectionNFTs(
  projectId: string,
  pageSize: number = 5,
  priceOrder: string = "DESC",
): Promise<ListedNFTResponse> {
  let listedNFTs: NFTListing[] = [];
  let hasMore = true;
  let pageNumber = 1;
  let pagesScraped = 0;
  const PAGE_SCRAPE_LIMIT = 10;
  while (listedNFTs.length < pageSize && hasMore && pagesScraped < PAGE_SCRAPE_LIMIT) {
    let results = await HYPERSPACE_CLIENT.getMarketplaceSnapshot({
      condition: {
        projects: [{ project_id: projectId }],
        onlyListings: true,
      },
      orderBy: {
        field_name: "lowest_listing_price",
        sort_order: priceOrder.toLocaleUpperCase() as any,
      },
      paginationInfo: {
        page_number: pageNumber,
      },
    });

    let snaps = results.getMarketPlaceSnapshots.market_place_snapshots!;
    let orderedListings = snaps.sort(
      (a, b) => a.lowest_listing_mpa!.price! - b.lowest_listing_mpa!.price!,
    );

    pageNumber += 1;
    let crucialInfo: NFTListing[] = orderedListings
      .filter(
        arr =>
          // We filter out Magic Eden's marketplace because they
          // require an API key to make purchases programmatically
          arr.lowest_listing_mpa?.marketplace_program_id !==
          "M2mx93ekt1fmXSVkTrUL9xVFHkmME8HTUi5Cyc5aF7K",
      )
      .map(arr => {
        return {
          price: arr.lowest_listing_mpa!.price!,
          token: arr.token_address,
          image: arr.meta_data_img ?? "",
          marketplace: arr.lowest_listing_mpa!.marketplace_program_id!,
        };
      });
    listedNFTs = listedNFTs.concat(crucialInfo);
    hasMore = results.getMarketPlaceSnapshots.pagination_info.has_next_page;
  }

  return {
    listings: listedNFTs.slice(0, pageSize),
    hasMore,
  };
}

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { projectId, pageSize, priceOrder } = req.body;
  const result = await hyperspaceGetListedCollectionNFTs(projectId, pageSize, priceOrder);
  res.status(200).send(JSON.stringify(result));
}

export default makeApiPostRequest(handler);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getSignaturesForAddress/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { PublicKey } from "@solana/web3.js";
import configConstants, { CONNECTION } from "../../constants";
import { makeApiPostRequest } from "@/lib/middleware";
configConstants();

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const accountAddress = req.body["address"];

  const beforeSig = req.body.beforeSignature ?? "";
  const untilSig = req.body.untilSignature ?? "";
  const signatures = await CONNECTION.getSignaturesForAddress(accountAddress, {
    limit: 11,
    before: beforeSig.length > 0 ? beforeSig : undefined,
    until: untilSig.length > 0 ? untilSig : undefined,
  });
  res.status(200).send({
    hasMore: signatures.length === 11,
    nextPage: signatures.length === 11 ? { beforeSignature: signatures[10].signature } : null,
    signatures: signatures.map(sig => {
      return {
        slot: sig.slot,
        signature: sig.signature,
        err: sig.err ?? undefined,
        memo: sig.memo ?? undefined,
        confirmationStatus: sig.confirmationStatus,
        blockTime: new Date((sig.blockTime as number) * 1000).toDateString(),
      };
    }),
  });
}

export default makeApiPostRequest(handler, { addresses: ["address"] });


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getTokenAccounts/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import configConstants, { CONNECTION } from "../../constants";
import { makeApiPostRequest } from "@/lib/middleware";
configConstants();

type TokenInfo = {
  mint: string;
  amount: string;
};

async function handler(req: NextApiRequest, res: NextApiResponse) {
  let result = await CONNECTION.getParsedTokenAccountsByOwner(
    req.body["address"],
    { programId: TOKEN_PROGRAM_ID },
    "confirmed",
  );
  const tokenInfos: TokenInfo[] = [];
  for (const accountInfo of result.value) {
    const info = accountInfo.account.data.parsed.info;
    if (info.tokenAmount.uiAmount !== 0) {
      tokenInfos.push({
        mint: info.mint.toString(),
        amount: info.tokenAmount.uiAmountString,
      });
    }
  }
  res.status(200).json(tokenInfos);
}

export default makeApiPostRequest(handler, { addresses: ["address"] });


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getTotalValue/index.ts
================================================
import { TokenPriceBatchedRequest, NftMintPriceByCreatorAvgRequest } from "@hellomoon/api";
import { PublicKey } from "@solana/web3.js";
import { NextApiRequest, NextApiResponse } from "next";

import { readApiGetAssetsByOwner } from "../getAssetsByOwner";
import configConstants, { CONNECTION, HELLOMOON_CLIENT } from "../../constants";
import { makeApiPostRequest } from "@/lib/middleware";
configConstants();

async function getTokenTotal(address: string) {
  let connection = CONNECTION;
  let tokenInfos = await (
    await fetch(
      `https://api.helius.xyz/v0/addresses/${address}/balances?api-key=${process.env.HELIUS_API_KEY}`,
    )
  ).json();

  let mints: string[] = [];
  let mintAmount: Record<string, number> = {};
  for (const info of tokenInfos["tokens"] as any) {
    if (info.amount !== "0") {
      mints.push(info.mint);
      mintAmount[info.mint] = Number.parseInt(info.amount);
    }
  }

  let mintPrice: Record<string, number> = {};
  let mintVolume: Record<string, number> = {};

  let pricePromises: Promise<any>[] = [];
  let decimalPromises: Promise<any>[] = [];
  let counter = 0;
  let batchSize = 10;
  while (counter < mints.length) {
    pricePromises.push(
      HELLOMOON_CLIENT.send(
        new TokenPriceBatchedRequest({ mints: mints.slice(counter, counter + batchSize) }),
      ),
    );

    for (let i = counter; i < Math.min(counter + batchSize, mints.length); i++) {
      decimalPromises.push(connection.getParsedAccountInfo(new PublicKey(mints[i])));
    }
    counter += batchSize;
  }
  let allData: any[] = [];
  try {
    allData = await Promise.all([...decimalPromises, ...pricePromises]);
  } catch (e) {
    console.error("Failed to getParsedAccountInfo:", e);
    throw e;
  }
  let decimalData = allData.slice(0, mints.length);
  let mintDecimals: Record<string, number> = {};
  decimalData.forEach((accountInfo, index) => {
    mintDecimals[mints[index]] = accountInfo!.value!.data?.parsed?.info?.decimals;
  });

  let priceData = allData.slice(mints.length);

  let tokenTotal = 0;
  for (const mintPriceData of priceData) {
    for (const price of (mintPriceData as any).data) {
      if (price.price) {
        let decimal = mintDecimals[price.mints];
        mintPrice[price.mints] = price.price / 1e6;
        mintVolume[price.mints] = price.volume;
        tokenTotal += (mintPrice[price.mints] * mintAmount[price.mints]) / Math.pow(10, decimal);
      }
    }
  }
  return (Number(tokenTotal * 100).toFixed(1) as any as number) / 100;
}

async function getNFTTotal(address: string) {
  let assets = ((await readApiGetAssetsByOwner(address, 1, 100)) as any).items;
  assets = assets.filter((asset: any) => asset.grouping.length > 0);

  let groupings: Record<string, number> = {};
  for (const asset of assets) {
    if (asset.grouping.length === 0) {
      continue;
    }
    let grouping = asset.grouping[0];
    let collection = grouping.group_value;
    groupings[collection] = (groupings[collection] || 0) + 1;
  }

  let assetIds = assets.map((asset: any) => asset.id);
  let nftPricePromises = assetIds.map((id: string) => {
    return HELLOMOON_CLIENT.send(
      new NftMintPriceByCreatorAvgRequest({
        nftMint: id,
      }),
    ).then(price => price.data[0]?.avg_usd_price ?? 0);
  });
  let prices = await Promise.all(nftPricePromises);

  let nftTotal: number = prices.reduce((a, b) => a + b, 0);
  return (Number(nftTotal * 100).toFixed(1) as any as number) / 100;
}

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const address = req.body["address"];

  let totals = await Promise.all([
    getTokenTotal(address.toString()),
    getNFTTotal(address.toString()),
  ]);
  let [tokenTotal, nftTotal] = totals;
  res.status(200).json({ tokenTotal, nftTotal, total: tokenTotal + nftTotal });
}

export default makeApiPostRequest(handler, { addresses: ["address"] });


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/getTransaction/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import configConstants, { CONNECTION } from "../../constants";
configConstants();

import * as anchor from "@coral-xyz/anchor";
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
import { stringifyAnchorObject } from "../getAccountInfo";
import {
  AccountMeta,
  ComputeBudgetInstruction,
  ComputeBudgetInstructionType,
  ComputeBudgetProgram,
  LAMPORTS_PER_SOL,
  SystemInstruction,
  SystemProgram,
  TransactionError,
  TransactionInstruction,
} from "@solana/web3.js";
import {
  TOKEN_PROGRAM_ID,
  TOKEN_2022_PROGRAM_ID,
  decodeInstruction,
  TokenInstruction,
} from "@solana/spl-token";
import { u8 } from "@solana/buffer-layout";

// Setup Solflare
import { Client } from "@solflare-wallet/utl-sdk";
import { makeApiPostRequest } from "@/lib/middleware";
const utl = new Client();

type IxArgs = Record<string, string>;

type Instruction = {
  programId: string;
  keys: string[];
  ixData: string | IxArgs;
  depth: number;
};

let PROGRAM_CACHE = new Map<string, anchor.Program | null>();

type ParsedTxResponse = {
  // TODO(ngundotra): I'm pretty sure amount needs to be a string bc u57 overflow, but this is what SPL Token uses
  tokenBalanceChanges: Record<string, { mint: string; amount: number }>;
  solBalanceChanges: Record<string, number>;
  instructions: Instruction[];
  success: boolean;
  timestamp: string;
  feePayer: string;
  err?: TransactionError;
  // Dev Mode Only params
  computeUnitsConsumed?: number;
  txFeeInLamports?: number;
  txVersion?: string;
  slot?: number;
  logs?: string[];
};

async function getAnchorProgram(programId: string) {
  if (PROGRAM_CACHE.has(programId)) {
    return PROGRAM_CACHE.get(programId);
  }

  try {
    const program = await anchor.Program.at(
      programId,
      new anchor.AnchorProvider(CONNECTION, new NodeWallet(anchor.web3.Keypair.generate()), {}),
    );
    PROGRAM_CACHE.set(programId, program);
    return program;
  } catch (err) {
    PROGRAM_CACHE.set(programId, null);
    return null;
  }
}

async function parseAnchorIxData(programId: anchor.web3.PublicKey, ixData: string) {
  const program = await getAnchorProgram(programId.toString());
  if (!program) {
    return null;
  }
  let ixCoder = new anchor.BorshInstructionCoder(program.idl);
  return ixCoder.decode(Buffer.from(ixData, "base64"));
}

async function parseAnchorIxAccounts(
  programAddress: string,
  accounts: string[],
  ix: anchor.Instruction,
) {
  const program = await getAnchorProgram(programAddress);

  if (!program) {
    return null;
  }

  const ixDef = program?.idl.instructions.find((ixDef: any) => ixDef.name === ix.name);
  if (ixDef) {
    let parsedAccounts = ixDef.accounts as {
      // type coercing since anchor doesn't export the underlying type
      name: string;
      isMut: boolean;
      isSigner: boolean;
      pda?: object;
    }[];

    let allAccounts = parsedAccounts.map((acct, idx) => {
      return JSON.stringify({
        name: acct.name,
        isMut: acct.isMut,
        isSigner: acct.isSigner,
        address: accounts[idx],
      });
    });
    if (parsedAccounts && parsedAccounts.length < accounts.length) {
      allAccounts = allAccounts.concat(accounts.slice(parsedAccounts.length));
    }
    return allAccounts;
  }
  return null;
}

export function snakeToTitleCase(str: string): string {
  const result = str.replace(/([-_]\w)/g, g => ` ${g[1].toUpperCase()}`);
  return result.charAt(0).toUpperCase() + result.slice(1);
}

async function parseAnchorIx(ix: Instruction) {
  let parsedIx = await parseAnchorIxData(
    new anchor.web3.PublicKey(ix.programId),
    ix.ixData as string,
  );
  if (!parsedIx) {
    return ix;
  }

  let parsedAccounts = await parseAnchorIxAccounts(ix.programId, ix.keys, parsedIx);

  let ixTitle = parsedIx.name;
  ixTitle = ixTitle.charAt(0).toUpperCase() + ixTitle.slice(1);
  let program = await getAnchorProgram(ix.programId);
  return {
    programId: `${snakeToTitleCase(program!.idl.name)} (${ix.programId})`,
    ixData: `${ixTitle} ${JSON.stringify(stringifyAnchorObject(parsedIx.data))}`,
    keys: parsedAccounts ?? ix.keys,
    depth: ix.depth,
  };
}

async function parseIx(ix: TransactionInstruction, depth: number): Promise<Instruction> {
  let programAddress = ix.programId.toBase58();

  let parsedIx: Instruction = {
    programId: programAddress,
    keys: ix.keys.map(k => k.pubkey.toBase58()),
    ixData: "",
    depth,
  };
  if (programAddress === SystemProgram.programId.toBase58()) {
    parsedIx.programId = "System Program";

    let type = SystemInstruction.decodeInstructionType(ix);
    switch (type) {
      case "AdvanceNonceAccount":
        parsedIx.ixData = stringifyAnchorObject({
          AdvanceNonceAccount: SystemInstruction.decodeNonceAdvance(ix),
        });
        break;
      case "Allocate":
        parsedIx.ixData = stringifyAnchorObject({
          Allocate: SystemInstruction.decodeAllocate(ix),
        });
        break;
      case "AllocateWithSeed":
        parsedIx.ixData = stringifyAnchorObject({
          AllocateWithSeed: SystemInstruction.decodeAllocateWithSeed(ix),
        });
        break;
      case "Assign":
        parsedIx.ixData = stringifyAnchorObject({ Assign: SystemInstruction.decodeAssign(ix) });
        break;
      case "AssignWithSeed":
        parsedIx.ixData = stringifyAnchorObject({
          AssignWithSeed: SystemInstruction.decodeAssignWithSeed(ix),
        });
        break;
      case "AuthorizeNonceAccount":
        parsedIx.ixData = stringifyAnchorObject({
          AuthorizeNonceAccount: SystemInstruction.decodeNonceAuthorize(ix),
        });
        break;
      case "Create":
        parsedIx.ixData = stringifyAnchorObject({
          Create: SystemInstruction.decodeCreateAccount(ix),
        });
        break;
      case "CreateWithSeed":
        parsedIx.ixData = stringifyAnchorObject({
          CreateWithSeed: SystemInstruction.decodeCreateWithSeed(ix),
        });
        break;
      case "InitializeNonceAccount":
        parsedIx.ixData = stringifyAnchorObject({
          InitializeNonceAccount: SystemInstruction.decodeNonceInitialize(ix),
        });
        break;
      case "Transfer":
        parsedIx.ixData = stringifyAnchorObject({ Transfer: SystemInstruction.decodeTransfer(ix) });
        break;
      case "TransferWithSeed":
        parsedIx.ixData = stringifyAnchorObject({
          TransferWithSeed: SystemInstruction.decodeTransferWithSeed(ix),
        });
        break;
      case "WithdrawNonceAccount":
        parsedIx.ixData = stringifyAnchorObject({
          WithdrawNonceAccount: SystemInstruction.decodeNonceWithdraw(ix),
        });
        break;
      case "UpgradeNonceAccount":
        break;
    }
  } else if (programAddress === TOKEN_2022_PROGRAM_ID.toBase58()) {
    parsedIx.programId = "SPL Token Program 2022";

    parsedIx.ixData = stringifyAnchorObject(await parseTokenInstruction(ix));
  } else if (programAddress === TOKEN_PROGRAM_ID.toBase58()) {
    parsedIx.programId = "SPL Token Program";

    parsedIx.ixData = stringifyAnchorObject(await parseTokenInstruction(ix));
  } else if (programAddress === ComputeBudgetProgram.programId.toBase58()) {
    parsedIx.programId = "Compute Budget Program";
    let type: ComputeBudgetInstructionType = ComputeBudgetInstruction.decodeInstructionType(ix);

    switch (type) {
      case "RequestHeapFrame":
        parsedIx.ixData = stringifyAnchorObject({
          RequestHeapFrame: ComputeBudgetInstruction.decodeRequestHeapFrame(ix),
        });
        break;
      case "RequestUnits":
        parsedIx.ixData = stringifyAnchorObject({
          RequestUnits: ComputeBudgetInstruction.decodeRequestUnits(ix),
        });
        break;
      case "SetComputeUnitLimit":
        parsedIx.ixData = stringifyAnchorObject({
          SetComputeUnitLimit: ComputeBudgetInstruction.decodeSetComputeUnitLimit(ix),
        });
        break;
      case "SetComputeUnitPrice":
        parsedIx.ixData = stringifyAnchorObject({
          SetComputeUnit: ComputeBudgetInstruction.decodeSetComputeUnitPrice(ix),
        });
        break;
    }
  } else {
    return await parseAnchorIx({
      programId: programAddress,
      ixData: anchor.utils.bytes.base64.encode(ix.data),
      keys: ix.keys.map(k => k.pubkey.toBase58()),
      depth,
    });
  }
  return parsedIx;
}

/**
 * Flattens `keys` to just be the name of the account and the address
 * Extends `mint` addresses with the mint name (e.g. "(USDC)")
 */
async function parseTokenInstruction(ix: TransactionInstruction): Promise<Record<string, any>> {
  let ixTypeByte = u8().decode(ix.data.slice(0, 1));
  let ixName = TokenInstruction[ixTypeByte];
  let decoded: Record<string, any> = {};
  let decodedIx = decodeInstruction(ix);

  let keys: Record<string, string> = {};
  for (const keyName of Object.keys(decodedIx.keys)) {
    const meta = (decodedIx.keys as Record<string, AccountMeta>)[keyName];
    if (keyName === "multiSigners") {
      continue;
    }
    let address = meta.pubkey.toBase58();

    if (keyName === "mint") {
      let mintData = await utl.fetchMint(meta.pubkey);
      address = `${mintData.symbol}`;
    }
    keys[keyName] = address;
  }
  // @ts-ignore
  decodedIx.keys = keys;

  if (decodedIx.data && "amount" in decodedIx.data) {
    let amount: anchor.BN;
    if (typeof decodedIx.data.amount === "bigint") {
      amount = new anchor.BN(decodedIx.data.amount.toString());
    } else {
      amount = new anchor.BN(decodedIx.data.amount);
    }

    // Todo(ngundotra): add support for decimals
    if ("decimals" in decodedIx.data) {
      let decimals = decodedIx.data.decimals;
      amount = amount.div(new anchor.BN(10).pow(new anchor.BN(decimals)));

      // @ts-ignore
      delete decodedIx.data["decimals"];
    }

    // @ts-ignore
    decodedIx.data.amount = amount;
  }

  decoded[ixName] = decodedIx;
  return decoded;
}

async function parseTokenChanges(
  preBalances: anchor.web3.ConfirmedTransactionMeta["preTokenBalances"],
  postBalances: anchor.web3.ConfirmedTransactionMeta["postTokenBalances"],
) {
  let mints = new Set([...preBalances!.map(b => b.mint), ...postBalances!.map(b => b.mint)]);
  let mintData = await utl.fetchMints(
    Array.from(mints.keys()).map(k => new anchor.web3.PublicKey(k)),
  );
  let mintMap: Record<string, string> = {};
  mintData
    .filter(token => token.verified ?? true)
    .forEach(m => {
      mintMap[m.address.toString()] = m.symbol;
    });

  if (!postBalances || !preBalances || postBalances.length != preBalances.length) {
    return null;
  }

  let changes: Record<string, { mint: string; amount: number }> = {};
  for (let i = 0; i < postBalances?.length; i++) {
    let pre = preBalances[i];
    let post = postBalances[i];
    let tokenChange = (post.uiTokenAmount.uiAmount ?? 0) - (pre.uiTokenAmount.uiAmount ?? 0);
    if (tokenChange !== 0) {
      changes[pre.owner!] = { mint: mintMap[pre.mint] ?? pre.mint, amount: tokenChange };
    }
  }
  return changes;
}

function parseSolChanges(
  accounts: anchor.web3.PublicKey[],
  preBalances: number[],
  postBalances: number[],
) {
  if (preBalances.length != postBalances.length) {
    return null;
  }
  const changes: Record<string, number> = {};
  for (let i = 0; i < preBalances.length; i++) {
    let pre = preBalances[i];
    let post = postBalances[i];
    let solChange = post - pre;
    if (solChange > 0.0000000001) {
      changes[accounts[i].toString()] = solChange / LAMPORTS_PER_SOL;
    }
  }
  return changes;
}

function parseLogs(logs: string[]): { programId: string; depth: number }[] {
  let traces: { programId: string; depth: number }[] = [];
  for (const log of logs) {
    let match = log.match(/Program (.*) invoke \[(.*)\]/);
    if (match) {
      let program = match[1];
      let depth = match[2];
      traces.push({ programId: program, depth: Number.parseInt(depth) });
    }
  }
  return traces;
}

// TODO(ngundotra): add support for System program + SPL programs
async function handler(req: NextApiRequest, res: NextApiResponse) {
  const signature = req.body.signature;
  const devMode = req.body.devMode ?? false;
  const transaction = await CONNECTION.getTransaction(signature, {
    maxSupportedTransactionVersion: 2,
  });

  if (!transaction) {
    res.status(404).send("Transaction not found");
  }

  let instructions: Instruction[] = [];

  // Reconstruct account array
  let accounts = transaction?.transaction.message.staticAccountKeys ?? [];
  accounts = accounts.concat(transaction?.meta?.loadedAddresses?.readonly ?? []);
  accounts = accounts.concat(transaction?.meta?.loadedAddresses?.writable ?? []);

  let tokenBalanceChanges = await parseTokenChanges(
    transaction?.meta?.preTokenBalances,
    transaction?.meta?.postTokenBalances,
  );
  let solChanges = parseSolChanges(
    accounts,
    transaction?.meta?.preBalances ?? [],
    transaction?.meta?.postBalances ?? [],
  );

  // Keep track of order of instructions (may not be able get stack depth for each inner ix because of log truncation)
  let traceIdx = 0;
  let parsedTrace = parseLogs(transaction?.meta?.logMessages ?? []);

  // Loop through top-level instructions
  let outerIdx = 0;
  let innerIdx = 0;
  for (const outerIx of transaction?.transaction.message.compiledInstructions ?? []) {
    const programId = accounts[outerIx.programIdIndex];
    instructions.push(
      await parseIx(
        {
          programId,
          data: Buffer.from(outerIx.data ?? []),
          keys: outerIx.accountKeyIndexes.map(idx => {
            return {
              pubkey: accounts[idx],
              isSigner: false,
              isWritable: false,
            };
          }),
        },
        0,
      ),
    );
    traceIdx += 1;

    // Loop through inner instructions
    let innerIxBucket = transaction?.meta?.innerInstructions?.[innerIdx];
    if (innerIxBucket && innerIxBucket.index === outerIdx) {
      for (const innerIx of innerIxBucket.instructions) {
        if (parsedTrace[traceIdx].programId !== accounts[innerIx.programIdIndex].toBase58()) {
          // Make a note that the depth is unknown (somehow)
          parsedTrace[traceIdx].depth = 1;
        }

        instructions.push(
          await parseIx(
            {
              programId: accounts[innerIx.programIdIndex],
              keys: innerIx.accounts.map(key => {
                return {
                  pubkey: accounts[key],
                  isSigner: false,
                  isWritable: false,
                };
              }),
              data: anchor.utils.bytes.bs58.decode(innerIx.data),
            },
            parsedTrace[traceIdx].depth,
          ),
        );
        traceIdx += 1;
      }
      innerIdx += 1;
    }

    outerIdx += 1;
  }
  const feePayer = transaction?.transaction.message.staticAccountKeys[0]!.toBase58();

  let timestamp: Date | undefined;
  if (transaction?.blockTime) {
    timestamp = new Date();
    timestamp.setTime(transaction?.blockTime! * 1000);
  }

  let response: ParsedTxResponse = {
    err: transaction?.meta?.err ?? undefined,
    feePayer: feePayer!,
    instructions,
    tokenBalanceChanges: tokenBalanceChanges!,
    solBalanceChanges: solChanges!,
    success: transaction?.meta?.err === null,
    timestamp: timestamp?.toISOString() ?? "unknown",
  };
  if (devMode) {
    response = {
      ...response,
      computeUnitsConsumed: transaction?.meta?.computeUnitsConsumed!,
      txFeeInLamports: transaction?.meta?.fee!,
      txVersion: transaction?.version?.toString() ?? "legacy",
      logs: transaction?.meta?.logMessages ?? [],
      slot: transaction?.slot!,
    };
  }

  res.status(200).send(JSON.stringify(response));
}

export default makeApiPostRequest(handler);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/page/[methodName].ts
================================================
/// DEPRECATED - NO LONGER IN USE
import { NextApiRequest, NextApiResponse } from "next";
import { encode } from "querystring";

import configConstants, { SELF_URL, TX_DESCRIPTIONS } from "../../../constants";
configConstants();

function createOpenGraphMetaPage(
  methodName: string,
  encoded: string,
  description: string
): string {
  let qrCodeUri = new URL(
    `${SELF_URL}/api/handlers/solana-pay/qr/${methodName}?${encoded}`
  );
  return `<html>
    <meta property="og:title" content="${description}" />
    <meta property="og:type" content="website" />
    <meta property="og:url" content="${SELF_URL}/page/${methodName}?${encoded}" />
    <meta property="og:image" content="${qrCodeUri}" />
    </html>`;
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const {
    query: { methodName },
  } = req;
  console.log("OpenGraph metapage requested:", methodName, req.query);

  let description = TX_DESCRIPTIONS[methodName as string];
  res
    .status(200)
    .send(
      createOpenGraphMetaPage(
        methodName as string,
        encode(Object(req.query)),
        description
      )
    );
}


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/qr/[methodName].ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { encode } from "querystring";

import { encodeURL } from "@solana/pay";
import * as qrcode from "qrcode";
import sharp from "sharp";

import configConstants, {
  SELF_URL,
  SOLANA_PAY_LABEL,
} from "../../../constants";
configConstants();

async function createQRCodePng(
  methodName: string,
  encoded: string
): Promise<Buffer> {
  let uri = new URL(
    `${SELF_URL}/api/handlers/solana-pay/sign/${methodName}?${encoded}`
  );
  let solanaPayUrl = encodeURL({
    link: uri,
    label: SOLANA_PAY_LABEL,
  });

  let dataUrl = await qrcode.toDataURL(solanaPayUrl.toString(), {
    errorCorrectionLevel: "H",
  });
  const base64Data = dataUrl.replace(/^data:image\/png;base64,/, "");
  const imageBuffer = Buffer.from(base64Data, "base64");
  return await sharp(imageBuffer)
    .extend({
      extendWith: "background",
      background: "#ffffff",
      left: 10,
      right: 10,
    })
    .toBuffer();
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const {
    query: { methodName },
  } = req;

  console.log("QR code requested:", methodName, req.query);

  let buffer = await createQRCodePng(
    methodName as string,
    encode(Object(req.query))
  );
  res.setHeader("Content-Type", "image/png");
  res.setHeader("Content-Disposition", "inline");
  res.status(200).send(buffer);
}


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createBurnAsset.ts
================================================
// DEPRECATED - not in use
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
import { createBurnInstruction } from "@metaplex-foundation/mpl-bubblegum";
import {
  SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  SPL_NOOP_PROGRAM_ID,
} from "@solana/spl-account-compression";
import { PublicKey, Transaction } from "@solana/web3.js";
import { NextApiRequest } from "next";
import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
import { bufferToArray, getAsset, getAssetProof, getBubblegumAuthorityPDA } from "../utils/helpers";
configConstants();

export async function createBurnAsset(req: NextApiRequest) {
  const { assetId } = req.query;
  const { account: owner } = req.body;
  if (!owner || !assetId) {
    throw new Error("Missing required parameters");
  }
  let assetProof = await getAssetProof(assetId, CONNECTION.rpcEndpoint);
  const rpcAsset = await getAsset(assetId, CONNECTION.rpcEndpoint);
  const leafNonce = rpcAsset.compression.leaf_id;
  let proofPath = assetProof.proof.map((node: string) => ({
    pubkey: new PublicKey(node),
    isSigner: false,
    isWritable: false,
  }));
  const treeAuthority = await getBubblegumAuthorityPDA(new PublicKey(assetProof.tree_id));
  const leafDelegate = rpcAsset.ownership.delegate
    ? new PublicKey(rpcAsset.ownership.delegate)
    : new PublicKey(rpcAsset.ownership.owner);

  if (rpcAsset.ownership.owner !== owner) {
    throw new Error(
      `NFT is not owned by the expected owner. Expected ${new PublicKey(owner)} but got ${
        rpcAsset.ownership.owner
      }.`,
    );
  }
  const burnIx = createBurnInstruction(
    {
      treeAuthority,
      leafOwner: new PublicKey(rpcAsset.ownership.owner),
      leafDelegate,
      merkleTree: new PublicKey(assetProof.tree_id),
      logWrapper: SPL_NOOP_PROGRAM_ID,
      compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
      anchorRemainingAccounts: proofPath,
    },
    {
      root: bufferToArray(bs58.decode(assetProof.root)),
      dataHash: bufferToArray(bs58.decode(rpcAsset.compression.data_hash.trim())),
      creatorHash: bufferToArray(bs58.decode(rpcAsset.compression.creator_hash.trim())),
      nonce: leafNonce,
      index: leafNonce,
    },
  );
  const tx = new Transaction().add(burnIx);
  tx.feePayer = new PublicKey(owner);
  tx.recentBlockhash = (await CONNECTION.getLatestBlockhash()).blockhash;
  return {
    transaction: tx.serialize({ requireAllSignatures: false }).toString("base64"),
  };
}

export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createBurnAsset));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createBuyNFT.ts
================================================
// DEPRECATED - not in use
import { NextApiRequest } from "next";

import { base64 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
import configConstants, { HYPERSPACE_CLIENT } from "../../../constants";
configConstants();
import { makeRespondToSolanaPayPost, makeRespondToSolanaPayGet } from ".";

async function hyperspaceCreateBuyTx(buyer: string, token: string, price: number) {
  let transactionData = await HYPERSPACE_CLIENT.createBuyTx({
    buyerAddress: buyer,
    tokenAddress: token,
    price: price,
    // Take no fee on making tx for ChatGPT users
    buyerBroker: "",
    buyerBrokerBasisPoints: 0,
  });
  const txBytes = base64.encode(Buffer.from(transactionData.createBuyTx.stdBuffer!));

  return {
    transaction: txBytes,
  };
}

export async function createBuyNFT(req: NextApiRequest) {
  const { token, price } = req.query;
  const { account: buyer } = req.body;
  return await hyperspaceCreateBuyTx(
    buyer as string,
    token as string,
    Number.parseFloat(price as string),
  );
}

export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createBuyNFT));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createCloseNFTMetadata.ts
================================================
// DEPRECATED - not in use
import { NextApiRequest } from "next";

import { createCloseNFTMetadataTx } from "@/lib/on-chain-metadata";
import { CONNECTION } from "../../../constants";
import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";

async function createCloseNFTMetadata(req: NextApiRequest) {
  const { account } = req.query;
  const { account: owner } = req.body;
  return await createCloseNFTMetadataTx(CONNECTION, owner as string, account as string);
}

export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createCloseNFTMetadata));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createListNFT.ts
================================================
// DEPRECATED - not in use
/**
 * Deprecated because Solana Pay compatible wallets block NFT/token delegation to prevent scams
 * This means we can't list via Solana Pay, but maybe we can get around this by using NFT AMMs
 * to sell at the floor.
 */
import { NextApiRequest } from "next";

import configConstants, { CONNECTION } from "../../../constants";
configConstants();

import { makeRespondToSolanaPayPost, makeRespondToSolanaPayGet } from ".";
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";

import { Hyperspace, hyperspaceIdl } from "@/lib/hyperspace/idl/hyperspace";
import {
  Keypair,
  LAMPORTS_PER_SOL,
  PublicKey,
  SYSVAR_CLOCK_PUBKEY,
  SYSVAR_INSTRUCTIONS_PUBKEY,
  SystemProgram,
  Transaction,
  TransactionInstruction,
} from "@solana/web3.js";
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
import {
  findTokenRecordPda,
  getAtaForMint,
  getEditionDataAccount,
  getHyperspaceProgramAsSigner,
  getHyperspaceTradeState,
  getMetadata,
} from "@/lib/hyperspace/account";
import { TOKEN_PROGRAM_ID, getAccount } from "@solana/spl-token";
import {
  Metadata,
  PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID,
} from "@metaplex-foundation/mpl-token-metadata";
import { HYPERSPACE_ID, HYPERSPACE_MARKETPLACE_INSTANCE } from "@/lib/hyperspace/constants";

const AUTH_PROGRAM_ID = new PublicKey("auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg");

// async function hyperspaceCreateListTx(
//   seller: string,
//   token: string,
//   price: number
// ) {
//   console.log(seller, token, price);
//   let transactionData = await HYPERSPACE_CLIENT.createListTx({
//     sellerAddress: seller,
//     tokenAddress: token,
//     price: price,
//     // Take no fee on making tx for ChatGPT users
//     sellerBroker: "",
//     sellerBrokerBasisPoints: 0,
//   });

//   console.log(transactionData);
//   const txBytes = base64.encode(
//     Buffer.from(transactionData.createListTx.stdBuffer!)
//   );
//   console.log(txBytes);

//   return {
//     transaction: txBytes,
//   };
// }

export const getPriceWithMantissa = async (
  price: number,
  mint: PublicKey,
  walletKeyPair: any,
  anchorProgram: Program<Hyperspace>,
): Promise<number> => {
  // // const token = new Token(
  // //   anchorProgram.provider.connection,
  // //   new PublicKey(mint),
  // //   TOKEN_PROGRAM_ID,
  // //   walletKeyPair
  // // );

  // let ata = getAssociatedTokenAddressSync(mint, walletKeypair);

  // const mintInfo = await token.getMintInfo();

  // const mantissa = 10 ** mintInfo.decimals;

  // return Math.ceil(price * mantissa);
  return 1;
};

async function createTradeStateInstruction(
  anchorProgram: Program<Hyperspace>,
  isBuy: boolean,
  tradeBump: number,
  buyPrice: BN,
  brokerBasisPoints: number,
  royalty_basis_points = 0,
  tokenSize: BN,
  user: PublicKey,
  broker: PublicKey,
  tokenAccount: PublicKey,
  tokenMint: PublicKey,
  tradeStateAddress: PublicKey,
): Promise<TransactionInstruction> {
  console.log(`Create instruction for creating trade state with address ${tradeStateAddress}
      for ${user.toBase58()} (broker: ${broker.toBase58()}, basis points: ${brokerBasisPoints})
      for token ${tokenMint.toBase58()} at price ${buyPrice}`);
  let instruction = anchorProgram.instruction.createTradeState(
    isBuy ? 1 : 0,
    tradeBump,
    buyPrice,
    brokerBasisPoints,
    tokenSize,
    royalty_basis_points,
    {
      accounts: {
        wallet: user,
        collection: HYPERSPACE_ID,
        brokerWallet: broker,
        tokenAccount: tokenAccount,
        tokenMint: tokenMint,
        tradeState: tradeStateAddress,
        systemProgram: SystemProgram.programId,
        clock: SYSVAR_CLOCK_PUBKEY,
      },
    },
  );
  instruction.keys.filter(k => k.pubkey.equals(user)).map(k => (k.isSigner = true));
  return instruction;
}

async function helper(
  anchorProgram: Program<Hyperspace>,
  seller: PublicKey,
  mintPublicKey: PublicKey,
  sellerBrokerKey: PublicKey,
  minAmountToReceive: BN,
  // We don't charge for creating this
  brokerBasisPoints: number = 0,
  // This only matters when you cross
  royaltyBasisPoints: number = 0,
) {
  const tokenSizeAdjusted = new BN(
    await getPriceWithMantissa(1, mintPublicKey, seller, anchorProgram),
  );

  const tokenAccountKey = (await getAtaForMint(mintPublicKey, seller))[0];

  // You should check that ATA exists
  let instructions: TransactionInstruction[] = [];

  const [programAsSigner, programAsSignerBump] = await getHyperspaceProgramAsSigner();

  const [tradeState, tradeBump] = await getHyperspaceTradeState(
    false,
    seller,
    tokenAccountKey,
    mintPublicKey,
    tokenSizeAdjusted,
  );

  const tradeStateAccount = await anchorProgram.provider.connection.getAccountInfo(
    tradeState,
    "confirmed",
  );

  if (!tradeStateAccount) {
    const initTradeStateInstruction = await createTradeStateInstruction(
      anchorProgram,
      false,
      tradeBump,
      minAmountToReceive,
      brokerBasisPoints,
      royaltyBasisPoints,
      tokenSizeAdjusted,
      seller,
      sellerBrokerKey,
      tokenAccountKey,
      mintPublicKey,
      tradeState,
    );
    instructions.push(initTradeStateInstruction);
  }

  const tokenRecord = findTokenRecordPda(mintPublicKey, tokenAccountKey);

  const editionAccount = (await getEditionDataAccount(mintPublicKey))[0];

  const metadataAccount = await getMetadata(mintPublicKey);

  const metadataObj = await anchorProgram.provider.connection.getAccountInfo(
    metadataAccount,
    "confirmed",
  );

  if (!metadataObj) {
    throw Error("NFT does not have a metadata account, it may have been burnt.");
  }
  const metadataParsed = Metadata.deserialize(metadataObj.data)[0];

  const signers: Keypair[] = [];

  let marketplaceObj = await anchorProgram.account.hyperspace.fetch(
    HYPERSPACE_MARKETPLACE_INSTANCE,
  );

  const sellInstruction = await anchorProgram.instruction.sell(
    tradeBump,
    programAsSignerBump,
    minAmountToReceive,
    brokerBasisPoints,
    tokenSizeAdjusted,
    royaltyBasisPoints,
    {
      accounts: {
        wallet: seller,
        sellerBrokerWallet: sellerBrokerKey,
        tokenMint: mintPublicKey,
        tokenAccount: tokenAccountKey,
        metadata: metadataAccount,
        authority: marketplaceObj.authority,
        hyperspace: HYPERSPACE_MARKETPLACE_INSTANCE,
        hyperspaceFeeAccount: marketplaceObj.hyperspaceFeeAccount,
        sellerTradeState: tradeState,
        tokenProgram: TOKEN_PROGRAM_ID,
        systemProgram: SystemProgram.programId,
        metadataProgram: TOKEN_METADATA_PROGRAM_ID,
        programAsSigner: programAsSigner,
        instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
        tokenRecord: tokenRecord,
        editionAccount: editionAccount,
        authorizationRules: metadataParsed.programmableConfig?.ruleSet
          ? metadataParsed.programmableConfig.ruleSet
          : TOKEN_METADATA_PROGRAM_ID,
        mplTokenAuthRulesProgram: AUTH_PROGRAM_ID,
        clock: SYSVAR_CLOCK_PUBKEY,
      },
      signers,
    },
  );
  instructions.push(sellInstruction);
  return instructions;
}

async function hyperspaceCreateListTx(seller: string, token: string, price: number) {
  let provider = new AnchorProvider(CONNECTION, new NodeWallet(Keypair.generate()), {});
  let program = new Program(hyperspaceIdl, HYPERSPACE_ID, provider);
  const sellerKey = new PublicKey(seller);

  const tokenKey = new PublicKey(token);
  let mint: PublicKey;
  try {
    const tokenAI = await getAccount(CONNECTION, tokenKey);
    console.log("found tokenAI:", tokenAI);
    mint = tokenAI.mint;
  } catch (e) {
    mint = tokenKey;
  }

  let instructions = await helper(
    program,
    sellerKey,
    mint,
    SystemProgram.programId,
    new BN(price * LAMPORTS_PER_SOL),
  );

  let tx = new Transaction();
  for (const ix of instructions) {
    tx = tx.add(ix);
  }
  tx.recentBlockhash = (await CONNECTION.getLatestBlockhash()).blockhash;
  tx.feePayer = sellerKey;

  const txBytes = tx.serialize({ requireAllSignatures: false }).toString("base64");

  return {
    transaction: txBytes,
  };
}

export async function createListNFT(req: NextApiRequest) {
  const { token, price } = req.query;
  const { account: seller } = req.body;
  console.log(seller, token, price);
  return await hyperspaceCreateListTx(
    seller as string,
    token as string,
    Number.parseFloat(price as string),
  );
}

export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createListNFT));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMerkleTree.ts
================================================
// DEPRECATED - not in use
import {
  PROGRAM_ID as BUBBLEGUM_PROGRAM_ID,
  createCreateTreeInstruction,
} from "@metaplex-foundation/mpl-bubblegum";
import {
  SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  SPL_NOOP_PROGRAM_ID,
  createAllocTreeIx,
} from "@solana/spl-account-compression";
import { Keypair, PublicKey, Transaction } from "@solana/web3.js";
import dotenv from "dotenv";
import { NextApiRequest } from "next";
import { CONNECTION } from "../../../constants";
dotenv.config();

//TODO(@ngundotra): have to add closeTree instruction before exposing this endpoint

export interface MerkleTreeArgs {
  maxDepth: number;
  maxBufferSize: number;
  canopyHeight: number;
}

export async function createTree(req: NextApiRequest) {
  const { account: payerPublicKey, canopyDepth, maxDepthSizePair } = req.body;
  const treeKeypair = Keypair.generate();

  const [treeAuthority, _bump] = PublicKey.findProgramAddressSync(
    [treeKeypair.publicKey.toBuffer()],
    BUBBLEGUM_PROGRAM_ID,
  );

  // instruction for space allocation for tree account
  const allocTreeIx = await createAllocTreeIx(
    CONNECTION,
    treeKeypair.publicKey,
    payerPublicKey,
    maxDepthSizePair,
    canopyDepth,
  );

  // instruction for tree creation
  const createTreeIx = createCreateTreeInstruction(
    {
      payer: payerPublicKey,
      treeCreator: payerPublicKey,
      treeAuthority: treeAuthority,
      merkleTree: treeKeypair.publicKey,
      compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
      logWrapper: SPL_NOOP_PROGRAM_ID,
    },
    {
      maxBufferSize: maxDepthSizePair.maxBufferSize,
      maxDepth: maxDepthSizePair.maxDepth,
      public: false,
    },
    BUBBLEGUM_PROGRAM_ID,
  );

  try {
    const tx = new Transaction();
    tx.add(allocTreeIx);
    tx.add(createTreeIx);
    tx.feePayer = payerPublicKey;
    return tx;
  } catch (e) {
    console.error(e);
    throw e;
  }
}


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMintCNFT.ts
================================================
// DEPRECATED - not in use
import { JsonMetadata, Metaplex } from "@metaplex-foundation/js";
import {
  PROGRAM_ID as BUBBLEGUM_PROGRAM_ID,
  MetadataArgs,
  TokenProgramVersion,
  TokenStandard,
  createMintToCollectionV1Instruction,
} from "@metaplex-foundation/mpl-bubblegum";
import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
import {
  SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  SPL_NOOP_PROGRAM_ID,
} from "@solana/spl-account-compression";
import { Keypair, PublicKey, Transaction } from "@solana/web3.js";
import dotenv from "dotenv";
import { NextApiRequest } from "next";
import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
configConstants();
dotenv.config();

async function createMintCNFT(req: NextApiRequest) {
  const { metadataUri } = req.query;
  const { account: payer } = req.body;

  const metaplex = Metaplex.make(CONNECTION);
  // create compressed nft
  const nftMetadata = await metaplex.storage().downloadJson<JsonMetadata>(metadataUri as string);
  const compressedNftMetadata: MetadataArgs = {
    name: nftMetadata.name ?? "",
    symbol: nftMetadata.symbol ?? "",
    uri: metadataUri as string,
    sellerFeeBasisPoints: 0,
    creators: [
      {
        address: new PublicKey(payer),
        verified: true,
        share: 100,
      },
    ],
    editionNonce: 0,
    uses: null,
    collection: null,
    isMutable: false,
    primarySaleHappened: false,
    tokenProgramVersion: TokenProgramVersion.Original,
    tokenStandard: TokenStandard.NonFungible,
  };

  // derive PDA (owned bt Bubblegum) to act as the signer of the compressed minting
  const [bubblegumSigner, _bump] = PublicKey.findProgramAddressSync(
    [Buffer.from("collection_cpi", "utf8")],
    BUBBLEGUM_PROGRAM_ID,
  );
  const collectionOwner = Keypair.fromSecretKey(
    Uint8Array.from(Buffer.from(process.env.COLLECTION_OWNER_SECRET_KEY as string, "base64")),
  );
  const mintToCollectionIx = createMintToCollectionV1Instruction(
    {
      payer: new PublicKey(payer),

      merkleTree: new PublicKey(process.env.TREE_ADDRESS_1 as string),
      treeAuthority: new PublicKey(process.env.TREE_AUTHORITY_1 as string),
      treeDelegate: new PublicKey(payer),

      collectionMint: new PublicKey(process.env.CHATGPT_COLLECTION_MINT as string),
      collectionAuthority: collectionOwner.publicKey,
      collectionMetadata: new PublicKey(process.env.CHATGPT_COLLECTION_METADATA_ACCOUNT as string),
      collectionAuthorityRecordPda: BUBBLEGUM_PROGRAM_ID,
      editionAccount: new PublicKey(
        process.env.CHATGPT_COLLECTION_MASTER_EDITION_ACCOUNT as string,
      ),

      leafOwner: new PublicKey(payer),
      leafDelegate: new PublicKey(payer),

      // other accounts
      compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
      logWrapper: SPL_NOOP_PROGRAM_ID,
      bubblegumSigner: bubblegumSigner,
      tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
    },
    {
      metadataArgs: Object.assign(compressedNftMetadata, {
        collection: {
          key: new PublicKey(process.env.CHATGPT_COLLECTION_MINT as string),
          verified: false,
        },
      }),
    },
  );

  const tx = new Transaction();
  tx.add(mintToCollectionIx);
  tx.feePayer = new PublicKey(payer);
  tx.recentBlockhash = (await CONNECTION.getLatestBlockhash()).blockhash;
  tx.partialSign(collectionOwner);
  return {
    transaction: tx.serialize({ requireAllSignatures: false }).toString("base64"),
  };
}
export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createMintCNFT));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMintNFT.ts
================================================
// DEPRECATED - not in use
import { Metaplex } from "@metaplex-foundation/js";
import { PublicKey } from "@solana/web3.js";
import { NextApiRequest } from "next";
import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
configConstants();

async function createMintNFT(req: NextApiRequest) {
  const { name, metadataUri, sellerFee = 0 } = req.query;
  const { account: sender } = req.body;
  const metaplex = Metaplex.make(CONNECTION);
  const mintTransactionBuilder = await metaplex
    .nfts()
    .builders()
    .create({
      name: name as string,
      uri: metadataUri as string,
      sellerFeeBasisPoints: Number(sellerFee),
    });
  const latestBlockhashWithExpiryBlockHeight = await CONNECTION.getLatestBlockhash();
  const tx = mintTransactionBuilder.toTransaction(latestBlockhashWithExpiryBlockHeight);
  tx.feePayer = new PublicKey(sender);
  return {
    transaction: tx.serialize({ requireAllSignatures: false }).toString("base64"),
  };
}
export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createMintNFT));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createSetProfilePic.ts
================================================
// DEPRECATED - not in use
import { NextApiRequest } from "next";
import { PublicKey } from "@solana/web3.js";

import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
import { createSetProfilePictureTransaction } from "@solflare-wallet/pfp";
configConstants();

async function createSetProfilePic(req: NextApiRequest) {
  const { mintPublicKey, tokenAccountPublicKey } = req.query;
  const { account: ownerAccountPublicKey } = req.body;

  const tx = await createSetProfilePictureTransaction(
    new PublicKey(ownerAccountPublicKey),
    new PublicKey(mintPublicKey as string),
    new PublicKey(tokenAccountPublicKey as string),
  );
  tx.feePayer = new PublicKey(ownerAccountPublicKey);
  tx.recentBlockhash = (await CONNECTION.getLatestBlockhash()).blockhash;

  return {
    transaction: tx.serialize({ requireAllSignatures: false }).toString("base64"),
  };
}

export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createSetProfilePic));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferAsset.ts
================================================
// DEPRECATED - not in use
import {
  SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  SPL_NOOP_PROGRAM_ID,
} from "@solana/spl-account-compression";
import { PublicKey, Transaction } from "@solana/web3.js";
import { NextApiRequest } from "next";

import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
import { createTransferInstruction } from "@metaplex-foundation/mpl-bubblegum";
import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
import { bufferToArray, getAsset, getAssetProof, getBubblegumAuthorityPDA } from "../utils/helpers";
configConstants();

async function createTransferAsset(req: NextApiRequest) {
  const { destination, assetId } = req.query;
  const { account: sender } = req.body;
  if (!sender || !destination || !assetId) {
    throw new Error("Missing required parameters");
  }

  const assetProof = await getAssetProof(assetId, CONNECTION.rpcEndpoint);
  if (!assetProof?.proof || assetProof.proof.length === 0) {
    throw new Error("Proof retrieved for the given assetId is empty. Please check the assetId.");
  }
  const proofPath = assetProof.proof.map((node: string) => ({
    pubkey: new PublicKey(node),
    isSigner: false,
    isWritable: false,
  }));

  const rpcAsset = await getAsset(assetId, CONNECTION.rpcEndpoint);
  if (rpcAsset.ownership.owner !== sender) {
    throw new Error(
      `NFT is not owned by the expected owner. Expected ${new PublicKey(sender)} but got ${
        rpcAsset.ownership.owner
      }.`,
    );
  }

  const leafNonce = rpcAsset.compression.leaf_id;
  const treeAuthority = await getBubblegumAuthorityPDA(new PublicKey(assetProof.tree_id));
  const leafDelegate = rpcAsset.ownership.delegate
    ? new PublicKey(rpcAsset.ownership.delegate)
    : new PublicKey(rpcAsset.ownership.owner);
  let transferIx = createTransferInstruction(
    {
      treeAuthority,
      leafOwner: new PublicKey(rpcAsset.ownership.owner),
      leafDelegate: leafDelegate,
      newLeafOwner: new PublicKey(destination as string),
      merkleTree: new PublicKey(assetProof.tree_id),
      logWrapper: SPL_NOOP_PROGRAM_ID,
      compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
      anchorRemainingAccounts: proofPath,
    },
    {
      root: bufferToArray(bs58.decode(assetProof.root)),
      dataHash: bufferToArray(bs58.decode(rpcAsset.compression.data_hash.trim())),
      creatorHash: bufferToArray(bs58.decode(rpcAsset.compression.creator_hash.trim())),
      nonce: leafNonce,
      index: leafNonce,
    },
  );
  const tx = new Transaction().add(transferIx);
  tx.feePayer = new PublicKey(sender);
  tx.recentBlockhash = (await CONNECTION.getLatestBlockhash()).blockhash;
  return {
    transaction: tx.serialize({ requireAllSignatures: false }).toString("base64"),
  };
}
export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createTransferAsset));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferSol.ts
================================================
import { NextApiRequest } from "next";
import { PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL } from "@solana/web3.js";

import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
configConstants();

async function createTransferSol(req: NextApiRequest) {
  const { amount } = req.query;
  const { account } = req.body;

  const sender = new PublicKey(account);
  const destination = req.query["destination"] as any as PublicKey;

  const tx = new Transaction();
  tx.add(
    SystemProgram.transfer({
      fromPubkey: sender,
      toPubkey: destination,
      lamports: Math.floor(parseFloat(amount as string) * LAMPORTS_PER_SOL),
    }),
  );
  tx.feePayer = sender;
  tx.recentBlockhash = (await CONNECTION.getLatestBlockhash()).blockhash;

  return {
    transaction: tx.serialize({ requireAllSignatures: false }).toString("base64"),
  };
}

export default makeRespondToSolanaPayGet(
  makeRespondToSolanaPayPost(createTransferSol, { addresses: ["destination"] }),
);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferToken.ts
================================================
import { NextApiRequest } from "next";
import { PublicKey, Transaction } from "@solana/web3.js";
import {
  getAssociatedTokenAddressSync,
  createTransferCheckedInstruction,
  getMint,
  Mint,
} from "@solana/spl-token";
import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
configConstants();

async function createTransferToken(req: NextApiRequest) {
  const { amount } = req.query;
  const { account } = req.body;

  const sender = new PublicKey(account);
  const destination = req.query["destination"] as any as PublicKey;
  const mint = req.query["mint"] as any as PublicKey;

  let mintAccount: Mint;
  try {
    mintAccount = await getMint(CONNECTION, mint, "confirmed");
  } catch (error) {
    throw new Error(`Mint ${mint.toString()} not found`);
  }

  const sourceToken = getAssociatedTokenAddressSync(mint, sender);
  const destinationToken = getAssociatedTokenAddressSync(mint, destination);

  const tx = new Transaction();
  const tokens = Math.round(Number(amount as string) * Math.pow(10, mintAccount.decimals));

  tx.add(
    createTransferCheckedInstruction(
      sourceToken,
      mint,
      destinationToken,
      sender,
      tokens,
      mintAccount.decimals,
    ),
  );
  tx.feePayer = sender;
  tx.recentBlockhash = (await CONNECTION.getLatestBlockhash()).blockhash;

  return {
    transaction: tx.serialize({ requireAllSignatures: false }).toString("base64"),
  };
}

export default makeRespondToSolanaPayGet(
  makeRespondToSolanaPayPost(createTransferToken, { addresses: ["destination"], tokens: ["mint"] }),
);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createWriteNFTMetadata.ts
================================================
// DEPRECATED - not in use
import { createWriteNFTMetadataTx } from "@/lib/on-chain-metadata";
import { NextApiRequest } from "next";
import { makeRespondToSolanaPayGet, makeRespondToSolanaPayPost } from ".";
import configConstants, { CONNECTION } from "../../../constants";
configConstants();

async function createWriteNFTMetadata(req: NextApiRequest) {
  const { image } = req.query;
  const { account: owner } = req.body;
  return await createWriteNFTMetadataTx(CONNECTION, owner as string, {
    image,
  });
}

export default makeRespondToSolanaPayGet(makeRespondToSolanaPayPost(createWriteNFTMetadata));


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/index.ts
================================================
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
import { SOLANA_PAY_LABEL } from "../../../constants";
import { Options, makeApiPostRequest } from "@/lib/middleware";
export type TransactionHandler = (req: NextApiRequest) => Promise<{ transaction: string }>;

export function makeRespondToSolanaPayGet(apiHandler: NextApiHandler) {
  return async (req: NextApiRequest, res: NextApiResponse) => {
    if (req.method === "GET") {
      res.status(200).json({
        label: SOLANA_PAY_LABEL,
        icon: "https://solanapay.com/src/img/branding/Solanapay.com/downloads/gradient.svg",
      });
    } else {
      await apiHandler(req, res);
    }
  };
}

export function makeRespondToSolanaPayPost(handler: TransactionHandler, options?: Options) {
  return makeApiPostRequest(
    async (req: NextApiRequest, res: NextApiResponse) => {
      let result = await handler(req);
      res.status(200).json(result);
    },
    { ...options, rewriteQuery: true },
  );
}


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/utils/helpers.ts
================================================
import { BN } from "@coral-xyz/anchor";
import { PROGRAM_ID, TreeConfig } from "@metaplex-foundation/mpl-bubblegum";
import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
import { Connection, PublicKey } from "@solana/web3.js";
import axios from "axios";

export async function getBubblegumAuthorityPDA(merkleRollPubKey: PublicKey) {
  const [bubblegumAuthorityPDAKey] = await PublicKey.findProgramAddress(
    [merkleRollPubKey.toBuffer()],
    PROGRAM_ID,
  );
  return bubblegumAuthorityPDAKey;
}

export async function getNonceCount(connection: Connection, tree: PublicKey): Promise<BN> {
  const treeAuthority = await getBubblegumAuthorityPDA(tree);
  return new BN((await TreeConfig.fromAccountAddress(connection, treeAuthority)).numMinted);
}

export function bufferToArray(buffer: Buffer): number[] {
  const nums = [];
  for (let i = 0; i < buffer.length; i++) {
    nums.push(buffer[i]);
  }
  return nums;
}

export async function getVoucherPDA(tree: PublicKey, leafIndex: number): Promise<PublicKey> {
  const [voucher] = await PublicKey.findProgramAddress(
    [
      Buffer.from("voucher", "utf8"),
      tree.toBuffer(),
      Uint8Array.from(new BN(leafIndex).toArray("le", 8)),
    ],
    PROGRAM_ID,
  );
  return voucher;
}

export async function getMetadata(mint: PublicKey) {
  return (
    await PublicKey.findProgramAddress(
      [Buffer.from("metadata"), TOKEN_METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer()],
      TOKEN_METADATA_PROGRAM_ID,
    )
  )[0];
}

export async function getMasterEdition(mint: PublicKey) {
  return (
    await PublicKey.findProgramAddress(
      [
        Buffer.from("metadata"),
        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
        mint.toBuffer(),
        Buffer.from("edition"),
      ],
      TOKEN_METADATA_PROGRAM_ID,
    )
  )[0];
}

export async function getAsset(assetId: any, rpcUrl: any): Promise<any> {
  try {
    const response = await axios.post(rpcUrl, {
      jsonrpc: "2.0",
      method: "get_asset",
      id: "compression-example",
      params: [assetId],
    });
    return response.data.result;
  } catch (error) {
    console.error(error);
  }
}

export async function getAssetProof(assetId: any, rpcUrl: any): Promise<any> {
  try {
    const response = await axios.post(rpcUrl, {
      jsonrpc: "2.0",
      method: "get_asset_proof",
      id: "compression-example",
      params: [assetId],
    });
    return response.data.result;
  } catch (error) {
    console.error(error);
  }
}


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/tokenName/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { Client } from "@solflare-wallet/utl-sdk";
import { makeApiPostRequest } from "@/lib/middleware";
const utl = new Client();

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { tokenName } = req.body;

  let results = await (
    await utl.searchMints(tokenName)
  )
    .filter((res: any) => {
      return res["verified"] && res["holders"] > 0 && res["chainId"] === 101;
    })
    .map((res: any) => {
      return {
        mintAddress: res["address"],
        tokenName: res["name"],
        tokenSymbol: res["symbol"],
        holders: res["holders"],
        verified: res["verified"],
        chainId: res["chainId"],
        logoURI: res["logoURI"],
      };
    });

  res.status(200).json(results.slice(0, 10));
}
export default makeApiPostRequest(handler);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/tx-link/[txSlug].ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { encode } from "querystring";
import configConstants, { SELF_URL } from "../../constants";
configConstants();
import { makeApiPostRequest } from "@/lib/middleware";

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const {
    query: { txSlug },
  } = req;

  let encoded = encode(Object(req.body));
  res.status(200).send({
    qrCode: `${SELF_URL}/api/handlers/solana-pay/qr/${txSlug}?${encoded}`,
    disclaimer: `This product uses artificial intelligence ("AI"), which may produce inaccurate information. You are responsible for transactions you authorize, so please confirm accuracy of instructions prior to authorizing any transaction.`,
  });
}

export default makeApiPostRequest(handler);


================================================
FILE: chatgpt-plugin/src/pages/api/handlers/walletName/index.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import { PublicKey } from "@solana/web3.js";
import { walletNameToAddressAndProfilePicture } from "@portal-payments/solana-wallet-names";
import { walletAddressToNameAndProfilePictureCustom } from "@/lib/address";
import configConstants, { CONNECTION } from "../../constants";
configConstants();
import { makeApiPostRequest } from "@/lib/middleware";

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { walletName } = req.body;
  try {
    const dotAnything = await walletAddressToNameAndProfilePictureCustom(
      CONNECTION,
      new PublicKey(walletName),
    );
    res.status(200).send(dotAnything);
  } catch (error) {
    const walletInfo = await walletNameToAddressAndProfilePicture(CONNECTION, walletName);
    res.status(200).send(walletInfo);
  }
}

export default makeApiPostRequest(handler);


================================================
FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/defi.yaml
================================================
openapi: 3.1.0
info:
  title: HelloMoon Defi Summary API
  description: An API for querying information about defi protocols on Solana
  version: 1.0.0
servers:
  - url: https://chatgpt.solanalabs.com/api/helloMoon
paths:
  /defi/programNewUsers:
    post:
      summary: Shows new users of a program over time.
      description:
        Shows new users of a program over time. A new user is defined as the first time a publicKey
        has been a fee payer for this program address.
      operationId: query_program_new_users
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/programNewUsersRequest"
      responses:
        "200":
          description: Successful Response
  /defi/programOverlap:
    post:
      summary: Shows overlap between users of two different programs
      description:
      Program overlap shows the overlap between the users of two protocols. The data will show what percentage of 'aProgramIds' users also use 'bProgramId'
      operationId: query_program_user_overlap
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/programOverlapRequest"
      responses:
        "200":
          description: Successful Response
  /defi/tokenUsers:
    post:
      summary:
      description:
      operationId: query_token_users
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/tokenUsersRequest"
      responses:
        "200":
          description: Successful Response
  /defi/tokenStats:
    post:
      summary:
      description:
      operationId: query_token_stats
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/tokenStatsRequest"
      responses:
        "200":
          description: Successful Response
components:
  schemas:
    stringComparisonOperator:
      type: string
      enum:
        - "="
        - "!="
        - ">"
        - "<"
        - ">="
      nullable: true
    nullableNumber:
      type: number
      nullable: true
    programNewUsersRequest:
      type: object
      required:
        - programId
      properties:
        programId:
          type: string
        day:
          type: string
          nullable: true
        limit:
          $ref: "#/components/schemas/nullableNumber"
    programOverlapRequest:
      type: object
      properties:
        aProgramId:
          type: string
        bProgramId:
          type: string
        limit:
          $ref: "#/components/schemas/nullableNumber"
    tokenUsersRequest:
      type: object
      properties:
        day:
          type: string
          nullable: true
        mint:
          type: string
        limit:
          $ref: "#/components/schemas/nullableNumber"
    tokenStatsRequest:
      type: object
      properties:
        granularity:
          type: string
          enum:
            - "one_week"
            - "one_month"
            - "one_day"
            - "six_hour"
            - "one_hour"
            - "thirty_min"
          nullable: true
        mint:
          type: string
          nullable: true
        limit:
          $ref: "#/components/schemas/nullableNumber"


================================================
FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/programNewUsers.ts
================================================
// Deprecated - Not in use
import { NextApiRequest, NextApiResponse } from "next";
import configConstants, { HELLOMOON_CLIENT } from "../../constants";
configConstants();

import { DefiProgramNetNewUsersDailyRequest } from "@hellomoon/api";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { programId, limit, day } = req.body;

  let date: Date = new Date();
  if (day) {
    try {
      date = new Date(day);
    } catch (e) {
      res.status(500).send("Invalid day: " + day);
      return;
    }
  }

  let args = new DefiProgramNetNewUsersDailyRequest({
    programId,
    limit: limit ?? 10,
    day: date ? date.toISOString() : undefined,
  });

  let data = await HELLOMOON_CLIENT.send(args)
    .then(result => result.data)
    .catch(console.error);

  res.status(200).send(data);
}


================================================
FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/programOverlap.ts
================================================
// Deprecated - Not in use
import { NextApiRequest, NextApiResponse } from "next";
import configConstants, { HELLOMOON_CLIENT } from "../../constants";

import { DefiProgramOverlapRequest } from "@hellomoon/api";
configConstants();

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { aProgramId, bProgramId, limit } = req.body;

  let args = new DefiProgramOverlapRequest({
    aProgramId,
    bProgramId,
    limit: limit ?? 10,
  });

  let data = await HELLOMOON_CLIENT.send(args)
    .then(result => result.data)
    .catch(console.error);

  res.status(200).send(data);
}


================================================
FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/tokenStats.ts
================================================
import { NextApiRequest, NextApiResponse } from "next";
import configConstants, { HELLOMOON_CLIENT } from "../../constants";
configConstants();

import { DefiTokenLeaderboardV3Request } from "@hellomoon/api";
import { makeApiPostRequest } from "@/lib/middleware";

const GRANULARITY = ["one_day", "one_week", "one_month", "thirty_min", "one_hour",
Download .txt
gitextract_4oy13ijj/

├── .gitignore
├── DISCLAIMER.md
├── LICENSE
├── README.md
├── chatgpt-plugin/
│   ├── .gitignore
│   ├── .prettierrc
│   ├── README.md
│   ├── next.config.js
│   ├── postcss.config.js
│   ├── public/
│   │   └── openapi.yaml
│   ├── src/
│   │   ├── app/
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── lib/
│   │   │   ├── address.ts
│   │   │   ├── features.tsx
│   │   │   ├── helloMoon/
│   │   │   │   └── index.ts
│   │   │   ├── hyperspace/
│   │   │   │   ├── account.ts
│   │   │   │   ├── constants.ts
│   │   │   │   └── idl/
│   │   │   │       └── hyperspace.ts
│   │   │   ├── middleware.ts
│   │   │   └── on-chain-metadata/
│   │   │       └── index.ts
│   │   └── pages/
│   │       └── api/
│   │           ├── constants.ts
│   │           ├── handlers/
│   │           │   ├── getAccountInfo/
│   │           │   │   └── index.ts
│   │           │   ├── getAssetsByOwner/
│   │           │   │   └── index.ts
│   │           │   ├── getBalance/
│   │           │   │   └── index.ts
│   │           │   ├── getCollectionsByFloorPrice/
│   │           │   │   └── index.ts
│   │           │   ├── getCollectionsByName/
│   │           │   │   └── index.ts
│   │           │   ├── getListedCollectionNFTs/
│   │           │   │   └── index.ts
│   │           │   ├── getSignaturesForAddress/
│   │           │   │   └── index.ts
│   │           │   ├── getTokenAccounts/
│   │           │   │   └── index.ts
│   │           │   ├── getTotalValue/
│   │           │   │   └── index.ts
│   │           │   ├── getTransaction/
│   │           │   │   └── index.ts
│   │           │   ├── solana-pay/
│   │           │   │   ├── page/
│   │           │   │   │   └── [methodName].ts
│   │           │   │   ├── qr/
│   │           │   │   │   └── [methodName].ts
│   │           │   │   ├── sign/
│   │           │   │   │   ├── createBurnAsset.ts
│   │           │   │   │   ├── createBuyNFT.ts
│   │           │   │   │   ├── createCloseNFTMetadata.ts
│   │           │   │   │   ├── createListNFT.ts
│   │           │   │   │   ├── createMerkleTree.ts
│   │           │   │   │   ├── createMintCNFT.ts
│   │           │   │   │   ├── createMintNFT.ts
│   │           │   │   │   ├── createSetProfilePic.ts
│   │           │   │   │   ├── createTransferAsset.ts
│   │           │   │   │   ├── createTransferSol.ts
│   │           │   │   │   ├── createTransferToken.ts
│   │           │   │   │   ├── createWriteNFTMetadata.ts
│   │           │   │   │   └── index.ts
│   │           │   │   └── utils/
│   │           │   │       └── helpers.ts
│   │           │   ├── tokenName/
│   │           │   │   └── index.ts
│   │           │   ├── tx-link/
│   │           │   │   └── [txSlug].ts
│   │           │   └── walletName/
│   │           │       └── index.ts
│   │           ├── helloMoon/
│   │           │   ├── defi/
│   │           │   │   ├── defi.yaml
│   │           │   │   ├── programNewUsers.ts
│   │           │   │   ├── programOverlap.ts
│   │           │   │   ├── tokenStats.ts
│   │           │   │   └── tokenUsers.ts
│   │           │   ├── jupiter/
│   │           │   │   ├── README.md
│   │           │   │   ├── historical.ts
│   │           │   │   ├── pairs.ts
│   │           │   │   ├── summary.ts
│   │           │   │   └── swaps.ts
│   │           │   └── jupiter.yaml
│   │           ├── metaplex/
│   │           │   ├── getCNFTRent/
│   │           │   │   └── index.ts
│   │           │   ├── getPublicTree/
│   │           │   │   └── index.ts
│   │           │   └── metaplex.yaml
│   │           ├── solflare-pfp/
│   │           │   └── getProfilePic.ts
│   │           └── tiplink/
│   │               └── makeLink.ts
│   └── tailwind.config.js
├── langchain_examples/
│   ├── README.md
│   └── python/
│       └── main.py
├── pyproject.toml
└── scripts/
    ├── createNFTCollection.ts
    ├── createTree.ts
    ├── helper.ts
    ├── runCreateCollection.ts
    ├── send.ts
    └── uploadMetadata.ts
Download .txt
SYMBOL INDEX (143 symbols across 58 files)

FILE: chatgpt-plugin/next.config.js
  method rewrites (line 3) | async rewrites() {

FILE: chatgpt-plugin/src/app/layout.tsx
  function RootLayout (line 13) | function RootLayout({ children }: { children: React.ReactNode }) {

FILE: chatgpt-plugin/src/app/page.tsx
  function Home (line 10) | function Home() {

FILE: chatgpt-plugin/src/lib/address.ts
  type WalletNames (line 12) | interface WalletNames {
  function resolveAddress (line 79) | async function resolveAddress(address: string): Promise<PublicKey> {
  function resolveToken (line 105) | async function resolveToken(tokenName: string): Promise<PublicKey> {

FILE: chatgpt-plugin/src/lib/features.tsx
  type Endpoint (line 3) | type Endpoint = {

FILE: chatgpt-plugin/src/lib/helloMoon/index.ts
  constant VALID_OPERATORS (line 1) | const VALID_OPERATORS = ["=", "!=", ">", "<", ">="];
  type Comparison (line 2) | type Comparison =
  function buildComparison (line 9) | function buildComparison(
  function cleanSwapPair (line 38) | function cleanSwapPair(pair: string) {

FILE: chatgpt-plugin/src/lib/hyperspace/account.ts
  function loadHyperspaceProgram (line 16) | async function loadHyperspaceProgram(

FILE: chatgpt-plugin/src/lib/hyperspace/constants.ts
  constant FEE_PAYER (line 3) | const FEE_PAYER = "fee_payer";
  constant HYPERSPACE (line 4) | const HYPERSPACE = "hyperspace";
  constant HYPERSPACE_ID (line 6) | const HYPERSPACE_ID = new PublicKey(
  constant HYPERSPACE_MARKETPLACE_INSTANCE_ID_STRING (line 10) | const HYPERSPACE_MARKETPLACE_INSTANCE_ID_STRING =
  constant HYPERSPACE_MARKETPLACE_INSTANCE (line 12) | const HYPERSPACE_MARKETPLACE_INSTANCE = new PublicKey(

FILE: chatgpt-plugin/src/lib/hyperspace/idl/hyperspace.ts
  type Hyperspace (line 1) | type Hyperspace = {

FILE: chatgpt-plugin/src/lib/middleware.ts
  type Options (line 4) | type Options = {
  function makeApiPostRequest (line 10) | function makeApiPostRequest(handler: NextApiHandler, options?: Options):...

FILE: chatgpt-plugin/src/lib/on-chain-metadata/index.ts
  type SolanaPayTx (line 4) | type SolanaPayTx = {
  class FakeWallet (line 12) | class FakeWallet {
    method constructor (line 14) | constructor(publicKey: anchor.web3.PublicKey) {
    method signTransaction (line 18) | async signTransaction<
    method signAllTransactions (line 24) | async signAllTransactions<
  function createWriteNFTMetadataTx (line 31) | async function createWriteNFTMetadataTx(
  function createCloseNFTMetadataTx (line 91) | async function createCloseNFTMetadataTx(

FILE: chatgpt-plugin/src/pages/api/constants.ts
  constant APP (line 7) | const APP = express();
  constant PORT (line 8) | const PORT = process.env.PORT || 3333;
  constant SOLANA_PAY_LABEL (line 14) | const SOLANA_PAY_LABEL = "Solana Labs ChatGPT Plugin";
  constant TRANSACTION_ENDPOINTS (line 15) | const TRANSACTION_ENDPOINTS = [
  type TransactionEndpoints (line 20) | type TransactionEndpoints = (typeof TRANSACTION_ENDPOINTS)[number];
  constant TX_DESCRIPTIONS (line 21) | const TX_DESCRIPTIONS: Record<TransactionEndpoints, string> = {
  constant HELIUS_URL (line 30) | let HELIUS_URL: string;
  constant SELF_URL (line 31) | let SELF_URL: string;
  constant HYPERSPACE_CLIENT (line 32) | let HYPERSPACE_CLIENT: HyperspaceClient;
  constant HELLOMOON_CLIENT (line 33) | let HELLOMOON_CLIENT: RestClient;
  constant CONNECTION (line 34) | let CONNECTION: Connection;
  function index (line 36) | function index() {

FILE: chatgpt-plugin/src/pages/api/handlers/getAccountInfo/index.ts
  function stringifyAnchorObject (line 15) | function stringifyAnchorObject(obj: any): any {
  function getParsedAccountInfo (line 44) | async function getParsedAccountInfo(connection: Connection, accountAddre...
  function handler (line 88) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getAssetsByOwner/index.ts
  function handler (line 35) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getBalance/index.ts
  function handler (line 7) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getCollectionsByFloorPrice/index.ts
  type CollectionStats (line 7) | type CollectionStats = {
  function hyperspaceGetCollectionsByFloorPrice (line 18) | async function hyperspaceGetCollectionsByFloorPrice(
  function handler (line 85) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getCollectionsByName/index.ts
  function getCollectionsByName (line 6) | async function getCollectionsByName(req: NextApiRequest, res: NextApiRes...

FILE: chatgpt-plugin/src/pages/api/handlers/getListedCollectionNFTs/index.ts
  type NFTListing (line 6) | type NFTListing = {
  type ListedNFTResponse (line 12) | type ListedNFTResponse = {
  function hyperspaceGetListedCollectionNFTs (line 17) | async function hyperspaceGetListedCollectionNFTs(
  function handler (line 74) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getSignaturesForAddress/index.ts
  function handler (line 7) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getTokenAccounts/index.ts
  type TokenInfo (line 7) | type TokenInfo = {
  function handler (line 12) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getTotalValue/index.ts
  function getTokenTotal (line 10) | async function getTokenTotal(address: string) {
  function getNFTTotal (line 75) | async function getNFTTotal(address: string) {
  function handler (line 103) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/getTransaction/index.ts
  type IxArgs (line 32) | type IxArgs = Record<string, string>;
  type Instruction (line 34) | type Instruction = {
  constant PROGRAM_CACHE (line 41) | let PROGRAM_CACHE = new Map<string, anchor.Program | null>();
  type ParsedTxResponse (line 43) | type ParsedTxResponse = {
  function getAnchorProgram (line 60) | async function getAnchorProgram(programId: string) {
  function parseAnchorIxData (line 78) | async function parseAnchorIxData(programId: anchor.web3.PublicKey, ixDat...
  function parseAnchorIxAccounts (line 87) | async function parseAnchorIxAccounts(
  function snakeToTitleCase (line 124) | function snakeToTitleCase(str: string): string {
  function parseAnchorIx (line 129) | async function parseAnchorIx(ix: Instruction) {
  function parseIx (line 151) | async function parseIx(ix: TransactionInstruction, depth: number): Promi...
  function parseTokenInstruction (line 273) | async function parseTokenInstruction(ix: TransactionInstruction): Promis...
  function parseTokenChanges (line 321) | async function parseTokenChanges(
  function parseSolChanges (line 352) | function parseSolChanges(
  function parseLogs (line 372) | function parseLogs(logs: string[]): { programId: string; depth: number }...
  function handler (line 386) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/page/[methodName].ts
  function createOpenGraphMetaPage (line 8) | function createOpenGraphMetaPage(
  function handler (line 24) | async function handler(

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/qr/[methodName].ts
  function createQRCodePng (line 14) | async function createQRCodePng(
  function handler (line 41) | async function handler(

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createBurnAsset.ts
  function createBurnAsset (line 15) | async function createBurnAsset(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createBuyNFT.ts
  function hyperspaceCreateBuyTx (line 9) | async function hyperspaceCreateBuyTx(buyer: string, token: string, price...
  function createBuyNFT (line 25) | async function createBuyNFT(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createCloseNFTMetadata.ts
  function createCloseNFTMetadata (line 8) | async function createCloseNFTMetadata(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createListNFT.ts
  constant AUTH_PROGRAM_ID (line 42) | const AUTH_PROGRAM_ID = new PublicKey("auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9s...
  function createTradeStateInstruction (line 93) | async function createTradeStateInstruction(
  function helper (line 134) | async function helper(
  function hyperspaceCreateListTx (line 247) | async function hyperspaceCreateListTx(seller: string, token: string, pri...
  function createListNFT (line 284) | async function createListNFT(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMerkleTree.ts
  type MerkleTreeArgs (line 19) | interface MerkleTreeArgs {
  function createTree (line 25) | async function createTree(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMintCNFT.ts
  function createMintCNFT (line 23) | async function createMintCNFT(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMintNFT.ts
  function createMintNFT (line 9) | async function createMintNFT(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createSetProfilePic.ts
  function createSetProfilePic (line 10) | async function createSetProfilePic(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferAsset.ts
  function createTransferAsset (line 16) | async function createTransferAsset(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferSol.ts
  function createTransferSol (line 8) | async function createTransferSol(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferToken.ts
  function createTransferToken (line 13) | async function createTransferToken(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createWriteNFTMetadata.ts
  function createWriteNFTMetadata (line 8) | async function createWriteNFTMetadata(req: NextApiRequest) {

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/index.ts
  type TransactionHandler (line 4) | type TransactionHandler = (req: NextApiRequest) => Promise<{ transaction...
  function makeRespondToSolanaPayGet (line 6) | function makeRespondToSolanaPayGet(apiHandler: NextApiHandler) {
  function makeRespondToSolanaPayPost (line 19) | function makeRespondToSolanaPayPost(handler: TransactionHandler, options...

FILE: chatgpt-plugin/src/pages/api/handlers/solana-pay/utils/helpers.ts
  function getBubblegumAuthorityPDA (line 7) | async function getBubblegumAuthorityPDA(merkleRollPubKey: PublicKey) {
  function getNonceCount (line 15) | async function getNonceCount(connection: Connection, tree: PublicKey): P...
  function bufferToArray (line 20) | function bufferToArray(buffer: Buffer): number[] {
  function getVoucherPDA (line 28) | async function getVoucherPDA(tree: PublicKey, leafIndex: number): Promis...
  function getMetadata (line 40) | async function getMetadata(mint: PublicKey) {
  function getMasterEdition (line 49) | async function getMasterEdition(mint: PublicKey) {
  function getAsset (line 63) | async function getAsset(assetId: any, rpcUrl: any): Promise<any> {
  function getAssetProof (line 77) | async function getAssetProof(assetId: any, rpcUrl: any): Promise<any> {

FILE: chatgpt-plugin/src/pages/api/handlers/tokenName/index.ts
  function handler (line 6) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/tx-link/[txSlug].ts
  function handler (line 7) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/handlers/walletName/index.ts
  function handler (line 9) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/programNewUsers.ts
  function handler (line 8) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/programOverlap.ts
  function handler (line 8) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/tokenStats.ts
  constant GRANULARITY (line 8) | const GRANULARITY = ["one_day", "one_week", "one_month", "thirty_min", "...
  function handler (line 9) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/defi/tokenUsers.ts
  function handler (line 8) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/jupiter/historical.ts
  constant VALID_GRANULARITY (line 8) | const VALID_GRANULARITY = ["DAILY", "WEEKLY", "MONTHLY"];
  function handler (line 9) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/jupiter/pairs.ts
  function handler (line 9) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/jupiter/summary.ts
  function handler (line 7) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/helloMoon/jupiter/swaps.ts
  constant VALID_CATEGORY (line 9) | const VALID_CATEGORY = ["per amm", "whole market", "jupiter only"];
  constant CATEGORY_MAP (line 11) | const CATEGORY_MAP: { [key: string]: string } = {
  function handler (line 17) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/metaplex/getCNFTRent/index.ts
  function isValidDepthSizePair (line 12) | function isValidDepthSizePair(maxDepth: number, maxBufferSize: number): ...
  function isEqualDepthSizePair (line 20) | function isEqualDepthSizePair(pair1: DepthSizePair, pair2: DepthSizePair...
  function handler (line 24) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/metaplex/getPublicTree/index.ts
  function handler (line 11) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/solflare-pfp/getProfilePic.ts
  function handler (line 7) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: chatgpt-plugin/src/pages/api/tiplink/makeLink.ts
  function handler (line 5) | async function handler(req: NextApiRequest, res: NextApiResponse) {

FILE: scripts/createNFTCollection.ts
  constant ASSETS_DIR (line 32) | const ASSETS_DIR = "../chatgpt-plugin/public/assets/";
  function createNFTCollection (line 33) | async function createNFTCollection(payer: Keypair, metaplex: Metaplex) {

FILE: scripts/createTree.ts
  type MerkleTreeArgs (line 23) | interface MerkleTreeArgs {
  function createTree (line 29) | async function createTree(

FILE: scripts/helper.ts
  constant DEFAULT_KEY_DIR_NAME (line 11) | const DEFAULT_KEY_DIR_NAME = ".local_keys";
  constant DEFAULT_PUBLIC_KEY_FILE (line 12) | const DEFAULT_PUBLIC_KEY_FILE = "keys.json";
  constant DEFAULT_NONCE_FILE (line 13) | const DEFAULT_NONCE_FILE = "nonce.json";
  function loadPublicKeysFromFile (line 18) | function loadPublicKeysFromFile(
  function savePublicKeyToFile (line 45) | function savePublicKeyToFile(
  function loadNonceFromFile (line 83) | function loadNonceFromFile(
  function saveNonceToFile (line 110) | function saveNonceToFile(

FILE: scripts/send.ts
  function simulate (line 6) | async function simulate(base64Transaction: string, signers: Signer[]) {
  function parse (line 13) | function parse(): {
  function main (line 34) | async function main() {

FILE: scripts/uploadMetadata.ts
  constant ASSETS_DIR (line 10) | const ASSETS_DIR = "../chatgpt-plugin/public/assets/";
  function uploadMetadata (line 11) | async function uploadMetadata(metaplex: Metaplex, nonce: number) {
Condensed preview — 77 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (250K chars).
[
  {
    "path": ".gitignore",
    "chars": 142,
    "preview": ".DS_Store\n.env\nnode_modules/\nyarn*\ntmp*\n\n# Debugging tools\nscripts/collection.ts\nscripts/sharp.ts\n\nlangchain_examples/py"
  },
  {
    "path": "DISCLAIMER.md",
    "chars": 2383,
    "preview": "# Disclaimer\n\nAll claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurement"
  },
  {
    "path": "LICENSE",
    "chars": 558,
    "preview": "Copyright 2023 Solana Labs, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this f"
  },
  {
    "path": "README.md",
    "chars": 5999,
    "preview": "# Solana ChatGPT Plugin\nA ChatGPT plugin for Solana. Install as an unverified plugin with url `https://chatgpt.solanalab"
  },
  {
    "path": "chatgpt-plugin/.gitignore",
    "chars": 368,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "chatgpt-plugin/.prettierrc",
    "chars": 185,
    "preview": "{\n  \"tabWidth\": 2,\n  \"useTabs\": false,\n  \"singleQuote\": false,\n  \"printWidth\": 100,\n  \"trailingComma\": \"all\",\n  \"arrowPa"
  },
  {
    "path": "chatgpt-plugin/README.md",
    "chars": 1370,
    "preview": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js"
  },
  {
    "path": "chatgpt-plugin/next.config.js",
    "chars": 311,
    "preview": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  async rewrites() {\n    return [\n      // temporary until"
  },
  {
    "path": "chatgpt-plugin/postcss.config.js",
    "chars": 82,
    "preview": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n"
  },
  {
    "path": "chatgpt-plugin/public/openapi.yaml",
    "chars": 9209,
    "preview": "openapi: 3.0.2\ninfo:\n  title: Solana Labs API\n  description: An API for retrieving human-readable information about the "
  },
  {
    "path": "chatgpt-plugin/src/app/globals.css",
    "chars": 1842,
    "preview": "@tailwind base;\n@tailwind components;\n\n:root {\n  --foreground-rgb: 255, 255, 255;\n  --background-start-rgb: 0, 0, 0;\n  -"
  },
  {
    "path": "chatgpt-plugin/src/app/layout.tsx",
    "chars": 1206,
    "preview": "import Link from \"next/link\";\nimport \"./globals.css\";\nimport { Inter } from \"next/font/google\";\nimport Image from \"next/"
  },
  {
    "path": "chatgpt-plugin/src/app/page.tsx",
    "chars": 2271,
    "preview": "\"use client\";\n\nimport Head from \"next/head\";\nimport Link from \"next/link\";\n\nimport { features } from \"@/lib/features\";\ni"
  },
  {
    "path": "chatgpt-plugin/src/lib/address.ts",
    "chars": 3936,
    "preview": "import {\n  walletAddressToDotAnything,\n  walletAddressToDotGlow,\n  walletAddressToDotBackpack,\n  walletNameToAddressAndP"
  },
  {
    "path": "chatgpt-plugin/src/lib/features.tsx",
    "chars": 5889,
    "preview": "import Link from \"next/link\";\n\nexport type Endpoint = {\n  label: string;\n  description: React.ReactNode;\n};\n\nexport cons"
  },
  {
    "path": "chatgpt-plugin/src/lib/helloMoon/index.ts",
    "chars": 1045,
    "preview": "export const VALID_OPERATORS = [\"=\", \"!=\", \">\", \"<\", \">=\"];\nexport type Comparison =\n  | {\n      operator: \"=\" | \"!=\" | "
  },
  {
    "path": "chatgpt-plugin/src/lib/hyperspace/account.ts",
    "chars": 3934,
    "preview": "import { Keypair, PublicKey } from \"@solana/web3.js\";\nimport * as anchor from \"@coral-xyz/anchor\";\nimport {\n  HYPERSPACE"
  },
  {
    "path": "chatgpt-plugin/src/lib/hyperspace/constants.ts",
    "chars": 443,
    "preview": "import { PublicKey } from \"@solana/web3.js\";\n\nexport const FEE_PAYER = \"fee_payer\";\nexport const HYPERSPACE = \"hyperspac"
  },
  {
    "path": "chatgpt-plugin/src/lib/hyperspace/idl/hyperspace.ts",
    "chars": 70704,
    "preview": "export type Hyperspace = {\n  version: \"0.1.0\";\n  name: \"hyperspace\";\n  instructions: [\n    {\n      name: \"initProgramAsS"
  },
  {
    "path": "chatgpt-plugin/src/lib/middleware.ts",
    "chars": 1199,
    "preview": "import { NextApiRequest, NextApiResponse, NextApiHandler } from \"next\";\nimport { resolveAddress, resolveToken } from \"./"
  },
  {
    "path": "chatgpt-plugin/src/lib/on-chain-metadata/index.ts",
    "chars": 2997,
    "preview": "import * as anchor from \"@coral-xyz/anchor\";\nimport { Connection } from \"@solana/web3.js\";\n\ntype SolanaPayTx = {\n  trans"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/constants.ts",
    "chars": 1484,
    "preview": "import express from \"express\";\n\nimport { RestClient } from \"@hellomoon/api\";\nimport { Connection } from \"@solana/web3.js"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getAccountInfo/index.ts",
    "chars": 3057,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { PublicKey, Connection, Keypair } from \"@solana/web3.js\""
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getAssetsByOwner/index.ts",
    "chars": 1116,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELIUS_URL } from \"../../constants\";\nc"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getBalance/index.ts",
    "chars": 564,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { PublicKey, LAMPORTS_PER_SOL } from \"@solana/web3.js\";\ni"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getCollectionsByFloorPrice/index.ts",
    "chars": 2720,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { bs58 } from \"@coral-xyz/anchor/dist/cjs/utils/bytes\";\ni"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getCollectionsByName/index.ts",
    "chars": 1422,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HYPERSPACE_CLIENT } from \"../../consta"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getListedCollectionNFTs/index.ts",
    "chars": 2442,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HYPERSPACE_CLIENT } from \"../../consta"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getSignaturesForAddress/index.ts",
    "chars": 1242,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport configConsta"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getTokenAccounts/index.ts",
    "chars": 940,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\nimport con"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getTotalValue/index.ts",
    "chars": 3876,
    "preview": "import { TokenPriceBatchedRequest, NftMintPriceByCreatorAvgRequest } from \"@hellomoon/api\";\nimport { PublicKey } from \"@"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/getTransaction/index.ts",
    "chars": 15801,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { CONNECTION } from \"../../constants\";\nc"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/page/[methodName].ts",
    "chars": 1157,
    "preview": "/// DEPRECATED - NO LONGER IN USE\nimport { NextApiRequest, NextApiResponse } from \"next\";\nimport { encode } from \"querys"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/qr/[methodName].ts",
    "chars": 1407,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { encode } from \"querystring\";\n\nimport { encodeURL } from"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createBurnAsset.ts",
    "chars": 2627,
    "preview": "// DEPRECATED - not in use\nimport { bs58 } from \"@coral-xyz/anchor/dist/cjs/utils/bytes\";\nimport { createBurnInstruction"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createBuyNFT.ts",
    "chars": 1101,
    "preview": "// DEPRECATED - not in use\nimport { NextApiRequest } from \"next\";\n\nimport { base64 } from \"@coral-xyz/anchor/dist/cjs/ut"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createCloseNFTMetadata.ts",
    "chars": 579,
    "preview": "// DEPRECATED - not in use\nimport { NextApiRequest } from \"next\";\n\nimport { createCloseNFTMetadataTx } from \"@/lib/on-ch"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createListNFT.ts",
    "chars": 8505,
    "preview": "// DEPRECATED - not in use\n/**\n * Deprecated because Solana Pay compatible wallets block NFT/token delegation to prevent"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMerkleTree.ts",
    "chars": 1906,
    "preview": "// DEPRECATED - not in use\nimport {\n  PROGRAM_ID as BUBBLEGUM_PROGRAM_ID,\n  createCreateTreeInstruction,\n} from \"@metapl"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMintCNFT.ts",
    "chars": 3651,
    "preview": "// DEPRECATED - not in use\nimport { JsonMetadata, Metaplex } from \"@metaplex-foundation/js\";\nimport {\n  PROGRAM_ID as BU"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createMintNFT.ts",
    "chars": 1127,
    "preview": "// DEPRECATED - not in use\nimport { Metaplex } from \"@metaplex-foundation/js\";\nimport { PublicKey } from \"@solana/web3.j"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createSetProfilePic.ts",
    "chars": 1044,
    "preview": "// DEPRECATED - not in use\nimport { NextApiRequest } from \"next\";\nimport { PublicKey } from \"@solana/web3.js\";\n\nimport {"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferAsset.ts",
    "chars": 2917,
    "preview": "// DEPRECATED - not in use\nimport {\n  SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,\n  SPL_NOOP_PROGRAM_ID,\n} from \"@solana/spl-acc"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferSol.ts",
    "chars": 1066,
    "preview": "import { NextApiRequest } from \"next\";\nimport { PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL } from \"@solana/"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createTransferToken.ts",
    "chars": 1638,
    "preview": "import { NextApiRequest } from \"next\";\nimport { PublicKey, Transaction } from \"@solana/web3.js\";\nimport {\n  getAssociate"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/createWriteNFTMetadata.ts",
    "chars": 611,
    "preview": "// DEPRECATED - not in use\nimport { createWriteNFTMetadataTx } from \"@/lib/on-chain-metadata\";\nimport { NextApiRequest }"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/sign/index.ts",
    "chars": 988,
    "preview": "import { NextApiHandler, NextApiRequest, NextApiResponse } from \"next\";\nimport { SOLANA_PAY_LABEL } from \"../../../const"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/solana-pay/utils/helpers.ts",
    "chars": 2516,
    "preview": "import { BN } from \"@coral-xyz/anchor\";\nimport { PROGRAM_ID, TreeConfig } from \"@metaplex-foundation/mpl-bubblegum\";\nimp"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/tokenName/index.ts",
    "chars": 859,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { Client } from \"@solflare-wallet/utl-sdk\";\nimport { make"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/tx-link/[txSlug].ts",
    "chars": 782,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { encode } from \"querystring\";\nimport configConstants, { "
  },
  {
    "path": "chatgpt-plugin/src/pages/api/handlers/walletName/index.ts",
    "chars": 890,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { walletName"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/defi/defi.yaml",
    "chars": 3328,
    "preview": "openapi: 3.1.0\ninfo:\n  title: HelloMoon Defi Summary API\n  description: An API for querying information about defi proto"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/defi/programNewUsers.ts",
    "chars": 836,
    "preview": "// Deprecated - Not in use\nimport { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_C"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/defi/programOverlap.ts",
    "chars": 619,
    "preview": "// Deprecated - Not in use\nimport { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_C"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/defi/tokenStats.ts",
    "chars": 1051,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_CLIENT } from \"../../constan"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/defi/tokenUsers.ts",
    "chars": 744,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_CLIENT } from \"../../constan"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/jupiter/README.md",
    "chars": 1403,
    "preview": "# Test Queries\n\n#### Summary \n\nCan you summarize Jupiter activity this past week on Solana?\n\n```\nIn the past week, Jupit"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/jupiter/historical.ts",
    "chars": 1650,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_CLIENT } from \"../../constan"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/jupiter/pairs.ts",
    "chars": 1261,
    "preview": "// DEPRECATED - not in use\nimport { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_C"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/jupiter/summary.ts",
    "chars": 547,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_CLIENT } from \"../../constan"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/jupiter/swaps.ts",
    "chars": 1418,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants, { HELLOMOON_CLIENT } from \"../../constan"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/helloMoon/jupiter.yaml",
    "chars": 4739,
    "preview": "openapi: 3.1.0\ninfo:\n  title: HelloMoon API\n  description: An API for querying information about protocols built on Sola"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/metaplex/getCNFTRent/index.ts",
    "chars": 2864,
    "preview": "// Deprecated - Not in use\nimport {\n  ALL_DEPTH_SIZE_PAIRS,\n  DepthSizePair,\n  getConcurrentMerkleTreeAccountSize,\n} fro"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/metaplex/getPublicTree/index.ts",
    "chars": 449,
    "preview": "// Deprecated - Not in use\nimport { NextApiRequest, NextApiResponse } from \"next\";\nimport configConstants from \"../../co"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/metaplex/metaplex.yaml",
    "chars": 4603,
    "preview": "openapi: 3.0.2\ninfo:\n  title: Metaplex API\n  description: An API for interacting with the Solana NFT collections using M"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/solflare-pfp/getProfilePic.ts",
    "chars": 561,
    "preview": "// Deprecated - Not in use\nimport { NextApiRequest, NextApiResponse } from \"next\";\nimport { getProfilePicture } from \"@s"
  },
  {
    "path": "chatgpt-plugin/src/pages/api/tiplink/makeLink.ts",
    "chars": 394,
    "preview": "import { NextApiRequest, NextApiResponse } from \"next\";\nimport { TipLink } from \"@tiplink/api\";\nimport { makeApiPostRequ"
  },
  {
    "path": "chatgpt-plugin/tailwind.config.js",
    "chars": 480,
    "preview": "/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  content: [\n    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',\n"
  },
  {
    "path": "langchain_examples/README.md",
    "chars": 378,
    "preview": "# Langchain Usage\n\nLangchain has support for using ChatGPTs in their Agent via their `tool` interface.\n\nWe have provided"
  },
  {
    "path": "langchain_examples/python/main.py",
    "chars": 1175,
    "preview": "from langchain.chat_models import ChatOpenAI\nfrom langchain.agents import load_tools, initialize_agent\nfrom langchain.ag"
  },
  {
    "path": "pyproject.toml",
    "chars": 402,
    "preview": "[tool.poetry]\nname = \"solana-gpt-plugin\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"ngundotra <noah@gundotra.org>\"]\n"
  },
  {
    "path": "scripts/createNFTCollection.ts",
    "chars": 5997,
    "preview": "import {\n  Metaplex,\n  toMetaplexFile,\n  UploadMetadataInput,\n} from \"@metaplex-foundation/js\";\nimport {\n  createAssocia"
  },
  {
    "path": "scripts/createTree.ts",
    "chars": 2510,
    "preview": "import {\n    Keypair,\n    Connection,\n    PublicKey,\n    Transaction,\n    sendAndConfirmTransaction,\n  } from \"@solana/w"
  },
  {
    "path": "scripts/helper.ts",
    "chars": 3790,
    "preview": "import fs from \"fs\";\nimport path from \"path\";\nimport {\n  Connection,\n  Keypair,\n  LAMPORTS_PER_SOL,\n  PublicKey,\n} from "
  },
  {
    "path": "scripts/runCreateCollection.ts",
    "chars": 1691,
    "preview": "import {\n  Metaplex,\n  bundlrStorage,\n  keypairIdentity,\n} from \"@metaplex-foundation/js\";\nimport { Connection, Keypair "
  },
  {
    "path": "scripts/send.ts",
    "chars": 1190,
    "preview": "// Deprecated - Not in use\nimport { Connection, Transaction, Keypair, Signer } from \"@solana/web3.js\";\nimport { readFile"
  },
  {
    "path": "scripts/uploadMetadata.ts",
    "chars": 1112,
    "preview": "// Deprecated - Not in use\nimport {\n  Metaplex,\n  toMetaplexFile,\n  UploadMetadataInput,\n} from \"@metaplex-foundation/js"
  }
]

About this extraction

This page contains the full source code of the solana-labs/chatgpt-plugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 77 files (225.9 KB), approximately 58.7k tokens, and a symbol index with 143 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!