├── .gitignore ├── .env.example ├── src ├── utils │ ├── calculateTokenPrice.ts │ ├── type.ts │ └── chart.ts ├── program │ ├── cli │ │ ├── programId.ts │ │ ├── accounts │ │ │ ├── index.ts │ │ │ ├── CurveConfiguration.ts │ │ │ ├── LiquidityProvider.ts │ │ │ └── LiquidityPool.ts │ │ ├── instructions │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── swap.ts │ │ │ ├── addLiquidity.ts │ │ │ ├── createRaydiumPool.ts │ │ │ └── removeLiquidity.ts │ │ └── errors │ │ │ ├── index.ts │ │ │ ├── custom.ts │ │ │ └── anchor.ts │ ├── web3.ts │ ├── web3Provider.ts │ └── idl.ts ├── models │ ├── Feedback.ts │ ├── PendingUser.ts │ ├── User.ts │ ├── Coin.ts │ └── CoinsStatus.ts ├── db │ └── dbConncetion.ts ├── sockets │ ├── logger.ts │ └── index.ts ├── routes │ ├── coinTradeRoutes.ts │ ├── chart.ts │ ├── coinStatus.ts │ ├── feedback.ts │ ├── coin.ts │ ├── user.ts │ └── chart copy.ts ├── app.ts └── middleware │ └── authorization.ts ├── id.json ├── tsconfig.json ├── server.ts ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | id.json -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | MONGODB_URI= 2 | PORT= 3 | SIGN_IN_MSG= -------------------------------------------------------------------------------- /src/utils/calculateTokenPrice.ts: -------------------------------------------------------------------------------- 1 | export const calculateTokenPrice = (supply: number, reserveBalance: number, constant: number): number => { 2 | return (reserveBalance * constant) / (supply + 1); 3 | } -------------------------------------------------------------------------------- /id.json: -------------------------------------------------------------------------------- 1 | [244,70,143,5,49,248,59,179,210,248,190,154,82,98,11,79,233,222,121,76,141,193,223,149,122,96,71,202,102,68,173,31,211,101,20,15,47,203,144,14,198,82,97,47,159,163,112,16,172,237,238,114,124,243,123,102,47,224,25,140,20,178,168,71] -------------------------------------------------------------------------------- /src/utils/type.ts: -------------------------------------------------------------------------------- 1 | export interface priceFeedInfo { 2 | price: number, 3 | time: Date, 4 | } 5 | export type CandlePrice = { 6 | open: number; 7 | high: number; 8 | low: number; 9 | close: number; 10 | time: number; 11 | }; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "outDir": "dist", 5 | "rootDir": "src", 6 | "strict": true, 7 | "module": "commonjs", 8 | "esModuleInterop": true, 9 | "typeRoots": ["@types", "./node_modules/@types"], 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "exclude": ["node_modules"] 13 | } -------------------------------------------------------------------------------- /src/program/cli/programId.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js" 2 | 3 | // Program ID defined in the provided IDL. Do not edit, it will get overwritten. 4 | export const PROGRAM_ID_IDL = new PublicKey( 5 | "7wUQXRQtBzTmyp9kcrmok9FKcc4RSYXxPYN9FGDLnqxb" 6 | ) 7 | 8 | // This constant will not get overwritten on subsequent code generations and it's safe to modify it's value. 9 | export const PROGRAM_ID: PublicKey = PROGRAM_ID_IDL 10 | -------------------------------------------------------------------------------- /server.ts: -------------------------------------------------------------------------------- 1 | import { createServer } from 'http' 2 | import app from './src/app' 3 | import socketio from './src/sockets/' 4 | import { logger } from './src/sockets/logger'; 5 | 6 | // Socket communication 7 | const server = createServer(app); 8 | socketio(server); 9 | 10 | /** 11 | * start Express server 12 | */ 13 | server.listen(app.get('port'), () => { 14 | logger.info(' App is running at http://localhost:%d in %s mode', app.get('port'), app.get('env')); 15 | }) 16 | 17 | export default server; -------------------------------------------------------------------------------- /src/models/Feedback.ts: -------------------------------------------------------------------------------- 1 | // models/Coin.js 2 | import mongoose from 'mongoose'; 3 | 4 | const messageSchema = new mongoose.Schema({ 5 | coinId : { type: mongoose.Schema.Types.ObjectId, ref: 'coin', required: true }, 6 | sender : {type : mongoose.Schema.Types.ObjectId, ref: 'user', required: true}, 7 | msg : { type: String, required: true}, 8 | time: {type: Date, default: Date.now} 9 | }); 10 | 11 | const Message = mongoose.model('Message', messageSchema); 12 | 13 | export default Message; 14 | -------------------------------------------------------------------------------- /src/program/cli/accounts/index.ts: -------------------------------------------------------------------------------- 1 | export { CurveConfiguration } from "./CurveConfiguration" 2 | export type { 3 | CurveConfigurationFields, 4 | CurveConfigurationJSON, 5 | } from "./CurveConfiguration" 6 | export { LiquidityProvider } from "./LiquidityProvider" 7 | export type { 8 | LiquidityProviderFields, 9 | LiquidityProviderJSON, 10 | } from "./LiquidityProvider" 11 | export { LiquidityPool } from "./LiquidityPool" 12 | export type { LiquidityPoolFields, LiquidityPoolJSON } from "./LiquidityPool" 13 | -------------------------------------------------------------------------------- /src/models/PendingUser.ts: -------------------------------------------------------------------------------- 1 | // models/PendingUser.js 2 | import mongoose from 'mongoose'; 3 | 4 | const pendingUserSchema = new mongoose.Schema({ 5 | name: { type: String, required: true, }, 6 | wallet: { type: String, required: true,}, 7 | nonce: { type: String, required: true}, 8 | isLedger:{type:Boolean, required: true}, 9 | expiredTime: { type: Date, expires: '20m', default: Date.now} 10 | }); 11 | 12 | const PendingUser = mongoose.model('PendingUser', pendingUserSchema); 13 | 14 | export default PendingUser; 15 | -------------------------------------------------------------------------------- /src/models/User.ts: -------------------------------------------------------------------------------- 1 | // models/User.js 2 | import mongoose, { Types } from 'mongoose'; 3 | 4 | const PINATA_GATEWAY_URL = process.env.PINATA_GATEWAY_URL; 5 | const defualtImg = process.env.DEFAULT_IMG_HASH 6 | 7 | const userSchema = new mongoose.Schema({ 8 | name: { type: String, required: true, }, 9 | wallet: { type: String, required: true, unique: true }, 10 | avatar: { type: String, default: `${PINATA_GATEWAY_URL}/${defualtImg}` } 11 | }); 12 | 13 | const User = mongoose.model('User', userSchema); 14 | 15 | export default User; -------------------------------------------------------------------------------- /src/db/dbConncetion.ts: -------------------------------------------------------------------------------- 1 | import database from "mongoose"; 2 | 3 | require("dotenv").config("../.env"); 4 | const DB_CONNECTION = process.env.MONGODB_URI; 5 | 6 | export const init = () => { 7 | if (DB_CONNECTION === undefined) return; 8 | if (database.connection.readyState === database.ConnectionStates.connected) 9 | return; 10 | database 11 | .connect(DB_CONNECTION) 12 | .then((v) => { 13 | console.log(`mongodb database connected`); 14 | }) 15 | .catch((e) => { 16 | console.error(`mongodb error ${e}`); 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /src/sockets/logger.ts: -------------------------------------------------------------------------------- 1 | import winston from "winston"; 2 | const { createLogger, format, transports } = winston; 3 | const { combine, printf } = format; 4 | 5 | const LOG_LEVEL = "info"; 6 | 7 | const logFormat = printf(({ level, message, timestamp }) => { 8 | return `[${level}][${timestamp}][API] ${message}`; 9 | }); 10 | 11 | export const logger = createLogger({ 12 | level: LOG_LEVEL, 13 | format: combine( 14 | format.prettyPrint(), 15 | format.splat(), 16 | format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), 17 | logFormat 18 | ), 19 | transports: [new transports.Console({})], 20 | }); 21 | 22 | export function showErrorLogOnly() { 23 | logger.level = "error"; 24 | } -------------------------------------------------------------------------------- /src/models/Coin.ts: -------------------------------------------------------------------------------- 1 | // models/Coin.js 2 | import mongoose from 'mongoose'; 3 | 4 | const coinSchema = new mongoose.Schema({ 5 | creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, 6 | name: { type: String, required: true, }, 7 | ticker: { type: String, required: true, }, 8 | description: { type: String }, 9 | token: { type: String, }, 10 | reserveOne: { type: Number, default: 1_000_000_000_000_000 }, 11 | reserveTwo: { type: Number, default: 30_000_000_000 }, 12 | url: { type: String, requried: true }, 13 | date:{type:Date, default:new Date} 14 | }); 15 | 16 | const Coin = mongoose.model('Coin', coinSchema); 17 | 18 | export default Coin; 19 | -------------------------------------------------------------------------------- /src/program/cli/instructions/index.ts: -------------------------------------------------------------------------------- 1 | export { initialize } from "./initialize" 2 | export type { InitializeArgs, InitializeAccounts } from "./initialize" 3 | export { addLiquidity } from "./addLiquidity" 4 | export type { AddLiquidityArgs, AddLiquidityAccounts } from "./addLiquidity" 5 | export { removeLiquidity } from "./removeLiquidity" 6 | export type { 7 | RemoveLiquidityArgs, 8 | RemoveLiquidityAccounts, 9 | } from "./removeLiquidity" 10 | export { swap } from "./swap" 11 | export type { SwapArgs, SwapAccounts } from "./swap" 12 | export { createRaydiumPool } from "./createRaydiumPool" 13 | export type { 14 | CreateRaydiumPoolArgs, 15 | CreateRaydiumPoolAccounts, 16 | } from "./createRaydiumPool" 17 | -------------------------------------------------------------------------------- /src/routes/coinTradeRoutes.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import CoinStatus from '../models/CoinsStatus'; 3 | import { ObjectId } from 'mongodb'; 4 | import { Types } from 'mongoose'; 5 | 6 | const router = express.Router(); 7 | 8 | router.get('/:id', async (req, res) => { 9 | const coinId = req.params.id; 10 | try { 11 | // console.log("Trade:::", coinId); 12 | const coinTrade = await CoinStatus.findOne({ coinId }).populate('coinId').populate('record.holder') 13 | // console.log("coinTrade:::", coinTrade) 14 | res.status(200).send(coinTrade); 15 | } catch (error) { 16 | res.status(500).send(error); 17 | } 18 | }); 19 | 20 | 21 | export default router; 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## pump.fun clone: Solana Pumpfun Backend source code(pump.fun fork), implementing main structure for pump fun. 2 | 3 | It was for to give basic understanding about pumpfun backend workflow, main structure. 4 | Whole working code is private, feel free to reach out of me if you wanna get it[Whatsapp: https://wa.me/13137423660, Telegram: https://t.me/DevCutup] 5 | Also you can access smart contract and frontend codebase also, can get it from me. 6 | 7 | ### What it contains 8 | - Smart contract event handler 9 | - User auth 10 | - Backend API 11 | - DB management 12 | 13 | ### Contact Information 14 | - Telegram: https://t.me/DevCutup 15 | - Whatsapp: https://wa.me/13137423660 16 | - Twitter: https://x.com/devcutup 17 | -------------------------------------------------------------------------------- /src/models/CoinsStatus.ts: -------------------------------------------------------------------------------- 1 | // models/Coin.js 2 | import { number, required } from 'joi'; 3 | import mongoose from 'mongoose'; 4 | 5 | const coinStatusSchema = new mongoose.Schema({ 6 | coinId: { type: mongoose.Schema.Types.ObjectId, ref: 'Coin', required: true }, 7 | record: [{ 8 | holder: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, 9 | holdingStatus: { type: Number, required: true }, 10 | time: { type: Date, default: Date.now }, 11 | amount: { type: Number, default: 0 }, 12 | price: { type: Number, required: true }, 13 | tx: { type: String, required: true } 14 | } 15 | ] 16 | }); 17 | 18 | const CoinStatus = mongoose.model('CoinStatus', coinStatusSchema); 19 | 20 | export default CoinStatus; 21 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import 'dotenv/config.js'; 3 | import bodyParser from 'body-parser' 4 | import cors from 'cors' 5 | import userRoutes from './routes/user' 6 | import coinRoutes from './routes/coin' 7 | import messageRoutes from './routes/feedback' 8 | import coinTradeRoutes from './routes/coinTradeRoutes' 9 | import chartRoutes from './routes/chart' 10 | import { init } from './db/dbConncetion'; 11 | 12 | 13 | const app = express(); 14 | const PORT = process.env.PORT || 5000; 15 | 16 | app.use(cors({ 17 | origin: 'http://localhost:3000' 18 | })) 19 | app.use(bodyParser.json()); 20 | app.use(bodyParser.urlencoded({ extended: true })); 21 | 22 | init() 23 | 24 | app.set('port', 5000) 25 | 26 | app.use('/user/', userRoutes); 27 | app.use('/coin/', coinRoutes); 28 | app.use('/feedback/', messageRoutes); 29 | app.use('/cointrade/', coinTradeRoutes) 30 | app.use('/chart/', chartRoutes) 31 | 32 | 33 | export default app; -------------------------------------------------------------------------------- /src/sockets/index.ts: -------------------------------------------------------------------------------- 1 | import { Server, Socket } from 'socket.io'; 2 | 3 | import { logger } from './logger'; 4 | // import { connectRedis } from './redis'; 5 | 6 | const socketio = async (server: any) => { 7 | try { 8 | // Socket communication 9 | const io = new Server(server, { 10 | cors: { 11 | origin: '*', 12 | methods: ['GET', 'POST'], 13 | }, 14 | }); 15 | 16 | io.close(() => { 17 | console.log('Server and all connected sockets closed'); 18 | }); 19 | 20 | 21 | io.on('connection', async (socket: Socket) => { 22 | const id = (socket as any).user?.user?.id; 23 | console.log(`socket (${socket.id}) -> ${id}`); 24 | 25 | 26 | 27 | }); 28 | 29 | // await connectRedis(io); 30 | 31 | logger.info(' Socket server is running'); 32 | } catch (err) { 33 | logger.error(' Socket server run failed'); 34 | console.error(err); 35 | } 36 | }; 37 | 38 | export default socketio; 39 | -------------------------------------------------------------------------------- /src/routes/chart.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import NodeCache from "node-cache"; 3 | import { logger } from "../sockets/logger"; 4 | import { fetchPriceChartData } from "../utils/chart"; 5 | 6 | 7 | 8 | const router = express.Router(); 9 | 10 | // @route GET /coin/ 11 | // @desc Get all created coins 12 | // @access Public 13 | router.get('/:pairIndex/:start/:end/:range/:token', async (req, res) => { 14 | console.log("config+++") 15 | const {pairIndex, start, end, range, token}= req.params 16 | logger.info(` get charts for pairIndex: ${pairIndex}, start: ${start}, end: ${end}, range: ${range}, token: ${token}`); 17 | try { 18 | const data = await fetchPriceChartData(parseInt(pairIndex), parseInt(start) * 1000, parseInt(end) * 1000, parseInt(range), token); 19 | return res.status(200).send({ table: data }); 20 | } catch (e) { 21 | console.error(e); 22 | return res.status(500).send({}); 23 | } 24 | } ) 25 | 26 | export default router; 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/middleware/authorization.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Request, Response } from "express" 2 | import jwt from 'jsonwebtoken' 3 | import { UserInfo } from "../routes/user"; 4 | 5 | export const auth = (req: AuthRequest, res: Response, next: NextFunction): void => { 6 | // const { authorization } = req.headers; 7 | // const token = authorization?.split(' ')[1]; 8 | const authHeader = req.header('Authorization'); 9 | const token = authHeader ? authHeader.replace('Bearer ', '') : null; 10 | if (!token) { 11 | res.status(400).json({ message: 'Token is required' }); 12 | return; 13 | } 14 | try { 15 | jwt.verify( token , 'secret', (err, decoded) => { 16 | if (err) { 17 | return res.status(401).json({ message: 'Failed to authenticate token' }); 18 | } 19 | 20 | req.user = decoded; 21 | next(); 22 | }); 23 | 24 | } catch (error) { 25 | res.status(401).json({ msg: "Token is not valid" }); 26 | } 27 | 28 | } 29 | 30 | export interface AuthRequest extends Request { 31 | user?: any; 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/routes/coinStatus.ts: -------------------------------------------------------------------------------- 1 | import CoinStatus from "../models/CoinsStatus"; 2 | import { ResultType } from "../program/web3"; 3 | import Coin from "../models/Coin"; 4 | import User from "../models/User"; 5 | 6 | 7 | export const setCoinStatus = async (data: ResultType) => { 8 | console.log("+++++++++++++++++++++++++++++++++++++++") 9 | const coinId = await Coin.findOne({ token: data.mint }).select('_id'); 10 | const userId = await User.findOne({ wallet: data.owner }).select('_id'); 11 | const newTx = { 12 | holder: userId?._id, 13 | holdingStatus: data.swapType, 14 | amount: data.swapAmount, 15 | tx:data.tx, 16 | price: data.reserve2/data.reserve1 17 | } 18 | 19 | CoinStatus.findOne({ coinId: coinId?._id }) 20 | .then((coinStatus) => { 21 | coinStatus?.record.push(newTx); 22 | coinStatus?.save() 23 | }) 24 | console.log("Update coin when buy or sell", data) 25 | const updateCoin =await Coin.findOneAndUpdate({ token: data.mint }, { reserveOne: data.reserve1, reserveTwo: data.reserve2 }, { new: true }) 26 | console.log("updat ed coin", updateCoin); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pump-backend", 3 | "version": "1.0.0", 4 | "main": "server.ts", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "dev": "nodemon && tsx src/server.ts" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "description": "", 13 | "dependencies": { 14 | "@coral-xyz/anchor": "^0.30.0", 15 | "@metaplex-foundation/mpl-token-metadata": "^3.2.1", 16 | "@metaplex-foundation/umi": "^0.9.1", 17 | "@metaplex-foundation/umi-bundle-defaults": "^0.9.1", 18 | "@pinata/sdk": "^2.1.0", 19 | "@raydium-io/raydium-sdk": "^1.3.1-beta.52", 20 | "@solana/spl-token": "^0.4.6", 21 | "@solana/web3.js": "^1.91.8", 22 | "@types/bn.js": "^5.1.5", 23 | "@types/jsonwebtoken": "^9.0.6", 24 | "body-parser": "^1.20.2", 25 | "bs58": "^5.0.0", 26 | "cors": "^2.8.5", 27 | "crypto": "^1.0.1", 28 | "dotenv": "^16.4.5", 29 | "express": "^4.19.2", 30 | "joi": "^17.13.1", 31 | "jsonwebtoken": "^9.0.2", 32 | "mongodb": "^6.6.2", 33 | "mongoose": "^8.4.0", 34 | "node-cache": "^5.1.2", 35 | "nodemon": "^3.1.0", 36 | "socket.io": "^4.7.5", 37 | "tweetnacl": "^1.0.3", 38 | "winston": "^3.13.0" 39 | }, 40 | "devDependencies": { 41 | "@types/cors": "^2.8.17", 42 | "@types/express": "^4.17.21", 43 | "ts-node-dev": "^2.0.0", 44 | "typescript": "^5.4.5" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/routes/feedback.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import Message from "../models/Feedback"; 3 | import { Date, Types } from "mongoose"; 4 | import { AuthRequest, auth } from "../middleware/authorization"; 5 | 6 | const router = express.Router(); 7 | 8 | // @route GET /message/: 9 | // @desc Get messages about this coin 10 | // @access Public 11 | router.get('/coin/:coinId', (req, res) => { 12 | const coinId: string = req.params.coinId; 13 | console.log(coinId) 14 | Message.find({ coinId }).populate('coinId','sender').then(messages => res.status(200).send(messages)) 15 | .catch(err => res.status(400).json(err)); 16 | }) 17 | 18 | // @route GET /message/: 19 | // @desc Get messages about this user 20 | // @access Public 21 | router.get('/user/:userId', (req, res) => { 22 | const sender: string = req.params.userId; 23 | Message.find({ sender }).then(messages => res.status(200).send(messages)) 24 | .catch(err => res.status(400).json(err)); 25 | }) 26 | 27 | // @route POST /message/ 28 | // @desc Save new Message 29 | // @access Public 30 | router.post('/', async (req, res) => { 31 | const { body } = req; 32 | try { 33 | const newMsg = new Message(body); 34 | const messages = await newMsg.save() 35 | return res.status(200).send(messages) 36 | } catch (err) { 37 | return res.status(400).json(err) 38 | } 39 | }) 40 | 41 | export default router; -------------------------------------------------------------------------------- /src/program/cli/errors/index.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from "@solana/web3.js" 2 | import { PROGRAM_ID } from "../programId" 3 | import * as anchor from "./anchor" 4 | import * as custom from "./custom" 5 | 6 | export function fromCode( 7 | code: number, 8 | logs?: string[] 9 | ): custom.CustomError | anchor.AnchorError | null { 10 | return code >= 6000 11 | ? custom.fromCode(code, logs) 12 | : anchor.fromCode(code, logs) 13 | } 14 | 15 | function hasOwnProperty( 16 | obj: X, 17 | prop: Y 18 | ): obj is X & Record { 19 | return Object.hasOwnProperty.call(obj, prop) 20 | } 21 | 22 | const errorRe = /Program (\w+) failed: custom program error: (\w+)/ 23 | 24 | export function fromTxError( 25 | err: unknown, 26 | programId: PublicKey = PROGRAM_ID 27 | ): custom.CustomError | anchor.AnchorError | null { 28 | if ( 29 | typeof err !== "object" || 30 | err === null || 31 | !hasOwnProperty(err, "logs") || 32 | !Array.isArray(err.logs) 33 | ) { 34 | return null 35 | } 36 | 37 | let firstMatch: RegExpExecArray | null = null 38 | for (const logLine of err.logs) { 39 | firstMatch = errorRe.exec(logLine) 40 | if (firstMatch !== null) { 41 | break 42 | } 43 | } 44 | 45 | if (firstMatch === null) { 46 | return null 47 | } 48 | 49 | const [programIdRaw, codeRaw] = firstMatch.slice(1) 50 | if (programIdRaw !== programId.toString()) { 51 | return null 52 | } 53 | 54 | let errorCode: number 55 | try { 56 | errorCode = parseInt(codeRaw, 16) 57 | } catch (parseErr) { 58 | return null 59 | } 60 | 61 | return fromCode(errorCode, err.logs) 62 | } 63 | -------------------------------------------------------------------------------- /src/program/cli/instructions/initialize.ts: -------------------------------------------------------------------------------- 1 | import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface InitializeArgs { 7 | fee: number 8 | } 9 | 10 | export interface InitializeAccounts { 11 | dexConfigurationAccount: PublicKey 12 | /** CHECK */ 13 | globalAccount: PublicKey 14 | admin: PublicKey 15 | rent: PublicKey 16 | systemProgram: PublicKey 17 | } 18 | 19 | export const layout = borsh.struct([borsh.f64("fee")]) 20 | 21 | export function initialize( 22 | args: InitializeArgs, 23 | accounts: InitializeAccounts, 24 | programId: PublicKey = PROGRAM_ID 25 | ) { 26 | const keys: Array = [ 27 | { 28 | pubkey: accounts.dexConfigurationAccount, 29 | isSigner: false, 30 | isWritable: true, 31 | }, 32 | { pubkey: accounts.globalAccount, isSigner: false, isWritable: true }, 33 | { pubkey: accounts.admin, isSigner: true, isWritable: true }, 34 | { pubkey: accounts.rent, isSigner: false, isWritable: false }, 35 | { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, 36 | ] 37 | const identifier = Buffer.from([175, 175, 109, 31, 13, 152, 155, 237]) 38 | const buffer = Buffer.alloc(1000) 39 | const len = layout.encode( 40 | { 41 | fee: args.fee, 42 | }, 43 | buffer 44 | ) 45 | const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) 46 | const ix = new TransactionInstruction({ keys, programId, data }) 47 | return ix 48 | } 49 | -------------------------------------------------------------------------------- /src/program/cli/accounts/CurveConfiguration.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, Connection } from "@solana/web3.js" 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface CurveConfigurationFields { 7 | fees: number 8 | } 9 | 10 | export interface CurveConfigurationJSON { 11 | fees: number 12 | } 13 | 14 | export class CurveConfiguration { 15 | readonly fees: number 16 | 17 | static readonly discriminator = Buffer.from([ 18 | 225, 242, 252, 198, 63, 77, 56, 255, 19 | ]) 20 | 21 | static readonly layout = borsh.struct([borsh.f64("fees")]) 22 | 23 | constructor(fields: CurveConfigurationFields) { 24 | this.fees = fields.fees 25 | } 26 | 27 | static async fetch( 28 | c: Connection, 29 | address: PublicKey, 30 | programId: PublicKey = PROGRAM_ID 31 | ): Promise { 32 | const info = await c.getAccountInfo(address) 33 | 34 | if (info === null) { 35 | return null 36 | } 37 | if (!info.owner.equals(programId)) { 38 | throw new Error("account doesn't belong to this program") 39 | } 40 | 41 | return this.decode(info.data) 42 | } 43 | 44 | static async fetchMultiple( 45 | c: Connection, 46 | addresses: PublicKey[], 47 | programId: PublicKey = PROGRAM_ID 48 | ): Promise> { 49 | const infos = await c.getMultipleAccountsInfo(addresses) 50 | 51 | return infos.map((info) => { 52 | if (info === null) { 53 | return null 54 | } 55 | if (!info.owner.equals(programId)) { 56 | throw new Error("account doesn't belong to this program") 57 | } 58 | 59 | return this.decode(info.data) 60 | }) 61 | } 62 | 63 | static decode(data: Buffer): CurveConfiguration { 64 | if (!data.slice(0, 8).equals(CurveConfiguration.discriminator)) { 65 | throw new Error("invalid account discriminator") 66 | } 67 | 68 | const dec = CurveConfiguration.layout.decode(data.slice(8)) 69 | 70 | return new CurveConfiguration({ 71 | fees: dec.fees, 72 | }) 73 | } 74 | 75 | toJSON(): CurveConfigurationJSON { 76 | return { 77 | fees: this.fees, 78 | } 79 | } 80 | 81 | static fromJSON(obj: CurveConfigurationJSON): CurveConfiguration { 82 | return new CurveConfiguration({ 83 | fees: obj.fees, 84 | }) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/program/cli/instructions/swap.ts: -------------------------------------------------------------------------------- 1 | import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface SwapArgs { 7 | amount: BN 8 | style: BN 9 | } 10 | 11 | export interface SwapAccounts { 12 | dexConfigurationAccount: PublicKey 13 | pool: PublicKey 14 | /** CHECK */ 15 | globalAccount: PublicKey 16 | mintTokenOne: PublicKey 17 | poolTokenAccountOne: PublicKey 18 | userTokenAccountOne: PublicKey 19 | user: PublicKey 20 | rent: PublicKey 21 | systemProgram: PublicKey 22 | tokenProgram: PublicKey 23 | associatedTokenProgram: PublicKey 24 | } 25 | 26 | export const layout = borsh.struct([borsh.u64("amount"), borsh.u64("style")]) 27 | 28 | export function swap( 29 | args: SwapArgs, 30 | accounts: SwapAccounts, 31 | programId: PublicKey = PROGRAM_ID 32 | ) { 33 | const keys: Array = [ 34 | { 35 | pubkey: accounts.dexConfigurationAccount, 36 | isSigner: false, 37 | isWritable: true, 38 | }, 39 | { pubkey: accounts.pool, isSigner: false, isWritable: true }, 40 | { pubkey: accounts.globalAccount, isSigner: false, isWritable: true }, 41 | { pubkey: accounts.mintTokenOne, isSigner: false, isWritable: true }, 42 | { pubkey: accounts.poolTokenAccountOne, isSigner: false, isWritable: true }, 43 | { pubkey: accounts.userTokenAccountOne, isSigner: false, isWritable: true }, 44 | { pubkey: accounts.user, isSigner: true, isWritable: true }, 45 | { pubkey: accounts.rent, isSigner: false, isWritable: false }, 46 | { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, 47 | { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false }, 48 | { 49 | pubkey: accounts.associatedTokenProgram, 50 | isSigner: false, 51 | isWritable: false, 52 | }, 53 | ] 54 | const identifier = Buffer.from([248, 198, 158, 145, 225, 117, 135, 200]) 55 | const buffer = Buffer.alloc(1000) 56 | const len = layout.encode( 57 | { 58 | amount: args.amount, 59 | style: args.style, 60 | }, 61 | buffer 62 | ) 63 | const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) 64 | const ix = new TransactionInstruction({ keys, programId, data }) 65 | return ix 66 | } 67 | -------------------------------------------------------------------------------- /src/program/cli/accounts/LiquidityProvider.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, Connection } from "@solana/web3.js" 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface LiquidityProviderFields { 7 | shares: BN 8 | } 9 | 10 | export interface LiquidityProviderJSON { 11 | shares: string 12 | } 13 | 14 | export class LiquidityProvider { 15 | readonly shares: BN 16 | 17 | static readonly discriminator = Buffer.from([ 18 | 219, 241, 238, 133, 56, 225, 229, 191, 19 | ]) 20 | 21 | static readonly layout = borsh.struct([borsh.u64("shares")]) 22 | 23 | constructor(fields: LiquidityProviderFields) { 24 | this.shares = fields.shares 25 | } 26 | 27 | static async fetch( 28 | c: Connection, 29 | address: PublicKey, 30 | programId: PublicKey = PROGRAM_ID 31 | ): Promise { 32 | const info = await c.getAccountInfo(address) 33 | 34 | if (info === null) { 35 | return null 36 | } 37 | if (!info.owner.equals(programId)) { 38 | throw new Error("account doesn't belong to this program") 39 | } 40 | 41 | return this.decode(info.data) 42 | } 43 | 44 | static async fetchMultiple( 45 | c: Connection, 46 | addresses: PublicKey[], 47 | programId: PublicKey = PROGRAM_ID 48 | ): Promise> { 49 | const infos = await c.getMultipleAccountsInfo(addresses) 50 | 51 | return infos.map((info) => { 52 | if (info === null) { 53 | return null 54 | } 55 | if (!info.owner.equals(programId)) { 56 | throw new Error("account doesn't belong to this program") 57 | } 58 | 59 | return this.decode(info.data) 60 | }) 61 | } 62 | 63 | static decode(data: Buffer): LiquidityProvider { 64 | if (!data.slice(0, 8).equals(LiquidityProvider.discriminator)) { 65 | throw new Error("invalid account discriminator") 66 | } 67 | 68 | const dec = LiquidityProvider.layout.decode(data.slice(8)) 69 | 70 | return new LiquidityProvider({ 71 | shares: dec.shares, 72 | }) 73 | } 74 | 75 | toJSON(): LiquidityProviderJSON { 76 | return { 77 | shares: this.shares.toString(), 78 | } 79 | } 80 | 81 | static fromJSON(obj: LiquidityProviderJSON): LiquidityProvider { 82 | return new LiquidityProvider({ 83 | shares: new BN(obj.shares), 84 | }) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/program/cli/instructions/addLiquidity.ts: -------------------------------------------------------------------------------- 1 | import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface AddLiquidityArgs { 7 | amountOne: BN 8 | amountTwo: BN 9 | } 10 | 11 | export interface AddLiquidityAccounts { 12 | pool: PublicKey 13 | /** CHECK */ 14 | globalAccount: PublicKey 15 | liquidityProviderAccount: PublicKey 16 | mintTokenOne: PublicKey 17 | poolTokenAccountOne: PublicKey 18 | userTokenAccountOne: PublicKey 19 | user: PublicKey 20 | rent: PublicKey 21 | systemProgram: PublicKey 22 | tokenProgram: PublicKey 23 | associatedTokenProgram: PublicKey 24 | } 25 | 26 | export const layout = borsh.struct([ 27 | borsh.u64("amountOne"), 28 | borsh.u64("amountTwo"), 29 | ]) 30 | 31 | export function addLiquidity( 32 | args: AddLiquidityArgs, 33 | accounts: AddLiquidityAccounts, 34 | programId: PublicKey = PROGRAM_ID 35 | ) { 36 | const keys: Array = [ 37 | { pubkey: accounts.pool, isSigner: false, isWritable: true }, 38 | { pubkey: accounts.globalAccount, isSigner: false, isWritable: true }, 39 | { 40 | pubkey: accounts.liquidityProviderAccount, 41 | isSigner: false, 42 | isWritable: true, 43 | }, 44 | { pubkey: accounts.mintTokenOne, isSigner: false, isWritable: true }, 45 | { pubkey: accounts.poolTokenAccountOne, isSigner: false, isWritable: true }, 46 | { pubkey: accounts.userTokenAccountOne, isSigner: false, isWritable: true }, 47 | { pubkey: accounts.user, isSigner: true, isWritable: true }, 48 | { pubkey: accounts.rent, isSigner: false, isWritable: false }, 49 | { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, 50 | { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false }, 51 | { 52 | pubkey: accounts.associatedTokenProgram, 53 | isSigner: false, 54 | isWritable: false, 55 | }, 56 | ] 57 | const identifier = Buffer.from([181, 157, 89, 67, 143, 182, 52, 72]) 58 | const buffer = Buffer.alloc(1000) 59 | const len = layout.encode( 60 | { 61 | amountOne: args.amountOne, 62 | amountTwo: args.amountTwo, 63 | }, 64 | buffer 65 | ) 66 | const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) 67 | const ix = new TransactionInstruction({ keys, programId, data }) 68 | return ix 69 | } 70 | -------------------------------------------------------------------------------- /src/utils/chart.ts: -------------------------------------------------------------------------------- 1 | import Coin from "../models/Coin"; 2 | import CoinStatus from "../models/CoinsStatus"; 3 | import { logger } from "../sockets/logger"; 4 | import { CandlePrice, priceFeedInfo } from "./type"; 5 | 6 | export async function fetchPriceChartData(pairIndex: number, start: number, end: number, range: number, token: string) { 7 | logger.info(` fetching chart data for pairIndex: ${pairIndex}, start: ${start}, end: ${end}, range: ${range}, token: ${token}`); 8 | 9 | // load price histories from DB 10 | const priceFeeds: priceFeedInfo[] | undefined = await Coin.findOne({ token }) 11 | .then(async (coin) => { 12 | const data = await CoinStatus.findOne({ coinId: coin?._id }, { 'record.price': 1, 'record.time': 1 }) 13 | if (data == undefined) return; 14 | return data?.record; 15 | }); 16 | if(priceFeeds== undefined) return; 17 | const priceHistory = priceFeeds.map((feed) => { 18 | let price = feed.price; 19 | 20 | return { 21 | price: price, 22 | ts: feed.time.getTime() / 1000, 23 | }; 24 | }).sort((price1, price2) => price1.ts - price2.ts); 25 | 26 | if (!priceHistory.length) return []; 27 | 28 | let candlePeriod = 60; // 1 min default 29 | switch (range) { 30 | case 1: 31 | // default candle period 32 | break; 33 | case 5: 34 | candlePeriod = 300; // 5 mins 35 | break; 36 | case 15: 37 | candlePeriod = 1_800; // 30 mins 38 | break; 39 | case 60: 40 | candlePeriod = 3_600; // 1 hr 41 | break; 42 | case 120: 43 | candlePeriod = 7_200; // 2 hrs 44 | break; 45 | } 46 | 47 | // convert price feed to candle price data 48 | let cdStart = Math.floor(priceHistory[0].ts / candlePeriod) * candlePeriod; 49 | let cdEnd = Math.floor(priceHistory[priceHistory.length - 1].ts / candlePeriod) * candlePeriod; 50 | 51 | let cdFeeds: CandlePrice[] = []; 52 | let pIndex = 0; 53 | for (let curCdStart = cdStart; curCdStart <= cdEnd; curCdStart += candlePeriod) { 54 | let st = priceHistory[pIndex].price; 55 | let hi = priceHistory[pIndex].price; 56 | let lo = priceHistory[pIndex].price; 57 | let en = priceHistory[pIndex].price; 58 | let prevIndex = pIndex; 59 | for (; pIndex < priceHistory.length; ) { 60 | if (hi < priceHistory[pIndex].price) hi = priceHistory[pIndex].price; 61 | if (lo > priceHistory[pIndex].price) lo = priceHistory[pIndex].price; 62 | en = priceHistory[pIndex].price; 63 | 64 | // break new candle data starts 65 | if (priceHistory[pIndex].ts >= curCdStart + candlePeriod) break; 66 | pIndex++; 67 | } 68 | if (prevIndex !== pIndex) 69 | cdFeeds.push({ 70 | open: st, 71 | high: hi, 72 | low: lo, 73 | close: en, 74 | time: curCdStart, 75 | }); 76 | } 77 | 78 | return cdFeeds; 79 | } 80 | -------------------------------------------------------------------------------- /src/routes/coin.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import Joi, { string } from "joi"; 3 | import Coin from "../models/Coin"; 4 | import { AuthRequest, auth } from "../middleware/authorization"; 5 | import { createToken, swapTx } from "../program/web3"; 6 | import { Types } from "mongoose"; 7 | import { Keypair, PublicKey } from "@solana/web3.js"; 8 | import CoinStatus from "../models/CoinsStatus"; 9 | 10 | 11 | const router = express.Router(); 12 | 13 | // @route GET /coin/ 14 | // @desc Get all created coins 15 | // @access Public 16 | router.get('/', async (req, res) => { 17 | const coins = await Coin.find({}).populate('creator') 18 | return res.status(200).send(coins) 19 | }) 20 | // @route GET /coin/:userID 21 | // @desc Get coins created by userID 22 | // @access Public 23 | router.get('/:id', (req, res) => { 24 | const id = req.params.id; 25 | Coin.findOne({ _id: id }).populate('creator').then(users => res.status(200).send(users)).catch(err => res.status(400).json('Nothing')) 26 | }) 27 | 28 | 29 | // @route GET /coin/user/:userID 30 | // @desc Get coins created by userID 31 | // @access Public 32 | router.get('/user/:userID', (req, res) => { 33 | const creator = req.params.userID; 34 | Coin.find({ creator }).populate('creator').then(users => res.status(200).send(users)).catch(err => res.status(400).json('Nothing')) 35 | }) 36 | 37 | // @route POST /coin 38 | // @desc Create coin 39 | // @access Public 40 | router.post('/', async (req, res) => { 41 | console.log("++++++++Create coin++++++++++", req.body.creator) 42 | const { body } = req; 43 | const UserSchema = Joi.object().keys({ 44 | creator: Joi.string().required(), 45 | name: Joi.string().required(), 46 | ticker: Joi.string().required(), 47 | description: Joi.string(), 48 | url: Joi.string().required(), 49 | 50 | // amount: Joi.number().required() 51 | }); 52 | // console.log(req.user); 53 | const inputValidation = UserSchema.validate(body); 54 | // console.log(inputValidation) 55 | if (inputValidation.error) { 56 | return res.status(400).json({ error: inputValidation.error.details[0].message }) 57 | } 58 | // Create Token with UMI 59 | const token:any = await createToken({ 60 | name: req.body.name, 61 | ticker: req.body.ticker, 62 | url: req.body.url, 63 | creator: req.body.creator, 64 | description: req.body.description, 65 | }); 66 | console.log("token====", token) 67 | if(token =="transaction failed") res.status(400).json("fialed") 68 | res.status(200).send(token) 69 | // const name = body.name; 70 | // const coinName = await Coin.findOne({ name }) 71 | // if (coinName) return res.status(400).json("Name is invalid") 72 | // const coinData = await Coin.findOne({ token }) 73 | // if (coinData) return res.status(400).json("This coin is already created.") 74 | 75 | }) 76 | 77 | // @route POST /coin/:coinId 78 | // @desc Update coin 79 | // @access Public 80 | router.post('/:coinId', (req, res) => { 81 | const { body } = req; 82 | const coinId = req.params.coinId; 83 | console.log(body) 84 | Coin.updateOne({ _id: coinId }, { $set: body }) 85 | .then((updateCoin) => { 86 | console.log(updateCoin) 87 | res.status(200).send(updateCoin) 88 | }) 89 | .catch(err => res.status(400).json("update is failed!!")); 90 | }) 91 | 92 | export default router; 93 | -------------------------------------------------------------------------------- /src/program/cli/instructions/createRaydiumPool.ts: -------------------------------------------------------------------------------- 1 | import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface CreateRaydiumPoolArgs { 7 | nonce: number 8 | initPcAmount: BN 9 | initCoinAmount: BN 10 | } 11 | 12 | export interface CreateRaydiumPoolAccounts { 13 | ammProgram: PublicKey 14 | tokenProgram: PublicKey 15 | associatedTokenProgram: PublicKey 16 | systemProgram: PublicKey 17 | sysvarRent: PublicKey 18 | amm: PublicKey 19 | ammAuthority: PublicKey 20 | ammOpenOrders: PublicKey 21 | lpMint: PublicKey 22 | coinMint: PublicKey 23 | pcMint: PublicKey 24 | coinVault: PublicKey 25 | pcVault: PublicKey 26 | targetOrders: PublicKey 27 | ammConfig: PublicKey 28 | feeDestination: PublicKey 29 | marketProgram: PublicKey 30 | market: PublicKey 31 | userWallet: PublicKey 32 | userTokenCoin: PublicKey 33 | userTokenPc: PublicKey 34 | userTokenLp: PublicKey 35 | } 36 | 37 | export const layout = borsh.struct([ 38 | borsh.u8("nonce"), 39 | borsh.u64("initPcAmount"), 40 | borsh.u64("initCoinAmount"), 41 | ]) 42 | 43 | export function createRaydiumPool( 44 | args: CreateRaydiumPoolArgs, 45 | accounts: CreateRaydiumPoolAccounts, 46 | programId: PublicKey = PROGRAM_ID 47 | ) { 48 | const keys: Array = [ 49 | { pubkey: accounts.ammProgram, isSigner: false, isWritable: false }, 50 | { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false }, 51 | { 52 | pubkey: accounts.associatedTokenProgram, 53 | isSigner: false, 54 | isWritable: false, 55 | }, 56 | { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, 57 | { pubkey: accounts.sysvarRent, isSigner: false, isWritable: false }, 58 | { pubkey: accounts.amm, isSigner: false, isWritable: true }, 59 | { pubkey: accounts.ammAuthority, isSigner: false, isWritable: false }, 60 | { pubkey: accounts.ammOpenOrders, isSigner: false, isWritable: true }, 61 | { pubkey: accounts.lpMint, isSigner: false, isWritable: true }, 62 | { pubkey: accounts.coinMint, isSigner: false, isWritable: false }, 63 | { pubkey: accounts.pcMint, isSigner: false, isWritable: false }, 64 | { pubkey: accounts.coinVault, isSigner: false, isWritable: true }, 65 | { pubkey: accounts.pcVault, isSigner: false, isWritable: true }, 66 | { pubkey: accounts.targetOrders, isSigner: false, isWritable: true }, 67 | { pubkey: accounts.ammConfig, isSigner: false, isWritable: false }, 68 | { pubkey: accounts.feeDestination, isSigner: false, isWritable: true }, 69 | { pubkey: accounts.marketProgram, isSigner: false, isWritable: false }, 70 | { pubkey: accounts.market, isSigner: false, isWritable: false }, 71 | { pubkey: accounts.userWallet, isSigner: true, isWritable: true }, 72 | { pubkey: accounts.userTokenCoin, isSigner: false, isWritable: true }, 73 | { pubkey: accounts.userTokenPc, isSigner: false, isWritable: true }, 74 | { pubkey: accounts.userTokenLp, isSigner: false, isWritable: true }, 75 | ] 76 | const identifier = Buffer.from([65, 45, 119, 77, 204, 178, 84, 2]) 77 | const buffer = Buffer.alloc(1000) 78 | const len = layout.encode( 79 | { 80 | nonce: args.nonce, 81 | initPcAmount: args.initPcAmount, 82 | initCoinAmount: args.initCoinAmount, 83 | }, 84 | buffer 85 | ) 86 | const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) 87 | const ix = new TransactionInstruction({ keys, programId, data }) 88 | return ix 89 | } 90 | -------------------------------------------------------------------------------- /src/program/cli/instructions/removeLiquidity.ts: -------------------------------------------------------------------------------- 1 | import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface RemoveLiquidityArgs { 7 | nonce: number 8 | initPcAmount: BN 9 | } 10 | 11 | export interface RemoveLiquidityAccounts { 12 | pool: PublicKey 13 | /** CHECK */ 14 | globalAccount: PublicKey 15 | ammProgram: PublicKey 16 | tokenProgram: PublicKey 17 | associatedTokenProgram: PublicKey 18 | systemProgram: PublicKey 19 | sysvarRent: PublicKey 20 | amm: PublicKey 21 | ammAuthority: PublicKey 22 | ammOpenOrders: PublicKey 23 | lpMint: PublicKey 24 | coinMint: PublicKey 25 | pcMint: PublicKey 26 | coinVault: PublicKey 27 | pcVault: PublicKey 28 | targetOrders: PublicKey 29 | ammConfig: PublicKey 30 | feeDestination: PublicKey 31 | marketProgram: PublicKey 32 | market: PublicKey 33 | userWallet: PublicKey 34 | userTokenCoin: PublicKey 35 | userTokenPc: PublicKey 36 | userTokenLp: PublicKey 37 | } 38 | 39 | export const layout = borsh.struct([ 40 | borsh.u8("nonce"), 41 | borsh.u64("initPcAmount"), 42 | ]) 43 | 44 | export function removeLiquidity( 45 | args: RemoveLiquidityArgs, 46 | accounts: RemoveLiquidityAccounts, 47 | programId: PublicKey = PROGRAM_ID 48 | ) { 49 | const keys: Array = [ 50 | { pubkey: accounts.pool, isSigner: false, isWritable: true }, 51 | { pubkey: accounts.globalAccount, isSigner: false, isWritable: true }, 52 | { pubkey: accounts.ammProgram, isSigner: false, isWritable: false }, 53 | { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false }, 54 | { 55 | pubkey: accounts.associatedTokenProgram, 56 | isSigner: false, 57 | isWritable: false, 58 | }, 59 | { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, 60 | { pubkey: accounts.sysvarRent, isSigner: false, isWritable: false }, 61 | { pubkey: accounts.amm, isSigner: false, isWritable: true }, 62 | { pubkey: accounts.ammAuthority, isSigner: false, isWritable: false }, 63 | { pubkey: accounts.ammOpenOrders, isSigner: false, isWritable: true }, 64 | { pubkey: accounts.lpMint, isSigner: false, isWritable: true }, 65 | { pubkey: accounts.coinMint, isSigner: false, isWritable: true }, 66 | { pubkey: accounts.pcMint, isSigner: false, isWritable: true }, 67 | { pubkey: accounts.coinVault, isSigner: false, isWritable: true }, 68 | { pubkey: accounts.pcVault, isSigner: false, isWritable: true }, 69 | { pubkey: accounts.targetOrders, isSigner: false, isWritable: true }, 70 | { pubkey: accounts.ammConfig, isSigner: false, isWritable: true }, 71 | { pubkey: accounts.feeDestination, isSigner: false, isWritable: true }, 72 | { pubkey: accounts.marketProgram, isSigner: false, isWritable: false }, 73 | { pubkey: accounts.market, isSigner: false, isWritable: true }, 74 | { pubkey: accounts.userWallet, isSigner: true, isWritable: true }, 75 | { pubkey: accounts.userTokenCoin, isSigner: false, isWritable: true }, 76 | { pubkey: accounts.userTokenPc, isSigner: false, isWritable: true }, 77 | { pubkey: accounts.userTokenLp, isSigner: false, isWritable: true }, 78 | ] 79 | const identifier = Buffer.from([80, 85, 209, 72, 24, 206, 177, 108]) 80 | const buffer = Buffer.alloc(1000) 81 | const len = layout.encode( 82 | { 83 | nonce: args.nonce, 84 | initPcAmount: args.initPcAmount, 85 | }, 86 | buffer 87 | ) 88 | const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) 89 | const ix = new TransactionInstruction({ keys, programId, data }) 90 | return ix 91 | } 92 | -------------------------------------------------------------------------------- /src/program/cli/accounts/LiquidityPool.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, Connection } from "@solana/web3.js" 2 | import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars 3 | import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars 4 | import { PROGRAM_ID } from "../programId" 5 | 6 | export interface LiquidityPoolFields { 7 | tokenOne: PublicKey 8 | tokenTwo: PublicKey 9 | totalSupply: BN 10 | reserveOne: BN 11 | reserveTwo: BN 12 | bump: number 13 | } 14 | 15 | export interface LiquidityPoolJSON { 16 | tokenOne: string 17 | tokenTwo: string 18 | totalSupply: string 19 | reserveOne: string 20 | reserveTwo: string 21 | bump: number 22 | } 23 | 24 | export class LiquidityPool { 25 | readonly tokenOne: PublicKey 26 | readonly tokenTwo: PublicKey 27 | readonly totalSupply: BN 28 | readonly reserveOne: BN 29 | readonly reserveTwo: BN 30 | readonly bump: number 31 | 32 | static readonly discriminator = Buffer.from([ 33 | 66, 38, 17, 64, 188, 80, 68, 129, 34 | ]) 35 | 36 | static readonly layout = borsh.struct([ 37 | borsh.publicKey("tokenOne"), 38 | borsh.publicKey("tokenTwo"), 39 | borsh.u64("totalSupply"), 40 | borsh.u64("reserveOne"), 41 | borsh.u64("reserveTwo"), 42 | borsh.u8("bump"), 43 | ]) 44 | 45 | constructor(fields: LiquidityPoolFields) { 46 | this.tokenOne = fields.tokenOne 47 | this.tokenTwo = fields.tokenTwo 48 | this.totalSupply = fields.totalSupply 49 | this.reserveOne = fields.reserveOne 50 | this.reserveTwo = fields.reserveTwo 51 | this.bump = fields.bump 52 | } 53 | 54 | static async fetch( 55 | c: Connection, 56 | address: PublicKey, 57 | programId: PublicKey = PROGRAM_ID 58 | ): Promise { 59 | const info = await c.getAccountInfo(address) 60 | 61 | if (info === null) { 62 | return null 63 | } 64 | if (!info.owner.equals(programId)) { 65 | throw new Error("account doesn't belong to this program") 66 | } 67 | 68 | return this.decode(info.data) 69 | } 70 | 71 | static async fetchMultiple( 72 | c: Connection, 73 | addresses: PublicKey[], 74 | programId: PublicKey = PROGRAM_ID 75 | ): Promise> { 76 | const infos = await c.getMultipleAccountsInfo(addresses) 77 | 78 | return infos.map((info) => { 79 | if (info === null) { 80 | return null 81 | } 82 | if (!info.owner.equals(programId)) { 83 | throw new Error("account doesn't belong to this program") 84 | } 85 | 86 | return this.decode(info.data) 87 | }) 88 | } 89 | 90 | static decode(data: Buffer): LiquidityPool { 91 | if (!data.slice(0, 8).equals(LiquidityPool.discriminator)) { 92 | throw new Error("invalid account discriminator") 93 | } 94 | 95 | const dec = LiquidityPool.layout.decode(data.slice(8)) 96 | 97 | return new LiquidityPool({ 98 | tokenOne: dec.tokenOne, 99 | tokenTwo: dec.tokenTwo, 100 | totalSupply: dec.totalSupply, 101 | reserveOne: dec.reserveOne, 102 | reserveTwo: dec.reserveTwo, 103 | bump: dec.bump, 104 | }) 105 | } 106 | 107 | toJSON(): LiquidityPoolJSON { 108 | return { 109 | tokenOne: this.tokenOne.toString(), 110 | tokenTwo: this.tokenTwo.toString(), 111 | totalSupply: this.totalSupply.toString(), 112 | reserveOne: this.reserveOne.toString(), 113 | reserveTwo: this.reserveTwo.toString(), 114 | bump: this.bump, 115 | } 116 | } 117 | 118 | static fromJSON(obj: LiquidityPoolJSON): LiquidityPool { 119 | return new LiquidityPool({ 120 | tokenOne: new PublicKey(obj.tokenOne), 121 | tokenTwo: new PublicKey(obj.tokenTwo), 122 | totalSupply: new BN(obj.totalSupply), 123 | reserveOne: new BN(obj.reserveOne), 124 | reserveTwo: new BN(obj.reserveTwo), 125 | bump: obj.bump, 126 | }) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/program/cli/errors/custom.ts: -------------------------------------------------------------------------------- 1 | export type CustomError = 2 | | DuplicateTokenNotAllowed 3 | | FailedToAllocateShares 4 | | FailedToDeallocateShares 5 | | InsufficientShares 6 | | InsufficientFunds 7 | | InvalidAmount 8 | | InvalidFee 9 | | FailedToAddLiquidity 10 | | FailedToRemoveLiquidity 11 | | OverflowOrUnderflowOccurred 12 | 13 | export class DuplicateTokenNotAllowed extends Error { 14 | static readonly code = 6000 15 | readonly code = 6000 16 | readonly name = "DuplicateTokenNotAllowed" 17 | readonly msg = "Duplicate tokens are not allowed" 18 | 19 | constructor(readonly logs?: string[]) { 20 | super("6000: Duplicate tokens are not allowed") 21 | } 22 | } 23 | 24 | export class FailedToAllocateShares extends Error { 25 | static readonly code = 6001 26 | readonly code = 6001 27 | readonly name = "FailedToAllocateShares" 28 | readonly msg = "Failed to allocate shares" 29 | 30 | constructor(readonly logs?: string[]) { 31 | super("6001: Failed to allocate shares") 32 | } 33 | } 34 | 35 | export class FailedToDeallocateShares extends Error { 36 | static readonly code = 6002 37 | readonly code = 6002 38 | readonly name = "FailedToDeallocateShares" 39 | readonly msg = "Failed to deallocate shares" 40 | 41 | constructor(readonly logs?: string[]) { 42 | super("6002: Failed to deallocate shares") 43 | } 44 | } 45 | 46 | export class InsufficientShares extends Error { 47 | static readonly code = 6003 48 | readonly code = 6003 49 | readonly name = "InsufficientShares" 50 | readonly msg = "Insufficient shares" 51 | 52 | constructor(readonly logs?: string[]) { 53 | super("6003: Insufficient shares") 54 | } 55 | } 56 | 57 | export class InsufficientFunds extends Error { 58 | static readonly code = 6004 59 | readonly code = 6004 60 | readonly name = "InsufficientFunds" 61 | readonly msg = "Insufficient funds to swap" 62 | 63 | constructor(readonly logs?: string[]) { 64 | super("6004: Insufficient funds to swap") 65 | } 66 | } 67 | 68 | export class InvalidAmount extends Error { 69 | static readonly code = 6005 70 | readonly code = 6005 71 | readonly name = "InvalidAmount" 72 | readonly msg = "Invalid amount to swap" 73 | 74 | constructor(readonly logs?: string[]) { 75 | super("6005: Invalid amount to swap") 76 | } 77 | } 78 | 79 | export class InvalidFee extends Error { 80 | static readonly code = 6006 81 | readonly code = 6006 82 | readonly name = "InvalidFee" 83 | readonly msg = "Invalid fee" 84 | 85 | constructor(readonly logs?: string[]) { 86 | super("6006: Invalid fee") 87 | } 88 | } 89 | 90 | export class FailedToAddLiquidity extends Error { 91 | static readonly code = 6007 92 | readonly code = 6007 93 | readonly name = "FailedToAddLiquidity" 94 | readonly msg = "Failed to add liquidity" 95 | 96 | constructor(readonly logs?: string[]) { 97 | super("6007: Failed to add liquidity") 98 | } 99 | } 100 | 101 | export class FailedToRemoveLiquidity extends Error { 102 | static readonly code = 6008 103 | readonly code = 6008 104 | readonly name = "FailedToRemoveLiquidity" 105 | readonly msg = "Failed to remove liquidity" 106 | 107 | constructor(readonly logs?: string[]) { 108 | super("6008: Failed to remove liquidity") 109 | } 110 | } 111 | 112 | export class OverflowOrUnderflowOccurred extends Error { 113 | static readonly code = 6009 114 | readonly code = 6009 115 | readonly name = "OverflowOrUnderflowOccurred" 116 | readonly msg = "Overflow or underflow occured" 117 | 118 | constructor(readonly logs?: string[]) { 119 | super("6009: Overflow or underflow occured") 120 | } 121 | } 122 | 123 | export function fromCode(code: number, logs?: string[]): CustomError | null { 124 | switch (code) { 125 | case 6000: 126 | return new DuplicateTokenNotAllowed(logs) 127 | case 6001: 128 | return new FailedToAllocateShares(logs) 129 | case 6002: 130 | return new FailedToDeallocateShares(logs) 131 | case 6003: 132 | return new InsufficientShares(logs) 133 | case 6004: 134 | return new InsufficientFunds(logs) 135 | case 6005: 136 | return new InvalidAmount(logs) 137 | case 6006: 138 | return new InvalidFee(logs) 139 | case 6007: 140 | return new FailedToAddLiquidity(logs) 141 | case 6008: 142 | return new FailedToRemoveLiquidity(logs) 143 | case 6009: 144 | return new OverflowOrUnderflowOccurred(logs) 145 | } 146 | 147 | return null 148 | } 149 | -------------------------------------------------------------------------------- /src/routes/user.ts: -------------------------------------------------------------------------------- 1 | // routes/users.js 2 | import express from 'express'; 3 | import User from '../models/User'; 4 | import PendingUser from '../models/PendingUser'; 5 | import crypto from 'crypto' 6 | import Joi from 'joi'; 7 | import base58 from 'bs58'; 8 | import nacl from 'tweetnacl'; 9 | import { PublicKey, Transaction } from '@solana/web3.js'; 10 | import jwt from 'jsonwebtoken'; 11 | 12 | 13 | const router = express.Router(); 14 | 15 | 16 | // @route POST api/users 17 | // @desc Resgister user 18 | // @access Public 19 | router.post('/', async (req, res) => { 20 | console.log("wallet connect") 21 | // Validate form 22 | const { body } = req; 23 | const UserSchema = Joi.object().keys({ 24 | name: Joi.string().required(), 25 | wallet: Joi.string().required(), 26 | isLedger: Joi.boolean().optional().required(), 27 | }) 28 | const inputValidation = UserSchema.validate(body); 29 | if (inputValidation.error) { 30 | return res.status(400).json({ error: inputValidation.error.details[0].message }) 31 | } 32 | const wallet = body.wallet; 33 | const userData = await User.findOne({ wallet }); 34 | console.log("userdata:", userData) 35 | console.log(!userData == false) 36 | if (!userData == false) return res.status(200).send(userData); 37 | const exisitingPendingUser = await PendingUser.findOne({ wallet }) 38 | console.log("pending:", exisitingPendingUser) 39 | if (exisitingPendingUser == null) { 40 | const nonce = crypto.randomBytes(8).toString('hex'); 41 | const newPendingUser = new PendingUser({ name: body.name, wallet, nonce, isLedger: body.isLedger }); 42 | console.log("newPendingUser::", newPendingUser) 43 | newPendingUser.save().then((user: PendingUserInfo) => { 44 | res.status(200).send(user) 45 | }); 46 | } else { 47 | res.status(400).json({ message: "A user with this wallet already requested." }); 48 | } 49 | }); 50 | 51 | // @route POST api/users/login 52 | // @desc Resgister user 53 | // @access Public 54 | router.post('/login', async (req, res) => { 55 | try { 56 | console.log(req.body) 57 | const { wallet } = req.body; 58 | const user = await User.findOne({ wallet }) 59 | if (!user) { 60 | res.status(404).json({ message: 'User not found' }); 61 | } else { 62 | console.log(user) 63 | const token = jwt.sign({ 64 | id: user._id, 65 | name: user.name, 66 | wallet 67 | }, 'secret', 68 | { 69 | algorithm: 'HS256', 70 | expiresIn: '60m', 71 | }) 72 | return res.status(200).json({ token }); 73 | } 74 | } catch (error) { 75 | res.status(500).json({ error }) 76 | } 77 | }) 78 | 79 | // @route POST api/users/:nonce 80 | // @desc Confirm and Register user 81 | // @access Public 82 | router.post('/confirm', async (req, res) => { 83 | console.log("req.body:::", req.body) 84 | const body = { 85 | name: req.body.name, 86 | wallet: req.body.wallet, 87 | isLedger: req.body.isLedger, 88 | signature: req.body.signature, 89 | nonce: req.body.nonce, 90 | } 91 | console.log("body", body) 92 | // Validate form 93 | const UserSchema = Joi.object().keys({ 94 | name: Joi.string().required(), 95 | wallet: Joi.string().required(), 96 | nonce: Joi.string().required(), 97 | signature: Joi.string().required(), 98 | isLedger: Joi.boolean().optional().required(), 99 | }) 100 | const inputValidation = UserSchema.validate(body); 101 | console.log(inputValidation) 102 | if (inputValidation.error) { 103 | return res.status(400).json({ error: inputValidation.error.details[0].message }) 104 | } 105 | console.log("validation OK") 106 | // const foundUser = await User.findOne({wallet : body.wallet}) 107 | // if(!foundUser == null ) return res.status(400).json("First of all, You have to register User") 108 | const foundNonce = await PendingUser.findOneAndDelete({ nonce: body.nonce }).exec(); 109 | if (foundNonce == null) return res.status(400).json("Your request expired") 110 | 111 | // nonce decode!! 112 | if (!body.isLedger) { 113 | const signatureUint8 = base58.decode(body.signature); 114 | const msgUint8 = new TextEncoder().encode(`${process.env.SIGN_IN_MSG} ${foundNonce.nonce}`); 115 | const pubKeyUint8 = base58.decode(body.wallet); 116 | const isValidSignature = nacl.sign.detached.verify(msgUint8, signatureUint8, pubKeyUint8); 117 | // const isValidSignature = true; 118 | if (!isValidSignature) return res.status(404).json({ error: "Invalid signature" }) 119 | } else { 120 | const ledgerSerializedTx = JSON.parse(body.signature); 121 | const signedTx = Transaction.from(Uint8Array.from(ledgerSerializedTx)); 122 | 123 | const feePayer = signedTx.feePayer?.toBase58() || ""; 124 | 125 | if (feePayer != body.wallet) { 126 | return res.status(400).json({ error: "Invalid wallet or fee payer" }); 127 | } 128 | 129 | const MEMO_PROGRAM_ID = new PublicKey( 130 | "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr" 131 | ); 132 | 133 | const inx = signedTx.instructions.find( 134 | (ix) => ix.programId.toBase58() == MEMO_PROGRAM_ID.toBase58() 135 | ); 136 | 137 | if (!inx) { 138 | return res 139 | .status(503) 140 | .json({ error: "Memo program couldn't be verified" }); 141 | } 142 | 143 | if (!signedTx.verifySignatures()) { 144 | return res 145 | .status(503) 146 | .json({ error: "Could not verify signatures" }); 147 | } 148 | } 149 | const userData = { 150 | name: body.name, 151 | wallet: body.wallet 152 | } 153 | const newUser = new User(userData); 154 | await newUser.save().then((user: UserInfo) => res.status(200).send(user)) 155 | 156 | }); 157 | 158 | // GET: Fetch user 159 | router.get('/', async (req, res) => { 160 | try { 161 | const users = await User.find({}); 162 | res.status(200).send(users); 163 | } catch (error) { 164 | res.status(500).send(error); 165 | } 166 | }); 167 | 168 | // GET: Fetch all users 169 | router.get('/:id', async (req, res) => { 170 | const id = req.params.id; 171 | console.log(id); 172 | try { 173 | const user = await User.findOne({ _id: id }); 174 | res.status(200).send(user); 175 | } catch (error) { 176 | res.status(500).send(error); 177 | } 178 | }); 179 | 180 | 181 | 182 | export default router; 183 | 184 | export interface UserInfo { 185 | name: string, 186 | wallet: string, 187 | avatar?: string 188 | } 189 | 190 | export interface PendingUserInfo { 191 | name: string, 192 | wallet: string, 193 | nonce: string, 194 | } -------------------------------------------------------------------------------- /src/routes/chart copy.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import Joi, { string } from "joi"; 3 | import Coin from "../models/Coin"; 4 | import CoinStatus from "../models/CoinsStatus"; 5 | import { Types } from "mongoose"; 6 | import NodeCache from "node-cache"; 7 | 8 | const tradeChart = { 9 | "s": "ok", 10 | "t": [1587945600, 1588032000, 1588118400], 11 | "o": [142.7, 144.9, 145.9], 12 | "h": [144.0, 145.8, 147.0], 13 | "l": [141.4, 142.5, 144.3], 14 | "c": [143.8, 144.4, 146.7], 15 | "v": [3285000, 3012000, 3796000] 16 | } 17 | const cache = new NodeCache({ stdTTL: 60 }); 18 | interface SymbolInfo { 19 | name: string; 20 | ticker: string; 21 | type: string; 22 | session: string; 23 | timezone: string; 24 | // exchange: string; 25 | minmov: number; 26 | pricescale: number; 27 | has_intraday: boolean; 28 | intraday_multipliers: string[]; 29 | supported_resolutions: string[]; 30 | volume_precision: number; 31 | } 32 | interface mockInfo { 33 | s: string, 34 | t: number[], 35 | o: number[], 36 | h: number[], 37 | l: number[], 38 | c: number[], 39 | v: number[], 40 | 41 | } 42 | // Mock data 43 | const mockSymbols: { [key: string]: SymbolInfo } = { 44 | 'ma': { 45 | name: 'ma', 46 | ticker: 'ma', 47 | type: 'stock', 48 | session: '24x7', 49 | timezone: 'Etc/UTC', 50 | // exchange: 'NASDAQ', 51 | minmov: 1, 52 | pricescale: 100, 53 | has_intraday: true, 54 | intraday_multipliers: ['1', '5', '15', '60', 'D'], 55 | supported_resolutions: ['1', '5', '15', '60', 'D'], 56 | volume_precision: 2, 57 | }, 58 | }; 59 | 60 | const mockHistory: { [key: string]: mockInfo } = { 61 | 'ma': { 62 | s: 'ok', 63 | t: [1587945600, 1588032000, 1588118400], 64 | o: [142.7, 144.9, 145.9], 65 | h: [144.0, 145.8, 147.0], 66 | l: [141.4, 142.5, 144.3], 67 | c: [143.8, 144.4, 146.7], 68 | v: [3285000, 3012000, 3796000], 69 | }, 70 | }; 71 | const config: mockInfo = { 72 | s: 'ok', 73 | t: [1587945600, 1588032000, 1588118400], 74 | o: [142.7, 144.9, 145.9], 75 | h: [144.0, 145.8, 147.0], 76 | l: [141.4, 142.5, 144.3], 77 | c: [143.8, 144.4, 146.7], 78 | v: [3285000, 3012000, 3796000], 79 | } 80 | 81 | const router = express.Router(); 82 | 83 | router.get('/', (req, res) => { 84 | console.log("config+++") 85 | 86 | res.json(config); 87 | }) 88 | // @route GET /coin/ 89 | // @desc Get all created coins 90 | // @access Public 91 | router.get('/config', (req, res) => { 92 | console.log("config+++") 93 | const config = { 94 | supports_search: true, 95 | supports_group_request: false, 96 | supported_resolutions: ['1', '5', '15', '60', 'D'], 97 | supports_marks: false, 98 | supports_timescale_marks: false, 99 | supports_time: true, 100 | }; 101 | res.json(config); 102 | }) 103 | 104 | router.get('/symbols', (req, res) => { 105 | const symbol = req.query.symbol; 106 | let symbolStr: string = ""; 107 | console.log("symbols;;;;;", symbol) 108 | if (typeof symbol === 'string') { 109 | symbolStr = symbol; 110 | } else if (Array.isArray(symbol) && symbol.length > 0) { 111 | symbolStr = symbol[0].toString(); 112 | } else if (typeof symbol === 'object' && symbol !== null) { 113 | symbolStr = Object.values(symbol).join(''); 114 | } else { 115 | console.error('Invalid symbol format'); 116 | } 117 | const symbolInfo = mockSymbols[symbolStr]; 118 | console.log("symbol::++++:::", symbolInfo) 119 | if (symbolInfo) { 120 | res.json(symbolInfo); 121 | } else { 122 | res.status(404).json({ error: 'Symbol not found' }); 123 | } 124 | }); 125 | router.get('/history', (req, res) => { 126 | const { symbol, resolution, from, to } = req.query; 127 | console.log("req.query;;;;;", req.query) 128 | let symbolStr: string = ""; 129 | 130 | 131 | const cacheKey = `${symbol}-${resolution}-${from}-${to}`; 132 | const cachedData = cache.get(cacheKey); 133 | 134 | if (cachedData) { 135 | console.log('Serving from cache:', cacheKey); 136 | return res.json(cachedData); 137 | } 138 | 139 | if (typeof symbol === 'string') { 140 | symbolStr = symbol; 141 | } else if (Array.isArray(symbol) && symbol.length > 0) { 142 | symbolStr = symbol[0].toString(); 143 | } else if (typeof symbol === 'object' && symbol !== null) { 144 | symbolStr = Object.values(symbol).join(''); 145 | } else { 146 | console.error('Invalid symbol format'); 147 | } 148 | const history = mockHistory[symbolStr]; 149 | console.log("history::::", history) 150 | if (history) { 151 | return res.json(history); 152 | } else { 153 | return res.status(404).json({ s: 'error', error: 'No data' }); 154 | } 155 | }); 156 | router.get('/search', (req, res) => { 157 | const query = req.query.query; 158 | if (query == undefined) return res.status(400).json("failed") 159 | const results = Object.keys(mockSymbols) 160 | .filter(symbol => { 161 | // Handle the query based on its type 162 | let queryString: string; 163 | if (typeof query === 'string') { 164 | queryString = query; 165 | } else if (Array.isArray(query)) { 166 | queryString = query.join(' ').toUpperCase(); 167 | } else if (typeof query === 'object' && query !== null) { 168 | // Convert ParsedQs or ParsedQs[] to a string representation 169 | queryString = Object.values(query).join(' ').toUpperCase(); 170 | } else { 171 | queryString = ''; // Handle other cases as needed 172 | } 173 | return symbol.includes(queryString); 174 | }) 175 | .map(symbol => ({ 176 | symbol, 177 | full_name: symbol, 178 | description: `Description of ${symbol}`, 179 | exchange: 'NASDAQ', 180 | ticker: symbol, 181 | type: 'stock', 182 | })); 183 | res.json(results); 184 | }); 185 | 186 | export default router; 187 | 188 | interface Trade { 189 | holder: Types.ObjectId; 190 | holdingStatus: number; 191 | time: number; 192 | amount: number; 193 | price: number; 194 | tx: string; 195 | } 196 | 197 | interface Bar { 198 | time: number; 199 | open: number; 200 | high: number; 201 | low: number; 202 | close: number; 203 | volume: number; 204 | 205 | } 206 | 207 | function calculateOHLCV(trades: Trade[], periodStart: number, periodEnd: number): Bar { 208 | let open = 0; 209 | let high = -Infinity; 210 | let low = Infinity; 211 | let close = 0; 212 | let volume = 0; 213 | if (trades.length > 0) { 214 | open = trades[0].price; // Initial open 215 | close = trades[trades.length - 1].price; // Final close 216 | 217 | for (let i = 0; i < trades.length; i++) { 218 | const trade = trades[i]; 219 | volume += trade.amount; 220 | 221 | if (trade.price > high) high = trade.price; 222 | if (trade.price < low) low = trade.price; 223 | } 224 | } 225 | 226 | return { 227 | time: periodStart, 228 | open, 229 | high, 230 | low, 231 | close, 232 | volume, 233 | }; 234 | } 235 | -------------------------------------------------------------------------------- /src/program/web3.ts: -------------------------------------------------------------------------------- 1 | import { TokenStandard, createAndMint, mplTokenMetadata } from "@metaplex-foundation/mpl-token-metadata"; 2 | import { Instruction, createSignerFromKeypair, generateSigner, percentAmount, signerIdentity } from "@metaplex-foundation/umi"; 3 | import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; 4 | import { ComputeBudgetProgram, Connection, Keypair, PublicKey, SYSVAR_RENT_PUBKEY, Signer, SystemProgram, Transaction, TransactionResponse, VersionedTransaction, clusterApiUrl, sendAndConfirmTransaction } from "@solana/web3.js"; 5 | import base58 from "bs58"; 6 | import { Types } from "mongoose"; 7 | import Coin from "../models/Coin"; 8 | import { createLPIx, initializeIx, removeLiquidityIx } from "./web3Provider"; 9 | import { web3 } from "@coral-xyz/anchor"; 10 | import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; 11 | import { PROGRAM_ID } from "./cli/programId"; 12 | import { AccountType, TOKEN_PROGRAM_ID, getAssociatedTokenAddress } from "@solana/spl-token"; 13 | import { BN } from "bn.js"; 14 | import { SwapAccounts, SwapArgs, swap } from "./cli/instructions"; 15 | import * as anchor from "@coral-xyz/anchor" 16 | import { ASSOCIATED_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token"; 17 | import { LiquidityPool } from "./cli/accounts"; 18 | import { string } from "joi"; 19 | import { Int32 } from "mongodb"; 20 | import { setCoinStatus } from "../routes/coinStatus"; 21 | import CoinStatus from "../models/CoinsStatus"; 22 | import { simulateTransaction } from "@coral-xyz/anchor/dist/cjs/utils/rpc"; 23 | import pinataSDK from '@pinata/sdk'; 24 | 25 | 26 | const curveSeed = "CurveConfiguration" 27 | const POOL_SEED_PREFIX = "liquidity_pool" 28 | const LP_SEED_PREFIX = "LiqudityProvider" 29 | const PINATA_SECRET_API_KEY = process.env.PINATA_SECRET_API_KEY 30 | const PINATA_GATEWAY_URL = process.env.PINATA_GATEWAY_URL; 31 | 32 | 33 | export const connection = new Connection(clusterApiUrl('devnet')) 34 | 35 | const privateKey = base58.decode(process.env.PRIVATE_KEY!); 36 | 37 | export const adminKeypair = web3.Keypair.fromSecretKey(privateKey); 38 | const adminWallet = new NodeWallet(adminKeypair); 39 | 40 | // const umi = createUmi(process.env.PUBLIC_SOLANA_RPC!); 41 | const umi = createUmi(clusterApiUrl('devnet')); 42 | 43 | const userWallet = umi.eddsa.createKeypairFromSecretKey(privateKey); 44 | 45 | const userWalletSigner = createSignerFromKeypair(umi, userWallet); 46 | umi.use(signerIdentity(userWalletSigner)); 47 | umi.use(mplTokenMetadata()); 48 | 49 | export const uploadMetadata = async (data: CoinInfo): Promise => { 50 | // const url = data.url; 51 | const url = 'https://api.pinata.cloud/pinning/pinFileToIPFS/' 52 | console.log(data) 53 | const metadata = { 54 | name: data.name, 55 | ticker: data.ticker, 56 | URL: data.url, 57 | description: data.description, 58 | } 59 | const pinata = new pinataSDK({ pinataJWTKey: PINATA_SECRET_API_KEY }); 60 | 61 | try { 62 | const res = await pinata.pinJSONToIPFS(metadata); 63 | console.log(res, "======") 64 | return res 65 | } catch (error) { 66 | console.error('Error uploading metadata: ', error); 67 | return error; 68 | } 69 | } 70 | // Initialize Transaction for smart contract 71 | export const initializeTx = async () => { 72 | const initTx = await initializeIx(adminWallet.publicKey); 73 | const createTx = new Transaction().add(initTx.ix); 74 | console.log(adminWallet.publicKey.toBase58()) 75 | 76 | createTx.feePayer = adminWallet.publicKey; 77 | createTx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash 78 | 79 | const txId = await sendAndConfirmTransaction(connection, createTx, [adminKeypair]); 80 | console.log("txId:", txId) 81 | } 82 | 83 | 84 | // Create Token and add liquidity transaction 85 | export const createToken = async (data: CoinInfo) => { 86 | const uri = await uploadMetadata(data); 87 | 88 | const mint = generateSigner(umi); 89 | const tx = createAndMint(umi, { 90 | mint, 91 | authority: umi.identity, 92 | name: data.name, 93 | symbol: data.ticker, 94 | uri: data.url, 95 | sellerFeeBasisPoints: percentAmount(0), 96 | decimals: 6, 97 | amount: 1000_000_000_000_000, 98 | tokenOwner: userWallet.publicKey, 99 | tokenStandard: TokenStandard.Fungible, 100 | }) 101 | const mintTx = await tx.sendAndConfirm(umi) 102 | console.log(userWallet.publicKey, "Successfully minted 1 million tokens (", mint.publicKey, ")"); 103 | const newCoin = new Coin({ 104 | ...data, 105 | // amount: tx.amount, 106 | token: mint.publicKey 107 | }) 108 | await sleep(5000); 109 | try { 110 | const lpTx = await createLPIx(new PublicKey(mint.publicKey), adminKeypair.publicKey) 111 | const createTx = new Transaction().add(lpTx.ix); 112 | createTx.feePayer = adminWallet.publicKey; 113 | createTx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash 114 | 115 | const txId = await sendAndConfirmTransaction(connection, createTx, [adminKeypair]); 116 | console.log("txId:", txId) 117 | // const checkTx = await checkTransactionStatus(txId); 118 | const urlSeg = data.url.split('/'); 119 | const url = `${PINATA_GATEWAY_URL}/${urlSeg[urlSeg.length - 1]}`; 120 | console.log(url) 121 | console.log('great') 122 | const newCoin = new Coin({ 123 | creator: data.creator, 124 | name: data.name, 125 | ticker: data.ticker, 126 | description: data.description, 127 | token: mint.publicKey, 128 | url, 129 | }); 130 | console.log(newCoin) 131 | const response = await newCoin.save(); 132 | const newCoinStatus = new CoinStatus({ 133 | coinId: response._id, 134 | record: [ 135 | { 136 | holder: response.creator, 137 | holdingStatus: 2, 138 | amount: 0, 139 | tx: txId, 140 | price: newCoin.reserveTwo / newCoin.reserveOne 141 | } 142 | ] 143 | }) 144 | await newCoinStatus.save(); 145 | console.log("Saved Successfully..."); 146 | return response 147 | } catch (error) { 148 | return "transaction failed" 149 | } 150 | 151 | } 152 | 153 | // check transaction 154 | export const checkTransactionStatus = async (transactionId: string) => { 155 | try { 156 | // Fetch the transaction details using the transaction ID 157 | const transactionResponse: TransactionResponse | null = await connection.getTransaction(transactionId); 158 | 159 | // If the transactionResponse is null, the transaction is not found 160 | if (transactionResponse === null) { 161 | console.log(`Transaction ${transactionId} not found.`); 162 | return false; 163 | } 164 | 165 | // Check the status of the transaction 166 | if (transactionResponse.meta && transactionResponse.meta.err === null) { 167 | return true; 168 | } else { 169 | console.log(`Transaction ${transactionId} failed with error: ${transactionResponse.meta?.err}`); 170 | return false 171 | } 172 | } catch (error) { 173 | console.error(`Error fetching transaction ${transactionId}:`, error); 174 | return false; 175 | } 176 | } 177 | 178 | // Swap transaction 179 | export const swapTx = async ( 180 | mint1: PublicKey, user: Signer 181 | ) => { 182 | try { 183 | const [curveConfig] = PublicKey.findProgramAddressSync( 184 | [Buffer.from(curveSeed)], 185 | PROGRAM_ID 186 | ) 187 | const [poolPda] = PublicKey.findProgramAddressSync( 188 | [Buffer.from(POOL_SEED_PREFIX), mint1.toBuffer()], 189 | PROGRAM_ID 190 | ) 191 | const [globalAccount] = PublicKey.findProgramAddressSync( 192 | [Buffer.from("global")], 193 | PROGRAM_ID 194 | ) 195 | 196 | const poolTokenOne = await getAssociatedTokenAddress( 197 | mint1, globalAccount, true 198 | ) 199 | const userAta1 = await getAssociatedTokenAddress( 200 | mint1, adminKeypair.publicKey 201 | ) 202 | 203 | const args: SwapArgs = { 204 | amount: new anchor.BN(20000000), 205 | style: new anchor.BN(2) 206 | } 207 | 208 | const acc: SwapAccounts = { 209 | dexConfigurationAccount: curveConfig, 210 | pool: poolPda, 211 | globalAccount, 212 | mintTokenOne: mint1, 213 | poolTokenAccountOne: poolTokenOne, 214 | userTokenAccountOne: userAta1, 215 | user: adminKeypair.publicKey, 216 | tokenProgram: TOKEN_PROGRAM_ID, 217 | associatedTokenProgram: ASSOCIATED_PROGRAM_ID, 218 | rent: SYSVAR_RENT_PUBKEY, 219 | systemProgram: SystemProgram.programId 220 | } 221 | 222 | const dataIx = await swap(args, acc, PROGRAM_ID) 223 | const tx = new Transaction().add(dataIx); 224 | tx.feePayer = adminKeypair.publicKey 225 | tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash 226 | // console.log(await connection.simulateTransaction(tx)) 227 | const sig = await sendAndConfirmTransaction(connection, tx, [adminKeypair], { skipPreflight: true }) 228 | return sig 229 | } catch (error) { 230 | console.log("Error in swap transaction", error) 231 | } 232 | } 233 | 234 | // Get info when user buy or sell token 235 | const logTx = connection.onLogs(PROGRAM_ID, async (logs, ctx) => { 236 | if (logs.err !== null) { 237 | return undefined 238 | } 239 | if (logs.logs[1].includes('AddLiquidity')) { 240 | return undefined 241 | } 242 | console.log(logs) 243 | // Get parsed log data 244 | const parsedData: ResultType = parseLogs(logs.logs, logs.signature); 245 | console.log(parsedData); 246 | 247 | if (parsedData.reserve2 > 80_000_000_000) { 248 | // Remove liquidity poll and move to Raydium 249 | // createRaydium() 250 | return; 251 | } 252 | await setCoinStatus(parsedData) 253 | 254 | 255 | }, "confirmed") 256 | 257 | // Remove liquidity pool and Create Raydium Pool 258 | export const createRaydium = async (mint1: PublicKey) => { 259 | const amountOne = 1000_000_000_000; 260 | const amountTwo = 1000_000_000_000; 261 | const radyiumIx = await removeLiquidityIx(mint1, adminKeypair.publicKey, connection); 262 | 263 | if (radyiumIx == undefined) return; 264 | for (const iTx of radyiumIx.willSendTx) { 265 | if (iTx instanceof VersionedTransaction) { 266 | iTx.sign([adminKeypair]); 267 | await connection.sendTransaction(iTx, { 268 | skipPreflight: true 269 | }); 270 | } else { 271 | await sendAndConfirmTransaction(connection, iTx, [adminKeypair], { 272 | skipPreflight: true 273 | }); 274 | } 275 | } 276 | // console.log(await connection.simulateTransaction(radyiumIx.tx1)) 277 | // await connection.sendTransaction(radyiumIx.tx1, [adminKeypair]); 278 | 279 | 280 | const tx = new Transaction().add(ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 })); 281 | 282 | for (let i = 0; i < radyiumIx.ixs.length; i++) { 283 | tx.add(radyiumIx.ixs[i]); 284 | } 285 | 286 | tx.feePayer = adminKeypair.publicKey; 287 | tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash 288 | 289 | // console.dir((await simulateTransaction(connection, tx)), { depth: null }) 290 | const ret = await simulateTransaction(connection, tx); 291 | 292 | if (!ret.value.logs) return ""; 293 | for (let i = 0; i < ret.value.logs?.length; i++) 294 | console.log(ret.value.logs[i]); 295 | 296 | const sig = await sendAndConfirmTransaction(connection, tx, [adminKeypair], { skipPreflight: true }) 297 | 298 | return sig; 299 | } 300 | 301 | function sleep(ms: number): Promise { 302 | return new Promise(resolve => setTimeout(resolve, ms)); 303 | } 304 | // Get swap(buy and sell) 305 | function parseLogs(logs: string[], tx: string) { 306 | const result: ResultType = { 307 | tx, 308 | mint: '', 309 | owner: '', 310 | swapType: 0, 311 | swapAmount: 0, 312 | reserve1: 0, 313 | reserve2: 0 314 | }; 315 | logs.forEach(log => { 316 | if (log.includes('Mint: ')) { 317 | result.mint = (log.split(' ')[3]); 318 | } 319 | if (log.includes('Swap: ')) { 320 | result.owner = log.split(' ')[3]; 321 | result.swapType = parseInt(log.split(' ')[4]); 322 | result.swapAmount = parseInt(log.split(' ')[5]); 323 | } 324 | if (log.includes('Reserves: ')) { 325 | result.reserve1 = parseInt(log.split(' ')[3]); 326 | result.reserve2 = parseInt(log.split(' ')[4]); 327 | } 328 | }); 329 | return result; 330 | } 331 | 332 | export interface CoinInfo { 333 | creator?: Types.ObjectId; 334 | name: string; 335 | ticker: string; 336 | url: string; 337 | description?: string; 338 | token?: string; 339 | reserve1?: number; 340 | reserve2?: number; 341 | } 342 | 343 | export interface ResultType { 344 | tx: string, 345 | mint: string; 346 | owner: string; 347 | swapType: number; 348 | swapAmount: number; 349 | reserve1: number; 350 | reserve2: number; 351 | } -------------------------------------------------------------------------------- /src/program/web3Provider.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@coral-xyz/anchor" 2 | import { PROGRAM_ID } from "./cli/programId" 3 | import { ComputeBudgetProgram, Connection, PublicKey, SYSVAR_RENT_PUBKEY, SystemProgram, Transaction, TransactionInstruction, VersionedTransaction, } from "@solana/web3.js" 4 | import { TOKEN_PROGRAM_ID, getAssociatedTokenAddress, getAssociatedTokenAddressSync, } from "@solana/spl-token" 5 | import { AddLiquidityAccounts, AddLiquidityArgs, InitializeAccounts, InitializeArgs, RemoveLiquidityAccounts, RemoveLiquidityArgs, SwapAccounts, SwapArgs, addLiquidity, initialize, removeLiquidity, swap } from "./cli/instructions" 6 | import { ASSOCIATED_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token" 7 | import { 8 | MarketV2, 9 | Token, 10 | DEVNET_PROGRAM_ID, 11 | TxVersion, 12 | LOOKUP_TABLE_CACHE, 13 | buildSimpleTransaction, 14 | Spl, 15 | parseBigNumberish, 16 | InstructionType 17 | } from '@raydium-io/raydium-sdk'; 18 | import { adminKeypair } from "./web3" 19 | 20 | const curveSeed = "CurveConfiguration" 21 | const POOL_SEED_PREFIX = "liquidity_pool" 22 | const LP_SEED_PREFIX = "LiqudityProvider" 23 | 24 | 25 | 26 | export const createLPIx = async ( 27 | mintToken: PublicKey, 28 | payer: PublicKey, 29 | ) => { 30 | const [poolPda] = PublicKey.findProgramAddressSync( 31 | [Buffer.from(POOL_SEED_PREFIX), mintToken.toBuffer()], 32 | PROGRAM_ID 33 | ) 34 | const [globalAccount] = PublicKey.findProgramAddressSync( 35 | [Buffer.from("global")], 36 | PROGRAM_ID 37 | ); 38 | const [liquidityProviderAccount] = PublicKey.findProgramAddressSync( 39 | [Buffer.from(LP_SEED_PREFIX), poolPda.toBuffer(), payer.toBuffer()], 40 | PROGRAM_ID 41 | ) 42 | const poolTokenOne = await getAssociatedTokenAddress( 43 | mintToken, globalAccount, true 44 | ) 45 | const userAta1 = await getAssociatedTokenAddress( 46 | mintToken, payer 47 | ) 48 | const acc: AddLiquidityAccounts = { 49 | pool: poolPda, 50 | globalAccount, 51 | mintTokenOne: mintToken, 52 | poolTokenAccountOne: poolTokenOne, 53 | userTokenAccountOne: userAta1, 54 | liquidityProviderAccount: liquidityProviderAccount, 55 | user: payer, 56 | tokenProgram: TOKEN_PROGRAM_ID, 57 | associatedTokenProgram: ASSOCIATED_PROGRAM_ID, 58 | rent: SYSVAR_RENT_PUBKEY, 59 | systemProgram: SystemProgram.programId 60 | } 61 | const args: AddLiquidityArgs = { 62 | amountOne: new anchor.BN(1000000000000000), 63 | amountTwo: new anchor.BN(30000000000) 64 | } 65 | const ix = addLiquidity(args, acc); 66 | 67 | return { ix, acc } 68 | } 69 | export const initializeIx = async ( 70 | payer: PublicKey 71 | ) => { 72 | const [curveConfig] = PublicKey.findProgramAddressSync( 73 | [Buffer.from(curveSeed)], 74 | PROGRAM_ID 75 | ); 76 | const [globalAccount] = PublicKey.findProgramAddressSync( 77 | [Buffer.from("global")], 78 | PROGRAM_ID 79 | ); 80 | 81 | const acc: InitializeAccounts = { 82 | dexConfigurationAccount: curveConfig, 83 | globalAccount, 84 | admin: payer, 85 | rent: SYSVAR_RENT_PUBKEY, 86 | systemProgram: SystemProgram.programId 87 | }; 88 | 89 | const args: InitializeArgs = { 90 | fee: 1 91 | } 92 | 93 | const ix = initialize(args, acc); 94 | return { ix, acc } 95 | 96 | } 97 | 98 | 99 | 100 | 101 | 102 | // export const performTx = async ( 103 | // address: string, 104 | // txId: string, 105 | // ) => { 106 | // try{ 107 | // console.log("==============") 108 | 109 | // let txInfo; 110 | // for(let i=0; ; i++) { 111 | // await sleep(2000) 112 | // txInfo = await getDataFromSignature(txId, io); 113 | 114 | // console.log(txInfo) 115 | // if (txInfo !== undefined) { 116 | // break; 117 | // } 118 | // if (i > 30) { 119 | // io.emit("performedTx", address, "Time Out"); 120 | // return; 121 | // } 122 | // } 123 | 124 | // } catch (err) { 125 | 126 | // } 127 | 128 | // } 129 | 130 | 131 | // const getDataFromSignature = async (sig: string, io: Server) => { 132 | 133 | // try { 134 | // let tx = await connection.getParsedTransaction(sig,'confirmed'); 135 | // if (tx && tx.meta && !tx.meta.err) { 136 | // let length = tx.transaction.message.instructions.length; 137 | 138 | // for (let i = length; i > 0; i--) { 139 | // const ix = tx.transaction.message.instructions[i-1] as ParsedInstruction 140 | 141 | // if (ix.programId.toBase58() === SPL_TOKEN_PROGRAM ) { 142 | // console.log(ix, " =============> ix") 143 | // const srcAcc = await connection.getParsedAccountInfo(new PublicKey(ix.parsed.info.source)); 144 | // const destAcc = await connection.getParsedAccountInfo(new PublicKey(ix.parsed.info.destination)); 145 | // const src = (srcAcc.value?.data as ParsedAccountData).parsed.info.owner; 146 | // const dest = (destAcc.value?.data as ParsedAccountData).parsed.info.owner; 147 | // const amount = parseInt(ix.parsed.info.amount); 148 | 149 | 150 | // break; 151 | // } 152 | 153 | // } 154 | 155 | // return true; 156 | 157 | // } 158 | 159 | // } catch (error) { 160 | // console.log("error:", error) 161 | // } 162 | // } 163 | 164 | // export const createAddLPIx = ( 165 | // mintTokenOne: PublicKey, 166 | // mintTokenTwo: PublicKey, 167 | // payer: PublicKey, 168 | // amountOne: anchor.BN, 169 | // amountTwo: anchor.BN 170 | // ) => { 171 | // const [poolPda] = PublicKey.findProgramAddressSync( 172 | // [Buffer.from("liquidity_pool"), Buffer.from(mintTokenOne > mintTokenTwo ? mintTokenOne.toBase58()+mintTokenTwo.toBase58() : mintTokenTwo.toBase58()+mintTokenOne.toBase58()) ], 173 | // PROGRAM_ID 174 | // ) 175 | 176 | // const [liquidityProviderAccount] = PublicKey.findProgramAddressSync( 177 | // [Buffer.from("LiqudityProvider"), poolPda.toBuffer(), payer.toBuffer()], 178 | // PROGRAM_ID 179 | // ) 180 | 181 | // const poolTokenAccountOne = getAssociatedTokenAddressSync(mintTokenOne, poolPda); 182 | // const poolTokenAccountTwo = getAssociatedTokenAddressSync(mintTokenOne, poolPda); 183 | // const userTokenAccountOne = getAssociatedTokenAddressSync(mintTokenOne, payer); 184 | // const userTokenAccountTwo = getAssociatedTokenAddressSync(mintTokenOne, payer); 185 | 186 | // const acc: AddLiquidityAccounts = { 187 | // pool: poolPda, 188 | // liquidityProviderAccount, 189 | // mintTokenOne, 190 | // mintTokenTwo, 191 | // poolTokenAccountOne, 192 | // poolTokenAccountTwo, 193 | // userTokenAccountOne, 194 | // userTokenAccountTwo, 195 | // user: payer, 196 | // systemProgram: SystemProgram.programId, 197 | // tokenProgram:TOKEN_PROGRAM_ID, 198 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID 199 | // } 200 | 201 | // const args: AddLiquidityArgs = { 202 | // amountOne, 203 | // amountTwo 204 | // } 205 | // const ix = addLiquidity(args, acc); 206 | 207 | // return {ix, acc} 208 | // } 209 | 210 | // export const createRemoveLPIx = ( 211 | // mintTokenOne: PublicKey, 212 | // mintTokenTwo: PublicKey, 213 | // payer: PublicKey, 214 | // shares: anchor.BN, 215 | // ) => { 216 | // const [poolPda] = PublicKey.findProgramAddressSync( 217 | // [Buffer.from("liquidity_pool"), Buffer.from(mintTokenOne > mintTokenTwo ? mintTokenOne.toBase58()+mintTokenTwo.toBase58() : mintTokenTwo.toBase58()+mintTokenOne.toBase58()) ], 218 | // PROGRAM_ID 219 | // ) 220 | 221 | // const [liquidityProviderAccount] = PublicKey.findProgramAddressSync( 222 | // [Buffer.from("LiqudityProvider"), poolPda.toBuffer(), payer.toBuffer()], 223 | // PROGRAM_ID 224 | // ) 225 | 226 | // const poolTokenAccountOne = getAssociatedTokenAddressSync(mintTokenOne, poolPda); 227 | // const poolTokenAccountTwo = getAssociatedTokenAddressSync(mintTokenOne, poolPda); 228 | // const userTokenAccountOne = getAssociatedTokenAddressSync(mintTokenOne, payer); 229 | // const userTokenAccountTwo = getAssociatedTokenAddressSync(mintTokenOne, payer); 230 | 231 | // const acc: RemoveLiquidityAccounts = { 232 | // pool: poolPda, 233 | // liquidityProviderAccount, 234 | // mintTokenOne, 235 | // mintTokenTwo, 236 | // poolTokenAccountOne, 237 | // poolTokenAccountTwo, 238 | // userTokenAccountOne, 239 | // userTokenAccountTwo, 240 | // user: payer, 241 | // systemProgram: SystemProgram.programId, 242 | // tokenProgram:TOKEN_PROGRAM_ID, 243 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID 244 | // } 245 | 246 | // const args: RemoveLiquidityArgs = { 247 | // shares 248 | // } 249 | // const ix = removeLiquidity(args, acc); 250 | 251 | // return {ix, acc} 252 | // } 253 | 254 | // export const createSwapIx = ( 255 | // mintTokenOne: PublicKey, 256 | // mintTokenTwo: PublicKey, 257 | // payer: PublicKey, 258 | // amount: anchor.BN, 259 | // ) => { 260 | // const [poolPda] = PublicKey.findProgramAddressSync( 261 | // [Buffer.from("liquidity_pool"), Buffer.from(mintTokenOne > mintTokenTwo ? mintTokenOne.toBase58()+mintTokenTwo.toBase58() : mintTokenTwo.toBase58()+mintTokenOne.toBase58()) ], 262 | // PROGRAM_ID 263 | // ) 264 | 265 | // const [dexConfigurationAccount] = PublicKey.findProgramAddressSync( 266 | // [Buffer.from("CurveConfiguration")], 267 | // PROGRAM_ID 268 | // ) 269 | 270 | // const poolTokenAccountOne = getAssociatedTokenAddressSync(mintTokenOne, poolPda); 271 | // const poolTokenAccountTwo = getAssociatedTokenAddressSync(mintTokenOne, poolPda); 272 | // const userTokenAccountOne = getAssociatedTokenAddressSync(mintTokenOne, payer); 273 | // const userTokenAccountTwo = getAssociatedTokenAddressSync(mintTokenOne, payer); 274 | 275 | // const acc: SwapAccounts = { 276 | // dexConfigurationAccount, 277 | // pool: poolPda, 278 | // mintTokenOne, 279 | // mintTokenTwo, 280 | // poolTokenAccountOne, 281 | // poolTokenAccountTwo, 282 | // userTokenAccountOne, 283 | // userTokenAccountTwo, 284 | // user: payer, 285 | // systemProgram: SystemProgram.programId, 286 | // tokenProgram:TOKEN_PROGRAM_ID, 287 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID 288 | // } 289 | 290 | // const args: SwapArgs = { 291 | // amount 292 | // } 293 | // const ix = swap(args, acc); 294 | 295 | // return {ix, acc} 296 | // } 297 | export const removeLiquidityIx = async ( 298 | mintToken: PublicKey, 299 | // amountOne: anchor.BN, 300 | // amountTwo: anchor.BN, 301 | payer: PublicKey, 302 | connection: Connection 303 | ) => { 304 | try { 305 | const ammProgram = new PublicKey("HWy1jotHpo6UqeQxx49dpYYdQB8wj9Qk9MdxwjLvDHB8"); 306 | 307 | console.log("Remove::::::::") 308 | // coin mint address 309 | const coinMint = mintToken; 310 | console.log("coinMint: ", coinMint.toBase58()); 311 | // coin mint address 312 | const pcMint = new PublicKey("So11111111111111111111111111111111111111112"); 313 | console.log("pcMint: ", pcMint.toBase58()); 314 | // market address 315 | const createMarketInstruments = await MarketV2.makeCreateMarketInstructionSimple({ 316 | connection, 317 | wallet: payer, 318 | baseInfo: {mint: mintToken, decimals: 9}, 319 | quoteInfo: {mint: pcMint, decimals: 9}, 320 | lotSize: 1, // default 1 321 | tickSize: 0.01, // default 0.01 322 | dexProgramId: DEVNET_PROGRAM_ID.OPENBOOK_MARKET, 323 | makeTxVersion, 324 | }) 325 | 326 | const willSendTx = await buildSimpleTransaction({ 327 | connection, 328 | makeTxVersion, 329 | payer, 330 | innerTransactions: createMarketInstruments.innerTransactions, 331 | }) 332 | 333 | 334 | const market = createMarketInstruments.address.marketId; 335 | 336 | const [poolPda] = PublicKey.findProgramAddressSync( 337 | [Buffer.from("liquidity_pool"), mintToken.toBuffer()], 338 | PROGRAM_ID 339 | ) 340 | const [globalAccount] = PublicKey.findProgramAddressSync( 341 | [Buffer.from("global")], 342 | PROGRAM_ID 343 | ) 344 | 345 | console.log("globalAccount: ", globalAccount.toBase58()) 346 | const [liquidityProviderAccount] = PublicKey.findProgramAddressSync( 347 | [Buffer.from("LiqudityProvider"), poolPda.toBuffer(), payer.toBuffer()], 348 | PROGRAM_ID 349 | ) 350 | 351 | console.log(poolPda, "===================") 352 | 353 | const [amm] = PublicKey.findProgramAddressSync( 354 | [ammProgram.toBuffer(), market.toBuffer(), Buffer.from("amm_associated_seed")], 355 | ammProgram 356 | ); 357 | console.log("amm: ", amm.toBase58()); 358 | 359 | const [ammAuthority] = PublicKey.findProgramAddressSync( 360 | [Buffer.from("amm authority")], 361 | ammProgram 362 | ); 363 | console.log("ammAuthority: ", ammAuthority.toBase58()); 364 | 365 | const [ammOpenOrders] = PublicKey.findProgramAddressSync( 366 | [ammProgram.toBuffer(), market.toBuffer(), Buffer.from("open_order_associated_seed")], 367 | ammProgram 368 | ); 369 | console.log("ammOpenOrders: ", ammOpenOrders.toBase58()); 370 | 371 | const [lpMint] = PublicKey.findProgramAddressSync( 372 | [ammProgram.toBuffer(), market.toBuffer(), Buffer.from("lp_mint_associated_seed")], 373 | ammProgram 374 | ); 375 | console.log("lpMint: ", lpMint.toBase58()); 376 | 377 | console.log("coinMint: ", coinMint.toBase58()); 378 | console.log("pcMint: ", pcMint.toBase58()); 379 | 380 | const [coinVault] = PublicKey.findProgramAddressSync( 381 | [ammProgram.toBuffer(), market.toBuffer(), Buffer.from("coin_vault_associated_seed")], 382 | ammProgram 383 | ); 384 | console.log("coinVault: ", coinVault.toBase58()); 385 | 386 | const [pcVault] = PublicKey.findProgramAddressSync( 387 | [ammProgram.toBuffer(), market.toBuffer(), Buffer.from("pc_vault_associated_seed")], 388 | ammProgram 389 | ); 390 | console.log("pcVault: ", pcVault.toBase58()); 391 | 392 | // fee destination 393 | const feeDestination = new PublicKey("3XMrhbv989VxAMi3DErLV9eJht1pHppW5LbKxe9fkEFR"); 394 | console.log("feeDestination: ", feeDestination.toBase58()); 395 | 396 | const [targetOrders] = PublicKey.findProgramAddressSync( 397 | [ammProgram.toBuffer(), market.toBuffer(), Buffer.from("target_associated_seed")], 398 | ammProgram 399 | ); 400 | console.log("targetOrders: ", targetOrders.toBase58()); 401 | 402 | const [ammConfig] = PublicKey.findProgramAddressSync( 403 | [Buffer.from("amm_config_account_seed")], 404 | ammProgram 405 | ); 406 | console.log("ammConfig: ", ammConfig.toBase58()); 407 | 408 | console.log("serumProgram: ", "EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj"); 409 | console.log("serumMarket: ", market.toBase58()); 410 | 411 | const userWallet = new PublicKey("EmPsWiBxEy6rXNj3VVtHLNAmP5hUaVUrDH3QXiTttDgy"); 412 | console.log("userWallet: ", userWallet.toBase58()); 413 | 414 | const userTokenCoin = await getAssociatedTokenAddress( 415 | coinMint, globalAccount, true 416 | ) 417 | console.log("userTokenCoin: ", userTokenCoin.toBase58()); 418 | 419 | const userTokenPc = await getAssociatedTokenAddress( 420 | pcMint, globalAccount, true 421 | ) 422 | console.log("userTokenPc: ", userTokenPc.toBase58()); 423 | 424 | const userTokenLp = await getAssociatedTokenAddress( 425 | lpMint, globalAccount, true 426 | ) 427 | console.log("userTokenLp: ", userTokenLp.toBase58()); 428 | 429 | const ixs: TransactionInstruction[] = []; 430 | const newTokenAccount = await Spl.insertCreateWrappedNativeAccount({ 431 | connection, 432 | owner: globalAccount, 433 | payer, 434 | instructions: ixs, 435 | instructionsType: [], 436 | signers: [adminKeypair], 437 | amount: new anchor.BN(1000000000), 438 | }); 439 | 440 | const nonce = 252; 441 | 442 | const acc: RemoveLiquidityAccounts = { 443 | pool: poolPda, 444 | globalAccount, 445 | ammProgram, 446 | tokenProgram: TOKEN_PROGRAM_ID, 447 | associatedTokenProgram: ASSOCIATED_PROGRAM_ID, 448 | systemProgram: SystemProgram.programId, 449 | sysvarRent: SYSVAR_RENT_PUBKEY, 450 | amm, 451 | ammAuthority, 452 | ammOpenOrders, 453 | lpMint, 454 | coinMint, 455 | pcMint, 456 | coinVault, 457 | pcVault, 458 | targetOrders, 459 | ammConfig, 460 | feeDestination, 461 | marketProgram: new PublicKey("EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj"), 462 | market, 463 | userWallet: payer, 464 | userTokenCoin, 465 | userTokenPc: newTokenAccount, 466 | userTokenLp, 467 | } 468 | const args: RemoveLiquidityArgs = { 469 | nonce, 470 | initPcAmount: new anchor.BN(880000), 471 | } 472 | 473 | ixs.push(removeLiquidity(args, acc)); 474 | 475 | // ixs.push(Spl.makeCloseAccountInstruction({ 476 | // programId: TOKEN_PROGRAM_ID, 477 | // tokenAccount: newTokenAccount, 478 | // owner: payer, 479 | // payer, 480 | // instructionsType: [], 481 | // })); 482 | 483 | return { ixs, acc, willSendTx } 484 | } catch (error) { 485 | console.log("Error in removing liquidity", error) 486 | } 487 | } 488 | 489 | export const makeTxVersion = TxVersion.LEGACY; // LEGACY 490 | -------------------------------------------------------------------------------- /src/program/idl.ts: -------------------------------------------------------------------------------- 1 | export type Pump = { 2 | "version": "0.1.0", 3 | "name": "pump", 4 | "instructions": [ 5 | { 6 | "name": "initialize", 7 | "accounts": [ 8 | { 9 | "name": "dexConfigurationAccount", 10 | "isMut": true, 11 | "isSigner": false, 12 | "pda": { 13 | "seeds": [ 14 | { 15 | "kind": "const", 16 | "type": "string", 17 | "value": "CurveConfiguration" 18 | } 19 | ] 20 | } 21 | }, 22 | { 23 | "name": "admin", 24 | "isMut": true, 25 | "isSigner": true 26 | }, 27 | { 28 | "name": "rent", 29 | "isMut": false, 30 | "isSigner": false 31 | }, 32 | { 33 | "name": "systemProgram", 34 | "isMut": false, 35 | "isSigner": false 36 | } 37 | ], 38 | "args": [ 39 | { 40 | "name": "fee", 41 | "type": "f64" 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "addLiquidity", 47 | "accounts": [ 48 | { 49 | "name": "pool", 50 | "isMut": true, 51 | "isSigner": false, 52 | "pda": { 53 | "seeds": [ 54 | { 55 | "kind": "const", 56 | "type": "string", 57 | "value": "liquidity_pool" 58 | }, 59 | { 60 | "kind": "account", 61 | "type": "publicKey", 62 | "account": "Mint", 63 | "path": "mint_token_one" 64 | } 65 | ] 66 | } 67 | }, 68 | { 69 | "name": "liquidityProviderAccount", 70 | "isMut": true, 71 | "isSigner": false, 72 | "pda": { 73 | "seeds": [ 74 | { 75 | "kind": "const", 76 | "type": "string", 77 | "value": "LiqudityProvider" 78 | }, 79 | { 80 | "kind": "account", 81 | "type": "publicKey", 82 | "account": "LiquidityPool", 83 | "path": "pool" 84 | }, 85 | { 86 | "kind": "account", 87 | "type": "publicKey", 88 | "path": "user" 89 | } 90 | ] 91 | } 92 | }, 93 | { 94 | "name": "mintTokenOne", 95 | "isMut": true, 96 | "isSigner": false 97 | }, 98 | { 99 | "name": "poolTokenAccountOne", 100 | "isMut": true, 101 | "isSigner": false 102 | }, 103 | { 104 | "name": "userTokenAccountOne", 105 | "isMut": true, 106 | "isSigner": false 107 | }, 108 | { 109 | "name": "user", 110 | "isMut": true, 111 | "isSigner": true 112 | }, 113 | { 114 | "name": "rent", 115 | "isMut": false, 116 | "isSigner": false 117 | }, 118 | { 119 | "name": "systemProgram", 120 | "isMut": false, 121 | "isSigner": false 122 | }, 123 | { 124 | "name": "tokenProgram", 125 | "isMut": false, 126 | "isSigner": false 127 | }, 128 | { 129 | "name": "associatedTokenProgram", 130 | "isMut": false, 131 | "isSigner": false 132 | } 133 | ], 134 | "args": [ 135 | { 136 | "name": "amountOne", 137 | "type": "u64" 138 | }, 139 | { 140 | "name": "amountTwo", 141 | "type": "u64" 142 | } 143 | ] 144 | }, 145 | { 146 | "name": "removeLiquidity", 147 | "accounts": [ 148 | { 149 | "name": "pool", 150 | "isMut": true, 151 | "isSigner": false, 152 | "pda": { 153 | "seeds": [ 154 | { 155 | "kind": "const", 156 | "type": "string", 157 | "value": "liquidity_pool" 158 | }, 159 | { 160 | "kind": "account", 161 | "type": "publicKey", 162 | "account": "Mint", 163 | "path": "mint_token_one" 164 | } 165 | ] 166 | } 167 | }, 168 | { 169 | "name": "liquidityProviderAccount", 170 | "isMut": true, 171 | "isSigner": false, 172 | "pda": { 173 | "seeds": [ 174 | { 175 | "kind": "const", 176 | "type": "string", 177 | "value": "LiqudityProvider" 178 | }, 179 | { 180 | "kind": "account", 181 | "type": "publicKey", 182 | "account": "LiquidityPool", 183 | "path": "pool" 184 | }, 185 | { 186 | "kind": "account", 187 | "type": "publicKey", 188 | "path": "user" 189 | } 190 | ] 191 | } 192 | }, 193 | { 194 | "name": "mintTokenOne", 195 | "isMut": true, 196 | "isSigner": false 197 | }, 198 | { 199 | "name": "poolTokenAccountOne", 200 | "isMut": true, 201 | "isSigner": false 202 | }, 203 | { 204 | "name": "userTokenAccountOne", 205 | "isMut": true, 206 | "isSigner": false 207 | }, 208 | { 209 | "name": "user", 210 | "isMut": true, 211 | "isSigner": true 212 | }, 213 | { 214 | "name": "rent", 215 | "isMut": false, 216 | "isSigner": false 217 | }, 218 | { 219 | "name": "systemProgram", 220 | "isMut": false, 221 | "isSigner": false 222 | }, 223 | { 224 | "name": "tokenProgram", 225 | "isMut": false, 226 | "isSigner": false 227 | }, 228 | { 229 | "name": "associatedTokenProgram", 230 | "isMut": false, 231 | "isSigner": false 232 | } 233 | ], 234 | "args": [ 235 | { 236 | "name": "shares", 237 | "type": "u64" 238 | } 239 | ] 240 | }, 241 | { 242 | "name": "swap", 243 | "accounts": [ 244 | { 245 | "name": "dexConfigurationAccount", 246 | "isMut": true, 247 | "isSigner": false, 248 | "pda": { 249 | "seeds": [ 250 | { 251 | "kind": "const", 252 | "type": "string", 253 | "value": "CurveConfiguration" 254 | } 255 | ] 256 | } 257 | }, 258 | { 259 | "name": "pool", 260 | "isMut": true, 261 | "isSigner": false, 262 | "pda": { 263 | "seeds": [ 264 | { 265 | "kind": "const", 266 | "type": "string", 267 | "value": "liquidity_pool" 268 | }, 269 | { 270 | "kind": "account", 271 | "type": "publicKey", 272 | "account": "Mint", 273 | "path": "mint_token_one" 274 | } 275 | ] 276 | } 277 | }, 278 | { 279 | "name": "mintTokenOne", 280 | "isMut": true, 281 | "isSigner": false 282 | }, 283 | { 284 | "name": "poolTokenAccountOne", 285 | "isMut": true, 286 | "isSigner": false 287 | }, 288 | { 289 | "name": "userTokenAccountOne", 290 | "isMut": true, 291 | "isSigner": false 292 | }, 293 | { 294 | "name": "user", 295 | "isMut": true, 296 | "isSigner": true 297 | }, 298 | { 299 | "name": "rent", 300 | "isMut": false, 301 | "isSigner": false 302 | }, 303 | { 304 | "name": "systemProgram", 305 | "isMut": false, 306 | "isSigner": false 307 | }, 308 | { 309 | "name": "tokenProgram", 310 | "isMut": false, 311 | "isSigner": false 312 | }, 313 | { 314 | "name": "associatedTokenProgram", 315 | "isMut": false, 316 | "isSigner": false 317 | } 318 | ], 319 | "args": [ 320 | { 321 | "name": "amount", 322 | "type": "u64" 323 | }, 324 | { 325 | "name": "style", 326 | "type": "u64" 327 | } 328 | ] 329 | } 330 | ], 331 | "accounts": [ 332 | { 333 | "name": "curveConfiguration", 334 | "type": { 335 | "kind": "struct", 336 | "fields": [ 337 | { 338 | "name": "fees", 339 | "type": "f64" 340 | } 341 | ] 342 | } 343 | }, 344 | { 345 | "name": "liquidityProvider", 346 | "type": { 347 | "kind": "struct", 348 | "fields": [ 349 | { 350 | "name": "shares", 351 | "type": "u64" 352 | } 353 | ] 354 | } 355 | }, 356 | { 357 | "name": "liquidityPool", 358 | "type": { 359 | "kind": "struct", 360 | "fields": [ 361 | { 362 | "name": "tokenOne", 363 | "type": "publicKey" 364 | }, 365 | { 366 | "name": "tokenTwo", 367 | "type": "publicKey" 368 | }, 369 | { 370 | "name": "totalSupply", 371 | "type": "u64" 372 | }, 373 | { 374 | "name": "reserveOne", 375 | "type": "u64" 376 | }, 377 | { 378 | "name": "reserveTwo", 379 | "type": "u64" 380 | }, 381 | { 382 | "name": "bump", 383 | "type": "u8" 384 | } 385 | ] 386 | } 387 | } 388 | ], 389 | "errors": [ 390 | { 391 | "code": 6000, 392 | "name": "DuplicateTokenNotAllowed", 393 | "msg": "Duplicate tokens are not allowed" 394 | }, 395 | { 396 | "code": 6001, 397 | "name": "FailedToAllocateShares", 398 | "msg": "Failed to allocate shares" 399 | }, 400 | { 401 | "code": 6002, 402 | "name": "FailedToDeallocateShares", 403 | "msg": "Failed to deallocate shares" 404 | }, 405 | { 406 | "code": 6003, 407 | "name": "InsufficientShares", 408 | "msg": "Insufficient shares" 409 | }, 410 | { 411 | "code": 6004, 412 | "name": "InsufficientFunds", 413 | "msg": "Insufficient funds to swap" 414 | }, 415 | { 416 | "code": 6005, 417 | "name": "InvalidAmount", 418 | "msg": "Invalid amount to swap" 419 | }, 420 | { 421 | "code": 6006, 422 | "name": "InvalidFee", 423 | "msg": "Invalid fee" 424 | }, 425 | { 426 | "code": 6007, 427 | "name": "FailedToAddLiquidity", 428 | "msg": "Failed to add liquidity" 429 | }, 430 | { 431 | "code": 6008, 432 | "name": "FailedToRemoveLiquidity", 433 | "msg": "Failed to remove liquidity" 434 | }, 435 | { 436 | "code": 6009, 437 | "name": "OverflowOrUnderflowOccurred", 438 | "msg": "Overflow or underflow occured" 439 | } 440 | ] 441 | }; 442 | 443 | export const IDL: Pump = { 444 | "version": "0.1.0", 445 | "name": "pump", 446 | "instructions": [ 447 | { 448 | "name": "initialize", 449 | "accounts": [ 450 | { 451 | "name": "dexConfigurationAccount", 452 | "isMut": true, 453 | "isSigner": false, 454 | "pda": { 455 | "seeds": [ 456 | { 457 | "kind": "const", 458 | "type": "string", 459 | "value": "CurveConfiguration" 460 | } 461 | ] 462 | } 463 | }, 464 | { 465 | "name": "admin", 466 | "isMut": true, 467 | "isSigner": true 468 | }, 469 | { 470 | "name": "rent", 471 | "isMut": false, 472 | "isSigner": false 473 | }, 474 | { 475 | "name": "systemProgram", 476 | "isMut": false, 477 | "isSigner": false 478 | } 479 | ], 480 | "args": [ 481 | { 482 | "name": "fee", 483 | "type": "f64" 484 | } 485 | ] 486 | }, 487 | { 488 | "name": "addLiquidity", 489 | "accounts": [ 490 | { 491 | "name": "pool", 492 | "isMut": true, 493 | "isSigner": false, 494 | "pda": { 495 | "seeds": [ 496 | { 497 | "kind": "const", 498 | "type": "string", 499 | "value": "liquidity_pool" 500 | }, 501 | { 502 | "kind": "account", 503 | "type": "publicKey", 504 | "account": "Mint", 505 | "path": "mint_token_one" 506 | } 507 | ] 508 | } 509 | }, 510 | { 511 | "name": "liquidityProviderAccount", 512 | "isMut": true, 513 | "isSigner": false, 514 | "pda": { 515 | "seeds": [ 516 | { 517 | "kind": "const", 518 | "type": "string", 519 | "value": "LiqudityProvider" 520 | }, 521 | { 522 | "kind": "account", 523 | "type": "publicKey", 524 | "account": "LiquidityPool", 525 | "path": "pool" 526 | }, 527 | { 528 | "kind": "account", 529 | "type": "publicKey", 530 | "path": "user" 531 | } 532 | ] 533 | } 534 | }, 535 | { 536 | "name": "mintTokenOne", 537 | "isMut": true, 538 | "isSigner": false 539 | }, 540 | { 541 | "name": "poolTokenAccountOne", 542 | "isMut": true, 543 | "isSigner": false 544 | }, 545 | { 546 | "name": "userTokenAccountOne", 547 | "isMut": true, 548 | "isSigner": false 549 | }, 550 | { 551 | "name": "user", 552 | "isMut": true, 553 | "isSigner": true 554 | }, 555 | { 556 | "name": "rent", 557 | "isMut": false, 558 | "isSigner": false 559 | }, 560 | { 561 | "name": "systemProgram", 562 | "isMut": false, 563 | "isSigner": false 564 | }, 565 | { 566 | "name": "tokenProgram", 567 | "isMut": false, 568 | "isSigner": false 569 | }, 570 | { 571 | "name": "associatedTokenProgram", 572 | "isMut": false, 573 | "isSigner": false 574 | } 575 | ], 576 | "args": [ 577 | { 578 | "name": "amountOne", 579 | "type": "u64" 580 | }, 581 | { 582 | "name": "amountTwo", 583 | "type": "u64" 584 | } 585 | ] 586 | }, 587 | { 588 | "name": "removeLiquidity", 589 | "accounts": [ 590 | { 591 | "name": "pool", 592 | "isMut": true, 593 | "isSigner": false, 594 | "pda": { 595 | "seeds": [ 596 | { 597 | "kind": "const", 598 | "type": "string", 599 | "value": "liquidity_pool" 600 | }, 601 | { 602 | "kind": "account", 603 | "type": "publicKey", 604 | "account": "Mint", 605 | "path": "mint_token_one" 606 | } 607 | ] 608 | } 609 | }, 610 | { 611 | "name": "liquidityProviderAccount", 612 | "isMut": true, 613 | "isSigner": false, 614 | "pda": { 615 | "seeds": [ 616 | { 617 | "kind": "const", 618 | "type": "string", 619 | "value": "LiqudityProvider" 620 | }, 621 | { 622 | "kind": "account", 623 | "type": "publicKey", 624 | "account": "LiquidityPool", 625 | "path": "pool" 626 | }, 627 | { 628 | "kind": "account", 629 | "type": "publicKey", 630 | "path": "user" 631 | } 632 | ] 633 | } 634 | }, 635 | { 636 | "name": "mintTokenOne", 637 | "isMut": true, 638 | "isSigner": false 639 | }, 640 | { 641 | "name": "poolTokenAccountOne", 642 | "isMut": true, 643 | "isSigner": false 644 | }, 645 | { 646 | "name": "userTokenAccountOne", 647 | "isMut": true, 648 | "isSigner": false 649 | }, 650 | { 651 | "name": "user", 652 | "isMut": true, 653 | "isSigner": true 654 | }, 655 | { 656 | "name": "rent", 657 | "isMut": false, 658 | "isSigner": false 659 | }, 660 | { 661 | "name": "systemProgram", 662 | "isMut": false, 663 | "isSigner": false 664 | }, 665 | { 666 | "name": "tokenProgram", 667 | "isMut": false, 668 | "isSigner": false 669 | }, 670 | { 671 | "name": "associatedTokenProgram", 672 | "isMut": false, 673 | "isSigner": false 674 | } 675 | ], 676 | "args": [ 677 | { 678 | "name": "shares", 679 | "type": "u64" 680 | } 681 | ] 682 | }, 683 | { 684 | "name": "swap", 685 | "accounts": [ 686 | { 687 | "name": "dexConfigurationAccount", 688 | "isMut": true, 689 | "isSigner": false, 690 | "pda": { 691 | "seeds": [ 692 | { 693 | "kind": "const", 694 | "type": "string", 695 | "value": "CurveConfiguration" 696 | } 697 | ] 698 | } 699 | }, 700 | { 701 | "name": "pool", 702 | "isMut": true, 703 | "isSigner": false, 704 | "pda": { 705 | "seeds": [ 706 | { 707 | "kind": "const", 708 | "type": "string", 709 | "value": "liquidity_pool" 710 | }, 711 | { 712 | "kind": "account", 713 | "type": "publicKey", 714 | "account": "Mint", 715 | "path": "mint_token_one" 716 | } 717 | ] 718 | } 719 | }, 720 | { 721 | "name": "mintTokenOne", 722 | "isMut": true, 723 | "isSigner": false 724 | }, 725 | { 726 | "name": "poolTokenAccountOne", 727 | "isMut": true, 728 | "isSigner": false 729 | }, 730 | { 731 | "name": "userTokenAccountOne", 732 | "isMut": true, 733 | "isSigner": false 734 | }, 735 | { 736 | "name": "user", 737 | "isMut": true, 738 | "isSigner": true 739 | }, 740 | { 741 | "name": "rent", 742 | "isMut": false, 743 | "isSigner": false 744 | }, 745 | { 746 | "name": "systemProgram", 747 | "isMut": false, 748 | "isSigner": false 749 | }, 750 | { 751 | "name": "tokenProgram", 752 | "isMut": false, 753 | "isSigner": false 754 | }, 755 | { 756 | "name": "associatedTokenProgram", 757 | "isMut": false, 758 | "isSigner": false 759 | } 760 | ], 761 | "args": [ 762 | { 763 | "name": "amount", 764 | "type": "u64" 765 | }, 766 | { 767 | "name": "style", 768 | "type": "u64" 769 | } 770 | ] 771 | } 772 | ], 773 | "accounts": [ 774 | { 775 | "name": "curveConfiguration", 776 | "type": { 777 | "kind": "struct", 778 | "fields": [ 779 | { 780 | "name": "fees", 781 | "type": "f64" 782 | } 783 | ] 784 | } 785 | }, 786 | { 787 | "name": "liquidityProvider", 788 | "type": { 789 | "kind": "struct", 790 | "fields": [ 791 | { 792 | "name": "shares", 793 | "type": "u64" 794 | } 795 | ] 796 | } 797 | }, 798 | { 799 | "name": "liquidityPool", 800 | "type": { 801 | "kind": "struct", 802 | "fields": [ 803 | { 804 | "name": "tokenOne", 805 | "type": "publicKey" 806 | }, 807 | { 808 | "name": "tokenTwo", 809 | "type": "publicKey" 810 | }, 811 | { 812 | "name": "totalSupply", 813 | "type": "u64" 814 | }, 815 | { 816 | "name": "reserveOne", 817 | "type": "u64" 818 | }, 819 | { 820 | "name": "reserveTwo", 821 | "type": "u64" 822 | }, 823 | { 824 | "name": "bump", 825 | "type": "u8" 826 | } 827 | ] 828 | } 829 | } 830 | ], 831 | "errors": [ 832 | { 833 | "code": 6000, 834 | "name": "DuplicateTokenNotAllowed", 835 | "msg": "Duplicate tokens are not allowed" 836 | }, 837 | { 838 | "code": 6001, 839 | "name": "FailedToAllocateShares", 840 | "msg": "Failed to allocate shares" 841 | }, 842 | { 843 | "code": 6002, 844 | "name": "FailedToDeallocateShares", 845 | "msg": "Failed to deallocate shares" 846 | }, 847 | { 848 | "code": 6003, 849 | "name": "InsufficientShares", 850 | "msg": "Insufficient shares" 851 | }, 852 | { 853 | "code": 6004, 854 | "name": "InsufficientFunds", 855 | "msg": "Insufficient funds to swap" 856 | }, 857 | { 858 | "code": 6005, 859 | "name": "InvalidAmount", 860 | "msg": "Invalid amount to swap" 861 | }, 862 | { 863 | "code": 6006, 864 | "name": "InvalidFee", 865 | "msg": "Invalid fee" 866 | }, 867 | { 868 | "code": 6007, 869 | "name": "FailedToAddLiquidity", 870 | "msg": "Failed to add liquidity" 871 | }, 872 | { 873 | "code": 6008, 874 | "name": "FailedToRemoveLiquidity", 875 | "msg": "Failed to remove liquidity" 876 | }, 877 | { 878 | "code": 6009, 879 | "name": "OverflowOrUnderflowOccurred", 880 | "msg": "Overflow or underflow occured" 881 | } 882 | ] 883 | }; 884 | -------------------------------------------------------------------------------- /src/program/cli/errors/anchor.ts: -------------------------------------------------------------------------------- 1 | export type AnchorError = 2 | | InstructionMissing 3 | | InstructionFallbackNotFound 4 | | InstructionDidNotDeserialize 5 | | InstructionDidNotSerialize 6 | | IdlInstructionStub 7 | | IdlInstructionInvalidProgram 8 | | ConstraintMut 9 | | ConstraintHasOne 10 | | ConstraintSigner 11 | | ConstraintRaw 12 | | ConstraintOwner 13 | | ConstraintRentExempt 14 | | ConstraintSeeds 15 | | ConstraintExecutable 16 | | ConstraintState 17 | | ConstraintAssociated 18 | | ConstraintAssociatedInit 19 | | ConstraintClose 20 | | ConstraintAddress 21 | | ConstraintZero 22 | | ConstraintTokenMint 23 | | ConstraintTokenOwner 24 | | ConstraintMintMintAuthority 25 | | ConstraintMintFreezeAuthority 26 | | ConstraintMintDecimals 27 | | ConstraintSpace 28 | | ConstraintAccountIsNone 29 | | RequireViolated 30 | | RequireEqViolated 31 | | RequireKeysEqViolated 32 | | RequireNeqViolated 33 | | RequireKeysNeqViolated 34 | | RequireGtViolated 35 | | RequireGteViolated 36 | | AccountDiscriminatorAlreadySet 37 | | AccountDiscriminatorNotFound 38 | | AccountDiscriminatorMismatch 39 | | AccountDidNotDeserialize 40 | | AccountDidNotSerialize 41 | | AccountNotEnoughKeys 42 | | AccountNotMutable 43 | | AccountOwnedByWrongProgram 44 | | InvalidProgramId 45 | | InvalidProgramExecutable 46 | | AccountNotSigner 47 | | AccountNotSystemOwned 48 | | AccountNotInitialized 49 | | AccountNotProgramData 50 | | AccountNotAssociatedTokenAccount 51 | | AccountSysvarMismatch 52 | | AccountReallocExceedsLimit 53 | | AccountDuplicateReallocs 54 | | DeclaredProgramIdMismatch 55 | | Deprecated 56 | 57 | export class InstructionMissing extends Error { 58 | static readonly code = 100 59 | readonly code = 100 60 | readonly name = "InstructionMissing" 61 | readonly msg = "8 byte instruction identifier not provided" 62 | 63 | constructor(readonly logs?: string[]) { 64 | super("100: 8 byte instruction identifier not provided") 65 | } 66 | } 67 | 68 | export class InstructionFallbackNotFound extends Error { 69 | static readonly code = 101 70 | readonly code = 101 71 | readonly name = "InstructionFallbackNotFound" 72 | readonly msg = "Fallback functions are not supported" 73 | 74 | constructor(readonly logs?: string[]) { 75 | super("101: Fallback functions are not supported") 76 | } 77 | } 78 | 79 | export class InstructionDidNotDeserialize extends Error { 80 | static readonly code = 102 81 | readonly code = 102 82 | readonly name = "InstructionDidNotDeserialize" 83 | readonly msg = "The program could not deserialize the given instruction" 84 | 85 | constructor(readonly logs?: string[]) { 86 | super("102: The program could not deserialize the given instruction") 87 | } 88 | } 89 | 90 | export class InstructionDidNotSerialize extends Error { 91 | static readonly code = 103 92 | readonly code = 103 93 | readonly name = "InstructionDidNotSerialize" 94 | readonly msg = "The program could not serialize the given instruction" 95 | 96 | constructor(readonly logs?: string[]) { 97 | super("103: The program could not serialize the given instruction") 98 | } 99 | } 100 | 101 | export class IdlInstructionStub extends Error { 102 | static readonly code = 1000 103 | readonly code = 1000 104 | readonly name = "IdlInstructionStub" 105 | readonly msg = "The program was compiled without idl instructions" 106 | 107 | constructor(readonly logs?: string[]) { 108 | super("1000: The program was compiled without idl instructions") 109 | } 110 | } 111 | 112 | export class IdlInstructionInvalidProgram extends Error { 113 | static readonly code = 1001 114 | readonly code = 1001 115 | readonly name = "IdlInstructionInvalidProgram" 116 | readonly msg = 117 | "The transaction was given an invalid program for the IDL instruction" 118 | 119 | constructor(readonly logs?: string[]) { 120 | super( 121 | "1001: The transaction was given an invalid program for the IDL instruction" 122 | ) 123 | } 124 | } 125 | 126 | export class ConstraintMut extends Error { 127 | static readonly code = 2000 128 | readonly code = 2000 129 | readonly name = "ConstraintMut" 130 | readonly msg = "A mut constraint was violated" 131 | 132 | constructor(readonly logs?: string[]) { 133 | super("2000: A mut constraint was violated") 134 | } 135 | } 136 | 137 | export class ConstraintHasOne extends Error { 138 | static readonly code = 2001 139 | readonly code = 2001 140 | readonly name = "ConstraintHasOne" 141 | readonly msg = "A has one constraint was violated" 142 | 143 | constructor(readonly logs?: string[]) { 144 | super("2001: A has one constraint was violated") 145 | } 146 | } 147 | 148 | export class ConstraintSigner extends Error { 149 | static readonly code = 2002 150 | readonly code = 2002 151 | readonly name = "ConstraintSigner" 152 | readonly msg = "A signer constraint was violated" 153 | 154 | constructor(readonly logs?: string[]) { 155 | super("2002: A signer constraint was violated") 156 | } 157 | } 158 | 159 | export class ConstraintRaw extends Error { 160 | static readonly code = 2003 161 | readonly code = 2003 162 | readonly name = "ConstraintRaw" 163 | readonly msg = "A raw constraint was violated" 164 | 165 | constructor(readonly logs?: string[]) { 166 | super("2003: A raw constraint was violated") 167 | } 168 | } 169 | 170 | export class ConstraintOwner extends Error { 171 | static readonly code = 2004 172 | readonly code = 2004 173 | readonly name = "ConstraintOwner" 174 | readonly msg = "An owner constraint was violated" 175 | 176 | constructor(readonly logs?: string[]) { 177 | super("2004: An owner constraint was violated") 178 | } 179 | } 180 | 181 | export class ConstraintRentExempt extends Error { 182 | static readonly code = 2005 183 | readonly code = 2005 184 | readonly name = "ConstraintRentExempt" 185 | readonly msg = "A rent exemption constraint was violated" 186 | 187 | constructor(readonly logs?: string[]) { 188 | super("2005: A rent exemption constraint was violated") 189 | } 190 | } 191 | 192 | export class ConstraintSeeds extends Error { 193 | static readonly code = 2006 194 | readonly code = 2006 195 | readonly name = "ConstraintSeeds" 196 | readonly msg = "A seeds constraint was violated" 197 | 198 | constructor(readonly logs?: string[]) { 199 | super("2006: A seeds constraint was violated") 200 | } 201 | } 202 | 203 | export class ConstraintExecutable extends Error { 204 | static readonly code = 2007 205 | readonly code = 2007 206 | readonly name = "ConstraintExecutable" 207 | readonly msg = "An executable constraint was violated" 208 | 209 | constructor(readonly logs?: string[]) { 210 | super("2007: An executable constraint was violated") 211 | } 212 | } 213 | 214 | export class ConstraintState extends Error { 215 | static readonly code = 2008 216 | readonly code = 2008 217 | readonly name = "ConstraintState" 218 | readonly msg = "Deprecated Error, feel free to replace with something else" 219 | 220 | constructor(readonly logs?: string[]) { 221 | super("2008: Deprecated Error, feel free to replace with something else") 222 | } 223 | } 224 | 225 | export class ConstraintAssociated extends Error { 226 | static readonly code = 2009 227 | readonly code = 2009 228 | readonly name = "ConstraintAssociated" 229 | readonly msg = "An associated constraint was violated" 230 | 231 | constructor(readonly logs?: string[]) { 232 | super("2009: An associated constraint was violated") 233 | } 234 | } 235 | 236 | export class ConstraintAssociatedInit extends Error { 237 | static readonly code = 2010 238 | readonly code = 2010 239 | readonly name = "ConstraintAssociatedInit" 240 | readonly msg = "An associated init constraint was violated" 241 | 242 | constructor(readonly logs?: string[]) { 243 | super("2010: An associated init constraint was violated") 244 | } 245 | } 246 | 247 | export class ConstraintClose extends Error { 248 | static readonly code = 2011 249 | readonly code = 2011 250 | readonly name = "ConstraintClose" 251 | readonly msg = "A close constraint was violated" 252 | 253 | constructor(readonly logs?: string[]) { 254 | super("2011: A close constraint was violated") 255 | } 256 | } 257 | 258 | export class ConstraintAddress extends Error { 259 | static readonly code = 2012 260 | readonly code = 2012 261 | readonly name = "ConstraintAddress" 262 | readonly msg = "An address constraint was violated" 263 | 264 | constructor(readonly logs?: string[]) { 265 | super("2012: An address constraint was violated") 266 | } 267 | } 268 | 269 | export class ConstraintZero extends Error { 270 | static readonly code = 2013 271 | readonly code = 2013 272 | readonly name = "ConstraintZero" 273 | readonly msg = "Expected zero account discriminant" 274 | 275 | constructor(readonly logs?: string[]) { 276 | super("2013: Expected zero account discriminant") 277 | } 278 | } 279 | 280 | export class ConstraintTokenMint extends Error { 281 | static readonly code = 2014 282 | readonly code = 2014 283 | readonly name = "ConstraintTokenMint" 284 | readonly msg = "A token mint constraint was violated" 285 | 286 | constructor(readonly logs?: string[]) { 287 | super("2014: A token mint constraint was violated") 288 | } 289 | } 290 | 291 | export class ConstraintTokenOwner extends Error { 292 | static readonly code = 2015 293 | readonly code = 2015 294 | readonly name = "ConstraintTokenOwner" 295 | readonly msg = "A token owner constraint was violated" 296 | 297 | constructor(readonly logs?: string[]) { 298 | super("2015: A token owner constraint was violated") 299 | } 300 | } 301 | 302 | export class ConstraintMintMintAuthority extends Error { 303 | static readonly code = 2016 304 | readonly code = 2016 305 | readonly name = "ConstraintMintMintAuthority" 306 | readonly msg = "A mint mint authority constraint was violated" 307 | 308 | constructor(readonly logs?: string[]) { 309 | super("2016: A mint mint authority constraint was violated") 310 | } 311 | } 312 | 313 | export class ConstraintMintFreezeAuthority extends Error { 314 | static readonly code = 2017 315 | readonly code = 2017 316 | readonly name = "ConstraintMintFreezeAuthority" 317 | readonly msg = "A mint freeze authority constraint was violated" 318 | 319 | constructor(readonly logs?: string[]) { 320 | super("2017: A mint freeze authority constraint was violated") 321 | } 322 | } 323 | 324 | export class ConstraintMintDecimals extends Error { 325 | static readonly code = 2018 326 | readonly code = 2018 327 | readonly name = "ConstraintMintDecimals" 328 | readonly msg = "A mint decimals constraint was violated" 329 | 330 | constructor(readonly logs?: string[]) { 331 | super("2018: A mint decimals constraint was violated") 332 | } 333 | } 334 | 335 | export class ConstraintSpace extends Error { 336 | static readonly code = 2019 337 | readonly code = 2019 338 | readonly name = "ConstraintSpace" 339 | readonly msg = "A space constraint was violated" 340 | 341 | constructor(readonly logs?: string[]) { 342 | super("2019: A space constraint was violated") 343 | } 344 | } 345 | 346 | export class ConstraintAccountIsNone extends Error { 347 | static readonly code = 2020 348 | readonly code = 2020 349 | readonly name = "ConstraintAccountIsNone" 350 | readonly msg = "A required account for the constraint is None" 351 | 352 | constructor(readonly logs?: string[]) { 353 | super("2020: A required account for the constraint is None") 354 | } 355 | } 356 | 357 | export class RequireViolated extends Error { 358 | static readonly code = 2500 359 | readonly code = 2500 360 | readonly name = "RequireViolated" 361 | readonly msg = "A require expression was violated" 362 | 363 | constructor(readonly logs?: string[]) { 364 | super("2500: A require expression was violated") 365 | } 366 | } 367 | 368 | export class RequireEqViolated extends Error { 369 | static readonly code = 2501 370 | readonly code = 2501 371 | readonly name = "RequireEqViolated" 372 | readonly msg = "A require_eq expression was violated" 373 | 374 | constructor(readonly logs?: string[]) { 375 | super("2501: A require_eq expression was violated") 376 | } 377 | } 378 | 379 | export class RequireKeysEqViolated extends Error { 380 | static readonly code = 2502 381 | readonly code = 2502 382 | readonly name = "RequireKeysEqViolated" 383 | readonly msg = "A require_keys_eq expression was violated" 384 | 385 | constructor(readonly logs?: string[]) { 386 | super("2502: A require_keys_eq expression was violated") 387 | } 388 | } 389 | 390 | export class RequireNeqViolated extends Error { 391 | static readonly code = 2503 392 | readonly code = 2503 393 | readonly name = "RequireNeqViolated" 394 | readonly msg = "A require_neq expression was violated" 395 | 396 | constructor(readonly logs?: string[]) { 397 | super("2503: A require_neq expression was violated") 398 | } 399 | } 400 | 401 | export class RequireKeysNeqViolated extends Error { 402 | static readonly code = 2504 403 | readonly code = 2504 404 | readonly name = "RequireKeysNeqViolated" 405 | readonly msg = "A require_keys_neq expression was violated" 406 | 407 | constructor(readonly logs?: string[]) { 408 | super("2504: A require_keys_neq expression was violated") 409 | } 410 | } 411 | 412 | export class RequireGtViolated extends Error { 413 | static readonly code = 2505 414 | readonly code = 2505 415 | readonly name = "RequireGtViolated" 416 | readonly msg = "A require_gt expression was violated" 417 | 418 | constructor(readonly logs?: string[]) { 419 | super("2505: A require_gt expression was violated") 420 | } 421 | } 422 | 423 | export class RequireGteViolated extends Error { 424 | static readonly code = 2506 425 | readonly code = 2506 426 | readonly name = "RequireGteViolated" 427 | readonly msg = "A require_gte expression was violated" 428 | 429 | constructor(readonly logs?: string[]) { 430 | super("2506: A require_gte expression was violated") 431 | } 432 | } 433 | 434 | export class AccountDiscriminatorAlreadySet extends Error { 435 | static readonly code = 3000 436 | readonly code = 3000 437 | readonly name = "AccountDiscriminatorAlreadySet" 438 | readonly msg = "The account discriminator was already set on this account" 439 | 440 | constructor(readonly logs?: string[]) { 441 | super("3000: The account discriminator was already set on this account") 442 | } 443 | } 444 | 445 | export class AccountDiscriminatorNotFound extends Error { 446 | static readonly code = 3001 447 | readonly code = 3001 448 | readonly name = "AccountDiscriminatorNotFound" 449 | readonly msg = "No 8 byte discriminator was found on the account" 450 | 451 | constructor(readonly logs?: string[]) { 452 | super("3001: No 8 byte discriminator was found on the account") 453 | } 454 | } 455 | 456 | export class AccountDiscriminatorMismatch extends Error { 457 | static readonly code = 3002 458 | readonly code = 3002 459 | readonly name = "AccountDiscriminatorMismatch" 460 | readonly msg = "8 byte discriminator did not match what was expected" 461 | 462 | constructor(readonly logs?: string[]) { 463 | super("3002: 8 byte discriminator did not match what was expected") 464 | } 465 | } 466 | 467 | export class AccountDidNotDeserialize extends Error { 468 | static readonly code = 3003 469 | readonly code = 3003 470 | readonly name = "AccountDidNotDeserialize" 471 | readonly msg = "Failed to deserialize the account" 472 | 473 | constructor(readonly logs?: string[]) { 474 | super("3003: Failed to deserialize the account") 475 | } 476 | } 477 | 478 | export class AccountDidNotSerialize extends Error { 479 | static readonly code = 3004 480 | readonly code = 3004 481 | readonly name = "AccountDidNotSerialize" 482 | readonly msg = "Failed to serialize the account" 483 | 484 | constructor(readonly logs?: string[]) { 485 | super("3004: Failed to serialize the account") 486 | } 487 | } 488 | 489 | export class AccountNotEnoughKeys extends Error { 490 | static readonly code = 3005 491 | readonly code = 3005 492 | readonly name = "AccountNotEnoughKeys" 493 | readonly msg = "Not enough account keys given to the instruction" 494 | 495 | constructor(readonly logs?: string[]) { 496 | super("3005: Not enough account keys given to the instruction") 497 | } 498 | } 499 | 500 | export class AccountNotMutable extends Error { 501 | static readonly code = 3006 502 | readonly code = 3006 503 | readonly name = "AccountNotMutable" 504 | readonly msg = "The given account is not mutable" 505 | 506 | constructor(readonly logs?: string[]) { 507 | super("3006: The given account is not mutable") 508 | } 509 | } 510 | 511 | export class AccountOwnedByWrongProgram extends Error { 512 | static readonly code = 3007 513 | readonly code = 3007 514 | readonly name = "AccountOwnedByWrongProgram" 515 | readonly msg = 516 | "The given account is owned by a different program than expected" 517 | 518 | constructor(readonly logs?: string[]) { 519 | super( 520 | "3007: The given account is owned by a different program than expected" 521 | ) 522 | } 523 | } 524 | 525 | export class InvalidProgramId extends Error { 526 | static readonly code = 3008 527 | readonly code = 3008 528 | readonly name = "InvalidProgramId" 529 | readonly msg = "Program ID was not as expected" 530 | 531 | constructor(readonly logs?: string[]) { 532 | super("3008: Program ID was not as expected") 533 | } 534 | } 535 | 536 | export class InvalidProgramExecutable extends Error { 537 | static readonly code = 3009 538 | readonly code = 3009 539 | readonly name = "InvalidProgramExecutable" 540 | readonly msg = "Program account is not executable" 541 | 542 | constructor(readonly logs?: string[]) { 543 | super("3009: Program account is not executable") 544 | } 545 | } 546 | 547 | export class AccountNotSigner extends Error { 548 | static readonly code = 3010 549 | readonly code = 3010 550 | readonly name = "AccountNotSigner" 551 | readonly msg = "The given account did not sign" 552 | 553 | constructor(readonly logs?: string[]) { 554 | super("3010: The given account did not sign") 555 | } 556 | } 557 | 558 | export class AccountNotSystemOwned extends Error { 559 | static readonly code = 3011 560 | readonly code = 3011 561 | readonly name = "AccountNotSystemOwned" 562 | readonly msg = "The given account is not owned by the system program" 563 | 564 | constructor(readonly logs?: string[]) { 565 | super("3011: The given account is not owned by the system program") 566 | } 567 | } 568 | 569 | export class AccountNotInitialized extends Error { 570 | static readonly code = 3012 571 | readonly code = 3012 572 | readonly name = "AccountNotInitialized" 573 | readonly msg = "The program expected this account to be already initialized" 574 | 575 | constructor(readonly logs?: string[]) { 576 | super("3012: The program expected this account to be already initialized") 577 | } 578 | } 579 | 580 | export class AccountNotProgramData extends Error { 581 | static readonly code = 3013 582 | readonly code = 3013 583 | readonly name = "AccountNotProgramData" 584 | readonly msg = "The given account is not a program data account" 585 | 586 | constructor(readonly logs?: string[]) { 587 | super("3013: The given account is not a program data account") 588 | } 589 | } 590 | 591 | export class AccountNotAssociatedTokenAccount extends Error { 592 | static readonly code = 3014 593 | readonly code = 3014 594 | readonly name = "AccountNotAssociatedTokenAccount" 595 | readonly msg = "The given account is not the associated token account" 596 | 597 | constructor(readonly logs?: string[]) { 598 | super("3014: The given account is not the associated token account") 599 | } 600 | } 601 | 602 | export class AccountSysvarMismatch extends Error { 603 | static readonly code = 3015 604 | readonly code = 3015 605 | readonly name = "AccountSysvarMismatch" 606 | readonly msg = "The given public key does not match the required sysvar" 607 | 608 | constructor(readonly logs?: string[]) { 609 | super("3015: The given public key does not match the required sysvar") 610 | } 611 | } 612 | 613 | export class AccountReallocExceedsLimit extends Error { 614 | static readonly code = 3016 615 | readonly code = 3016 616 | readonly name = "AccountReallocExceedsLimit" 617 | readonly msg = 618 | "The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit" 619 | 620 | constructor(readonly logs?: string[]) { 621 | super( 622 | "3016: The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit" 623 | ) 624 | } 625 | } 626 | 627 | export class AccountDuplicateReallocs extends Error { 628 | static readonly code = 3017 629 | readonly code = 3017 630 | readonly name = "AccountDuplicateReallocs" 631 | readonly msg = "The account was duplicated for more than one reallocation" 632 | 633 | constructor(readonly logs?: string[]) { 634 | super("3017: The account was duplicated for more than one reallocation") 635 | } 636 | } 637 | 638 | export class DeclaredProgramIdMismatch extends Error { 639 | static readonly code = 4100 640 | readonly code = 4100 641 | readonly name = "DeclaredProgramIdMismatch" 642 | readonly msg = "The declared program id does not match the actual program id" 643 | 644 | constructor(readonly logs?: string[]) { 645 | super("4100: The declared program id does not match the actual program id") 646 | } 647 | } 648 | 649 | export class Deprecated extends Error { 650 | static readonly code = 5000 651 | readonly code = 5000 652 | readonly name = "Deprecated" 653 | readonly msg = "The API being used is deprecated and should no longer be used" 654 | 655 | constructor(readonly logs?: string[]) { 656 | super("5000: The API being used is deprecated and should no longer be used") 657 | } 658 | } 659 | 660 | export function fromCode(code: number, logs?: string[]): AnchorError | null { 661 | switch (code) { 662 | case 100: 663 | return new InstructionMissing(logs) 664 | case 101: 665 | return new InstructionFallbackNotFound(logs) 666 | case 102: 667 | return new InstructionDidNotDeserialize(logs) 668 | case 103: 669 | return new InstructionDidNotSerialize(logs) 670 | case 1000: 671 | return new IdlInstructionStub(logs) 672 | case 1001: 673 | return new IdlInstructionInvalidProgram(logs) 674 | case 2000: 675 | return new ConstraintMut(logs) 676 | case 2001: 677 | return new ConstraintHasOne(logs) 678 | case 2002: 679 | return new ConstraintSigner(logs) 680 | case 2003: 681 | return new ConstraintRaw(logs) 682 | case 2004: 683 | return new ConstraintOwner(logs) 684 | case 2005: 685 | return new ConstraintRentExempt(logs) 686 | case 2006: 687 | return new ConstraintSeeds(logs) 688 | case 2007: 689 | return new ConstraintExecutable(logs) 690 | case 2008: 691 | return new ConstraintState(logs) 692 | case 2009: 693 | return new ConstraintAssociated(logs) 694 | case 2010: 695 | return new ConstraintAssociatedInit(logs) 696 | case 2011: 697 | return new ConstraintClose(logs) 698 | case 2012: 699 | return new ConstraintAddress(logs) 700 | case 2013: 701 | return new ConstraintZero(logs) 702 | case 2014: 703 | return new ConstraintTokenMint(logs) 704 | case 2015: 705 | return new ConstraintTokenOwner(logs) 706 | case 2016: 707 | return new ConstraintMintMintAuthority(logs) 708 | case 2017: 709 | return new ConstraintMintFreezeAuthority(logs) 710 | case 2018: 711 | return new ConstraintMintDecimals(logs) 712 | case 2019: 713 | return new ConstraintSpace(logs) 714 | case 2020: 715 | return new ConstraintAccountIsNone(logs) 716 | case 2500: 717 | return new RequireViolated(logs) 718 | case 2501: 719 | return new RequireEqViolated(logs) 720 | case 2502: 721 | return new RequireKeysEqViolated(logs) 722 | case 2503: 723 | return new RequireNeqViolated(logs) 724 | case 2504: 725 | return new RequireKeysNeqViolated(logs) 726 | case 2505: 727 | return new RequireGtViolated(logs) 728 | case 2506: 729 | return new RequireGteViolated(logs) 730 | case 3000: 731 | return new AccountDiscriminatorAlreadySet(logs) 732 | case 3001: 733 | return new AccountDiscriminatorNotFound(logs) 734 | case 3002: 735 | return new AccountDiscriminatorMismatch(logs) 736 | case 3003: 737 | return new AccountDidNotDeserialize(logs) 738 | case 3004: 739 | return new AccountDidNotSerialize(logs) 740 | case 3005: 741 | return new AccountNotEnoughKeys(logs) 742 | case 3006: 743 | return new AccountNotMutable(logs) 744 | case 3007: 745 | return new AccountOwnedByWrongProgram(logs) 746 | case 3008: 747 | return new InvalidProgramId(logs) 748 | case 3009: 749 | return new InvalidProgramExecutable(logs) 750 | case 3010: 751 | return new AccountNotSigner(logs) 752 | case 3011: 753 | return new AccountNotSystemOwned(logs) 754 | case 3012: 755 | return new AccountNotInitialized(logs) 756 | case 3013: 757 | return new AccountNotProgramData(logs) 758 | case 3014: 759 | return new AccountNotAssociatedTokenAccount(logs) 760 | case 3015: 761 | return new AccountSysvarMismatch(logs) 762 | case 3016: 763 | return new AccountReallocExceedsLimit(logs) 764 | case 3017: 765 | return new AccountDuplicateReallocs(logs) 766 | case 4100: 767 | return new DeclaredProgramIdMismatch(logs) 768 | case 5000: 769 | return new Deprecated(logs) 770 | } 771 | 772 | return null 773 | } 774 | --------------------------------------------------------------------------------