├── Cargo.toml ├── .DS_Store ├── programs └── nut_marketplace │ ├── Xargo.toml │ ├── src │ ├── constants.rs │ ├── account.rs │ └── error.rs │ └── Cargo.toml ├── .prettierignore ├── target ├── deploy │ ├── nut_marketplace.so │ └── nut_marketplace-keypair.json └── idl │ └── nut_marketplace.json ├── .gitignore ├── tsconfig.json ├── Anchor.toml ├── migrations └── deploy.ts ├── package.json ├── lib ├── types.ts └── utils.ts ├── README.md ├── cli ├── be.ts ├── command.ts └── scripts.ts ├── tests └── nut_marketplace.ts └── Cargo.lock /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whisdev/magiceden-nutmarket/HEAD/.DS_Store -------------------------------------------------------------------------------- /programs/nut_marketplace/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /target/deploy/nut_marketplace.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whisdev/magiceden-nutmarket/HEAD/target/deploy/nut_marketplace.so -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .anchor 3 | .DS_Store 4 | target/bpfel*/ 5 | target/debug/ 6 | target/release/ 7 | target/rls/ 8 | target/*.* 9 | programs/**/target/ 10 | dist/ 11 | build/ 12 | test-ledger/ 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["mocha", "chai"], 4 | "typeRoots": ["./node_modules/@types"], 5 | "lib": ["es2015"], 6 | "module": "commonjs", 7 | "target": "es6", 8 | "esModuleInterop": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /target/deploy/nut_marketplace-keypair.json: -------------------------------------------------------------------------------- 1 | [125,195,174,34,205,50,107,154,129,35,171,176,178,178,28,79,65,29,61,246,184,175,21,43,58,242,7,226,198,131,46,205,31,125,212,197,234,176,38,97,51,170,223,71,58,140,185,98,64,151,189,129,196,176,240,46,69,230,103,242,119,155,241,130] -------------------------------------------------------------------------------- /Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.devnet] 4 | nut_marketplace = "37vvcTUnSSstVDgzd1jhujmpbw3jtw8ioi3mB7YfZJuP" 5 | 6 | [registry] 7 | url = "https://anchor.projectserum.com" 8 | 9 | [provider] 10 | # cluster = "http://127.0.0.1:8899" 11 | cluster = "localnet" 12 | wallet = "/home/ubuntu/fury/deploy-keypair.json" 13 | 14 | [scripts] 15 | test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" 16 | -------------------------------------------------------------------------------- /programs/nut_marketplace/src/constants.rs: -------------------------------------------------------------------------------- 1 | pub const GLOBAL_AUTHORITY_SEED: &str = "global-authority-v1"; 2 | pub const SELL_DATA_SEED: &str = "sell-info-v1"; 3 | pub const OFFER_DATA_SEED: &str = "offer-info-v1"; 4 | pub const USER_DATA_SEED: &str = "user-info-v1"; 5 | pub const AUCTION_DATA_SEED: &str = "auction-info-v1"; 6 | pub const ESCROW_VAULT_SEED: &str = "escrow-vault"; 7 | 8 | pub const PERMYRIAD: u64 = 10_000; // Permyriad Measure Unit -------------------------------------------------------------------------------- /migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | const anchor = require("@project-serum/anchor"); 6 | 7 | module.exports = async function (provider) { 8 | // Configure client to use the provider. 9 | anchor.setProvider(provider); 10 | 11 | // Add your deploy script here. 12 | }; 13 | -------------------------------------------------------------------------------- /programs/nut_marketplace/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nut_marketplace" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "nut_marketplace" 10 | 11 | [features] 12 | no-entrypoint = [] 13 | no-idl = [] 14 | no-log-ix-name = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | 18 | [profile.release] 19 | overflow-checks = true 20 | 21 | [dependencies] 22 | anchor-lang = "0.24.2" 23 | anchor-spl = "0.24.2" 24 | metaplex-token-metadata = { version = "0.0.1", features = ["no-entrypoint"] } 25 | spl-associated-token-account = {version = "1.0.3", features = [ "no-entrypoint" ]} 26 | solana-program = "1.9.5" 27 | spl-token = "3.3.0" 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", 4 | "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check", 5 | "ts-node": "export ANCHOR_WALLET=/home/root/fury/deploy-231218.json&& ts-node ./cli/command.ts", 6 | "be": "export ANCHOR_WALLET=/home/root/fury/deploy-231218.json&& ts-node ./cli/be.ts" 7 | }, 8 | "dependencies": { 9 | "@metaplex/js": "^4.12.0", 10 | "@project-serum/anchor": "^0.24.2", 11 | "@solana/spl-token": "^0.1.8", 12 | "commander": "^9.1.0", 13 | "fs": "^0.0.1-security" 14 | }, 15 | "devDependencies": { 16 | "@types/bn.js": "^5.1.0", 17 | "@types/chai": "^4.3.0", 18 | "@types/mocha": "^9.0.0", 19 | "chai": "^4.3.4", 20 | "mocha": "^9.0.3", 21 | "prettier": "^2.6.2", 22 | "ts-mocha": "^8.0.0", 23 | "typescript": "^4.3.5" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /programs/nut_marketplace/src/account.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | #[account] 4 | #[derive(Default)] 5 | pub struct GlobalPool { 6 | // 8 + 368 7 | pub super_admin: Pubkey, // 32 8 | pub market_fee_sol: u64, // 8 Permyriad 9 | pub team_count: u64, // 8 10 | pub team_treasury: [Pubkey; 8], // 8 * 32 11 | pub treasury_rate: [u64; 8], // 8 * 8 12 | } 13 | 14 | #[account] 15 | #[derive(Default)] 16 | pub struct SellData { 17 | // 8 + 120 18 | pub mint: Pubkey, // 32 19 | pub seller: Pubkey, // 32 20 | pub collection: Pubkey, // 32 21 | pub price_sol: u64, // 8 22 | pub listed_date: i64, // 8 23 | pub active: u64, // 8 24 | } 25 | 26 | #[account] 27 | #[derive(Default)] 28 | pub struct OfferData { 29 | // 8 + 88 30 | pub mint: Pubkey, // 32 31 | pub buyer: Pubkey, // 32 32 | pub offer_price: u64, // 8 33 | pub offer_listing_date: i64, // 8 34 | pub active: u64, // 8 35 | } 36 | 37 | #[account] 38 | #[derive(Default)] 39 | pub struct AuctionData { 40 | // 8 + 152 41 | pub mint: Pubkey, // 32 42 | pub creator: Pubkey, // 32 43 | pub start_price: u64, // 8 44 | pub min_increase_amount: u64, // 8 45 | pub start_date: i64, // 8 46 | pub last_bid_date: i64, // 8 47 | pub last_bidder: Pubkey, // 32 48 | pub highest_bid: u64, // 8 49 | pub duration: i64, // 8 50 | // 0-canceled, 1-started, 2-claimed, 3-reserved 51 | pub status: u64, // 8 52 | } 53 | 54 | #[account] 55 | #[derive(Default)] 56 | pub struct UserData { 57 | // 8 + 48 58 | pub address: Pubkey, // 32 59 | pub traded_volume: u64, // 8 60 | pub escrow_sol_balance: u64, // 8 61 | } 62 | 63 | impl AuctionData { 64 | pub fn get_end_date(&self) -> i64 { 65 | self.start_date + self.duration 66 | } 67 | } -------------------------------------------------------------------------------- /lib/types.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from '@project-serum/anchor'; 2 | import { PublicKey } from '@solana/web3.js'; 3 | 4 | export const GLOBAL_AUTHORITY_SEED = "global-authority-v1"; 5 | export const SELL_DATA_SEED = "sell-info-v1"; 6 | export const SELL_DATA_SIZE = 128; 7 | export const OFFER_DATA_SEED = "offer-info-v1"; 8 | export const OFFER_DATA_SIZE = 96; 9 | export const USER_DATA_SEED = "user-info-v1"; 10 | export const AUCTION_DATA_SEED = "auction-info-v1"; 11 | export const AUCTION_DATA_SIZE = 160; 12 | export const ESCROW_VAULT_SEED = "escrow-vault"; 13 | 14 | export const MARKETPLACE_PROGRAM_ID = new PublicKey("37vvcTUnSSstVDgzd1jhujmpbw3jtw8ioi3mB7YfZJuP"); 15 | 16 | export interface GlobalPool { 17 | // 8 + 368 18 | superAdmin: PublicKey, // 32 19 | marketFeeSol: anchor.BN, // 8 20 | teamCount: anchor.BN, // 8 21 | teamTreasury: PublicKey[], // 8 * 32 22 | treasuryRate: anchor.BN[], // 8 * 8 23 | } 24 | 25 | export interface SellData { 26 | // 8 + 120 27 | mint: PublicKey, // 32 28 | seller: PublicKey, // 32 29 | collection: PublicKey, // 32 30 | priceSol: anchor.BN, // 8 31 | listedDate: anchor.BN, // 8 32 | active: anchor.BN, // 8 33 | } 34 | 35 | export interface OfferData { 36 | // 8 + 88 37 | mint: PublicKey, // 32 38 | buyer: PublicKey, // 32 39 | offerPrice: anchor.BN, // 8 40 | offerListingDate: anchor.BN, // 8 41 | active: anchor.BN, // 8 42 | } 43 | 44 | export interface AuctionData { 45 | // 8 + 152 46 | mint: PublicKey, // 32 47 | creator: PublicKey, // 32 48 | startPrice: anchor.BN, // 8 49 | minIncreaseAmount: anchor.BN, // 8 50 | startDate: anchor.BN, // 8 51 | lastBidDate: anchor.BN, // 8 52 | lastBidder: PublicKey, // 32 53 | highestBid: anchor.BN, // 8 54 | duration: anchor.BN, // 8 55 | status: anchor.BN, // 8 56 | } 57 | 58 | export interface UserData { 59 | // 8 + 48 60 | address: PublicKey, // 32 61 | tradedVolume: anchor.BN, // 8 62 | escrowSolBalance: anchor.BN, // 8 63 | } -------------------------------------------------------------------------------- /programs/nut_marketplace/src/error.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | #[error_code] 4 | pub enum MarketplaceError { 5 | // 0x1770 - 0 6 | #[msg("Invalid Super Owner")] 7 | InvalidSuperOwner, 8 | // 0x1771 9 | #[msg("Invalid Owner")] 10 | InvalidOwner, 11 | // 0x1772 12 | #[msg("Invalid Global Pool Address")] 13 | InvalidGlobalPool, 14 | // 0x1773 15 | #[msg("Marketplace Fee is Permyriad")] 16 | InvalidFeePercent, 17 | 18 | // 0x1774 19 | #[msg("Max Team Count is 8")] 20 | MaxTeamCountExceed, 21 | // 0x1775 - 5 22 | #[msg("Treasury Wallet Not Configured")] 23 | NoTeamTreasuryYet, 24 | // 0x1776 25 | #[msg("Treasury Address Not Exist")] 26 | TreasuryAddressNotFound, 27 | // 0x1777 28 | #[msg("Treasury Address Already Exist")] 29 | TreasuryAddressAlreadyAdded, 30 | // 0x1778 31 | #[msg("Total Treasury Rate Sum Should Less Than 100%")] 32 | MaxTreasuryRateSumExceed, 33 | // 0x1779 34 | #[msg("Team Treasury Wallet Count Mismatch")] 35 | TeamTreasuryCountMismatch, 36 | // 0x177a - 10 37 | #[msg("Team Treasury Wallet Address Mismatch")] 38 | TeamTreasuryAddressMismatch, 39 | 40 | // 0x177b 41 | #[msg("Uninitialized Account")] 42 | Uninitialized, 43 | // 0x177c 44 | #[msg("Instruction Parameter is Invalid")] 45 | InvalidParamInput, 46 | 47 | // 0x177d 48 | #[msg("Payer Mismatch with NFT Seller")] 49 | SellerMismatch, 50 | // 0x177e 51 | #[msg("Invalid NFT Data Account")] 52 | InvalidNFTDataAcount, 53 | // 0x177f - 15 54 | #[msg("The NFT Is Not Listed")] 55 | NotListedNFT, 56 | 57 | // 0x1780 58 | #[msg("Seller Account Mismatch with NFT Seller Data")] 59 | SellerAccountMismatch, 60 | // 0x1781 61 | #[msg("Buyer Sol Balance is Less than NFT SOL Price")] 62 | InsufficientBuyerSolBalance, 63 | // 0x1782 64 | #[msg("Buyer Token Balance is Less than NFT Token Price")] 65 | InsufficientBuyerTokenBalance, 66 | 67 | // 0x1783 68 | #[msg("Invalid Metadata Address")] 69 | InvaliedMetadata, 70 | // 0x1784 - 20 71 | #[msg("Can't Parse The NFT's Creators")] 72 | MetadataCreatorParseError, 73 | 74 | // 0x1785 75 | #[msg("Offer Data Mint mismatch with NFT Pubkey")] 76 | InvalidOfferDataMint, 77 | // 0x1786 78 | #[msg("Offer Data Buyer mismatch with Payer Pubkey")] 79 | InvalidOfferDataBuyer, 80 | // 0x1787 81 | #[msg("Making Offer for Not Listed NFT")] 82 | OfferForNotListedNFT, 83 | // 0x1788 84 | #[msg("Offer Price Over Thank Listed Price")] 85 | InvalidOfferPrice, 86 | // 0x1789 - 25 87 | #[msg("Already Canceled Offer")] 88 | DisabledOffer, 89 | // 0x178a 90 | #[msg("Offer For Sold Or Canceled NFT Listing")] 91 | OfferForExpiredListingNFT, 92 | 93 | // 0x178b 94 | #[msg("Placing Bid For Ended Auction")] 95 | EndedAuction, 96 | // 0x178c 97 | #[msg("Placing Bid With Lower Than Highest Bid")] 98 | InvalidBidPrice, 99 | // 0x178d 100 | #[msg("Placing Bid Double From One Bidder")] 101 | DoubleBidFromOneBidder, 102 | // 0x178e - 30 103 | #[msg("Out Bidder Account Mismatch With LastBidder Data")] 104 | OutBidderMismatch, 105 | // 0x178f 106 | #[msg("Claiming Auction For Not Ended Auction")] 107 | NotEndedAuction, 108 | // 0x1790 109 | #[msg("Creator Account Mismatch with Auction Data")] 110 | CreatorAccountMismatch, 111 | // 0x1791 112 | #[msg("Bidder Account Mismatch with Auction Data")] 113 | BidderAccountMismatch, 114 | // 0x1792 115 | #[msg("Canceling Auction which has Bid")] 116 | AuctionHasBid, 117 | // 0x1793 118 | #[msg("Placing Bid From Auction Creator")] 119 | BidFromAuctionCreator, 120 | 121 | // 0x1794 122 | #[msg("Only Listing and Reserved Auction are possible to exist together")] 123 | ListingNotAvailable, 124 | // 0x1795 125 | #[msg("NFT Is Not In User ATA")] 126 | NFTIsNotInUserATA, 127 | // 0x1796 128 | #[msg("NFT Is Not In Escrow ATA")] 129 | NFTIsNotInEscrowATA, 130 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nut-Marketplace-Contract 2 | Solana NFT Marketplace program with NFT Trading & Auction 3 | 4 | ## Prerequirements 5 | 6 | Need to build up anchor development environment
7 | ``` 8 | anchor version 0.24.2 9 | solana version 1.14.17 10 | node version 18.17.0 11 | ``` 12 | 13 | ## Program Deployment 14 | 15 | - Prepare anchor development environments 16 | - Prepare aroun 12 SOL in the deploy wallet keypair 17 | - Confirm Network cluster in `Anchor.toml` file : f.e. `[programs.devnet]`, `cluster = "devnet"` 18 | - Confirm deploy authority wallet keypair location : f.e. `wallet = "/home/ubuntu/deploy-keypair.json" 19 | - Configure solana cli with deploy authority keypair and deploying cluster : f.e. `solana config set -h` 20 | - Build program with `anchor build` 21 | - Copy and paste the result deploy scripts from Build terminal message : f.e. `solana program deploy /home/ubuntu/project/target/deploy/nut_marketplace.so` 22 | 23 | ### To Change Program Address 24 | 25 | - Delete the program keypair in `/target/deploy/nut_marketplace-keypair.json` 26 | - Build project with `anchor build`. This will generate new keypair 27 | - Get the address of new keypair with `solana address --keypair ./target/deploy/nut_marketplace-keypair.json` 28 | - Change program addresses in project code. `Anchor.toml`, `/program/nut_marketplace/src/lib.rs` 29 | - Build program object again with `anchor build` 30 | - Deploy newly built so file with `solana program deploy` 31 | 32 | ## Cli Command usage 33 | 34 | Able to run all commands in `/cli/command.ts` file by running `yarn ts-node xxx`. 35 | When you get this error
36 | `Error: Provider local is not available on browser.` 37 | You can run this command `export BROWSER=` once. 38 | 39 | ### Install Dependencies 40 | 41 | - Install `node` and `yarn` 42 | - Install `ts-node` as global command 43 | - Confirm the solana wallet preparation in `package.json`: `/home/fury/.config/solana/id.json` in test case 44 | 45 | ### Init Program 46 | 47 | - Initialize program with `init` command 48 | - Should configure the marketplace fee with `update_fee` command 49 | - Should add at least one `treasury` wallet with `add_treasury` command for the fee distribution 50 | - Should Initialize user PDA with `init_user` command for the first time usage 51 | 52 | ## Commands Help 53 | 54 | ### init 55 | Initialize Program with creating Global PDA account as Contract Deployer. 56 | 57 | ### status 58 | Get global PDA info of program. This will show marketplace fee the treasury wallet distributions. 59 | 60 | ### update_fee 61 | Admin able to update the Marketplace Fee with this command as Admin. 62 | - `sol_fee` is the fee in permyraid 63 | 64 | ### add_treasury 65 | Admin able to add the team treasury wallet distribution rate for the marketplace fee charge. 66 | - `address` is the treasury wallet 67 | - `rate` is the wallet's distribution rate by permyraid 68 | 69 | ### remove_treasury 70 | Admin able to remove the team treasury wallet. 71 | - `address` is the treasury wallet 72 | 73 | ### init_user 74 | Initialize User Data PDA for Escrow Balance & Traded Volume. 75 | This command should be executed for the first time usage of each traders. 76 | 77 | ### user_status 78 | Get user PDA info for traders. This will show user escrow balance and traded volume info. 79 | - `address` is the trader wallet address 80 | 81 | ### transfer 82 | Transfer NFT from Sender wallet or it's listed Escrow Account to the Recipient. 83 | - `address` is the NFT mint address 84 | - `recipient` is the recipient wallet address 85 | 86 | ### list 87 | List NFT for sale as Seller. 88 | - `address` is the NFT mint address 89 | - `price_sol` is the listing price of NFT 90 | 91 | ### delist 92 | Cancel Listing of NFT as Seller. 93 | - `address` is the NFT mint address 94 | 95 | ### purchase 96 | Purchase the Listed NFT with `Buy Now` price as Buyer. 97 | - `address` is the NFT mint address 98 | 99 | ### make_offer 100 | Make offer for a particular Listed NFT as Buyer. 101 | - `address` is the NFT mint address 102 | - `price` is the offering price. Should be in range of `x1 ~ x0.5` of listed price 103 | 104 | ### cancel_offer 105 | Cancel maden offer for a particular Listed NFT as Buyer. 106 | - `address` is the NFT mint address 107 | 108 | ### accept_offer 109 | Accpet proper offer from a certain Buyer as Seller. 110 | - `address` is the NFT mint addres 111 | - `buyer` is the Offer provider address 112 | 113 | ### create_auction 114 | Create Auction for a particular NFT for funny trading as Seller. 115 | - `address` is the NFT mint address 116 | - `start_price` is the bidding start price 117 | - `min_increase` is the minimum increasing amount for the higer bidding 118 | - `duration` is the auction period since started time by second 119 | - `reserve` if this is 1, then the auction is reserve to start from the first bid placed date. Default 0 120 | 121 | ### palce_bid 122 | Participate in auction with higher bidding as Buyer. 123 | - `address` is the NFT mint address 124 | - `price` is the higher bidding price. Should be more than the latest bid + min_increase_amount 125 | 126 | ### claim_auction 127 | Claim NFT for winner as Buyer when auction is ended. 128 | - `address` is the NFT mint address 129 | 130 | ### cancel_auction 131 | Cancel auction as Seller if there is no bid until auction ended. 132 | - `address` is the NFT mint address 133 | 134 | ### listed_nft_data 135 | Get nft Sell Data PDA info for a particular listed NFT status. 136 | - `address` NFT mint address 137 | 138 | ### get_offer_data 139 | Get Offer Data PDA info for a particular Offer status. 140 | - `address` NFT mint address 141 | - `buyer` is the offer provider address 142 | 143 | ### get_auction_data 144 | Get Auction Data PDA info for a particular auction status. 145 | - `address` NFT mint address 146 | 147 | ### get_all_listed_nfts 148 | Get all listed NFTs info which is active for sale now. 149 | 150 | ### get_all_offers_for_nft 151 | Get all offers info for a particular NFT which is active for accept now. 152 | 153 | ### get_all_auctions 154 | Get all auctions info which is live now or not claimed ended auction. 155 | 156 | ## Notes for FE Integration 157 | 158 | For the FE side web3 integration, the scripts in `lib` directory can be use without no change. 159 | The only thing the FE dev should change is providing `web3 connection` & the `anchor program` object from idl. 160 | There is the code part for the `keypair` wallet based `cli` environement case in `cli/scripts`. 161 | Should configure properly in `BROWSER` environment. 162 | 163 | ## BE Tracking Service Activity Parsing Script 164 | This script will fetch past Txs reacted with Our Marketplace Smartcontract. Then will parse an activity from each Txs so that use the info for DB sync up. \ 165 | `yarn be` 166 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | PublicKey, 4 | SystemProgram, 5 | SYSVAR_RENT_PUBKEY, 6 | TransactionInstruction, 7 | Transaction, 8 | Keypair, 9 | } from '@solana/web3.js'; 10 | import { TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, Token, MintLayout } from "@solana/spl-token"; 11 | import { ESCROW_VAULT_SEED, GLOBAL_AUTHORITY_SEED, MARKETPLACE_PROGRAM_ID, USER_DATA_SEED } from './types'; 12 | 13 | export const METAPLEX = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'); 14 | 15 | export const getOwnerOfNFT = async (nftMintPk : PublicKey, connection: Connection) : Promise => { 16 | let tokenAccountPK = await getNFTTokenAccount(nftMintPk, connection); 17 | let tokenAccountInfo = await connection.getAccountInfo(tokenAccountPK); 18 | 19 | console.log("nftMintPk=", nftMintPk.toBase58()); 20 | console.log("tokenAccountInfo =", tokenAccountInfo); 21 | 22 | if (tokenAccountInfo && tokenAccountInfo.data ) { 23 | let ownerPubkey = new PublicKey(tokenAccountInfo.data.slice(32, 64)) 24 | console.log("ownerPubkey=", ownerPubkey.toBase58()); 25 | return ownerPubkey; 26 | } 27 | return new PublicKey(""); 28 | } 29 | 30 | export const getTokenAccount = async (mintPk : PublicKey, userPk: PublicKey, connection: Connection) : Promise => { 31 | let tokenAccount = await connection.getProgramAccounts( 32 | TOKEN_PROGRAM_ID, 33 | { 34 | filters: [ 35 | { 36 | dataSize: 165 37 | }, 38 | { 39 | memcmp: { 40 | offset: 0, 41 | bytes: mintPk.toBase58() 42 | } 43 | }, 44 | { 45 | memcmp: { 46 | offset: 32, 47 | bytes: userPk.toBase58() 48 | } 49 | }, 50 | ] 51 | } 52 | ); 53 | return tokenAccount[0].pubkey; 54 | } 55 | 56 | export const getNFTTokenAccount = async (nftMintPk : PublicKey, connection: Connection) : Promise => { 57 | console.log("getNFTTokenAccount nftMintPk=", nftMintPk.toBase58()); 58 | let tokenAccount = await connection.getProgramAccounts( 59 | TOKEN_PROGRAM_ID, 60 | { 61 | filters: [ 62 | { 63 | dataSize: 165 64 | }, 65 | { 66 | memcmp: { 67 | offset: 64, 68 | bytes: '2' 69 | } 70 | }, 71 | { 72 | memcmp: { 73 | offset: 0, 74 | bytes: nftMintPk.toBase58() 75 | } 76 | }, 77 | ] 78 | } 79 | ); 80 | return tokenAccount[0].pubkey; 81 | } 82 | 83 | export const getAssociatedTokenAccount = async (ownerPubkey : PublicKey, mintPk : PublicKey) : Promise => { 84 | let associatedTokenAccountPubkey = (await PublicKey.findProgramAddress( 85 | [ 86 | ownerPubkey.toBuffer(), 87 | TOKEN_PROGRAM_ID.toBuffer(), 88 | mintPk.toBuffer(), // mint address 89 | ], 90 | ASSOCIATED_TOKEN_PROGRAM_ID 91 | ))[0]; 92 | return associatedTokenAccountPubkey; 93 | } 94 | 95 | export const getATokenAccountsNeedCreate = async ( 96 | connection: Connection, 97 | walletAddress: PublicKey, 98 | owner: PublicKey, 99 | nfts: PublicKey[], 100 | ) => { 101 | let instructions = [], destinationAccounts = []; 102 | for (const mint of nfts) { 103 | const destinationPubkey = await getAssociatedTokenAccount(owner, mint); 104 | const response = await connection.getAccountInfo(destinationPubkey); 105 | if (!response) { 106 | const createATAIx = createAssociatedTokenAccountInstruction( 107 | destinationPubkey, 108 | walletAddress, 109 | owner, 110 | mint, 111 | ); 112 | instructions.push(createATAIx); 113 | } 114 | destinationAccounts.push(destinationPubkey); 115 | } 116 | return { 117 | instructions, 118 | destinationAccounts, 119 | }; 120 | } 121 | 122 | export const createAssociatedTokenAccountInstruction = ( 123 | associatedTokenAddress: PublicKey, 124 | payer: PublicKey, 125 | walletAddress: PublicKey, 126 | splTokenMintAddress: PublicKey 127 | ) => { 128 | const keys = [ 129 | { pubkey: payer, isSigner: true, isWritable: true }, 130 | { pubkey: associatedTokenAddress, isSigner: false, isWritable: true }, 131 | { pubkey: walletAddress, isSigner: false, isWritable: false }, 132 | { pubkey: splTokenMintAddress, isSigner: false, isWritable: false }, 133 | { 134 | pubkey: SystemProgram.programId, 135 | isSigner: false, 136 | isWritable: false, 137 | }, 138 | { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, 139 | { 140 | pubkey: SYSVAR_RENT_PUBKEY, 141 | isSigner: false, 142 | isWritable: false, 143 | }, 144 | ]; 145 | return new TransactionInstruction({ 146 | keys, 147 | programId: ASSOCIATED_TOKEN_PROGRAM_ID, 148 | data: Buffer.from([]), 149 | }); 150 | } 151 | 152 | /** Get metaplex mint metadata account address */ 153 | export const getMetadata = async (mint: PublicKey): Promise => { 154 | return ( 155 | await PublicKey.findProgramAddress([Buffer.from('metadata'), METAPLEX.toBuffer(), mint.toBuffer()], METAPLEX) 156 | )[0]; 157 | }; 158 | 159 | export const airdropSOL = async (address: PublicKey, amount: number, connection: Connection) => { 160 | try { 161 | const txId = await connection.requestAirdrop(address, amount); 162 | await connection.confirmTransaction(txId); 163 | } catch (e) { 164 | console.log('Aridrop Failure', address.toBase58(), amount); 165 | } 166 | } 167 | 168 | export const createTokenMint = async ( 169 | connection: Connection, 170 | payer: Keypair, 171 | mint: Keypair, 172 | ) => { 173 | const ret = await connection.getAccountInfo(mint.publicKey); 174 | if(ret && ret.data) { 175 | console.log('Token already in use', mint.publicKey.toBase58()); 176 | return; 177 | }; 178 | // Allocate memory for the account 179 | const balanceNeeded = await Token.getMinBalanceRentForExemptMint( 180 | connection, 181 | ); 182 | const transaction = new Transaction(); 183 | transaction.add( 184 | SystemProgram.createAccount({ 185 | fromPubkey: payer.publicKey, 186 | newAccountPubkey: mint.publicKey, 187 | lamports: balanceNeeded, 188 | space: MintLayout.span, 189 | programId: TOKEN_PROGRAM_ID, 190 | }), 191 | ); 192 | transaction.add( 193 | Token.createInitMintInstruction( 194 | TOKEN_PROGRAM_ID, 195 | mint.publicKey, 196 | 9, 197 | payer.publicKey, 198 | payer.publicKey, 199 | ), 200 | ); 201 | const txId = await connection.sendTransaction(transaction, [payer, mint]); 202 | await connection.confirmTransaction(txId); 203 | 204 | console.log('Tx Hash=', txId); 205 | } 206 | 207 | export const isExistAccount = async (address: PublicKey, connection: Connection) => { 208 | try { 209 | const res = await connection.getAccountInfo(address); 210 | if (res && res.data) return true; 211 | } catch (e) { 212 | return false; 213 | } 214 | } 215 | 216 | export const getTokenAccountBalance = async (account: PublicKey, connection: Connection) => { 217 | try { 218 | const res = await connection.getTokenAccountBalance(account); 219 | if (res && res.value) return res.value.uiAmount; 220 | return 0; 221 | } catch (e) { 222 | console.log(e) 223 | return 0; 224 | } 225 | } 226 | 227 | export const getEscrowBalance = async (connection: Connection) => { 228 | const [escrowVault] = await PublicKey.findProgramAddress( 229 | [Buffer.from(ESCROW_VAULT_SEED)], 230 | MARKETPLACE_PROGRAM_ID, 231 | ); 232 | 233 | const res = await connection.getBalance(escrowVault); 234 | 235 | console.log('Escrow:', escrowVault.toBase58()); 236 | 237 | return { 238 | sol: res, 239 | } 240 | } 241 | 242 | export const getGlobalNFTBalance = async (mint: PublicKey, connection: Connection) => { 243 | const [globalAuthority, _] = await PublicKey.findProgramAddress( 244 | [Buffer.from(GLOBAL_AUTHORITY_SEED)], 245 | MARKETPLACE_PROGRAM_ID, 246 | ); 247 | 248 | const globalNFTAcount = await getAssociatedTokenAccount(globalAuthority, mint); 249 | console.log('GlobalNFTAccount:', globalNFTAcount.toBase58()); 250 | return await getTokenAccountBalance(globalNFTAcount, connection); 251 | } 252 | 253 | export const isInitializedUser = async (address: PublicKey, connection: Connection) => { 254 | const [userPool, _] = await PublicKey.findProgramAddress( 255 | [Buffer.from(USER_DATA_SEED), address.toBuffer()], 256 | MARKETPLACE_PROGRAM_ID, 257 | ); 258 | console.log('User Data PDA: ', userPool.toBase58()); 259 | return await isExistAccount(userPool, connection); 260 | } -------------------------------------------------------------------------------- /cli/be.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from '@project-serum/anchor'; 2 | import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; 3 | import { Program, web3 } from '@project-serum/anchor'; 4 | import { 5 | PublicKey, 6 | Connection, 7 | SystemProgram, 8 | SYSVAR_RENT_PUBKEY, 9 | Transaction, 10 | PartiallyDecodedInstruction, 11 | ParsedInstruction 12 | } from '@solana/web3.js'; 13 | import { Buffer } from 'node:buffer'; 14 | import fs from 'fs'; 15 | import path from 'path'; 16 | import NodeWallet from '@project-serum/anchor/dist/cjs/nodewallet'; 17 | import { decode } from '@project-serum/anchor/dist/cjs/utils/bytes/base64'; 18 | import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes'; 19 | 20 | anchor.setProvider(anchor.AnchorProvider.local(web3.clusterApiUrl("devnet"))); 21 | const solConnection = anchor.getProvider().connection; 22 | const payer = anchor.AnchorProvider.local().wallet; 23 | var nonce = [ 24 | 'AsUkG8p1', 25 | '3BzKBJUk', 26 | 'HY2XrSxn', 27 | 'AJbPzu2U', 28 | 'PcLYN6YP', 29 | '4G2WiD2C', 30 | '4eW8amCV', 31 | '6Ahuf6jr', 32 | 'UJJfJRLD', 33 | '5p6KPRCQ', 34 | 'QPHXB9jL', 35 | 'BE4DeeJT', 36 | 'AnGz4SzU', 37 | 'VcryEr2T', 38 | '3zENZMgC', 39 | '2BWUiNsL', 40 | '2SaBBC7P', 41 | 'ZkCkv1Hg', 42 | 'QMNFmXsk', 43 | 'AtH7do4b', 44 | '882wV271', 45 | '9mtdhZPt', 46 | '9mE5kJpm', 47 | 'Sc9FjYDt', 48 | ]; 49 | 50 | const main = async () => { 51 | 52 | await getAllTransactions(new PublicKey("C29hER4SXQr3atHsuCrRmLAkXBpxvfLMCNeXg2TRTd9o")); 53 | // 44GoMVetnJTUJUYzbVbydKVU2f6UoK73Hhew7WW76xBRuyqJZwRXNcCt2dmPhnvjPjZmAsVCLoQDTDuKjQoYFZq3 54 | // 5JUKdSyZBVtiFxapy54dLoUda1muBeLhQNQcMXTrfU3CmrChmvAFbGxoxZW3s8vmpDzm18fCHBn6gmAyStUDw7Dh 55 | } 56 | 57 | export const getAllTransactions = async ( 58 | contractId: PublicKey, 59 | ) => { 60 | const data = await solConnection.getSignaturesForAddress(contractId, {}, "confirmed"); 61 | data.map( async (datum) => { 62 | let tx = await getDataFromSignature(datum.signature); 63 | console.log(tx); 64 | }) 65 | } 66 | 67 | export const getDataFromSignature = async ( 68 | sig: string 69 | ) => { 70 | const tx = await solConnection.getParsedTransaction(sig, 'confirmed'); 71 | let length = tx.transaction.message.instructions.length; 72 | let valid = -1; 73 | let hash; 74 | let ixId; 75 | 76 | for (let i = 0; i < length; i ++) { 77 | for (let j = 0; j < nonce.length; j ++) { 78 | hash = (tx.transaction.message.instructions[i] as PartiallyDecodedInstruction).data; 79 | if (hash != undefined && hash.slice(0, 8) == nonce[j]) { 80 | valid = j; 81 | break; 82 | } 83 | } 84 | if (valid > -1) { 85 | ixId = i; 86 | break; 87 | } 88 | } 89 | 90 | let ts = tx.blockTime; 91 | let date = new Date(ts * 1000) 92 | if (valid == -1) return; 93 | // return { 94 | // 'type': 'Unknown', 95 | // 'address': tx.transaction.message.accountKeys[0].pubkey.toBase58(), 96 | // 'timestamp': ts, 97 | // 'date': date, 98 | // 'signature': sig, 99 | // }; 100 | 101 | let innerIx; 102 | if (tx.meta.innerInstructions.length !== 0) { 103 | innerIx = tx.meta.innerInstructions[ixId].instructions; 104 | } 105 | 106 | let accountKeys = (tx.transaction.message.instructions[ixId] as PartiallyDecodedInstruction).accounts; 107 | let signer = accountKeys[0].toBase58(); 108 | let result; 109 | switch (valid) { 110 | case 0: 111 | console.log("Initialize"); 112 | result = {'type': "Initialize"} 113 | break; 114 | case 1: { 115 | console.log("UpdateFee"); 116 | result = {'type': "UpdateFee"} 117 | break; 118 | } 119 | case 2: 120 | console.log("AddTeamTreasury"); 121 | result = {'type': 'AddTeamTreasury'} 122 | break; 123 | case 3: 124 | console.log("RemoveTeamTreasury"); 125 | result = {'type': 'RemoveTeamTreasury'} 126 | break; 127 | case 4:{ 128 | console.log("InitUserPool"); 129 | result = {'type': 'InitUserPool'} 130 | break; 131 | } 132 | case 5: 133 | console.log("InitSellData"); 134 | break; 135 | case 6: { 136 | console.log("ListNftForSale"); 137 | let bytes = bs58.decode(hash) 138 | let b = bytes.slice(10, 18).reverse(); 139 | let sol_price = new anchor.BN(b).toNumber() 140 | 141 | result = { 142 | 'type': 'ListNftForSale', 143 | 'address': signer, 144 | 'mint': accountKeys[5].toBase58(), 145 | 'sol_price': sol_price, 146 | 'timestamp': ts, 147 | 'date': date, 148 | 'signature': sig, 149 | } 150 | break; 151 | } 152 | case 7: { 153 | console.log("DelistNft"); 154 | result = { 155 | 'type': 'DelistNft', 156 | 'address': signer, 157 | 'mint': accountKeys[5].toBase58(), 158 | 'timestamp': ts, 159 | 'date': date, 160 | 'signature': sig, 161 | } 162 | break; 163 | } 164 | case 8: { 165 | console.log("Transfer"); 166 | result = { 167 | 'type': 'Transfer', 168 | 'address': signer, 169 | 'recipient': accountKeys[2].toBase58(), 170 | 'mint': accountKeys[4].toBase58(), 171 | 'timestamp': ts, 172 | 'date': date, 173 | 'signature': sig, 174 | } 175 | break; 176 | } 177 | case 9: 178 | console.log("TransferFromVault"); 179 | result = { 180 | 'type': 'TransferFromVault', 181 | 'address': signer, 182 | 'recipient': accountKeys[3].toBase58(), 183 | 'mint': accountKeys[6].toBase58(), 184 | 'timestamp': ts, 185 | 'date': date, 186 | 'signature': sig, 187 | } 188 | break; 189 | case 10: 190 | console.log("Purchase"); 191 | let price = 0; 192 | for(let i = 0; i { 47 | const { 48 | env, 49 | } = cmd.opts(); 50 | console.log('Solana config: ', env); 51 | await setClusterConfig(env); 52 | console.log(await getGlobalInfo()); 53 | }); 54 | 55 | programCommand('user_status') 56 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 57 | .option('-a, --address ', 'nft user pubkey') 58 | .action(async (directory, cmd) => { 59 | const { 60 | env, 61 | address, 62 | } = cmd.opts(); 63 | console.log('Solana config: ', env); 64 | await setClusterConfig(env); 65 | if (address === undefined) { 66 | console.log("Error User Address input"); 67 | return; 68 | } 69 | console.log(await getUserPoolInfo(new PublicKey(address))); 70 | }); 71 | 72 | programCommand('update_fee') 73 | .option('-s, --sol_fee ', 'marketplace trading by sol fee as permyraid') 74 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 75 | .action(async (directory, cmd) => { 76 | const { 77 | env, 78 | sol_fee, 79 | } = cmd.opts(); 80 | 81 | console.log('Solana config: ', env); 82 | await setClusterConfig(env); 83 | 84 | if (sol_fee === undefined || isNaN(parseInt(sol_fee))) { 85 | console.log("Error Sol Fee Input"); 86 | return; 87 | } 88 | 89 | await updateFee(parseInt(sol_fee)); 90 | }); 91 | 92 | programCommand('add_treasury') 93 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 94 | .option('-a, --address ', 'team treasury account pubkey') 95 | .option('-r, --rate ', 'treasury distribution rate as permyraid') 96 | .action(async (directory, cmd) => { 97 | const { 98 | env, 99 | address, 100 | rate, 101 | } = cmd.opts(); 102 | console.log('Solana config: ', env); 103 | await setClusterConfig(env); 104 | if (address === undefined) { 105 | console.log("Error Treasury input"); 106 | return; 107 | } 108 | if (rate === undefined || isNaN(parseInt(rate))) { 109 | console.log("Error Treasury Rate Input"); 110 | return; 111 | } 112 | await addTreasury(new PublicKey(address), parseInt(rate)); 113 | }); 114 | 115 | programCommand('remove_treasury') 116 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 117 | .option('-a, --address ', 'team treasury account pubkey') 118 | .action(async (directory, cmd) => { 119 | const { 120 | env, 121 | address, 122 | } = cmd.opts(); 123 | console.log('Solana config: ', env); 124 | await setClusterConfig(env); 125 | if (address === undefined) { 126 | console.log("Error Treasury input"); 127 | return; 128 | } 129 | await removeTreasury(new PublicKey(address)); 130 | }); 131 | 132 | programCommand('deposit') 133 | .option('-s, --sol ', 'deposit sol amount') 134 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 135 | .action(async (directory, cmd) => { 136 | const { 137 | env, 138 | sol, 139 | } = cmd.opts(); 140 | 141 | console.log('Solana config: ', env); 142 | await setClusterConfig(env); 143 | 144 | if (sol === undefined || isNaN(parseFloat(sol))) { 145 | console.log("Error Sol Amount input"); 146 | return; 147 | } 148 | 149 | await depositEscrow(parseFloat(sol) * LAMPORTS_PER_SOL); 150 | }); 151 | 152 | programCommand('withdraw') 153 | .option('-s, --sol ', 'withdraw sol amount') 154 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 155 | .action(async (directory, cmd) => { 156 | const { 157 | env, 158 | sol, 159 | token, 160 | } = cmd.opts(); 161 | 162 | console.log('Solana config: ', env); 163 | await setClusterConfig(env); 164 | 165 | if (sol === undefined || isNaN(parseFloat(sol))) { 166 | console.log("Error Sol Amount input"); 167 | return; 168 | } 169 | 170 | await withdrawEscrow(parseFloat(sol) * LAMPORTS_PER_SOL); 171 | }); 172 | 173 | programCommand('transfer') 174 | .option('-a, --address ', 'nft mint pubkey') 175 | .option('-r, --recipient ', 'recipient user address') 176 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 177 | .action(async (directory, cmd) => { 178 | const { 179 | env, 180 | address, 181 | recipient, 182 | } = cmd.opts(); 183 | 184 | console.log('Solana config: ', env); 185 | await setClusterConfig(env); 186 | 187 | if (address === undefined) { 188 | console.log("Error Mint input"); 189 | return; 190 | } 191 | 192 | if (recipient === undefined) { 193 | console.log("Error Recipint Address input"); 194 | return; 195 | } 196 | 197 | await transfer(new PublicKey(address), new PublicKey(recipient)); 198 | }); 199 | 200 | programCommand('list') 201 | .option('-a, --address ', 'nft mint pubkey') 202 | .option('-p, --price_sol ', 'sell sol price') 203 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 204 | .action(async (directory, cmd) => { 205 | const { 206 | env, 207 | address, 208 | price_sol, 209 | } = cmd.opts(); 210 | 211 | console.log('Solana config: ', env); 212 | await setClusterConfig(env); 213 | 214 | if (address === undefined) { 215 | console.log("Error Mint input"); 216 | return; 217 | } 218 | if (price_sol === undefined || isNaN(parseFloat(price_sol))) { 219 | console.log("Error Sol Price input"); 220 | return; 221 | } 222 | 223 | await listNftForSale(new PublicKey(address), parseFloat(price_sol) * LAMPORTS_PER_SOL); 224 | }); 225 | 226 | programCommand('delist') 227 | .option('-a, --address ', 'nft mint pubkey') 228 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 229 | .action(async (directory, cmd) => { 230 | const { 231 | env, 232 | address, 233 | } = cmd.opts(); 234 | 235 | console.log('Solana config: ', env); 236 | await setClusterConfig(env); 237 | 238 | if (address === undefined) { 239 | console.log("Error Mint input"); 240 | return; 241 | } 242 | 243 | await delistNft(new PublicKey(address)); 244 | }); 245 | 246 | programCommand('set_price') 247 | .option('-a, --address ', 'nft mint pubkey') 248 | .option('-p, --price_sol ', 'new sell price') 249 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 250 | .action(async (directory, cmd) => { 251 | const { 252 | env, 253 | address, 254 | price_sol, 255 | } = cmd.opts(); 256 | 257 | console.log('Solana config: ', env); 258 | await setClusterConfig(env); 259 | 260 | if (address === undefined) { 261 | console.log("Error Mint input"); 262 | return; 263 | } 264 | if (price_sol === undefined || isNaN(parseFloat(price_sol))) { 265 | console.log("Error Sol Price input"); 266 | return; 267 | } 268 | 269 | await setPrice(new PublicKey(address), parseFloat(price_sol) * LAMPORTS_PER_SOL); 270 | }); 271 | 272 | programCommand('purchase') 273 | .option('-a, --address ', 'nft mint pubkey') 274 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 275 | .action(async (directory, cmd) => { 276 | const { 277 | env, 278 | address, 279 | } = cmd.opts(); 280 | 281 | console.log('Solana config: ', env); 282 | await setClusterConfig(env); 283 | 284 | if (address === undefined) { 285 | console.log("Error Mint input"); 286 | return; 287 | } 288 | 289 | await purchase(new PublicKey(address)); 290 | }); 291 | 292 | programCommand('make_offer') 293 | .option('-a, --address ', 'nft mint pubkey') 294 | .option('-p, --price ', 'offer price') 295 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 296 | .action(async (directory, cmd) => { 297 | const { 298 | env, 299 | address, 300 | price, 301 | } = cmd.opts(); 302 | 303 | console.log('Solana config: ', env); 304 | await setClusterConfig(env); 305 | 306 | if (address === undefined) { 307 | console.log("Error Mint input"); 308 | return; 309 | } 310 | if (price === undefined || isNaN(parseFloat(price))) { 311 | console.log("Error Offer Price input"); 312 | return; 313 | } 314 | 315 | await makeOffer(new PublicKey(address), parseFloat(price) * LAMPORTS_PER_SOL); 316 | }); 317 | 318 | programCommand('cancel_offer') 319 | .option('-a, --address ', 'nft mint pubkey') 320 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 321 | .action(async (directory, cmd) => { 322 | const { 323 | env, 324 | address, 325 | } = cmd.opts(); 326 | 327 | console.log('Solana config: ', env); 328 | await setClusterConfig(env); 329 | 330 | if (address === undefined) { 331 | console.log("Error Mint input"); 332 | return; 333 | } 334 | 335 | await cancelOffer(new PublicKey(address)); 336 | }); 337 | 338 | programCommand('accept_offer') 339 | .option('-a, --address ', 'nft mint pubkey') 340 | .option('-b, --buyer ', 'buyer address') 341 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 342 | .action(async (directory, cmd) => { 343 | const { 344 | env, 345 | address, 346 | buyer, 347 | } = cmd.opts(); 348 | 349 | console.log('Solana config: ', env); 350 | await setClusterConfig(env); 351 | 352 | if (address === undefined) { 353 | console.log("Error Mint input"); 354 | return; 355 | } 356 | 357 | if (buyer === undefined) { 358 | console.log("Error Buyer input"); 359 | return; 360 | } 361 | 362 | await acceptOffer(new PublicKey(address), new PublicKey(buyer)); 363 | }); 364 | 365 | programCommand('create_auction') 366 | .option('-a, --address ', 'nft mint pubkey') 367 | .option('-p, --start_price ', 'start price') 368 | .option('-m, --min_increase ', 'min increase amount') 369 | .option('-d, --duration ', 'duration by second') 370 | .option('-r, --reserve ', 'reserved auction flag') 371 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 372 | .action(async (directory, cmd) => { 373 | const { 374 | env, 375 | address, 376 | start_price, 377 | min_increase, 378 | duration, 379 | reserve, 380 | } = cmd.opts(); 381 | 382 | console.log('Solana config: ', env); 383 | await setClusterConfig(env); 384 | 385 | if (address === undefined) { 386 | console.log("Error Mint input"); 387 | return; 388 | } 389 | if (start_price === undefined || isNaN(parseFloat(start_price))) { 390 | console.log("Error Auction Start Price input"); 391 | return; 392 | } 393 | if (min_increase === undefined || isNaN(parseFloat(min_increase))) { 394 | console.log("Error Auction Min Increase Amount input"); 395 | return; 396 | } 397 | if (duration === undefined || isNaN(parseInt(duration))) { 398 | console.log("Error Auction Duration input"); 399 | return; 400 | } 401 | if (reserve === undefined || isNaN(parseInt(reserve)) || parseInt(reserve) > 1) { 402 | console.log("Error Reserve Flag input"); 403 | return; 404 | } 405 | 406 | await createAuction( 407 | new PublicKey(address), 408 | parseFloat(start_price) * LAMPORTS_PER_SOL, 409 | parseFloat(min_increase) * LAMPORTS_PER_SOL, 410 | parseInt(duration), 411 | parseInt(reserve) == 1, 412 | ); 413 | }); 414 | 415 | programCommand('place_bid') 416 | .option('-a, --address ', 'nft mint pubkey') 417 | .option('-p, --price ', 'auction price') 418 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 419 | .action(async (directory, cmd) => { 420 | const { 421 | env, 422 | address, 423 | price, 424 | } = cmd.opts(); 425 | 426 | console.log('Solana config: ', env); 427 | await setClusterConfig(env); 428 | 429 | if (address === undefined) { 430 | console.log("Error Mint input"); 431 | return; 432 | } 433 | if (price === undefined || isNaN(parseFloat(price))) { 434 | console.log("Error Auction Price input"); 435 | return; 436 | } 437 | 438 | await placeBid(new PublicKey(address), parseFloat(price) * 1e9); 439 | }); 440 | 441 | 442 | programCommand('claim_auction') 443 | .option('-a, --address ', 'nft mint pubkey') 444 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 445 | .action(async (directory, cmd) => { 446 | const { 447 | env, 448 | address, 449 | } = cmd.opts(); 450 | 451 | console.log('Solana config: ', env); 452 | await setClusterConfig(env); 453 | 454 | if (address === undefined) { 455 | console.log("Error Mint input"); 456 | return; 457 | } 458 | 459 | await claimAuction(new PublicKey(address)); 460 | }); 461 | 462 | programCommand('update_reserve') 463 | .option('-a, --address ', 'nft mint pubkey') 464 | .option('-p, --start_price ', 'start price') 465 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 466 | .action(async (directory, cmd) => { 467 | const { 468 | env, 469 | address, 470 | start_price, 471 | } = cmd.opts(); 472 | 473 | console.log('Solana config: ', env); 474 | await setClusterConfig(env); 475 | 476 | if (address === undefined) { 477 | console.log("Error Mint input"); 478 | return; 479 | } 480 | if (start_price === undefined || isNaN(parseFloat(start_price))) { 481 | console.log("Error Auction Start Price input"); 482 | return; 483 | } 484 | 485 | await updateReserve( 486 | new PublicKey(address), 487 | parseFloat(start_price) * LAMPORTS_PER_SOL, 488 | ); 489 | }); 490 | 491 | programCommand('cancel_auction') 492 | .option('-a, --address ', 'nft mint pubkey') 493 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 494 | .action(async (directory, cmd) => { 495 | const { 496 | env, 497 | address, 498 | } = cmd.opts(); 499 | 500 | console.log('Solana config: ', env); 501 | await setClusterConfig(env); 502 | 503 | if (address === undefined) { 504 | console.log("Error Mint input"); 505 | return; 506 | } 507 | 508 | await cancelAuction(new PublicKey(address)); 509 | }); 510 | 511 | programCommand('listed_nft_data') 512 | .option('-a, --address ', 'nft mint pubkey') 513 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 514 | .action(async (directory, cmd) => { 515 | const { 516 | env, 517 | address, 518 | } = cmd.opts(); 519 | 520 | console.log('Solana config: ', env); 521 | await setClusterConfig(env); 522 | 523 | if (address === undefined) { 524 | console.log("Error input"); 525 | return; 526 | } 527 | console.log(await getNFTPoolInfo(new PublicKey(address))); 528 | }); 529 | 530 | programCommand('get_offer_data') 531 | .option('-a, --address ', 'nft mint pubkey') 532 | .option('-b, --buyer ', 'buyer address pubkey') 533 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 534 | .action(async (directory, cmd) => { 535 | const { 536 | env, 537 | address, 538 | buyer, 539 | } = cmd.opts(); 540 | 541 | console.log('Solana config: ', env); 542 | await setClusterConfig(env); 543 | 544 | if (address === undefined) { 545 | console.log("Error Mint input"); 546 | return; 547 | } 548 | if (buyer === undefined) { 549 | console.log("Error Buyer input"); 550 | return; 551 | } 552 | console.log(await getOfferDataInfo(new PublicKey(address), new PublicKey(buyer))); 553 | }); 554 | 555 | programCommand('get_auction_data') 556 | .option('-a, --address ', 'nft mint pubkey') 557 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 558 | .action(async (directory, cmd) => { 559 | const { 560 | env, 561 | address, 562 | } = cmd.opts(); 563 | 564 | console.log('Solana config: ', env); 565 | await setClusterConfig(env); 566 | 567 | if (address === undefined) { 568 | console.log("Error Mint input"); 569 | return; 570 | } 571 | console.log(await getAuctionDataInfo(new PublicKey(address))); 572 | }); 573 | 574 | programCommand('get_all_listed_nfts') 575 | .option('-r, --rpc ', 'custom rpc url') 576 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 577 | .action(async (directory, cmd) => { 578 | const { 579 | env, 580 | rpc, 581 | } = cmd.opts(); 582 | 583 | console.log('Solana config: ', env); 584 | await setClusterConfig(env); 585 | 586 | console.log(await getAllNFTs(rpc)); 587 | }); 588 | 589 | programCommand('get_all_offers_for_nft') 590 | .option('-a, --address ', 'nft mint pubkey') 591 | .option('-r, --rpc ', 'custom rpc url') 592 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 593 | .action(async (directory, cmd) => { 594 | const { 595 | env, 596 | address, 597 | rpc, 598 | } = cmd.opts(); 599 | 600 | console.log('Solana config: ', env); 601 | await setClusterConfig(env); 602 | 603 | if (address === undefined) { 604 | console.log("Error input"); 605 | return; 606 | } 607 | console.log(await getAllOffersForNFT(address, rpc)); 608 | }); 609 | 610 | programCommand('get_all_auctions') 611 | .option('-r, --rpc ', 'custom rpc url') 612 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 613 | .action(async (directory, cmd) => { 614 | const { 615 | env, 616 | rpc, 617 | } = cmd.opts(); 618 | 619 | console.log('Solana config: ', env); 620 | await setClusterConfig(env); 621 | 622 | console.log(await getAllAuctions(rpc)); 623 | }); 624 | 625 | programCommand('init') 626 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 627 | .action(async (directory, cmd) => { 628 | const { 629 | env, 630 | } = cmd.opts(); 631 | console.log('Solana config: ', env); 632 | await setClusterConfig(env); 633 | 634 | await initProject(); 635 | }); 636 | 637 | programCommand('init_user') 638 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 639 | .action(async (directory, cmd) => { 640 | const { 641 | env, 642 | } = cmd.opts(); 643 | console.log('Solana config: ', env); 644 | await setClusterConfig(env); 645 | await initUserPool(); 646 | }); 647 | 648 | function programCommand(name: string) { 649 | return program 650 | .command(name) 651 | .option( 652 | '-e, --env ', 653 | 'Solana cluster env name', 654 | 'devnet', //mainnet-beta, testnet, devnet 655 | ) 656 | } 657 | 658 | program.parse(process.argv); 659 | -------------------------------------------------------------------------------- /cli/scripts.ts: -------------------------------------------------------------------------------- 1 | import { Program, web3 } from '@project-serum/anchor'; 2 | import * as anchor from '@project-serum/anchor'; 3 | import { 4 | Keypair, 5 | PublicKey, 6 | } from '@solana/web3.js'; 7 | import fs from 'fs'; 8 | import path from 'path'; 9 | import NodeWallet from '@project-serum/anchor/dist/cjs/nodewallet'; 10 | 11 | import { AuctionData, AUCTION_DATA_SEED, GlobalPool, GLOBAL_AUTHORITY_SEED, MARKETPLACE_PROGRAM_ID, OfferData, OFFER_DATA_SEED, SellData, SELL_DATA_SEED, UserData } from '../lib/types'; 12 | import { IDL as MarketplaceIDL } from "../target/types/nut_marketplace"; 13 | import { 14 | createAcceptOfferTx, 15 | createAddTreasuryTx, 16 | createCancelAuctionTx, 17 | createCancelOfferTx, 18 | createClaimAuctionTx, 19 | createCreateAuctionTx, 20 | createDelistNftTx, 21 | createDepositTx, 22 | createInitAuctionDataTx, 23 | createInitializeTx, 24 | createInitOfferDataTx, 25 | createInitSellDataTx, 26 | createInitUserTx, 27 | createListForSellNftTx, 28 | createMakeOfferTx, 29 | createPlaceBidTx, 30 | createPurchaseTx, 31 | createRemoveTreasuryTx, 32 | createSetPriceTx, 33 | createTransferFromVaultTx, 34 | createTransferTx, 35 | createUpdateFeeTx, 36 | createUpdateReserveTx, 37 | createWithdrawTx, 38 | getAllListedNFTs, 39 | getAllOffersForListedNFT, 40 | getAllStartedAuctions, 41 | getAuctionDataState, 42 | getGlobalState, 43 | getNFTPoolState, 44 | getOfferDataState, 45 | getUserPoolState 46 | } from '../lib/scripts'; 47 | import { isInitializedUser } from '../lib/utils'; 48 | 49 | let solConnection = null; 50 | let payer = null; 51 | let program: Program = null; 52 | 53 | // Address of the deployed program. 54 | let programId = new anchor.web3.PublicKey(MARKETPLACE_PROGRAM_ID); 55 | 56 | export const setClusterConfig = async (cluster: web3.Cluster) => { 57 | solConnection = new web3.Connection(web3.clusterApiUrl(cluster)); 58 | const walletKeypair = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(fs.readFileSync(path.resolve(process.env.ANCHOR_WALLET), 'utf-8'))), { skipValidation: true }); 59 | const wallet = new NodeWallet(walletKeypair); 60 | // anchor.setProvider(anchor.AnchorProvider.local(web3.clusterApiUrl(cluster))); 61 | // Configure the client to use the local cluster. 62 | anchor.setProvider(new anchor.AnchorProvider(solConnection, wallet, { skipPreflight: true, commitment: 'confirmed' })); 63 | payer = wallet; 64 | 65 | // Generate the program client from IDL. 66 | program = new anchor.Program(MarketplaceIDL as anchor.Idl, programId); 67 | console.log('ProgramId: ', program.programId.toBase58()); 68 | 69 | const [globalAuthority, bump] = await PublicKey.findProgramAddress( 70 | [Buffer.from(GLOBAL_AUTHORITY_SEED)], 71 | program.programId 72 | ); 73 | console.log('GlobalAuthority: ', globalAuthority.toBase58()); 74 | 75 | // await main(); 76 | } 77 | 78 | const main = async () => { 79 | 80 | // await initProject(); 81 | // await addCollection(new PublicKey('B2FmSY81mionC1DYvKky5Y8nUXSWnhMmd5L5nbm99VHQ')); 82 | // await removeCollection(new PublicKey('B2FmSY81mionC1DYvKky5Y8nUXSWnhMmd5L5nbm99VHQ')); 83 | 84 | // const globalPool: GlobalPool = await getGlobalState(); 85 | // console.log("globalPool =", globalPool.superAdmin.toBase58(), globalPool.fullStakePeriod.toNumber() 86 | // , globalPool.minStakePeriod.toNumber(), globalPool.rewardPeriod.toNumber() 87 | // , globalPool.rewardAmount.toNumber(), globalPool.totalStakedCount.toNumber(), 88 | // globalPool.collectionCount.toNumber(), globalPool.collections.slice(0, globalPool.collectionCount.toNumber()).map((addr) => addr.toBase58())); 89 | 90 | // await initUserPool(payer.publicKey); 91 | 92 | // await stakeNft(payer.publicKey, new PublicKey('554AJqCuVFWL7ZHtLqmh18NvuC4UYLP12Bc8fN4RvTex')); 93 | // await claimReward(payer.publicKey); 94 | // await withdrawNft(payer.publicKey, new PublicKey('554AJqCuVFWL7ZHtLqmh18NvuC4UYLP12Bc8fN4RvTex')); 95 | // await burnNft(payer.publicKey, new PublicKey('4Qw3PQqY3q8LbZAYXfwpjUGS4k7anqdRrPyDL9LWue4d')); 96 | 97 | // const userPool: UserPool = await getUserPoolState(new PublicKey('2EnGnSaf89uP6n7prHrKWK9Q41yAWbRkTN1b5ry8XxCw')); 98 | // console.log({ 99 | // ...userPool, 100 | // owner: userPool.owner.toBase58(), 101 | // stakedMints: userPool.stakedMints.slice(0, userPool.stakedCount.toNumber()).map((info) => { 102 | // return { 103 | // mint: info.mint.toBase58(), 104 | // stakedTime: info.stakedTime.toNumber(), 105 | // } 106 | // }) 107 | // }); 108 | // calculateRewards(new PublicKey('GyjFWXkMn4AGrD5FPfBegP75zmodBeBxr9gBRJjr8qke')); 109 | 110 | }; 111 | 112 | export const initProject = async ( 113 | ) => { 114 | const tx = await createInitializeTx(payer.publicKey, program); 115 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 116 | tx.feePayer = payer.publicKey; 117 | tx.recentBlockhash = blockhash; 118 | payer.signTransaction(tx); 119 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 120 | await solConnection.confirmTransaction(txId, "confirmed"); 121 | console.log("txHash =", txId); 122 | } 123 | 124 | export const initSellData = async ( 125 | mint: PublicKey, 126 | ) => { 127 | const tx = await createInitSellDataTx(mint, payer.publicKey, program); 128 | const { blockhash } = await solConnection.getRecentBlockhash('finalized'); 129 | tx.feePayer = payer.publicKey; 130 | tx.recentBlockhash = blockhash; 131 | payer.signTransaction(tx); 132 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 133 | await solConnection.confirmTransaction(txId, "finalized"); 134 | console.log("Your transaction signature", txId); 135 | } 136 | 137 | export const initUserPool = async () => { 138 | const tx = await createInitUserTx(payer.publicKey, program); 139 | const { blockhash } = await solConnection.getRecentBlockhash('finalized'); 140 | tx.feePayer = payer.publicKey; 141 | tx.recentBlockhash = blockhash; 142 | payer.signTransaction(tx); 143 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 144 | await solConnection.confirmTransaction(txId, "finalized"); 145 | console.log("Your transaction signature", txId); 146 | } 147 | 148 | export const initAuctionData = async ( 149 | mint: PublicKey, 150 | ) => { 151 | const tx = await createInitAuctionDataTx(mint, payer.publicKey, program); 152 | const { blockhash } = await solConnection.getRecentBlockhash('finalized'); 153 | tx.feePayer = payer.publicKey; 154 | tx.recentBlockhash = blockhash; 155 | payer.signTransaction(tx); 156 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 157 | await solConnection.confirmTransaction(txId, "finalized"); 158 | console.log("Your transaction signature", txId); 159 | } 160 | 161 | export const updateFee = async ( 162 | solFee: number, 163 | ) => { 164 | console.log(solFee); 165 | const tx = await createUpdateFeeTx(payer.publicKey, program, solFee); 166 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 167 | tx.feePayer = payer.publicKey; 168 | tx.recentBlockhash = blockhash; 169 | payer.signTransaction(tx); 170 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 171 | await solConnection.confirmTransaction(txId, "confirmed"); 172 | console.log("Your transaction signature", txId); 173 | } 174 | 175 | export const addTreasury = async ( 176 | treasury: PublicKey, 177 | rate: number, 178 | ) => { 179 | console.log(treasury.toBase58(), rate); 180 | 181 | const tx = await createAddTreasuryTx(payer.publicKey, treasury, rate, program); 182 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 183 | tx.feePayer = payer.publicKey; 184 | tx.recentBlockhash = blockhash; 185 | payer.signTransaction(tx); 186 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 187 | await solConnection.confirmTransaction(txId, "confirmed"); 188 | console.log("Your transaction signature", txId); 189 | } 190 | 191 | export const removeTreasury = async ( 192 | treasury: PublicKey, 193 | ) => { 194 | console.log(treasury.toBase58()); 195 | 196 | const tx = await createRemoveTreasuryTx(payer.publicKey, program, treasury); 197 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 198 | tx.feePayer = payer.publicKey; 199 | tx.recentBlockhash = blockhash; 200 | payer.signTransaction(tx); 201 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 202 | await solConnection.confirmTransaction(txId, "confirmed"); 203 | console.log("Your transaction signature", txId); 204 | } 205 | 206 | export const depositEscrow = async ( 207 | sol: number, 208 | ) => { 209 | let userAddress = payer.publicKey; 210 | console.log(userAddress.toBase58(), sol); 211 | 212 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 213 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 214 | return; 215 | } 216 | 217 | const tx = await createDepositTx(userAddress, sol, program); 218 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 219 | tx.feePayer = payer.publicKey; 220 | tx.recentBlockhash = blockhash; 221 | payer.signTransaction(tx); 222 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 223 | await solConnection.confirmTransaction(txId, "confirmed"); 224 | console.log("Your transaction signature", txId); 225 | } 226 | 227 | export const withdrawEscrow = async ( 228 | sol: number, 229 | ) => { 230 | let userAddress = payer.publicKey; 231 | console.log(userAddress.toBase58(), sol); 232 | 233 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 234 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 235 | return; 236 | } 237 | 238 | const tx = await createWithdrawTx(userAddress, sol, program); 239 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 240 | tx.feePayer = payer.publicKey; 241 | tx.recentBlockhash = blockhash; 242 | payer.signTransaction(tx); 243 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 244 | await solConnection.confirmTransaction(txId, "confirmed"); 245 | console.log("Your transaction signature", txId); 246 | } 247 | 248 | export const transfer = async ( 249 | mint: PublicKey, 250 | recipient: PublicKey, 251 | ) => { 252 | console.log(mint.toBase58(), recipient.toBase58()); 253 | 254 | const [sellData, _] = await PublicKey.findProgramAddress( 255 | [Buffer.from(SELL_DATA_SEED), mint.toBuffer()], 256 | MARKETPLACE_PROGRAM_ID, 257 | ); 258 | console.log('Sell Data PDA: ', sellData.toBase58()); 259 | 260 | let fromVault = 1; 261 | let poolAccount = await solConnection.getAccountInfo(sellData); 262 | if (poolAccount === null || poolAccount.data === null) { 263 | fromVault = 0; 264 | } else { 265 | const data = await getNFTPoolInfo(mint); 266 | if (data.active != 1) fromVault = 0; 267 | } 268 | 269 | let tx; 270 | if (fromVault) tx = await createTransferFromVaultTx(mint, payer.publicKey, recipient, program, solConnection); 271 | else tx = await createTransferTx(mint, payer.publicKey, recipient, program, solConnection); 272 | 273 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 274 | tx.feePayer = payer.publicKey; 275 | tx.recentBlockhash = blockhash; 276 | payer.signTransaction(tx); 277 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 278 | await solConnection.confirmTransaction(txId, "confirmed"); 279 | console.log("Your transaction signature", txId); 280 | } 281 | 282 | export const listNftForSale = async ( 283 | mint: PublicKey, 284 | priceSol: number, 285 | ) => { 286 | console.log(mint.toBase58(), priceSol); 287 | 288 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 289 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 290 | return; 291 | } 292 | 293 | const [sellData, _] = await PublicKey.findProgramAddress( 294 | [Buffer.from(SELL_DATA_SEED), mint.toBuffer()], 295 | MARKETPLACE_PROGRAM_ID, 296 | ); 297 | console.log('Sell Data PDA: ', sellData.toBase58()); 298 | 299 | let poolAccount = await solConnection.getAccountInfo(sellData); 300 | if (poolAccount === null || poolAccount.data === null) { 301 | await initSellData(mint); 302 | } 303 | 304 | const [auctionData] = await PublicKey.findProgramAddress( 305 | [Buffer.from(AUCTION_DATA_SEED), mint.toBuffer()], 306 | MARKETPLACE_PROGRAM_ID, 307 | ); 308 | console.log('Auction Data PDA: ', auctionData.toBase58()); 309 | 310 | poolAccount = await solConnection.getAccountInfo(auctionData); 311 | if (poolAccount === null || poolAccount.data === null) { 312 | await initAuctionData(mint); 313 | } 314 | 315 | const tx = await createListForSellNftTx(mint, payer.publicKey, program, solConnection, priceSol); 316 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 317 | tx.feePayer = payer.publicKey; 318 | tx.recentBlockhash = blockhash; 319 | payer.signTransaction(tx); 320 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 321 | await solConnection.confirmTransaction(txId, "confirmed"); 322 | console.log("Your transaction signature", txId); 323 | } 324 | 325 | export const delistNft = async ( 326 | mint: PublicKey, 327 | ) => { 328 | console.log(mint.toBase58()); 329 | 330 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 331 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 332 | return; 333 | } 334 | 335 | const tx = await createDelistNftTx(mint, payer.publicKey, program, solConnection); 336 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 337 | tx.feePayer = payer.publicKey; 338 | tx.recentBlockhash = blockhash; 339 | payer.signTransaction(tx); 340 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 341 | await solConnection.confirmTransaction(txId, "confirmed"); 342 | console.log("Your transaction signature", txId); 343 | } 344 | 345 | export const setPrice = async ( 346 | mint: PublicKey, 347 | newPrice: number, 348 | ) => { 349 | console.log(mint.toBase58(), newPrice); 350 | 351 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 352 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 353 | return; 354 | } 355 | 356 | const tx = await createSetPriceTx(mint, payer.publicKey, newPrice, program); 357 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 358 | tx.feePayer = payer.publicKey; 359 | tx.recentBlockhash = blockhash; 360 | payer.signTransaction(tx); 361 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 362 | await solConnection.confirmTransaction(txId, "confirmed"); 363 | console.log("Your transaction signature", txId); 364 | } 365 | 366 | export const purchase = async ( 367 | mint: PublicKey, 368 | ) => { 369 | console.log(mint.toBase58()); 370 | 371 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 372 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 373 | return; 374 | } 375 | 376 | const globalPool: GlobalPool = await getGlobalState(program); 377 | 378 | const tx = await createPurchaseTx(mint, payer.publicKey, globalPool.teamTreasury.slice(0, globalPool.teamCount.toNumber()), program, solConnection); 379 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 380 | tx.feePayer = payer.publicKey; 381 | tx.recentBlockhash = blockhash; 382 | payer.signTransaction(tx); 383 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 384 | await solConnection.confirmTransaction(txId, "confirmed"); 385 | console.log("Your transaction signature", txId); 386 | } 387 | 388 | export const initOfferData = async ( 389 | mint: PublicKey, 390 | ) => { 391 | const tx = await createInitOfferDataTx(mint, payer.publicKey, program); 392 | const { blockhash } = await solConnection.getRecentBlockhash('finalized'); 393 | tx.feePayer = payer.publicKey; 394 | tx.recentBlockhash = blockhash; 395 | payer.signTransaction(tx); 396 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 397 | await solConnection.confirmTransaction(txId, "finalized"); 398 | console.log("Your transaction signature", txId); 399 | } 400 | 401 | export const makeOffer = async ( 402 | mint: PublicKey, 403 | price: number, 404 | ) => { 405 | console.log(mint.toBase58(), price); 406 | 407 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 408 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 409 | return; 410 | } 411 | 412 | const [offerData, _] = await PublicKey.findProgramAddress( 413 | [Buffer.from(OFFER_DATA_SEED), mint.toBuffer(), payer.publicKey.toBuffer()], 414 | MARKETPLACE_PROGRAM_ID, 415 | ); 416 | console.log('Offer Data PDA: ', offerData.toBase58()); 417 | 418 | let poolAccount = await solConnection.getAccountInfo(offerData); 419 | if (poolAccount === null || poolAccount.data === null) { 420 | await initOfferData(mint); 421 | } 422 | 423 | const tx = await createMakeOfferTx(mint, payer.publicKey, price, program); 424 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 425 | tx.feePayer = payer.publicKey; 426 | tx.recentBlockhash = blockhash; 427 | payer.signTransaction(tx); 428 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 429 | await solConnection.confirmTransaction(txId, "confirmed"); 430 | console.log("Your transaction signature", txId); 431 | } 432 | 433 | export const cancelOffer = async ( 434 | mint: PublicKey, 435 | ) => { 436 | console.log(mint.toBase58()); 437 | 438 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 439 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 440 | return; 441 | } 442 | 443 | const tx = await createCancelOfferTx(mint, payer.publicKey, program); 444 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 445 | tx.feePayer = payer.publicKey; 446 | tx.recentBlockhash = blockhash; 447 | payer.signTransaction(tx); 448 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 449 | await solConnection.confirmTransaction(txId, "confirmed"); 450 | console.log("Your transaction signature", txId); 451 | } 452 | 453 | export const acceptOffer = async ( 454 | mint: PublicKey, 455 | buyer: PublicKey, 456 | ) => { 457 | console.log(mint.toBase58(), buyer.toBase58()); 458 | 459 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 460 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 461 | return; 462 | } 463 | 464 | const globalPool: GlobalPool = await getGlobalState(program); 465 | 466 | const tx = await createAcceptOfferTx(mint, buyer, globalPool.teamTreasury.slice(0, globalPool.teamCount.toNumber()), program, solConnection); 467 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 468 | tx.feePayer = payer.publicKey; 469 | tx.recentBlockhash = blockhash; 470 | payer.signTransaction(tx); 471 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 472 | await solConnection.confirmTransaction(txId, "confirmed"); 473 | console.log("Your transaction signature", txId); 474 | } 475 | 476 | export const createAuction = async ( 477 | mint: PublicKey, 478 | startPrice: number, 479 | minIncrease: number, 480 | duration: number, 481 | reserved: boolean, 482 | ) => { 483 | console.log(mint.toBase58(), startPrice, minIncrease, duration, reserved); 484 | 485 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 486 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 487 | return; 488 | } 489 | 490 | const [sellData, _] = await PublicKey.findProgramAddress( 491 | [Buffer.from(SELL_DATA_SEED), mint.toBuffer()], 492 | MARKETPLACE_PROGRAM_ID, 493 | ); 494 | console.log('Sell Data PDA: ', sellData.toBase58()); 495 | 496 | let poolAccount = await solConnection.getAccountInfo(sellData); 497 | if (poolAccount === null || poolAccount.data === null) { 498 | await initSellData(mint); 499 | } 500 | 501 | const [auctionData] = await PublicKey.findProgramAddress( 502 | [Buffer.from(AUCTION_DATA_SEED), mint.toBuffer()], 503 | MARKETPLACE_PROGRAM_ID, 504 | ); 505 | console.log('Auction Data PDA: ', auctionData.toBase58()); 506 | 507 | poolAccount = await solConnection.getAccountInfo(auctionData); 508 | if (poolAccount === null || poolAccount.data === null) { 509 | await initAuctionData(mint); 510 | } 511 | 512 | const tx = await createCreateAuctionTx( 513 | mint, 514 | payer.publicKey, 515 | startPrice, 516 | minIncrease, 517 | duration, 518 | reserved, 519 | program, 520 | solConnection, 521 | ); 522 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 523 | tx.feePayer = payer.publicKey; 524 | tx.recentBlockhash = blockhash; 525 | payer.signTransaction(tx); 526 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 527 | await solConnection.confirmTransaction(txId, "confirmed"); 528 | console.log("Your transaction signature", txId); 529 | } 530 | 531 | export const placeBid = async ( 532 | mint: PublicKey, 533 | price: number, 534 | ) => { 535 | console.log(mint.toBase58(), price); 536 | 537 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 538 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 539 | return; 540 | } 541 | 542 | const tx = await createPlaceBidTx(mint, payer.publicKey, price, program); 543 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 544 | tx.feePayer = payer.publicKey; 545 | tx.recentBlockhash = blockhash; 546 | payer.signTransaction(tx); 547 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 548 | await solConnection.confirmTransaction(txId, "confirmed"); 549 | console.log("Your transaction signature", txId); 550 | } 551 | 552 | export const claimAuction = async ( 553 | mint: PublicKey, 554 | ) => { 555 | console.log(mint.toBase58()); 556 | 557 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 558 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 559 | return; 560 | } 561 | 562 | const globalPool: GlobalPool = await getGlobalState(program); 563 | 564 | const tx = await createClaimAuctionTx(mint, payer.publicKey, globalPool.teamTreasury.slice(0, globalPool.teamCount.toNumber()), program, solConnection); 565 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 566 | tx.feePayer = payer.publicKey; 567 | tx.recentBlockhash = blockhash; 568 | payer.signTransaction(tx); 569 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 570 | await solConnection.confirmTransaction(txId, "confirmed"); 571 | console.log("Your transaction signature", txId); 572 | } 573 | 574 | export const updateReserve = async ( 575 | mint: PublicKey, 576 | newPrice: number, 577 | ) => { 578 | console.log(mint.toBase58(), newPrice); 579 | 580 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 581 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 582 | return; 583 | } 584 | 585 | const tx = await createUpdateReserveTx(mint, payer.publicKey, newPrice, program); 586 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 587 | tx.feePayer = payer.publicKey; 588 | tx.recentBlockhash = blockhash; 589 | payer.signTransaction(tx); 590 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 591 | await solConnection.confirmTransaction(txId, "confirmed"); 592 | console.log("Your transaction signature", txId); 593 | } 594 | 595 | export const cancelAuction = async ( 596 | mint: PublicKey, 597 | ) => { 598 | console.log(mint.toBase58()); 599 | 600 | if (!await isInitializedUser(payer.publicKey, solConnection)) { 601 | console.log('User PDA is not Initialized. Should Init User PDA for first usage'); 602 | return; 603 | } 604 | 605 | const tx = await createCancelAuctionTx(mint, payer.publicKey, program, solConnection); 606 | const { blockhash } = await solConnection.getRecentBlockhash('confirmed'); 607 | tx.feePayer = payer.publicKey; 608 | tx.recentBlockhash = blockhash; 609 | payer.signTransaction(tx); 610 | let txId = await solConnection.sendTransaction(tx, [(payer as NodeWallet).payer]); 611 | await solConnection.confirmTransaction(txId, "confirmed"); 612 | console.log("Your transaction signature", txId); 613 | } 614 | 615 | export const getNFTPoolInfo = async ( 616 | mint: PublicKey, 617 | ) => { 618 | const nftData: SellData = await getNFTPoolState(mint, program); 619 | return { 620 | mint: nftData.mint.toBase58(), 621 | seller: nftData.seller.toBase58(), 622 | collection: nftData.collection.toBase58(), 623 | priceSol: nftData.priceSol.toNumber(), 624 | listedDate: nftData.listedDate.toNumber(), 625 | active: nftData.active.toNumber(), 626 | }; 627 | } 628 | 629 | export const getOfferDataInfo = async ( 630 | mint: PublicKey, 631 | userAddress: PublicKey, 632 | ) => { 633 | const offerData: OfferData = await getOfferDataState(mint, userAddress, program); 634 | return { 635 | mint: offerData.mint.toBase58(), 636 | buyer: offerData.buyer.toBase58(), 637 | offerPrice: offerData.offerPrice.toNumber(), 638 | offerListingDate: offerData.offerListingDate.toNumber(), 639 | active: offerData.active.toNumber(), 640 | }; 641 | } 642 | 643 | export const getAuctionDataInfo = async ( 644 | mint: PublicKey, 645 | ) => { 646 | const auctionData: AuctionData = await getAuctionDataState(mint, program); 647 | return { 648 | mint: auctionData.mint.toBase58(), 649 | creator: auctionData.creator.toBase58(), 650 | startPrice: auctionData.startPrice.toNumber(), 651 | minIncreaseAmount: auctionData.minIncreaseAmount.toNumber(), 652 | startDate: auctionData.startDate.toNumber(), 653 | lastBidder: auctionData.lastBidder.toBase58(), 654 | lastBidDate: auctionData.lastBidDate.toNumber(), 655 | highestBid: auctionData.highestBid.toNumber(), 656 | duration: auctionData.duration.toNumber(), 657 | status: auctionData.status.toNumber(), 658 | }; 659 | } 660 | 661 | export const getUserPoolInfo = async ( 662 | userAddress: PublicKey, 663 | ) => { 664 | const userData: UserData = await getUserPoolState(userAddress, program); 665 | return { 666 | address: userData.address.toBase58(), 667 | escrowSol: userData.escrowSolBalance.toNumber(), 668 | tradedVolume: userData.tradedVolume.toNumber(), 669 | }; 670 | } 671 | 672 | export const getGlobalInfo = async () => { 673 | const globalPool: GlobalPool = await getGlobalState(program); 674 | const result = { 675 | admin: globalPool.superAdmin.toBase58(), 676 | marketFeeSol: globalPool.marketFeeSol.toNumber(), 677 | teamCount: globalPool.teamCount.toNumber(), 678 | teamTreasury: globalPool.teamTreasury.slice(0, globalPool.teamCount.toNumber()).map((info) => info.toBase58()), 679 | treasuryRate: globalPool.treasuryRate.slice(0, globalPool.teamCount.toNumber()).map((info) => info.toNumber()), 680 | }; 681 | 682 | return result; 683 | } 684 | 685 | export const getAllNFTs = async (rpc?: string) => { 686 | return await getAllListedNFTs(solConnection, rpc); 687 | } 688 | 689 | export const getAllOffersForNFT = async (address: string, rpc?: string) => { 690 | return await getAllOffersForListedNFT(address, solConnection, rpc); 691 | } 692 | 693 | export const getAllAuctions = async (rpc?: string) => { 694 | return await getAllStartedAuctions(solConnection, rpc); 695 | } -------------------------------------------------------------------------------- /target/idl/nut_marketplace.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "name": "nut_marketplace", 4 | "instructions": [ 5 | { 6 | "name": "initialize", 7 | "accounts": [ 8 | { 9 | "name": "admin", 10 | "isMut": true, 11 | "isSigner": true 12 | }, 13 | { 14 | "name": "globalAuthority", 15 | "isMut": true, 16 | "isSigner": false 17 | }, 18 | { 19 | "name": "escrowVault", 20 | "isMut": true, 21 | "isSigner": false 22 | }, 23 | { 24 | "name": "systemProgram", 25 | "isMut": false, 26 | "isSigner": false 27 | }, 28 | { 29 | "name": "rent", 30 | "isMut": false, 31 | "isSigner": false 32 | } 33 | ], 34 | "args": [ 35 | { 36 | "name": "globalBump", 37 | "type": "u8" 38 | }, 39 | { 40 | "name": "escrowBump", 41 | "type": "u8" 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "updateFee", 47 | "accounts": [ 48 | { 49 | "name": "admin", 50 | "isMut": true, 51 | "isSigner": true 52 | }, 53 | { 54 | "name": "globalAuthority", 55 | "isMut": true, 56 | "isSigner": false 57 | } 58 | ], 59 | "args": [ 60 | { 61 | "name": "globalBump", 62 | "type": "u8" 63 | }, 64 | { 65 | "name": "solFee", 66 | "type": "u64" 67 | } 68 | ] 69 | }, 70 | { 71 | "name": "addTeamTreasury", 72 | "accounts": [ 73 | { 74 | "name": "admin", 75 | "isMut": true, 76 | "isSigner": true 77 | }, 78 | { 79 | "name": "globalAuthority", 80 | "isMut": true, 81 | "isSigner": false 82 | } 83 | ], 84 | "args": [ 85 | { 86 | "name": "globalBump", 87 | "type": "u8" 88 | }, 89 | { 90 | "name": "address", 91 | "type": "publicKey" 92 | }, 93 | { 94 | "name": "rate", 95 | "type": "u64" 96 | } 97 | ] 98 | }, 99 | { 100 | "name": "removeTeamTreasury", 101 | "accounts": [ 102 | { 103 | "name": "admin", 104 | "isMut": true, 105 | "isSigner": true 106 | }, 107 | { 108 | "name": "globalAuthority", 109 | "isMut": true, 110 | "isSigner": false 111 | } 112 | ], 113 | "args": [ 114 | { 115 | "name": "globalBump", 116 | "type": "u8" 117 | }, 118 | { 119 | "name": "address", 120 | "type": "publicKey" 121 | } 122 | ] 123 | }, 124 | { 125 | "name": "initUserPool", 126 | "accounts": [ 127 | { 128 | "name": "owner", 129 | "isMut": true, 130 | "isSigner": true 131 | }, 132 | { 133 | "name": "userPool", 134 | "isMut": true, 135 | "isSigner": false 136 | }, 137 | { 138 | "name": "systemProgram", 139 | "isMut": false, 140 | "isSigner": false 141 | }, 142 | { 143 | "name": "rent", 144 | "isMut": false, 145 | "isSigner": false 146 | } 147 | ], 148 | "args": [ 149 | { 150 | "name": "bump", 151 | "type": "u8" 152 | } 153 | ] 154 | }, 155 | { 156 | "name": "initSellData", 157 | "accounts": [ 158 | { 159 | "name": "payer", 160 | "isMut": true, 161 | "isSigner": true 162 | }, 163 | { 164 | "name": "sellDataInfo", 165 | "isMut": true, 166 | "isSigner": false 167 | }, 168 | { 169 | "name": "systemProgram", 170 | "isMut": false, 171 | "isSigner": false 172 | }, 173 | { 174 | "name": "rent", 175 | "isMut": false, 176 | "isSigner": false 177 | } 178 | ], 179 | "args": [ 180 | { 181 | "name": "nft", 182 | "type": "publicKey" 183 | }, 184 | { 185 | "name": "bump", 186 | "type": "u8" 187 | } 188 | ] 189 | }, 190 | { 191 | "name": "listNftForSale", 192 | "accounts": [ 193 | { 194 | "name": "owner", 195 | "isMut": true, 196 | "isSigner": true 197 | }, 198 | { 199 | "name": "globalAuthority", 200 | "isMut": true, 201 | "isSigner": false 202 | }, 203 | { 204 | "name": "sellDataInfo", 205 | "isMut": true, 206 | "isSigner": false 207 | }, 208 | { 209 | "name": "userTokenAccount", 210 | "isMut": true, 211 | "isSigner": false 212 | }, 213 | { 214 | "name": "destNftTokenAccount", 215 | "isMut": true, 216 | "isSigner": false 217 | }, 218 | { 219 | "name": "nftMint", 220 | "isMut": false, 221 | "isSigner": false 222 | }, 223 | { 224 | "name": "mintMetadata", 225 | "isMut": true, 226 | "isSigner": false 227 | }, 228 | { 229 | "name": "tokenProgram", 230 | "isMut": false, 231 | "isSigner": false 232 | }, 233 | { 234 | "name": "tokenMetadataProgram", 235 | "isMut": false, 236 | "isSigner": false 237 | }, 238 | { 239 | "name": "auctionDataInfo", 240 | "isMut": true, 241 | "isSigner": false 242 | } 243 | ], 244 | "args": [ 245 | { 246 | "name": "globalBump", 247 | "type": "u8" 248 | }, 249 | { 250 | "name": "sellBump", 251 | "type": "u8" 252 | }, 253 | { 254 | "name": "auctionBump", 255 | "type": "u8" 256 | }, 257 | { 258 | "name": "priceSol", 259 | "type": "u64" 260 | } 261 | ] 262 | }, 263 | { 264 | "name": "delistNft", 265 | "accounts": [ 266 | { 267 | "name": "owner", 268 | "isMut": true, 269 | "isSigner": true 270 | }, 271 | { 272 | "name": "globalAuthority", 273 | "isMut": true, 274 | "isSigner": false 275 | }, 276 | { 277 | "name": "sellDataInfo", 278 | "isMut": true, 279 | "isSigner": false 280 | }, 281 | { 282 | "name": "userTokenAccount", 283 | "isMut": true, 284 | "isSigner": false 285 | }, 286 | { 287 | "name": "destNftTokenAccount", 288 | "isMut": true, 289 | "isSigner": false 290 | }, 291 | { 292 | "name": "nftMint", 293 | "isMut": false, 294 | "isSigner": false 295 | }, 296 | { 297 | "name": "tokenProgram", 298 | "isMut": false, 299 | "isSigner": false 300 | }, 301 | { 302 | "name": "auctionDataInfo", 303 | "isMut": true, 304 | "isSigner": false 305 | } 306 | ], 307 | "args": [ 308 | { 309 | "name": "globalBump", 310 | "type": "u8" 311 | }, 312 | { 313 | "name": "sellBump", 314 | "type": "u8" 315 | } 316 | ] 317 | }, 318 | { 319 | "name": "setPrice", 320 | "accounts": [ 321 | { 322 | "name": "owner", 323 | "isMut": true, 324 | "isSigner": true 325 | }, 326 | { 327 | "name": "sellDataInfo", 328 | "isMut": true, 329 | "isSigner": false 330 | }, 331 | { 332 | "name": "nftMint", 333 | "isMut": false, 334 | "isSigner": false 335 | } 336 | ], 337 | "args": [ 338 | { 339 | "name": "sellBump", 340 | "type": "u8" 341 | }, 342 | { 343 | "name": "price", 344 | "type": "u64" 345 | } 346 | ] 347 | }, 348 | { 349 | "name": "transfer", 350 | "accounts": [ 351 | { 352 | "name": "owner", 353 | "isMut": true, 354 | "isSigner": true 355 | }, 356 | { 357 | "name": "userTokenAccount", 358 | "isMut": true, 359 | "isSigner": false 360 | }, 361 | { 362 | "name": "recipient", 363 | "isMut": true, 364 | "isSigner": false 365 | }, 366 | { 367 | "name": "destNftTokenAccount", 368 | "isMut": true, 369 | "isSigner": false 370 | }, 371 | { 372 | "name": "nftMint", 373 | "isMut": false, 374 | "isSigner": false 375 | }, 376 | { 377 | "name": "tokenProgram", 378 | "isMut": false, 379 | "isSigner": false 380 | } 381 | ], 382 | "args": [] 383 | }, 384 | { 385 | "name": "transferFromVault", 386 | "accounts": [ 387 | { 388 | "name": "owner", 389 | "isMut": true, 390 | "isSigner": true 391 | }, 392 | { 393 | "name": "globalAuthority", 394 | "isMut": true, 395 | "isSigner": false 396 | }, 397 | { 398 | "name": "sellDataInfo", 399 | "isMut": true, 400 | "isSigner": false 401 | }, 402 | { 403 | "name": "recipient", 404 | "isMut": true, 405 | "isSigner": false 406 | }, 407 | { 408 | "name": "userTokenAccount", 409 | "isMut": true, 410 | "isSigner": false 411 | }, 412 | { 413 | "name": "destNftTokenAccount", 414 | "isMut": true, 415 | "isSigner": false 416 | }, 417 | { 418 | "name": "nftMint", 419 | "isMut": false, 420 | "isSigner": false 421 | }, 422 | { 423 | "name": "tokenProgram", 424 | "isMut": false, 425 | "isSigner": false 426 | }, 427 | { 428 | "name": "auctionDataInfo", 429 | "isMut": true, 430 | "isSigner": false 431 | } 432 | ], 433 | "args": [ 434 | { 435 | "name": "globalBump", 436 | "type": "u8" 437 | }, 438 | { 439 | "name": "sellBump", 440 | "type": "u8" 441 | } 442 | ] 443 | }, 444 | { 445 | "name": "purchase", 446 | "accounts": [ 447 | { 448 | "name": "buyer", 449 | "isMut": true, 450 | "isSigner": true 451 | }, 452 | { 453 | "name": "globalAuthority", 454 | "isMut": true, 455 | "isSigner": false 456 | }, 457 | { 458 | "name": "sellDataInfo", 459 | "isMut": true, 460 | "isSigner": false 461 | }, 462 | { 463 | "name": "buyerUserPool", 464 | "isMut": true, 465 | "isSigner": false 466 | }, 467 | { 468 | "name": "userNftTokenAccount", 469 | "isMut": true, 470 | "isSigner": false 471 | }, 472 | { 473 | "name": "destNftTokenAccount", 474 | "isMut": true, 475 | "isSigner": false 476 | }, 477 | { 478 | "name": "seller", 479 | "isMut": true, 480 | "isSigner": false 481 | }, 482 | { 483 | "name": "sellerUserPool", 484 | "isMut": true, 485 | "isSigner": false 486 | }, 487 | { 488 | "name": "nftMint", 489 | "isMut": false, 490 | "isSigner": false 491 | }, 492 | { 493 | "name": "mintMetadata", 494 | "isMut": true, 495 | "isSigner": false 496 | }, 497 | { 498 | "name": "tokenProgram", 499 | "isMut": false, 500 | "isSigner": false 501 | }, 502 | { 503 | "name": "systemProgram", 504 | "isMut": false, 505 | "isSigner": false 506 | }, 507 | { 508 | "name": "tokenMetadataProgram", 509 | "isMut": false, 510 | "isSigner": false 511 | }, 512 | { 513 | "name": "auctionDataInfo", 514 | "isMut": true, 515 | "isSigner": false 516 | } 517 | ], 518 | "args": [ 519 | { 520 | "name": "globalBump", 521 | "type": "u8" 522 | }, 523 | { 524 | "name": "nftBump", 525 | "type": "u8" 526 | }, 527 | { 528 | "name": "sellerBump", 529 | "type": "u8" 530 | }, 531 | { 532 | "name": "buyerBump", 533 | "type": "u8" 534 | } 535 | ] 536 | }, 537 | { 538 | "name": "depositToEscrow", 539 | "accounts": [ 540 | { 541 | "name": "owner", 542 | "isMut": true, 543 | "isSigner": true 544 | }, 545 | { 546 | "name": "userPool", 547 | "isMut": true, 548 | "isSigner": false 549 | }, 550 | { 551 | "name": "escrowVault", 552 | "isMut": true, 553 | "isSigner": false 554 | }, 555 | { 556 | "name": "systemProgram", 557 | "isMut": false, 558 | "isSigner": false 559 | } 560 | ], 561 | "args": [ 562 | { 563 | "name": "userBump", 564 | "type": "u8" 565 | }, 566 | { 567 | "name": "escrowBump", 568 | "type": "u8" 569 | }, 570 | { 571 | "name": "sol", 572 | "type": "u64" 573 | } 574 | ] 575 | }, 576 | { 577 | "name": "withdrawFromEscrow", 578 | "accounts": [ 579 | { 580 | "name": "owner", 581 | "isMut": true, 582 | "isSigner": true 583 | }, 584 | { 585 | "name": "userPool", 586 | "isMut": true, 587 | "isSigner": false 588 | }, 589 | { 590 | "name": "escrowVault", 591 | "isMut": true, 592 | "isSigner": false 593 | }, 594 | { 595 | "name": "systemProgram", 596 | "isMut": false, 597 | "isSigner": false 598 | } 599 | ], 600 | "args": [ 601 | { 602 | "name": "userBump", 603 | "type": "u8" 604 | }, 605 | { 606 | "name": "escrowBump", 607 | "type": "u8" 608 | }, 609 | { 610 | "name": "sol", 611 | "type": "u64" 612 | } 613 | ] 614 | }, 615 | { 616 | "name": "initOfferData", 617 | "accounts": [ 618 | { 619 | "name": "payer", 620 | "isMut": true, 621 | "isSigner": true 622 | }, 623 | { 624 | "name": "offerDataInfo", 625 | "isMut": true, 626 | "isSigner": false 627 | }, 628 | { 629 | "name": "systemProgram", 630 | "isMut": false, 631 | "isSigner": false 632 | }, 633 | { 634 | "name": "rent", 635 | "isMut": false, 636 | "isSigner": false 637 | } 638 | ], 639 | "args": [ 640 | { 641 | "name": "nft", 642 | "type": "publicKey" 643 | }, 644 | { 645 | "name": "bump", 646 | "type": "u8" 647 | } 648 | ] 649 | }, 650 | { 651 | "name": "makeOffer", 652 | "accounts": [ 653 | { 654 | "name": "owner", 655 | "isMut": true, 656 | "isSigner": true 657 | }, 658 | { 659 | "name": "sellDataInfo", 660 | "isMut": true, 661 | "isSigner": false 662 | }, 663 | { 664 | "name": "offerDataInfo", 665 | "isMut": true, 666 | "isSigner": false 667 | }, 668 | { 669 | "name": "nftMint", 670 | "isMut": false, 671 | "isSigner": false 672 | }, 673 | { 674 | "name": "userPool", 675 | "isMut": true, 676 | "isSigner": false 677 | }, 678 | { 679 | "name": "escrowVault", 680 | "isMut": true, 681 | "isSigner": false 682 | }, 683 | { 684 | "name": "systemProgram", 685 | "isMut": false, 686 | "isSigner": false 687 | } 688 | ], 689 | "args": [ 690 | { 691 | "name": "sellBump", 692 | "type": "u8" 693 | }, 694 | { 695 | "name": "offerBump", 696 | "type": "u8" 697 | }, 698 | { 699 | "name": "userBump", 700 | "type": "u8" 701 | }, 702 | { 703 | "name": "escrowBump", 704 | "type": "u8" 705 | }, 706 | { 707 | "name": "price", 708 | "type": "u64" 709 | } 710 | ] 711 | }, 712 | { 713 | "name": "cancelOffer", 714 | "accounts": [ 715 | { 716 | "name": "owner", 717 | "isMut": true, 718 | "isSigner": true 719 | }, 720 | { 721 | "name": "offerDataInfo", 722 | "isMut": true, 723 | "isSigner": false 724 | }, 725 | { 726 | "name": "nftMint", 727 | "isMut": false, 728 | "isSigner": false 729 | } 730 | ], 731 | "args": [ 732 | { 733 | "name": "offerBump", 734 | "type": "u8" 735 | } 736 | ] 737 | }, 738 | { 739 | "name": "acceptOffer", 740 | "accounts": [ 741 | { 742 | "name": "seller", 743 | "isMut": true, 744 | "isSigner": true 745 | }, 746 | { 747 | "name": "sellDataInfo", 748 | "isMut": true, 749 | "isSigner": false 750 | }, 751 | { 752 | "name": "buyer", 753 | "isMut": true, 754 | "isSigner": false 755 | }, 756 | { 757 | "name": "offerDataInfo", 758 | "isMut": true, 759 | "isSigner": false 760 | }, 761 | { 762 | "name": "sellerUserPool", 763 | "isMut": true, 764 | "isSigner": false 765 | }, 766 | { 767 | "name": "nftMint", 768 | "isMut": false, 769 | "isSigner": false 770 | }, 771 | { 772 | "name": "globalAuthority", 773 | "isMut": true, 774 | "isSigner": false 775 | }, 776 | { 777 | "name": "buyerUserPool", 778 | "isMut": true, 779 | "isSigner": false 780 | }, 781 | { 782 | "name": "userNftTokenAccount", 783 | "isMut": true, 784 | "isSigner": false 785 | }, 786 | { 787 | "name": "destNftTokenAccount", 788 | "isMut": true, 789 | "isSigner": false 790 | }, 791 | { 792 | "name": "escrowVault", 793 | "isMut": true, 794 | "isSigner": false 795 | }, 796 | { 797 | "name": "mintMetadata", 798 | "isMut": true, 799 | "isSigner": false 800 | }, 801 | { 802 | "name": "tokenProgram", 803 | "isMut": false, 804 | "isSigner": false 805 | }, 806 | { 807 | "name": "systemProgram", 808 | "isMut": false, 809 | "isSigner": false 810 | }, 811 | { 812 | "name": "tokenMetadataProgram", 813 | "isMut": false, 814 | "isSigner": false 815 | }, 816 | { 817 | "name": "auctionDataInfo", 818 | "isMut": true, 819 | "isSigner": false 820 | } 821 | ], 822 | "args": [ 823 | { 824 | "name": "globalBump", 825 | "type": "u8" 826 | }, 827 | { 828 | "name": "nftBump", 829 | "type": "u8" 830 | }, 831 | { 832 | "name": "offerBump", 833 | "type": "u8" 834 | }, 835 | { 836 | "name": "buyerBump", 837 | "type": "u8" 838 | }, 839 | { 840 | "name": "sellerBump", 841 | "type": "u8" 842 | }, 843 | { 844 | "name": "escrowBump", 845 | "type": "u8" 846 | } 847 | ] 848 | }, 849 | { 850 | "name": "initAuctionData", 851 | "accounts": [ 852 | { 853 | "name": "payer", 854 | "isMut": true, 855 | "isSigner": true 856 | }, 857 | { 858 | "name": "auctionDataInfo", 859 | "isMut": true, 860 | "isSigner": false 861 | }, 862 | { 863 | "name": "systemProgram", 864 | "isMut": false, 865 | "isSigner": false 866 | }, 867 | { 868 | "name": "rent", 869 | "isMut": false, 870 | "isSigner": false 871 | } 872 | ], 873 | "args": [ 874 | { 875 | "name": "nft", 876 | "type": "publicKey" 877 | }, 878 | { 879 | "name": "bump", 880 | "type": "u8" 881 | } 882 | ] 883 | }, 884 | { 885 | "name": "createAuction", 886 | "accounts": [ 887 | { 888 | "name": "owner", 889 | "isMut": true, 890 | "isSigner": true 891 | }, 892 | { 893 | "name": "globalAuthority", 894 | "isMut": true, 895 | "isSigner": false 896 | }, 897 | { 898 | "name": "auctionDataInfo", 899 | "isMut": true, 900 | "isSigner": false 901 | }, 902 | { 903 | "name": "userTokenAccount", 904 | "isMut": true, 905 | "isSigner": false 906 | }, 907 | { 908 | "name": "destNftTokenAccount", 909 | "isMut": true, 910 | "isSigner": false 911 | }, 912 | { 913 | "name": "nftMint", 914 | "isMut": false, 915 | "isSigner": false 916 | }, 917 | { 918 | "name": "tokenProgram", 919 | "isMut": false, 920 | "isSigner": false 921 | }, 922 | { 923 | "name": "sellDataInfo", 924 | "isMut": true, 925 | "isSigner": false 926 | } 927 | ], 928 | "args": [ 929 | { 930 | "name": "globalBump", 931 | "type": "u8" 932 | }, 933 | { 934 | "name": "auctionBump", 935 | "type": "u8" 936 | }, 937 | { 938 | "name": "sellBump", 939 | "type": "u8" 940 | }, 941 | { 942 | "name": "startPrice", 943 | "type": "u64" 944 | }, 945 | { 946 | "name": "minIncrease", 947 | "type": "u64" 948 | }, 949 | { 950 | "name": "duration", 951 | "type": "i64" 952 | }, 953 | { 954 | "name": "reserved", 955 | "type": "u8" 956 | } 957 | ] 958 | }, 959 | { 960 | "name": "placeBid", 961 | "accounts": [ 962 | { 963 | "name": "bidder", 964 | "isMut": true, 965 | "isSigner": true 966 | }, 967 | { 968 | "name": "auctionDataInfo", 969 | "isMut": true, 970 | "isSigner": false 971 | }, 972 | { 973 | "name": "nftMint", 974 | "isMut": false, 975 | "isSigner": false 976 | }, 977 | { 978 | "name": "escrowVault", 979 | "isMut": true, 980 | "isSigner": false 981 | }, 982 | { 983 | "name": "outBidder", 984 | "isMut": true, 985 | "isSigner": false 986 | }, 987 | { 988 | "name": "systemProgram", 989 | "isMut": false, 990 | "isSigner": false 991 | }, 992 | { 993 | "name": "sellDataInfo", 994 | "isMut": true, 995 | "isSigner": false 996 | } 997 | ], 998 | "args": [ 999 | { 1000 | "name": "auctionBump", 1001 | "type": "u8" 1002 | }, 1003 | { 1004 | "name": "escrowBump", 1005 | "type": "u8" 1006 | }, 1007 | { 1008 | "name": "price", 1009 | "type": "u64" 1010 | } 1011 | ] 1012 | }, 1013 | { 1014 | "name": "claimAuction", 1015 | "accounts": [ 1016 | { 1017 | "name": "bidder", 1018 | "isMut": true, 1019 | "isSigner": true 1020 | }, 1021 | { 1022 | "name": "globalAuthority", 1023 | "isMut": true, 1024 | "isSigner": false 1025 | }, 1026 | { 1027 | "name": "auctionDataInfo", 1028 | "isMut": true, 1029 | "isSigner": false 1030 | }, 1031 | { 1032 | "name": "userTokenAccount", 1033 | "isMut": true, 1034 | "isSigner": false 1035 | }, 1036 | { 1037 | "name": "destNftTokenAccount", 1038 | "isMut": true, 1039 | "isSigner": false 1040 | }, 1041 | { 1042 | "name": "nftMint", 1043 | "isMut": false, 1044 | "isSigner": false 1045 | }, 1046 | { 1047 | "name": "escrowVault", 1048 | "isMut": true, 1049 | "isSigner": false 1050 | }, 1051 | { 1052 | "name": "bidderUserPool", 1053 | "isMut": true, 1054 | "isSigner": false 1055 | }, 1056 | { 1057 | "name": "creator", 1058 | "isMut": true, 1059 | "isSigner": false 1060 | }, 1061 | { 1062 | "name": "creatorUserPool", 1063 | "isMut": true, 1064 | "isSigner": false 1065 | }, 1066 | { 1067 | "name": "mintMetadata", 1068 | "isMut": true, 1069 | "isSigner": false 1070 | }, 1071 | { 1072 | "name": "tokenProgram", 1073 | "isMut": false, 1074 | "isSigner": false 1075 | }, 1076 | { 1077 | "name": "systemProgram", 1078 | "isMut": false, 1079 | "isSigner": false 1080 | }, 1081 | { 1082 | "name": "tokenMetadataProgram", 1083 | "isMut": false, 1084 | "isSigner": false 1085 | } 1086 | ], 1087 | "args": [ 1088 | { 1089 | "name": "globalBump", 1090 | "type": "u8" 1091 | }, 1092 | { 1093 | "name": "auctionBump", 1094 | "type": "u8" 1095 | }, 1096 | { 1097 | "name": "escrowBump", 1098 | "type": "u8" 1099 | } 1100 | ] 1101 | }, 1102 | { 1103 | "name": "updateReserve", 1104 | "accounts": [ 1105 | { 1106 | "name": "creator", 1107 | "isMut": true, 1108 | "isSigner": true 1109 | }, 1110 | { 1111 | "name": "auctionDataInfo", 1112 | "isMut": true, 1113 | "isSigner": false 1114 | }, 1115 | { 1116 | "name": "nftMint", 1117 | "isMut": false, 1118 | "isSigner": false 1119 | } 1120 | ], 1121 | "args": [ 1122 | { 1123 | "name": "auctionBump", 1124 | "type": "u8" 1125 | }, 1126 | { 1127 | "name": "price", 1128 | "type": "u64" 1129 | } 1130 | ] 1131 | }, 1132 | { 1133 | "name": "cancelAuction", 1134 | "accounts": [ 1135 | { 1136 | "name": "creator", 1137 | "isMut": true, 1138 | "isSigner": true 1139 | }, 1140 | { 1141 | "name": "globalAuthority", 1142 | "isMut": true, 1143 | "isSigner": false 1144 | }, 1145 | { 1146 | "name": "auctionDataInfo", 1147 | "isMut": true, 1148 | "isSigner": false 1149 | }, 1150 | { 1151 | "name": "userTokenAccount", 1152 | "isMut": true, 1153 | "isSigner": false 1154 | }, 1155 | { 1156 | "name": "destNftTokenAccount", 1157 | "isMut": true, 1158 | "isSigner": false 1159 | }, 1160 | { 1161 | "name": "nftMint", 1162 | "isMut": false, 1163 | "isSigner": false 1164 | }, 1165 | { 1166 | "name": "tokenProgram", 1167 | "isMut": false, 1168 | "isSigner": false 1169 | }, 1170 | { 1171 | "name": "sellDataInfo", 1172 | "isMut": true, 1173 | "isSigner": false 1174 | } 1175 | ], 1176 | "args": [ 1177 | { 1178 | "name": "globalBump", 1179 | "type": "u8" 1180 | }, 1181 | { 1182 | "name": "auctionBump", 1183 | "type": "u8" 1184 | } 1185 | ] 1186 | } 1187 | ], 1188 | "accounts": [ 1189 | { 1190 | "name": "GlobalPool", 1191 | "type": { 1192 | "kind": "struct", 1193 | "fields": [ 1194 | { 1195 | "name": "superAdmin", 1196 | "type": "publicKey" 1197 | }, 1198 | { 1199 | "name": "marketFeeSol", 1200 | "type": "u64" 1201 | }, 1202 | { 1203 | "name": "teamCount", 1204 | "type": "u64" 1205 | }, 1206 | { 1207 | "name": "teamTreasury", 1208 | "type": { 1209 | "array": [ 1210 | "publicKey", 1211 | 8 1212 | ] 1213 | } 1214 | }, 1215 | { 1216 | "name": "treasuryRate", 1217 | "type": { 1218 | "array": [ 1219 | "u64", 1220 | 8 1221 | ] 1222 | } 1223 | } 1224 | ] 1225 | } 1226 | }, 1227 | { 1228 | "name": "SellData", 1229 | "type": { 1230 | "kind": "struct", 1231 | "fields": [ 1232 | { 1233 | "name": "mint", 1234 | "type": "publicKey" 1235 | }, 1236 | { 1237 | "name": "seller", 1238 | "type": "publicKey" 1239 | }, 1240 | { 1241 | "name": "collection", 1242 | "type": "publicKey" 1243 | }, 1244 | { 1245 | "name": "priceSol", 1246 | "type": "u64" 1247 | }, 1248 | { 1249 | "name": "listedDate", 1250 | "type": "i64" 1251 | }, 1252 | { 1253 | "name": "active", 1254 | "type": "u64" 1255 | } 1256 | ] 1257 | } 1258 | }, 1259 | { 1260 | "name": "OfferData", 1261 | "type": { 1262 | "kind": "struct", 1263 | "fields": [ 1264 | { 1265 | "name": "mint", 1266 | "type": "publicKey" 1267 | }, 1268 | { 1269 | "name": "buyer", 1270 | "type": "publicKey" 1271 | }, 1272 | { 1273 | "name": "offerPrice", 1274 | "type": "u64" 1275 | }, 1276 | { 1277 | "name": "offerListingDate", 1278 | "type": "i64" 1279 | }, 1280 | { 1281 | "name": "active", 1282 | "type": "u64" 1283 | } 1284 | ] 1285 | } 1286 | }, 1287 | { 1288 | "name": "AuctionData", 1289 | "type": { 1290 | "kind": "struct", 1291 | "fields": [ 1292 | { 1293 | "name": "mint", 1294 | "type": "publicKey" 1295 | }, 1296 | { 1297 | "name": "creator", 1298 | "type": "publicKey" 1299 | }, 1300 | { 1301 | "name": "startPrice", 1302 | "type": "u64" 1303 | }, 1304 | { 1305 | "name": "minIncreaseAmount", 1306 | "type": "u64" 1307 | }, 1308 | { 1309 | "name": "startDate", 1310 | "type": "i64" 1311 | }, 1312 | { 1313 | "name": "lastBidDate", 1314 | "type": "i64" 1315 | }, 1316 | { 1317 | "name": "lastBidder", 1318 | "type": "publicKey" 1319 | }, 1320 | { 1321 | "name": "highestBid", 1322 | "type": "u64" 1323 | }, 1324 | { 1325 | "name": "duration", 1326 | "type": "i64" 1327 | }, 1328 | { 1329 | "name": "status", 1330 | "type": "u64" 1331 | } 1332 | ] 1333 | } 1334 | }, 1335 | { 1336 | "name": "UserData", 1337 | "type": { 1338 | "kind": "struct", 1339 | "fields": [ 1340 | { 1341 | "name": "address", 1342 | "type": "publicKey" 1343 | }, 1344 | { 1345 | "name": "tradedVolume", 1346 | "type": "u64" 1347 | }, 1348 | { 1349 | "name": "escrowSolBalance", 1350 | "type": "u64" 1351 | } 1352 | ] 1353 | } 1354 | } 1355 | ], 1356 | "errors": [ 1357 | { 1358 | "code": 6000, 1359 | "name": "InvalidSuperOwner", 1360 | "msg": "Invalid Super Owner" 1361 | }, 1362 | { 1363 | "code": 6001, 1364 | "name": "InvalidOwner", 1365 | "msg": "Invalid Owner" 1366 | }, 1367 | { 1368 | "code": 6002, 1369 | "name": "InvalidGlobalPool", 1370 | "msg": "Invalid Global Pool Address" 1371 | }, 1372 | { 1373 | "code": 6003, 1374 | "name": "InvalidFeePercent", 1375 | "msg": "Marketplace Fee is Permyriad" 1376 | }, 1377 | { 1378 | "code": 6004, 1379 | "name": "MaxTeamCountExceed", 1380 | "msg": "Max Team Count is 8" 1381 | }, 1382 | { 1383 | "code": 6005, 1384 | "name": "NoTeamTreasuryYet", 1385 | "msg": "Treasury Wallet Not Configured" 1386 | }, 1387 | { 1388 | "code": 6006, 1389 | "name": "TreasuryAddressNotFound", 1390 | "msg": "Treasury Address Not Exist" 1391 | }, 1392 | { 1393 | "code": 6007, 1394 | "name": "TreasuryAddressAlreadyAdded", 1395 | "msg": "Treasury Address Already Exist" 1396 | }, 1397 | { 1398 | "code": 6008, 1399 | "name": "MaxTreasuryRateSumExceed", 1400 | "msg": "Total Treasury Rate Sum Should Less Than 100%" 1401 | }, 1402 | { 1403 | "code": 6009, 1404 | "name": "TeamTreasuryCountMismatch", 1405 | "msg": "Team Treasury Wallet Count Mismatch" 1406 | }, 1407 | { 1408 | "code": 6010, 1409 | "name": "TeamTreasuryAddressMismatch", 1410 | "msg": "Team Treasury Wallet Address Mismatch" 1411 | }, 1412 | { 1413 | "code": 6011, 1414 | "name": "Uninitialized", 1415 | "msg": "Uninitialized Account" 1416 | }, 1417 | { 1418 | "code": 6012, 1419 | "name": "InvalidParamInput", 1420 | "msg": "Instruction Parameter is Invalid" 1421 | }, 1422 | { 1423 | "code": 6013, 1424 | "name": "SellerMismatch", 1425 | "msg": "Payer Mismatch with NFT Seller" 1426 | }, 1427 | { 1428 | "code": 6014, 1429 | "name": "InvalidNFTDataAcount", 1430 | "msg": "Invalid NFT Data Account" 1431 | }, 1432 | { 1433 | "code": 6015, 1434 | "name": "NotListedNFT", 1435 | "msg": "The NFT Is Not Listed" 1436 | }, 1437 | { 1438 | "code": 6016, 1439 | "name": "SellerAccountMismatch", 1440 | "msg": "Seller Account Mismatch with NFT Seller Data" 1441 | }, 1442 | { 1443 | "code": 6017, 1444 | "name": "InsufficientBuyerSolBalance", 1445 | "msg": "Buyer Sol Balance is Less than NFT SOL Price" 1446 | }, 1447 | { 1448 | "code": 6018, 1449 | "name": "InsufficientBuyerTokenBalance", 1450 | "msg": "Buyer Token Balance is Less than NFT Token Price" 1451 | }, 1452 | { 1453 | "code": 6019, 1454 | "name": "InvaliedMetadata", 1455 | "msg": "Invalid Metadata Address" 1456 | }, 1457 | { 1458 | "code": 6020, 1459 | "name": "MetadataCreatorParseError", 1460 | "msg": "Can't Parse The NFT's Creators" 1461 | }, 1462 | { 1463 | "code": 6021, 1464 | "name": "InvalidOfferDataMint", 1465 | "msg": "Offer Data Mint mismatch with NFT Pubkey" 1466 | }, 1467 | { 1468 | "code": 6022, 1469 | "name": "InvalidOfferDataBuyer", 1470 | "msg": "Offer Data Buyer mismatch with Payer Pubkey" 1471 | }, 1472 | { 1473 | "code": 6023, 1474 | "name": "OfferForNotListedNFT", 1475 | "msg": "Making Offer for Not Listed NFT" 1476 | }, 1477 | { 1478 | "code": 6024, 1479 | "name": "InvalidOfferPrice", 1480 | "msg": "Offer Price Over Thank Listed Price" 1481 | }, 1482 | { 1483 | "code": 6025, 1484 | "name": "DisabledOffer", 1485 | "msg": "Already Canceled Offer" 1486 | }, 1487 | { 1488 | "code": 6026, 1489 | "name": "OfferForExpiredListingNFT", 1490 | "msg": "Offer For Sold Or Canceled NFT Listing" 1491 | }, 1492 | { 1493 | "code": 6027, 1494 | "name": "EndedAuction", 1495 | "msg": "Placing Bid For Ended Auction" 1496 | }, 1497 | { 1498 | "code": 6028, 1499 | "name": "InvalidBidPrice", 1500 | "msg": "Placing Bid With Lower Than Highest Bid" 1501 | }, 1502 | { 1503 | "code": 6029, 1504 | "name": "DoubleBidFromOneBidder", 1505 | "msg": "Placing Bid Double From One Bidder" 1506 | }, 1507 | { 1508 | "code": 6030, 1509 | "name": "OutBidderMismatch", 1510 | "msg": "Out Bidder Account Mismatch With LastBidder Data" 1511 | }, 1512 | { 1513 | "code": 6031, 1514 | "name": "NotEndedAuction", 1515 | "msg": "Claiming Auction For Not Ended Auction" 1516 | }, 1517 | { 1518 | "code": 6032, 1519 | "name": "CreatorAccountMismatch", 1520 | "msg": "Creator Account Mismatch with Auction Data" 1521 | }, 1522 | { 1523 | "code": 6033, 1524 | "name": "BidderAccountMismatch", 1525 | "msg": "Bidder Account Mismatch with Auction Data" 1526 | }, 1527 | { 1528 | "code": 6034, 1529 | "name": "AuctionHasBid", 1530 | "msg": "Canceling Auction which has Bid" 1531 | }, 1532 | { 1533 | "code": 6035, 1534 | "name": "BidFromAuctionCreator", 1535 | "msg": "Placing Bid From Auction Creator" 1536 | }, 1537 | { 1538 | "code": 6036, 1539 | "name": "ListingNotAvailable", 1540 | "msg": "Only Listing and Reserved Auction are possible to exist together" 1541 | }, 1542 | { 1543 | "code": 6037, 1544 | "name": "NFTIsNotInUserATA", 1545 | "msg": "NFT Is Not In User ATA" 1546 | }, 1547 | { 1548 | "code": 6038, 1549 | "name": "NFTIsNotInEscrowATA", 1550 | "msg": "NFT Is Not In Escrow ATA" 1551 | } 1552 | ] 1553 | } -------------------------------------------------------------------------------- /tests/nut_marketplace.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Token, TOKEN_PROGRAM_ID } from "@solana/spl-token"; 4 | import { assert } from "chai"; 5 | import fs from "fs"; 6 | import { 7 | createAcceptOfferTx, 8 | createAddTreasuryTx, 9 | createCancelAuctionTx, 10 | createCancelOfferTx, 11 | createClaimAuctionTx, 12 | createCreateAuctionTx, 13 | createDelistNftTx, 14 | createDepositTx, 15 | createInitAuctionDataTx, 16 | createInitializeTx, 17 | createInitOfferDataTx, 18 | createInitSellDataTx, 19 | createInitUserTx, 20 | createListForSellNftTx, 21 | createMakeOfferTx, 22 | createPlaceBidTx, 23 | createPurchaseTx, 24 | createRemoveTreasuryTx, 25 | createUpdateFeeTx, 26 | createWithdrawTx, 27 | getAuctionDataState, 28 | getGlobalState, 29 | getNFTPoolState, 30 | getOfferDataState, 31 | getUserPoolState, 32 | } from "../lib/scripts"; 33 | import { ABB_TOKEN_DECIMAL, ABB_TOKEN_MINT, MARKETPLACE_PROGRAM_ID, SELL_DATA_SEED, USER_DATA_SEED } from "../lib/types"; 34 | import { airdropSOL, createTokenMint, getAssociatedTokenAccount, getATokenAccountsNeedCreate, getEscrowBalance, getTokenAccountBalance, isExistAccount } from "../lib/utils"; 35 | import { NutMarketplace } from "../target/types/nut_marketplace"; 36 | 37 | // Configure the client to use the local cluster. 38 | const provider = anchor.AnchorProvider.env(); 39 | anchor.setProvider(provider); 40 | const payer = provider.wallet; 41 | console.log('Payer: ', payer.publicKey.toBase58()); 42 | 43 | const program = anchor.workspace.NutMarketplace as Program; 44 | 45 | let superOwner = null; 46 | let user = null; 47 | let user1 = null; 48 | let reward = null; 49 | let nft = null; 50 | 51 | describe("Nut_Marketplace Load Program Object & Prepare testers", () => { 52 | assert(program.programId.toBase58() == MARKETPLACE_PROGRAM_ID.toBase58(), "Program load Failure!"); 53 | 54 | it('Load Testers', async () => { 55 | const rawdata = fs.readFileSync(process.env.ANCHOR_WALLET); 56 | const keyData = JSON.parse(rawdata.toString()); 57 | 58 | superOwner = anchor.web3.Keypair.fromSecretKey(new Uint8Array(keyData)); 59 | user = anchor.web3.Keypair.generate(); 60 | user1 = anchor.web3.Keypair.generate(); 61 | 62 | console.log('Admin: ', superOwner.publicKey.toBase58()); 63 | console.log('User: ', user.publicKey.toBase58()); 64 | console.log('user1: ', user1.publicKey.toBase58()); 65 | }); 66 | it('Load Reward Token', async () => { 67 | const rawdata = fs.readFileSync('./tests/keys/reward_mint.json'); 68 | const keyData = JSON.parse(rawdata.toString()); 69 | reward = anchor.web3.Keypair.fromSecretKey(new Uint8Array(keyData)); 70 | assert(reward.publicKey.toBase58() == ABB_TOKEN_MINT.toBase58(), 'Load ABB Token Keypair Failure!'); 71 | 72 | await createTokenMint( 73 | provider.connection, 74 | superOwner, 75 | reward, 76 | ); 77 | 78 | assert(await isExistAccount(reward.publicKey, provider.connection), 'Create ABB Token mint failure!'); 79 | }); 80 | it('Airdrop SOL for Testers', async () => { 81 | await airdropSOL(user.publicKey, 1000 * 1e9, provider.connection); 82 | let res = await provider.connection.getBalance(user.publicKey); 83 | assert(res == 1000 * 1e9, 'Airdrop 1000 SOL for user Failed'); 84 | 85 | await airdropSOL(user1.publicKey, 1000 * 1e9, provider.connection); 86 | res = await provider.connection.getBalance(user1.publicKey); 87 | assert(res == 1000 * 1e9, 'Airdrop 1000 SOL for user1 Failed'); 88 | }); 89 | }); 90 | 91 | describe('Contract Creation', async () => { 92 | it('Contract creator has a role of Admin', async () => { 93 | const tx = await createInitializeTx( 94 | superOwner.publicKey, 95 | program as unknown as anchor.Program, 96 | ); 97 | const txId = await provider.connection.sendTransaction(tx, [superOwner]); 98 | await provider.connection.confirmTransaction(txId, 'confirmed'); 99 | console.log("TxHash=", txId); 100 | 101 | let globalInfo = await getGlobalState(program as unknown as anchor.Program); 102 | assert(globalInfo.superAdmin.toBase58() == superOwner.publicKey.toBase58(), "GlobalInfo Admin Address mismatch with SuperOwner Pubkey"); 103 | }); 104 | it('Admin can change the Marketplace Fee', async () => { 105 | let globalInfo = await getGlobalState(program as unknown as anchor.Program); 106 | assert(globalInfo.superAdmin.toBase58() == superOwner.publicKey.toBase58(), "GlobalInfo Admin Address mismatch with SuperOwner Pubkey"); 107 | 108 | const tx = await createUpdateFeeTx( 109 | superOwner.publicKey, 110 | program as unknown as anchor.Program, 111 | 100, 112 | 12, 113 | ); 114 | const txId = await provider.connection.sendTransaction(tx, [superOwner]); 115 | await provider.connection.confirmTransaction(txId, 'confirmed'); 116 | console.log("TxHash=", txId); 117 | 118 | globalInfo = await getGlobalState(program as unknown as anchor.Program); 119 | assert(globalInfo.marketFeeSol.toNumber() == 100, "Sol Fee is not 1%"); 120 | assert(globalInfo.marketFeeToken.toNumber() == 12, "Token Fee is not 0.12%"); 121 | }); 122 | it('Admin can add himself as team', async () => { 123 | let globalInfo = await getGlobalState(program as unknown as anchor.Program); 124 | assert(globalInfo.superAdmin.toBase58() == superOwner.publicKey.toBase58(), "GlobalInfo Admin Address mismatch with SuperOwner Pubkey"); 125 | 126 | const tx = await createAddTreasuryTx( 127 | superOwner.publicKey, 128 | program as unknown as anchor.Program, 129 | superOwner.publicKey, 130 | 500, 131 | ); 132 | const txId = await provider.connection.sendTransaction(tx, [superOwner]); 133 | await provider.connection.confirmTransaction(txId, 'confirmed'); 134 | console.log("TxHash=", txId); 135 | 136 | globalInfo = await getGlobalState(program as unknown as anchor.Program); 137 | assert(globalInfo.teamCount.toNumber() == 1, "No team treasury added"); 138 | assert(globalInfo.teamTreasury[0].toBase58() == superOwner.publicKey.toBase58(), "Superowner is team"); 139 | assert(globalInfo.treasuryRate[0].toNumber() == 500, "Superowner is treasury rate is 5%"); 140 | }); 141 | it('Admin can remove himself from team', async () => { 142 | let globalInfo = await getGlobalState(program as unknown as anchor.Program); 143 | assert(globalInfo.superAdmin.toBase58() == superOwner.publicKey.toBase58(), "GlobalInfo Admin Address mismatch with SuperOwner Pubkey"); 144 | assert(globalInfo.teamCount.toNumber() == 1, "GlobalInfo Team Treasury Count is not 1"); 145 | 146 | const tx = await createRemoveTreasuryTx( 147 | superOwner.publicKey, 148 | program as unknown as anchor.Program, 149 | superOwner.publicKey, 150 | ); 151 | const txId = await provider.connection.sendTransaction(tx, [superOwner]); 152 | await provider.connection.confirmTransaction(txId, 'confirmed'); 153 | console.log("TxHash=", txId); 154 | 155 | globalInfo = await getGlobalState(program as unknown as anchor.Program); 156 | assert(globalInfo.teamCount.toNumber() == 0, "Team treasury is still exist"); 157 | }); 158 | it('Admin can add himself as team', async () => { 159 | let globalInfo = await getGlobalState(program as unknown as anchor.Program); 160 | assert(globalInfo.superAdmin.toBase58() == superOwner.publicKey.toBase58(), "GlobalInfo Admin Address mismatch with SuperOwner Pubkey"); 161 | 162 | const tx = await createAddTreasuryTx( 163 | superOwner.publicKey, 164 | program as unknown as anchor.Program, 165 | superOwner.publicKey, 166 | 30, 167 | ); 168 | const txId = await provider.connection.sendTransaction(tx, [superOwner]); 169 | await provider.connection.confirmTransaction(txId, 'confirmed'); 170 | console.log("TxHash=", txId); 171 | 172 | globalInfo = await getGlobalState(program as unknown as anchor.Program); 173 | assert(globalInfo.teamCount.toNumber() == 1, "No team treasury added"); 174 | assert(globalInfo.teamTreasury[0].toBase58() == superOwner.publicKey.toBase58(), "Superowner is team"); 175 | assert(globalInfo.treasuryRate[0].toNumber() == 30, "Superowner is treasury rate is 0.3% finally"); 176 | }); 177 | }); 178 | 179 | describe('NFT Listing / Cancel Listing', async () => { 180 | it('Create one NFT for testing', async () => { 181 | nft = await Token.createMint( 182 | provider.connection, 183 | superOwner, 184 | superOwner.publicKey, 185 | superOwner.publicKey, 186 | 0, 187 | TOKEN_PROGRAM_ID, 188 | ); 189 | console.log('NFT Address:', nft.publicKey.toBase58()) 190 | assert(await isExistAccount(nft.publicKey, provider.connection), 'NFT Create Mint Failure'); 191 | }); 192 | it('User can init NFT SellData PDA', async () => { 193 | const [nftData, _] = await anchor.web3.PublicKey.findProgramAddress( 194 | [Buffer.from(SELL_DATA_SEED), nft.publicKey.toBuffer()], 195 | MARKETPLACE_PROGRAM_ID, 196 | ); 197 | 198 | assert((await isExistAccount(nftData, provider.connection)) != true, 'NFT SellData PDA is Already Initialized'); 199 | 200 | const tx = await createInitSellDataTx( 201 | nft.publicKey, 202 | user.publicKey, 203 | program as unknown as anchor.Program, 204 | ); 205 | const txId = await provider.connection.sendTransaction(tx, [user]); 206 | await provider.connection.confirmTransaction(txId, 'confirmed'); 207 | console.log("TxHash=", txId); 208 | 209 | let nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 210 | assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 211 | }); 212 | it('Mint one NFT in my ATA for testing', async () => { 213 | const userNFTAccount = await nft.createAssociatedTokenAccount( 214 | user.publicKey, 215 | ); 216 | console.log('User NFT Account:', userNFTAccount.toBase58()) 217 | 218 | await nft.mintTo( 219 | userNFTAccount, 220 | superOwner, 221 | [], 222 | 1, 223 | ); 224 | 225 | assert((await getTokenAccountBalance(userNFTAccount, provider.connection)) == 1, 'Mint 1 NFT to User ATA failure'); 226 | }); 227 | it('User can list NFT for sale', async () => { 228 | const [nftData, _] = await anchor.web3.PublicKey.findProgramAddress( 229 | [Buffer.from(SELL_DATA_SEED), nft.publicKey.toBuffer()], 230 | MARKETPLACE_PROGRAM_ID, 231 | ); 232 | 233 | assert((await isExistAccount(nftData, provider.connection)) == true, 'NFT SellData PDA is Not Initialized'); 234 | 235 | const tx = await createListForSellNftTx( 236 | nft.publicKey, 237 | user.publicKey, 238 | program as unknown as anchor.Program, 239 | provider.connection, 240 | 1.2 * 1e9, 241 | 150 * ABB_TOKEN_DECIMAL, 242 | ); 243 | const txId = await provider.connection.sendTransaction(tx, [user]); 244 | await provider.connection.confirmTransaction(txId, 'confirmed'); 245 | console.log("TxHash=", txId); 246 | 247 | let nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 248 | assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 249 | assert(nftInfo.priceSol.toNumber() == 1.2 * 1e9, "NFT SellData solPrice is not 1.2"); 250 | assert(nftInfo.priceToken.toNumber() == 150 * ABB_TOKEN_DECIMAL, "NFT SellData TokenPrice is not 150"); 251 | assert(nftInfo.active.toNumber() == 1, "NFT SellData is not actived"); 252 | }); 253 | // it('User can cancel listing', async () => { 254 | // const [nftData, _] = await anchor.web3.PublicKey.findProgramAddress( 255 | // [Buffer.from(SELL_DATA_SEED), nft.publicKey.toBuffer()], 256 | // MARKETPLACE_PROGRAM_ID, 257 | // ); 258 | 259 | // assert((await isExistAccount(nftData, provider.connection)) == true, 'NFT SellData PDA is Not Initialized'); 260 | 261 | // let nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 262 | // assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 263 | // assert(nftInfo.seller.toBase58() == user.publicKey.toBase58(), "NFT Seller is not User Pubkey"); 264 | // assert(nftInfo.active.toNumber() == 1, "NFT SellData is not actived"); 265 | 266 | // const tx = await createDelistNftTx( 267 | // nft.publicKey, 268 | // user.publicKey, 269 | // program as unknown as anchor.Program, 270 | // provider.connection, 271 | // ); 272 | // const txId = await provider.connection.sendTransaction(tx, [user]); 273 | // await provider.connection.confirmTransaction(txId, 'confirmed'); 274 | // console.log("TxHash=", txId); 275 | 276 | // nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 277 | // assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 278 | // assert(nftInfo.active.toNumber() == 0, "NFT SellData is still actived"); 279 | // }); 280 | }); 281 | 282 | describe('user1 Can Purchase NFT', async () => { 283 | it('Mint Enough ABB TOken in user1 ATA for staking', async () => { 284 | const rewardToken = new Token( 285 | provider.connection, 286 | ABB_TOKEN_MINT, 287 | TOKEN_PROGRAM_ID, 288 | superOwner, 289 | ) 290 | let {instructions, destinationAccounts} = await getATokenAccountsNeedCreate( 291 | provider.connection, 292 | user1.publicKey, 293 | user1.publicKey, 294 | [ABB_TOKEN_MINT], 295 | ); 296 | let user1ATA = destinationAccounts[0]; 297 | console.log('user1ATA: ', user1ATA.toBase58()); 298 | 299 | if (instructions.length > 0) { 300 | const tx = new anchor.web3.Transaction(); 301 | tx.add(instructions[0]); 302 | const txId = await anchor.web3.sendAndConfirmTransaction( 303 | provider.connection, 304 | tx, 305 | [user1], 306 | ); 307 | console.log("Tx Hash=", txId); 308 | } 309 | 310 | assert((await isExistAccount(user1ATA, provider.connection)), 'Create ABB ATA of my wallet failure!'); 311 | 312 | await rewardToken.mintTo(user1ATA, superOwner, [], 100_000 * ABB_TOKEN_DECIMAL); 313 | assert((await getTokenAccountBalance(user1ATA, provider.connection)) == 100_000, 'Testing ABB Token amount is not 100_000'); 314 | }); 315 | it('User can init own UserPool PDA', async () => { 316 | const [userPool, _] = await anchor.web3.PublicKey.findProgramAddress( 317 | [Buffer.from(USER_DATA_SEED), user.publicKey.toBuffer()], 318 | MARKETPLACE_PROGRAM_ID, 319 | ); 320 | 321 | assert((await isExistAccount(userPool, provider.connection)) != true, 'UserPool PDA is Already Initialized'); 322 | 323 | const tx = await createInitUserTx( 324 | user.publicKey, 325 | program as unknown as anchor.Program, 326 | ); 327 | const txId = await provider.connection.sendTransaction(tx, [user]); 328 | await provider.connection.confirmTransaction(txId, 'confirmed'); 329 | console.log("TxHash=", txId); 330 | 331 | let userInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 332 | assert(userInfo.address.toBase58() == user.publicKey.toBase58(), "UserData Address mismatch with User Pubkey"); 333 | }); 334 | it('User1 can init own UserPool PDA', async () => { 335 | const [userPool, _] = await anchor.web3.PublicKey.findProgramAddress( 336 | [Buffer.from(USER_DATA_SEED), user1.publicKey.toBuffer()], 337 | MARKETPLACE_PROGRAM_ID, 338 | ); 339 | 340 | assert((await isExistAccount(userPool, provider.connection)) != true, 'UserPool PDA is Already Initialized'); 341 | 342 | const tx = await createInitUserTx( 343 | user1.publicKey, 344 | program as unknown as anchor.Program, 345 | ); 346 | const txId = await provider.connection.sendTransaction(tx, [user1]); 347 | await provider.connection.confirmTransaction(txId, 'confirmed'); 348 | console.log("TxHash=", txId); 349 | 350 | let userInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 351 | assert(userInfo.address.toBase58() == user1.publicKey.toBase58(), "UserData Address mismatch with User1 Pubkey"); 352 | }); 353 | it('user1 can purchase NFT from user with ABB Token payment', async () => { 354 | let nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 355 | assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 356 | assert(nftInfo.priceSol.toNumber() == 1.2 * 1e9, "NFT SellData solPrice is not 1.2"); 357 | assert(nftInfo.priceToken.toNumber() == 150 * ABB_TOKEN_DECIMAL, "NFT SellData TokenPrice is not 150"); 358 | assert(nftInfo.active.toNumber() == 1, "NFT SellData is not actived"); 359 | assert(nftInfo.seller.toBase58() == user.publicKey.toBase58(), "NFT Seller is not user Pubkey"); 360 | 361 | let globalInfo = await getGlobalState(program as unknown as anchor.Program); 362 | assert(globalInfo.teamCount.toNumber() == 1, "No team treasury added"); 363 | assert(globalInfo.teamTreasury[0].toBase58() == superOwner.publicKey.toBase58(), "Superowner is team"); 364 | assert(globalInfo.treasuryRate[0].toNumber() == 30, "Superowner is treasury rate is 0.3% finally"); 365 | console.log("Treasury Count:", globalInfo.teamCount.toNumber()); 366 | const tx = await createPurchaseTx( 367 | nft.publicKey, 368 | user1.publicKey, 369 | true, 370 | globalInfo.teamTreasury.slice(0, globalInfo.teamCount.toNumber()), 371 | program as unknown as anchor.Program, 372 | provider.connection, 373 | ); 374 | const txId = await provider.connection.sendTransaction(tx, [user1]); 375 | await provider.connection.confirmTransaction(txId, 'confirmed'); 376 | console.log("TxHash=", txId); 377 | 378 | const user1ATA = await getAssociatedTokenAccount(user1.publicKey, nft.publicKey); 379 | assert((await getTokenAccountBalance(user1ATA, provider.connection)) == 1, 'Buyer NFT Account balance is zero'); 380 | let fee_amount = Math.floor(nftInfo.priceToken.toNumber() * globalInfo.marketFeeToken.toNumber() / 10_000); 381 | const userATA = await getAssociatedTokenAccount(user.publicKey, ABB_TOKEN_MINT); 382 | console.log(await getTokenAccountBalance(userATA, provider.connection), (nftInfo.priceToken.toNumber() - fee_amount) / ABB_TOKEN_DECIMAL, fee_amount, 'Seller ABB Account balance is not same with TokenPrice'); 383 | // assert((await getTokenAccountBalance(userATA, provider.connection)) - (nftInfo.priceToken.toNumber() - fee_amount) / ABB_TOKEN_DECIMAL, 'Seller ABB Account balance is not same with TokenPrice'); 384 | let buyerUserInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 385 | assert(buyerUserInfo.address.toBase58() == user1.publicKey.toBase58(), "UserData Address mismatch with User1 Pubkey"); 386 | assert(buyerUserInfo.tradedTokenVolume.toNumber() == nftInfo.priceToken.toNumber() - fee_amount, "UserData TradeVolume is not priceToken"); 387 | let sellerUserInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 388 | assert(sellerUserInfo.address.toBase58() == user.publicKey.toBase58(), "UserData Address mismatch with User Pubkey"); 389 | assert(sellerUserInfo.tradedTokenVolume.toNumber() == nftInfo.priceToken.toNumber() - fee_amount, "UserData TradeVolume is not priceToken"); 390 | });return; 391 | it('User1 can list NFT for sale', async () => { 392 | const [nftData, _] = await anchor.web3.PublicKey.findProgramAddress( 393 | [Buffer.from(SELL_DATA_SEED), nft.publicKey.toBuffer()], 394 | MARKETPLACE_PROGRAM_ID, 395 | ); 396 | 397 | assert((await isExistAccount(nftData, provider.connection)) == true, 'NFT SellData PDA is Not Initialized'); 398 | 399 | const tx = await createListForSellNftTx( 400 | nft.publicKey, 401 | user1.publicKey, 402 | program as unknown as anchor.Program, 403 | provider.connection, 404 | 1.2 * 1e9, 405 | 150 * ABB_TOKEN_DECIMAL, 406 | ); 407 | const txId = await provider.connection.sendTransaction(tx, [user1]); 408 | await provider.connection.confirmTransaction(txId, 'confirmed'); 409 | console.log("TxHash=", txId); 410 | 411 | let nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 412 | assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 413 | assert(nftInfo.priceSol.toNumber() == 1.2 * 1e9, "NFT SellData solPrice is not 1.2"); 414 | assert(nftInfo.priceToken.toNumber() == 150 * ABB_TOKEN_DECIMAL, "NFT SellData TokenPrice is not 150"); 415 | assert(nftInfo.active.toNumber() == 1, "NFT SellData is not actived"); 416 | }); 417 | }); 418 | /* 419 | describe('Deposit / Withdraw Escrow Balance', async () => { 420 | it('User1 can deposit sol', async () => { 421 | const tx = await createDepositTx( 422 | user1.publicKey, 423 | 1.2 * 1e9, 424 | 0, 425 | program as unknown as anchor.Program, 426 | provider.connection, 427 | ); 428 | const txId = await provider.connection.sendTransaction(tx, [user1]); 429 | await provider.connection.confirmTransaction(txId, 'confirmed'); 430 | console.log("TxHash=", txId); 431 | 432 | let userInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 433 | assert(userInfo.address.toBase58() == user1.publicKey.toBase58(), "UserData Address mismatch with User1 Pubkey"); 434 | assert(userInfo.escrowSolBalance.toNumber() == 1.2 * 1e9, "UserData Sol Balance is not 1.2"); 435 | 436 | const escrowBalance = await getEscrowBalance(provider.connection); 437 | assert(escrowBalance.sol == 1.2 * 1e9, 'Escrow Sol Balance is not 1.2'); 438 | assert(escrowBalance.token == 0, 'Escrow ABB Token balance is not 0'); 439 | }); 440 | it('User1 can deposit token', async () => { 441 | const tx = await createDepositTx( 442 | user1.publicKey, 443 | 0, 444 | 1.3 * ABB_TOKEN_DECIMAL, 445 | program as unknown as anchor.Program, 446 | provider.connection, 447 | ); 448 | const txId = await provider.connection.sendTransaction(tx, [user1]); 449 | await provider.connection.confirmTransaction(txId, 'confirmed'); 450 | console.log("TxHash=", txId); 451 | 452 | let userInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 453 | assert(userInfo.address.toBase58() == user1.publicKey.toBase58(), "UserData Address mismatch with User1 Pubkey"); 454 | assert(userInfo.escrowTokenBalance.toNumber() == 1.3 * ABB_TOKEN_DECIMAL, "UserData Token Balance is not 1.3"); 455 | 456 | const escrowBalance = await getEscrowBalance(provider.connection); 457 | assert(escrowBalance.sol == 1.2 * 1e9, 'Escrow Sol Balance is not 1.2'); 458 | assert(escrowBalance.token == 1.3 * ABB_TOKEN_DECIMAL, 'Escrow ABB Token balance is not 1.3'); 459 | }); 460 | it('User1 can withdraw token', async () => { 461 | const tx = await createWithdrawTx( 462 | user1.publicKey, 463 | 0, 464 | 0.2 * ABB_TOKEN_DECIMAL, 465 | program as unknown as anchor.Program, 466 | provider.connection, 467 | ); 468 | const txId = await provider.connection.sendTransaction(tx, [user1]); 469 | await provider.connection.confirmTransaction(txId, 'confirmed'); 470 | console.log("TxHash=", txId); 471 | 472 | let userInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 473 | assert(userInfo.address.toBase58() == user1.publicKey.toBase58(), "UserData Address mismatch with User1 Pubkey"); 474 | assert(userInfo.escrowTokenBalance.toNumber() == 1.1 * ABB_TOKEN_DECIMAL, "UserData Token Balance is not 1.3"); 475 | 476 | const escrowBalance = await getEscrowBalance(provider.connection); 477 | assert(escrowBalance.sol == 1.2 * 1e9, 'Escrow Sol Balance is not 1.2'); 478 | assert(escrowBalance.token == 1.1 * ABB_TOKEN_DECIMAL, 'Escrow ABB Token balance is not 1.1'); 479 | }); 480 | it('User1 can withdraw sol', async () => { 481 | const tx = await createWithdrawTx( 482 | user1.publicKey, 483 | 0.3 * 1e9, 484 | 0, 485 | program as unknown as anchor.Program, 486 | provider.connection, 487 | ); 488 | const txId = await provider.connection.sendTransaction(tx, [user1]); 489 | await provider.connection.confirmTransaction(txId, 'confirmed'); 490 | console.log("TxHash=", txId); 491 | 492 | let userInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 493 | assert(userInfo.address.toBase58() == user1.publicKey.toBase58(), "UserData Address mismatch with User1 Pubkey"); 494 | assert(userInfo.escrowSolBalance.toNumber() == 0.9 * 1e9, "UserData Sol Balance is not 0.9"); 495 | 496 | const escrowBalance = await getEscrowBalance(provider.connection); 497 | assert(escrowBalance.sol == 0.9 * 1e9, 'Escrow Sol Balance is not 0.9'); 498 | assert(escrowBalance.token == 1.1 * ABB_TOKEN_DECIMAL, 'Escrow ABB Token balance is not 1.1'); 499 | }); 500 | }); 501 | 502 | describe('Offer for Listed NFT', async () => { 503 | it('User can init Offer Data for listed NFT', async () => { 504 | let nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 505 | assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 506 | assert(nftInfo.seller.toBase58() == user1.publicKey.toBase58(), "NFT SellData Seller mismatch with User1 Pubkey"); 507 | assert(nftInfo.priceSol.toNumber() == 1.2 * 1e9, "NFT SellData solPrice is not 1.2"); 508 | assert(nftInfo.priceToken.toNumber() == 150 * ABB_TOKEN_DECIMAL, "NFT SellData TokenPrice is not 150"); 509 | assert(nftInfo.active.toNumber() == 1, "NFT SellData is not actived"); 510 | 511 | const tx = await createInitOfferDataTx( 512 | nft.publicKey, 513 | user.publicKey, 514 | program as unknown as anchor.Program, 515 | ); 516 | const txId = await provider.connection.sendTransaction(tx, [user]); 517 | await provider.connection.confirmTransaction(txId, 'confirmed'); 518 | console.log("TxHash=", txId); 519 | 520 | let offerInfo = await getOfferDataState(nft.publicKey, user.publicKey, program as unknown as anchor.Program); 521 | assert(offerInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT OfferData Mint mismatch with NFT Pubkey"); 522 | assert(offerInfo.buyer.toBase58() == user.publicKey.toBase58(), "NFT OfferData Buyer mismatch with User Pubkey"); 523 | }); 524 | it('User can make offer for listed NFT with depositing escrow', async () => { 525 | let userInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 526 | assert(userInfo.address.toBase58() == user.publicKey.toBase58(), "UserData Address mismatch with User Pubkey"); 527 | assert(userInfo.escrowSolBalance.toNumber() == 0, "UserData Sol Balance is not 0"); 528 | assert(userInfo.escrowTokenBalance.toNumber() == 0, "UserData Token Balance is not 0"); 529 | 530 | const tx = await createMakeOfferTx( 531 | nft.publicKey, 532 | user.publicKey, 533 | 0.7 * 1e9, 534 | false, 535 | program as unknown as anchor.Program, 536 | provider.connection, 537 | ); 538 | const txId = await provider.connection.sendTransaction(tx, [user]); 539 | await provider.connection.confirmTransaction(txId, 'confirmed'); 540 | console.log("TxHash=", txId); 541 | 542 | let offerInfo = await getOfferDataState(nft.publicKey, user.publicKey, program as unknown as anchor.Program); 543 | assert(offerInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT OfferData Mint mismatch with NFT Pubkey"); 544 | assert(offerInfo.buyer.toBase58() == user.publicKey.toBase58(), "NFT OfferData Buyer mismatch with User Pubkey"); 545 | assert(offerInfo.offerPrice.toNumber() == 0.7 * 1e9, "NFT OfferData Offer Price is not 0.7 sol"); 546 | assert(offerInfo.byToken.toNumber() == 0, "NFT OfferData ByToken is not 0"); 547 | assert(offerInfo.active.toNumber() == 1, "NFT OfferData Active is not 1"); 548 | 549 | userInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 550 | assert(userInfo.escrowSolBalance.toNumber() == 0.7 * 1e9, "UserData Sol Balance is not 0.7"); 551 | assert(userInfo.escrowTokenBalance.toNumber() == 0, "UserData Token Balance is not 0"); 552 | }); 553 | it('User can cancel offer for listed NFT without withdrawing escrow', async () => { 554 | let userInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 555 | assert(userInfo.address.toBase58() == user.publicKey.toBase58(), "UserData Address mismatch with User Pubkey"); 556 | assert(userInfo.escrowSolBalance.toNumber() == 0.7 * 1e9, "UserData Sol Balance is not 0.7"); 557 | assert(userInfo.escrowTokenBalance.toNumber() == 0, "UserData Token Balance is not 0"); 558 | 559 | const tx = await createCancelOfferTx( 560 | nft.publicKey, 561 | user.publicKey, 562 | program as unknown as anchor.Program, 563 | ); 564 | const txId = await provider.connection.sendTransaction(tx, [user]); 565 | await provider.connection.confirmTransaction(txId, 'confirmed'); 566 | console.log("TxHash=", txId); 567 | 568 | let offerInfo = await getOfferDataState(nft.publicKey, user.publicKey, program as unknown as anchor.Program); 569 | assert(offerInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT OfferData Mint mismatch with NFT Pubkey"); 570 | assert(offerInfo.buyer.toBase58() == user.publicKey.toBase58(), "NFT OfferData Buyer mismatch with User Pubkey"); 571 | assert(offerInfo.active.toNumber() == 0, "NFT OfferData Active is not 1"); 572 | 573 | userInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 574 | assert(userInfo.escrowSolBalance.toNumber() == 0.7 * 1e9, "UserData Sol Balance is not 0.7"); 575 | assert(userInfo.escrowTokenBalance.toNumber() == 0, "UserData Token Balance is not 0"); 576 | }); 577 | it('User can make offer for listed NFT finally', async () => { 578 | let userInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 579 | assert(userInfo.address.toBase58() == user.publicKey.toBase58(), "UserData Address mismatch with User Pubkey"); 580 | assert(userInfo.escrowSolBalance.toNumber() == 0.7 * 1e9, "UserData Sol Balance is not 0.7 * 1e9"); 581 | assert(userInfo.escrowTokenBalance.toNumber() == 0, "UserData Token Balance is not 0"); 582 | 583 | const tx = await createMakeOfferTx( 584 | nft.publicKey, 585 | user.publicKey, 586 | 0.6 * 1e9, 587 | false, 588 | program as unknown as anchor.Program, 589 | provider.connection, 590 | ); 591 | const txId = await provider.connection.sendTransaction(tx, [user]); 592 | await provider.connection.confirmTransaction(txId, 'confirmed'); 593 | console.log("TxHash=", txId); 594 | 595 | let offerInfo = await getOfferDataState(nft.publicKey, user.publicKey, program as unknown as anchor.Program); 596 | assert(offerInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT OfferData Mint mismatch with NFT Pubkey"); 597 | assert(offerInfo.buyer.toBase58() == user.publicKey.toBase58(), "NFT OfferData Buyer mismatch with User Pubkey"); 598 | assert(offerInfo.offerPrice.toNumber() == 0.6 * 1e9, "NFT OfferData Offer Price is not 0.6 sol"); 599 | assert(offerInfo.byToken.toNumber() == 0, "NFT OfferData ByToken is not 0"); 600 | assert(offerInfo.active.toNumber() == 1, "NFT OfferData Active is not 1"); 601 | 602 | userInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 603 | assert(userInfo.escrowSolBalance.toNumber() == 1.3 * 1e9, "UserData Sol Balance is not 1.3"); 604 | assert(userInfo.escrowTokenBalance.toNumber() == 0, "UserData Token Balance is not 0"); 605 | }); 606 | it('User1 can accept user\'s offer', async () => { 607 | let nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 608 | assert(nftInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT SellData Mint mismatch with NFT Pubkey"); 609 | assert(nftInfo.seller.toBase58() == user1.publicKey, "NFT SellData seller is not User1 Pubkey"); 610 | assert(nftInfo.priceSol.toNumber() == 1.2 * 1e9, "NFT SellData solPrice is not 1.2"); 611 | assert(nftInfo.priceToken.toNumber() == 150 * ABB_TOKEN_DECIMAL, "NFT SellData TokenPrice is not 150"); 612 | assert(nftInfo.active.toNumber() == 1, "NFT SellData is not actived"); 613 | 614 | let offerInfo = await getOfferDataState(nft.publicKey, user.publicKey, program as unknown as anchor.Program); 615 | assert(offerInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT OfferData Mint mismatch with NFT Pubkey"); 616 | assert(offerInfo.buyer.toBase58() == user.publicKey.toBase58(), "NFT OfferData Buyer mismatch with User Pubkey"); 617 | assert(offerInfo.offerPrice.toNumber() == 0.6 * 1e9, "NFT OfferData Offer Price is not 0.6 sol"); 618 | assert(offerInfo.byToken.toNumber() == 0, "NFT OfferData ByToken is not 0"); 619 | assert(offerInfo.active.toNumber() == 1, "NFT OfferData Active is not 1"); 620 | 621 | let escrowBalance = await getEscrowBalance(provider.connection); 622 | assert(escrowBalance.sol == 2.2 * 1e9, 'Escrow Sol Balance is not 2.2'); 623 | assert(escrowBalance.token == 1.1 * ABB_TOKEN_DECIMAL, 'Escrow ABB Token balance is not 1.1'); 624 | 625 | let sellerUserInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 626 | assert(sellerUserInfo.address.toBase58() == user1.publicKey.toBase58(), "UserData Address mismatch with User1 Pubkey"); 627 | assert(sellerUserInfo.tradedVolume.toNumber() == 0, "UserData TradeVolume is not 0"); 628 | let buyerUserInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 629 | assert(buyerUserInfo.address.toBase58() == user.publicKey.toBase58(), "UserData Address mismatch with User Pubkey"); 630 | assert(buyerUserInfo.escrowSolBalance.toNumber() == 1.3 * 1e9, "UserData Sol Balance is not 1.3"); 631 | assert(buyerUserInfo.tradedVolume.toNumber() == 0, "UserData TradeVolume is not 0"); 632 | 633 | const tx = await createAcceptOfferTx( 634 | nft.publicKey, 635 | user.publicKey, 636 | program as unknown as anchor.Program, 637 | provider.connection, 638 | ); 639 | const txId = await provider.connection.sendTransaction(tx, [user1]); 640 | await provider.connection.confirmTransaction(txId, 'confirmed'); 641 | console.log("TxHash=", txId); 642 | 643 | nftInfo = await getNFTPoolState(nft.publicKey, program as unknown as anchor.Program); 644 | assert(nftInfo.active.toNumber() == 0, "NFT SellData is not 0"); 645 | offerInfo = await getOfferDataState(nft.publicKey, user.publicKey, program as unknown as anchor.Program); 646 | assert(offerInfo.active.toNumber() == 0, "NFT OfferData Active is not 0"); 647 | escrowBalance = await getEscrowBalance(provider.connection); 648 | assert(escrowBalance.sol == 1.6 * 1e9, 'Escrow Sol Balance is not 1.6'); 649 | sellerUserInfo = await getUserPoolState(user1.publicKey, program as unknown as anchor.Program); 650 | assert(sellerUserInfo.tradedVolume.toNumber() == 0.6 * 1e9, "UserData TradeVolume is not 0.6"); 651 | buyerUserInfo = await getUserPoolState(user.publicKey, program as unknown as anchor.Program); 652 | assert(buyerUserInfo.escrowSolBalance.toNumber() == 0.7 * 1e9, "UserData Sol Balance is not 0.7"); 653 | assert(buyerUserInfo.tradedVolume.toNumber() == 0.6 * 1e9, "UserData TradeVolume is not 0.6"); 654 | }); 655 | }); 656 | 657 | describe('Auction and Bid', async () => { 658 | it('User can init auction Data for Creating Auction', async () => { 659 | const tx = await createInitAuctionDataTx( 660 | nft.publicKey, 661 | user.publicKey, 662 | program as unknown as anchor.Program, 663 | ); 664 | const txId = await provider.connection.sendTransaction(tx, [user]); 665 | await provider.connection.confirmTransaction(txId, 'confirmed'); 666 | console.log("TxHash=", txId); 667 | 668 | let auctionInfo = await getAuctionDataState(nft.publicKey, program as unknown as anchor.Program); 669 | assert(auctionInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT AuctionData Mint mismatch with NFT Pubkey"); 670 | }); 671 | it('User can Create Auction', async () => { 672 | let now = Math.floor(Date.now() / 1000); 673 | const tx = await createCreateAuctionTx( 674 | nft.publicKey, 675 | user.publicKey, 676 | 1 * 1e9, 677 | 0.2 * 1e9, 678 | true, 679 | now + 10, 680 | program as unknown as anchor.Program, 681 | provider.connection, 682 | ); 683 | const txId = await provider.connection.sendTransaction(tx, [user]); 684 | await provider.connection.confirmTransaction(txId, 'confirmed'); 685 | console.log("TxHash=", txId); 686 | 687 | let auctionInfo = await getAuctionDataState(nft.publicKey, program as unknown as anchor.Program); 688 | assert(auctionInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT AuctionData Mint mismatch with NFT Pubkey"); 689 | assert(auctionInfo.creator.toBase58() == user.publicKey.toBase58(), "NFT AuctionData Creator mismatch with User Pubkey"); 690 | assert(auctionInfo.startPrice.toNumber() == 1 * 1e9, "StartPrice is not 1 SOL"); 691 | assert(auctionInfo.minIncreaseAmount.toNumber() == 0.2 * 1e9, "MinIncreaseAmount is not 0.2 SOL"); 692 | assert(auctionInfo.byToken.toNumber() == 1, "ByToken is not true"); 693 | assert(auctionInfo.endDate.toNumber() == now + 10, `EndDate is not ${now + 10}`); 694 | assert(auctionInfo.status.toNumber() == 1, 'Status is not 1'); 695 | }); 696 | it('User1 can Place Bid', async () => { 697 | const tx = await createPlaceBidTx( 698 | nft.publicKey, 699 | user1.publicKey, 700 | 1.5 * 1e9, 701 | program as unknown as anchor.Program, 702 | provider.connection, 703 | ); 704 | const txId = await provider.connection.sendTransaction(tx, [user1]); 705 | await provider.connection.confirmTransaction(txId, 'confirmed'); 706 | console.log("TxHash=", txId); 707 | let auctionInfo = await getAuctionDataState(nft.publicKey, program as unknown as anchor.Program); 708 | assert(auctionInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT AuctionData Mint mismatch with NFT Pubkey"); 709 | assert(auctionInfo.lastBidder.toBase58() == user1.publicKey.toBase58(), "LastBidder mismatch with User1 Pubkey"); 710 | assert(auctionInfo.highestBid.toNumber() == 1.5 * 1e9, 'HighestBid is not 1.5'); 711 | assert(auctionInfo.status.toNumber() == 1, 'Status is not 1'); 712 | 713 | const escrowBalance = await getEscrowBalance(provider.connection); 714 | console.log(escrowBalance); 715 | // assert(escrowBalance.sol == 1.5, 'Escrow Sol Balance is not 1.5'); 716 | // assert(escrowBalance.token == 0, 'Escrow ABB Token balance is not 0'); 717 | }); 718 | it('User1 can Claim Auction', async () => { 719 | await new Promise((resolve) => { 720 | setTimeout(() => { 721 | resolve(true); 722 | }, 11000); 723 | }); 724 | const tx = await createClaimAuctionTx( 725 | nft.publicKey, 726 | user1.publicKey, 727 | program as unknown as anchor.Program, 728 | provider.connection, 729 | ); 730 | const txId = await provider.connection.sendTransaction(tx, [user1]); 731 | await provider.connection.confirmTransaction(txId, 'confirmed'); 732 | console.log("TxHash=", txId); 733 | 734 | let auctionInfo = await getAuctionDataState(nft.publicKey, program as unknown as anchor.Program); 735 | assert(auctionInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT AuctionData Mint mismatch with NFT Pubkey"); 736 | assert(auctionInfo.status.toNumber() == 2, 'Status is not 2'); 737 | 738 | const escrowBalance = await getEscrowBalance(provider.connection); 739 | console.log(escrowBalance); 740 | // assert(escrowBalance.sol == 0, 'Escrow Sol Balance is not 0'); 741 | // assert(escrowBalance.token == 0, 'Escrow ABB Token balance is not 0'); 742 | 743 | const user1ATA = await getAssociatedTokenAccount(user1.publicKey, nft.publicKey); 744 | assert((await getTokenAccountBalance(user1ATA, provider.connection)) == 1, 'Winner NFT Account balance is zero'); 745 | }); 746 | it('User1 can Create Auction', async () => { 747 | let now = Math.floor(Date.now() / 1000); 748 | const tx = await createCreateAuctionTx( 749 | nft.publicKey, 750 | user1.publicKey, 751 | 1 * 1e9, 752 | 0.2 * 1e9, 753 | false, 754 | now + 10, 755 | program as unknown as anchor.Program, 756 | provider.connection, 757 | ); 758 | const txId = await provider.connection.sendTransaction(tx, [user1]); 759 | await provider.connection.confirmTransaction(txId, 'confirmed'); 760 | console.log("TxHash=", txId); 761 | 762 | let auctionInfo = await getAuctionDataState(nft.publicKey, program as unknown as anchor.Program); 763 | assert(auctionInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT AuctionData Mint mismatch with NFT Pubkey"); 764 | assert(auctionInfo.creator.toBase58() == user1.publicKey.toBase58(), "NFT AuctionData Creator mismatch with User Pubkey"); 765 | assert(auctionInfo.startPrice.toNumber() == 1 * 1e9, "StartPrice is not 1 SOL"); 766 | assert(auctionInfo.minIncreaseAmount.toNumber() == 0.2 * 1e9, "MinIncreaseAmount is not 0.2 SOL"); 767 | assert(auctionInfo.byToken.toNumber() == 0, "ByToken is not false"); 768 | assert(auctionInfo.endDate.toNumber() == now + 10, `EndDate is not ${now + 10}`); 769 | assert(auctionInfo.status.toNumber() == 1, 'Status is not 1'); 770 | }); 771 | it('User1 can Cancel Auction', async () => { 772 | await new Promise((resolve) => { 773 | setTimeout(() => { 774 | resolve(true); 775 | }, 11000); 776 | }); 777 | const tx = await createCancelAuctionTx( 778 | nft.publicKey, 779 | user1.publicKey, 780 | program as unknown as anchor.Program, 781 | provider.connection, 782 | ); 783 | const txId = await provider.connection.sendTransaction(tx, [user1]); 784 | await provider.connection.confirmTransaction(txId, 'confirmed'); 785 | console.log("TxHash=", txId); 786 | 787 | let auctionInfo = await getAuctionDataState(nft.publicKey, program as unknown as anchor.Program); 788 | assert(auctionInfo.mint.toBase58() == nft.publicKey.toBase58(), "NFT AuctionData Mint mismatch with NFT Pubkey"); 789 | assert(auctionInfo.status.toNumber() == 0, 'Status is not 0'); 790 | 791 | const user1ATA = await getAssociatedTokenAccount(user1.publicKey, nft.publicKey); 792 | assert((await getTokenAccountBalance(user1ATA, provider.connection)) == 1, 'Creator NFT Account balance is zero'); 793 | }); 794 | }); */ -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.7.6" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 10 | dependencies = [ 11 | "getrandom 0.2.6", 12 | "once_cell", 13 | "version_check", 14 | ] 15 | 16 | [[package]] 17 | name = "aho-corasick" 18 | version = "0.7.18" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 21 | dependencies = [ 22 | "memchr", 23 | ] 24 | 25 | [[package]] 26 | name = "anchor-attribute-access-control" 27 | version = "0.24.2" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "a9b75d05b6b4ac9d95bb6e3b786b27d3a708c4c5a87c92ffaa25bbe9ae4c5d91" 30 | dependencies = [ 31 | "anchor-syn", 32 | "anyhow", 33 | "proc-macro2", 34 | "quote", 35 | "regex", 36 | "syn", 37 | ] 38 | 39 | [[package]] 40 | name = "anchor-attribute-account" 41 | version = "0.24.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "485351a6d8157750d10d88c8e256f1bf8339262b2220ae9125aed3471309b5de" 44 | dependencies = [ 45 | "anchor-syn", 46 | "anyhow", 47 | "bs58 0.4.0", 48 | "proc-macro2", 49 | "quote", 50 | "rustversion", 51 | "syn", 52 | ] 53 | 54 | [[package]] 55 | name = "anchor-attribute-constant" 56 | version = "0.24.2" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "dc632c540913dd051a78b00587cc47f57013d303163ddfaf4fa18717f7ccc1e0" 59 | dependencies = [ 60 | "anchor-syn", 61 | "proc-macro2", 62 | "syn", 63 | ] 64 | 65 | [[package]] 66 | name = "anchor-attribute-error" 67 | version = "0.24.2" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "3b5bd1dcfa7f3bc22dacef233d70a9e0bee269c4ac484510662f257cba2353a1" 70 | dependencies = [ 71 | "anchor-syn", 72 | "proc-macro2", 73 | "quote", 74 | "syn", 75 | ] 76 | 77 | [[package]] 78 | name = "anchor-attribute-event" 79 | version = "0.24.2" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "6c6f9e6ce551ac9a177a45c99a65699a860c9e95fac68675138af1246e2591b0" 82 | dependencies = [ 83 | "anchor-syn", 84 | "anyhow", 85 | "proc-macro2", 86 | "quote", 87 | "syn", 88 | ] 89 | 90 | [[package]] 91 | name = "anchor-attribute-interface" 92 | version = "0.24.2" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "d104aa17418cb329ed7418b227e083d5f326a27f26ce98f5d92e33da62a5f459" 95 | dependencies = [ 96 | "anchor-syn", 97 | "anyhow", 98 | "heck", 99 | "proc-macro2", 100 | "quote", 101 | "syn", 102 | ] 103 | 104 | [[package]] 105 | name = "anchor-attribute-program" 106 | version = "0.24.2" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "b6831b920b173c004ddf7ae1167d1d25e9f002ffcb1773bbc5c7ce532a4441e1" 109 | dependencies = [ 110 | "anchor-syn", 111 | "anyhow", 112 | "proc-macro2", 113 | "quote", 114 | "syn", 115 | ] 116 | 117 | [[package]] 118 | name = "anchor-attribute-state" 119 | version = "0.24.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "cde147b10c71d95dc679785db0b5f3abac0091f789167aa62ac0135e2f54e8b9" 122 | dependencies = [ 123 | "anchor-syn", 124 | "anyhow", 125 | "proc-macro2", 126 | "quote", 127 | "syn", 128 | ] 129 | 130 | [[package]] 131 | name = "anchor-derive-accounts" 132 | version = "0.24.2" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "9cde98a0e1a56046b040ff591dfda391f88917af2b6487d02b45093c05be3514" 135 | dependencies = [ 136 | "anchor-syn", 137 | "anyhow", 138 | "proc-macro2", 139 | "quote", 140 | "syn", 141 | ] 142 | 143 | [[package]] 144 | name = "anchor-lang" 145 | version = "0.24.2" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "a85dd2c5e29e20c7f4701a43724d6cd5406d0ee5694705522e43da0f26542a84" 148 | dependencies = [ 149 | "anchor-attribute-access-control", 150 | "anchor-attribute-account", 151 | "anchor-attribute-constant", 152 | "anchor-attribute-error", 153 | "anchor-attribute-event", 154 | "anchor-attribute-interface", 155 | "anchor-attribute-program", 156 | "anchor-attribute-state", 157 | "anchor-derive-accounts", 158 | "arrayref", 159 | "base64 0.13.0", 160 | "bincode", 161 | "borsh", 162 | "bytemuck", 163 | "solana-program", 164 | "thiserror", 165 | ] 166 | 167 | [[package]] 168 | name = "anchor-spl" 169 | version = "0.24.2" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "0188c33b4a3c124c4e593f2b440415aaea70a7650fac6ba0772395385d71c003" 172 | dependencies = [ 173 | "anchor-lang", 174 | "solana-program", 175 | "spl-associated-token-account", 176 | "spl-token", 177 | ] 178 | 179 | [[package]] 180 | name = "anchor-syn" 181 | version = "0.24.2" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "03549dc2eae0b20beba6333b14520e511822a6321cdb1760f841064a69347316" 184 | dependencies = [ 185 | "anyhow", 186 | "bs58 0.3.1", 187 | "heck", 188 | "proc-macro2", 189 | "proc-macro2-diagnostics", 190 | "quote", 191 | "serde", 192 | "serde_json", 193 | "sha2", 194 | "syn", 195 | "thiserror", 196 | ] 197 | 198 | [[package]] 199 | name = "anyhow" 200 | version = "1.0.57" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" 203 | 204 | [[package]] 205 | name = "arrayref" 206 | version = "0.3.6" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 209 | 210 | [[package]] 211 | name = "arrayvec" 212 | version = "0.7.2" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" 215 | 216 | [[package]] 217 | name = "atty" 218 | version = "0.2.14" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 221 | dependencies = [ 222 | "hermit-abi", 223 | "libc", 224 | "winapi", 225 | ] 226 | 227 | [[package]] 228 | name = "autocfg" 229 | version = "1.1.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 232 | 233 | [[package]] 234 | name = "base64" 235 | version = "0.12.3" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 238 | 239 | [[package]] 240 | name = "base64" 241 | version = "0.13.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 244 | 245 | [[package]] 246 | name = "bincode" 247 | version = "1.3.3" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 250 | dependencies = [ 251 | "serde", 252 | ] 253 | 254 | [[package]] 255 | name = "bitflags" 256 | version = "1.3.2" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 259 | 260 | [[package]] 261 | name = "blake3" 262 | version = "1.3.1" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" 265 | dependencies = [ 266 | "arrayref", 267 | "arrayvec", 268 | "cc", 269 | "cfg-if", 270 | "constant_time_eq", 271 | "digest 0.10.3", 272 | ] 273 | 274 | [[package]] 275 | name = "block-buffer" 276 | version = "0.9.0" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 279 | dependencies = [ 280 | "block-padding", 281 | "generic-array", 282 | ] 283 | 284 | [[package]] 285 | name = "block-buffer" 286 | version = "0.10.2" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 289 | dependencies = [ 290 | "generic-array", 291 | ] 292 | 293 | [[package]] 294 | name = "block-padding" 295 | version = "0.2.1" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" 298 | 299 | [[package]] 300 | name = "borsh" 301 | version = "0.9.3" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" 304 | dependencies = [ 305 | "borsh-derive", 306 | "hashbrown", 307 | ] 308 | 309 | [[package]] 310 | name = "borsh-derive" 311 | version = "0.9.3" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" 314 | dependencies = [ 315 | "borsh-derive-internal", 316 | "borsh-schema-derive-internal", 317 | "proc-macro-crate 0.1.5", 318 | "proc-macro2", 319 | "syn", 320 | ] 321 | 322 | [[package]] 323 | name = "borsh-derive-internal" 324 | version = "0.9.3" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" 327 | dependencies = [ 328 | "proc-macro2", 329 | "quote", 330 | "syn", 331 | ] 332 | 333 | [[package]] 334 | name = "borsh-schema-derive-internal" 335 | version = "0.9.3" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" 338 | dependencies = [ 339 | "proc-macro2", 340 | "quote", 341 | "syn", 342 | ] 343 | 344 | [[package]] 345 | name = "bs58" 346 | version = "0.3.1" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" 349 | 350 | [[package]] 351 | name = "bs58" 352 | version = "0.4.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" 355 | 356 | [[package]] 357 | name = "bumpalo" 358 | version = "3.10.0" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" 361 | 362 | [[package]] 363 | name = "bv" 364 | version = "0.11.1" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" 367 | dependencies = [ 368 | "feature-probe", 369 | "serde", 370 | ] 371 | 372 | [[package]] 373 | name = "bytemuck" 374 | version = "1.9.1" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" 377 | dependencies = [ 378 | "bytemuck_derive", 379 | ] 380 | 381 | [[package]] 382 | name = "bytemuck_derive" 383 | version = "1.1.0" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e" 386 | dependencies = [ 387 | "proc-macro2", 388 | "quote", 389 | "syn", 390 | ] 391 | 392 | [[package]] 393 | name = "byteorder" 394 | version = "1.4.3" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 397 | 398 | [[package]] 399 | name = "cc" 400 | version = "1.0.73" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 403 | 404 | [[package]] 405 | name = "cfg-if" 406 | version = "1.0.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 409 | 410 | [[package]] 411 | name = "console_error_panic_hook" 412 | version = "0.1.7" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" 415 | dependencies = [ 416 | "cfg-if", 417 | "wasm-bindgen", 418 | ] 419 | 420 | [[package]] 421 | name = "console_log" 422 | version = "0.2.0" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" 425 | dependencies = [ 426 | "log", 427 | "web-sys", 428 | ] 429 | 430 | [[package]] 431 | name = "constant_time_eq" 432 | version = "0.1.5" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 435 | 436 | [[package]] 437 | name = "cpufeatures" 438 | version = "0.2.2" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" 441 | dependencies = [ 442 | "libc", 443 | ] 444 | 445 | [[package]] 446 | name = "crunchy" 447 | version = "0.2.2" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 450 | 451 | [[package]] 452 | name = "crypto-common" 453 | version = "0.1.3" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" 456 | dependencies = [ 457 | "generic-array", 458 | "typenum", 459 | ] 460 | 461 | [[package]] 462 | name = "crypto-mac" 463 | version = "0.8.0" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" 466 | dependencies = [ 467 | "generic-array", 468 | "subtle", 469 | ] 470 | 471 | [[package]] 472 | name = "curve25519-dalek" 473 | version = "3.2.1" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" 476 | dependencies = [ 477 | "byteorder", 478 | "digest 0.9.0", 479 | "rand_core", 480 | "subtle", 481 | "zeroize", 482 | ] 483 | 484 | [[package]] 485 | name = "digest" 486 | version = "0.9.0" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 489 | dependencies = [ 490 | "generic-array", 491 | ] 492 | 493 | [[package]] 494 | name = "digest" 495 | version = "0.10.3" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 498 | dependencies = [ 499 | "block-buffer 0.10.2", 500 | "crypto-common", 501 | "subtle", 502 | ] 503 | 504 | [[package]] 505 | name = "either" 506 | version = "1.6.1" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 509 | 510 | [[package]] 511 | name = "env_logger" 512 | version = "0.9.0" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" 515 | dependencies = [ 516 | "atty", 517 | "humantime", 518 | "log", 519 | "regex", 520 | "termcolor", 521 | ] 522 | 523 | [[package]] 524 | name = "feature-probe" 525 | version = "0.1.1" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" 528 | 529 | [[package]] 530 | name = "generic-array" 531 | version = "0.14.5" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 534 | dependencies = [ 535 | "serde", 536 | "typenum", 537 | "version_check", 538 | ] 539 | 540 | [[package]] 541 | name = "getrandom" 542 | version = "0.1.16" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 545 | dependencies = [ 546 | "cfg-if", 547 | "js-sys", 548 | "libc", 549 | "wasi 0.9.0+wasi-snapshot-preview1", 550 | "wasm-bindgen", 551 | ] 552 | 553 | [[package]] 554 | name = "getrandom" 555 | version = "0.2.6" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" 558 | dependencies = [ 559 | "cfg-if", 560 | "libc", 561 | "wasi 0.10.2+wasi-snapshot-preview1", 562 | ] 563 | 564 | [[package]] 565 | name = "hashbrown" 566 | version = "0.11.2" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 569 | dependencies = [ 570 | "ahash", 571 | ] 572 | 573 | [[package]] 574 | name = "heck" 575 | version = "0.3.3" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 578 | dependencies = [ 579 | "unicode-segmentation", 580 | ] 581 | 582 | [[package]] 583 | name = "hermit-abi" 584 | version = "0.1.19" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 587 | dependencies = [ 588 | "libc", 589 | ] 590 | 591 | [[package]] 592 | name = "hmac" 593 | version = "0.8.1" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" 596 | dependencies = [ 597 | "crypto-mac", 598 | "digest 0.9.0", 599 | ] 600 | 601 | [[package]] 602 | name = "hmac-drbg" 603 | version = "0.3.0" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" 606 | dependencies = [ 607 | "digest 0.9.0", 608 | "generic-array", 609 | "hmac", 610 | ] 611 | 612 | [[package]] 613 | name = "humantime" 614 | version = "2.1.0" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 617 | 618 | [[package]] 619 | name = "instant" 620 | version = "0.1.12" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 623 | dependencies = [ 624 | "cfg-if", 625 | ] 626 | 627 | [[package]] 628 | name = "itertools" 629 | version = "0.10.3" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 632 | dependencies = [ 633 | "either", 634 | ] 635 | 636 | [[package]] 637 | name = "itoa" 638 | version = "1.0.2" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" 641 | 642 | [[package]] 643 | name = "js-sys" 644 | version = "0.3.57" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" 647 | dependencies = [ 648 | "wasm-bindgen", 649 | ] 650 | 651 | [[package]] 652 | name = "keccak" 653 | version = "0.1.2" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" 656 | 657 | [[package]] 658 | name = "lazy_static" 659 | version = "1.4.0" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 662 | 663 | [[package]] 664 | name = "libc" 665 | version = "0.2.126" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 668 | 669 | [[package]] 670 | name = "libsecp256k1" 671 | version = "0.6.0" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" 674 | dependencies = [ 675 | "arrayref", 676 | "base64 0.12.3", 677 | "digest 0.9.0", 678 | "hmac-drbg", 679 | "libsecp256k1-core", 680 | "libsecp256k1-gen-ecmult", 681 | "libsecp256k1-gen-genmult", 682 | "rand", 683 | "serde", 684 | "sha2", 685 | "typenum", 686 | ] 687 | 688 | [[package]] 689 | name = "libsecp256k1-core" 690 | version = "0.2.2" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" 693 | dependencies = [ 694 | "crunchy", 695 | "digest 0.9.0", 696 | "subtle", 697 | ] 698 | 699 | [[package]] 700 | name = "libsecp256k1-gen-ecmult" 701 | version = "0.2.1" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" 704 | dependencies = [ 705 | "libsecp256k1-core", 706 | ] 707 | 708 | [[package]] 709 | name = "libsecp256k1-gen-genmult" 710 | version = "0.2.1" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" 713 | dependencies = [ 714 | "libsecp256k1-core", 715 | ] 716 | 717 | [[package]] 718 | name = "lock_api" 719 | version = "0.4.7" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" 722 | dependencies = [ 723 | "autocfg", 724 | "scopeguard", 725 | ] 726 | 727 | [[package]] 728 | name = "log" 729 | version = "0.4.17" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 732 | dependencies = [ 733 | "cfg-if", 734 | ] 735 | 736 | [[package]] 737 | name = "memchr" 738 | version = "2.5.0" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 741 | 742 | [[package]] 743 | name = "memmap2" 744 | version = "0.5.4" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae" 747 | dependencies = [ 748 | "libc", 749 | ] 750 | 751 | [[package]] 752 | name = "metaplex-token-metadata" 753 | version = "0.0.1" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "abcc939f0afdc6db054b9998a1292d0a016244b382462e61cfc7c570624982cb" 756 | dependencies = [ 757 | "arrayref", 758 | "borsh", 759 | "metaplex-token-vault", 760 | "num-derive", 761 | "num-traits", 762 | "solana-program", 763 | "spl-token", 764 | "thiserror", 765 | ] 766 | 767 | [[package]] 768 | name = "metaplex-token-vault" 769 | version = "0.0.1" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "a5211991ba3273df89cd5e0f6f558bc8d7453c87c0546f915b4a319e1541df33" 772 | dependencies = [ 773 | "borsh", 774 | "num-derive", 775 | "num-traits", 776 | "solana-program", 777 | "spl-token", 778 | "thiserror", 779 | ] 780 | 781 | [[package]] 782 | name = "num-derive" 783 | version = "0.3.3" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" 786 | dependencies = [ 787 | "proc-macro2", 788 | "quote", 789 | "syn", 790 | ] 791 | 792 | [[package]] 793 | name = "num-traits" 794 | version = "0.2.15" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 797 | dependencies = [ 798 | "autocfg", 799 | ] 800 | 801 | [[package]] 802 | name = "num_enum" 803 | version = "0.5.7" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" 806 | dependencies = [ 807 | "num_enum_derive", 808 | ] 809 | 810 | [[package]] 811 | name = "num_enum_derive" 812 | version = "0.5.7" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" 815 | dependencies = [ 816 | "proc-macro-crate 1.1.3", 817 | "proc-macro2", 818 | "quote", 819 | "syn", 820 | ] 821 | 822 | [[package]] 823 | name = "nut_marketplace" 824 | version = "0.1.0" 825 | dependencies = [ 826 | "anchor-lang", 827 | "anchor-spl", 828 | "metaplex-token-metadata", 829 | "solana-program", 830 | "spl-associated-token-account", 831 | "spl-token", 832 | ] 833 | 834 | [[package]] 835 | name = "once_cell" 836 | version = "1.12.0" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" 839 | 840 | [[package]] 841 | name = "opaque-debug" 842 | version = "0.3.0" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 845 | 846 | [[package]] 847 | name = "parking_lot" 848 | version = "0.11.2" 849 | source = "registry+https://github.com/rust-lang/crates.io-index" 850 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 851 | dependencies = [ 852 | "instant", 853 | "lock_api", 854 | "parking_lot_core", 855 | ] 856 | 857 | [[package]] 858 | name = "parking_lot_core" 859 | version = "0.8.5" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 862 | dependencies = [ 863 | "cfg-if", 864 | "instant", 865 | "libc", 866 | "redox_syscall", 867 | "smallvec", 868 | "winapi", 869 | ] 870 | 871 | [[package]] 872 | name = "ppv-lite86" 873 | version = "0.2.16" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 876 | 877 | [[package]] 878 | name = "proc-macro-crate" 879 | version = "0.1.5" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" 882 | dependencies = [ 883 | "toml", 884 | ] 885 | 886 | [[package]] 887 | name = "proc-macro-crate" 888 | version = "1.1.3" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" 891 | dependencies = [ 892 | "thiserror", 893 | "toml", 894 | ] 895 | 896 | [[package]] 897 | name = "proc-macro2" 898 | version = "1.0.39" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" 901 | dependencies = [ 902 | "unicode-ident", 903 | ] 904 | 905 | [[package]] 906 | name = "proc-macro2-diagnostics" 907 | version = "0.9.1" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" 910 | dependencies = [ 911 | "proc-macro2", 912 | "quote", 913 | "syn", 914 | "version_check", 915 | "yansi", 916 | ] 917 | 918 | [[package]] 919 | name = "quote" 920 | version = "1.0.18" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" 923 | dependencies = [ 924 | "proc-macro2", 925 | ] 926 | 927 | [[package]] 928 | name = "rand" 929 | version = "0.7.3" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 932 | dependencies = [ 933 | "getrandom 0.1.16", 934 | "libc", 935 | "rand_chacha", 936 | "rand_core", 937 | "rand_hc", 938 | ] 939 | 940 | [[package]] 941 | name = "rand_chacha" 942 | version = "0.2.2" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 945 | dependencies = [ 946 | "ppv-lite86", 947 | "rand_core", 948 | ] 949 | 950 | [[package]] 951 | name = "rand_core" 952 | version = "0.5.1" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 955 | dependencies = [ 956 | "getrandom 0.1.16", 957 | ] 958 | 959 | [[package]] 960 | name = "rand_hc" 961 | version = "0.2.0" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 964 | dependencies = [ 965 | "rand_core", 966 | ] 967 | 968 | [[package]] 969 | name = "redox_syscall" 970 | version = "0.2.13" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 973 | dependencies = [ 974 | "bitflags", 975 | ] 976 | 977 | [[package]] 978 | name = "regex" 979 | version = "1.5.6" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" 982 | dependencies = [ 983 | "aho-corasick", 984 | "memchr", 985 | "regex-syntax", 986 | ] 987 | 988 | [[package]] 989 | name = "regex-syntax" 990 | version = "0.6.26" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" 993 | 994 | [[package]] 995 | name = "rustc_version" 996 | version = "0.4.0" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 999 | dependencies = [ 1000 | "semver", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "rustversion" 1005 | version = "1.0.6" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" 1008 | 1009 | [[package]] 1010 | name = "ryu" 1011 | version = "1.0.10" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" 1014 | 1015 | [[package]] 1016 | name = "scopeguard" 1017 | version = "1.1.0" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1020 | 1021 | [[package]] 1022 | name = "semver" 1023 | version = "1.0.10" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" 1026 | 1027 | [[package]] 1028 | name = "serde" 1029 | version = "1.0.137" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" 1032 | dependencies = [ 1033 | "serde_derive", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "serde_bytes" 1038 | version = "0.11.6" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" 1041 | dependencies = [ 1042 | "serde", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "serde_derive" 1047 | version = "1.0.137" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" 1050 | dependencies = [ 1051 | "proc-macro2", 1052 | "quote", 1053 | "syn", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "serde_json" 1058 | version = "1.0.81" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" 1061 | dependencies = [ 1062 | "itoa", 1063 | "ryu", 1064 | "serde", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "sha2" 1069 | version = "0.9.9" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1072 | dependencies = [ 1073 | "block-buffer 0.9.0", 1074 | "cfg-if", 1075 | "cpufeatures", 1076 | "digest 0.9.0", 1077 | "opaque-debug", 1078 | ] 1079 | 1080 | [[package]] 1081 | name = "sha3" 1082 | version = "0.9.1" 1083 | source = "registry+https://github.com/rust-lang/crates.io-index" 1084 | checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" 1085 | dependencies = [ 1086 | "block-buffer 0.9.0", 1087 | "digest 0.9.0", 1088 | "keccak", 1089 | "opaque-debug", 1090 | ] 1091 | 1092 | [[package]] 1093 | name = "smallvec" 1094 | version = "1.8.0" 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" 1096 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 1097 | 1098 | [[package]] 1099 | name = "solana-frozen-abi" 1100 | version = "1.9.29" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "2d4fcb89eb3d0f30bd4b4a31ad1825c9d95cd638509acead00969d7601713288" 1103 | dependencies = [ 1104 | "bs58 0.4.0", 1105 | "bv", 1106 | "generic-array", 1107 | "log", 1108 | "memmap2", 1109 | "rustc_version", 1110 | "serde", 1111 | "serde_derive", 1112 | "sha2", 1113 | "solana-frozen-abi-macro", 1114 | "solana-logger", 1115 | "thiserror", 1116 | ] 1117 | 1118 | [[package]] 1119 | name = "solana-frozen-abi-macro" 1120 | version = "1.9.29" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "d63ab101db88ecccd8da34065b9097b88367e0744fdfd05cb7de87b4ede3717f" 1123 | dependencies = [ 1124 | "proc-macro2", 1125 | "quote", 1126 | "rustc_version", 1127 | "syn", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "solana-logger" 1132 | version = "1.9.29" 1133 | source = "registry+https://github.com/rust-lang/crates.io-index" 1134 | checksum = "9ce1805d52fc8277a84c4803c7850c8f41471b57fb0dec7750338955ad6e43e2" 1135 | dependencies = [ 1136 | "env_logger", 1137 | "lazy_static", 1138 | "log", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "solana-program" 1143 | version = "1.9.29" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "f5deafc4902425d40197f74166640300dd20b078e4ffd518c1bb56ceb7e01680" 1146 | dependencies = [ 1147 | "base64 0.13.0", 1148 | "bincode", 1149 | "bitflags", 1150 | "blake3", 1151 | "borsh", 1152 | "borsh-derive", 1153 | "bs58 0.4.0", 1154 | "bv", 1155 | "bytemuck", 1156 | "console_error_panic_hook", 1157 | "console_log", 1158 | "curve25519-dalek", 1159 | "getrandom 0.1.16", 1160 | "itertools", 1161 | "js-sys", 1162 | "lazy_static", 1163 | "libsecp256k1", 1164 | "log", 1165 | "num-derive", 1166 | "num-traits", 1167 | "parking_lot", 1168 | "rand", 1169 | "rustc_version", 1170 | "rustversion", 1171 | "serde", 1172 | "serde_bytes", 1173 | "serde_derive", 1174 | "sha2", 1175 | "sha3", 1176 | "solana-frozen-abi", 1177 | "solana-frozen-abi-macro", 1178 | "solana-logger", 1179 | "solana-sdk-macro", 1180 | "thiserror", 1181 | "wasm-bindgen", 1182 | ] 1183 | 1184 | [[package]] 1185 | name = "solana-sdk-macro" 1186 | version = "1.9.29" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "3db4c93bd43c91290ad54fe6ff86179a859954f196507c4789a4876d38a62f17" 1189 | dependencies = [ 1190 | "bs58 0.4.0", 1191 | "proc-macro2", 1192 | "quote", 1193 | "rustversion", 1194 | "syn", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "spl-associated-token-account" 1199 | version = "1.0.5" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "2b013067447a1396303ddfc294f36e3d260a32f8a16c501c295bcdc7de39b490" 1202 | dependencies = [ 1203 | "borsh", 1204 | "solana-program", 1205 | "spl-token", 1206 | ] 1207 | 1208 | [[package]] 1209 | name = "spl-token" 1210 | version = "3.3.0" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "0cc67166ef99d10c18cb5e9c208901e6d8255c6513bb1f877977eba48e6cc4fb" 1213 | dependencies = [ 1214 | "arrayref", 1215 | "num-derive", 1216 | "num-traits", 1217 | "num_enum", 1218 | "solana-program", 1219 | "thiserror", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "subtle" 1224 | version = "2.4.1" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1227 | 1228 | [[package]] 1229 | name = "syn" 1230 | version = "1.0.96" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" 1233 | dependencies = [ 1234 | "proc-macro2", 1235 | "quote", 1236 | "unicode-ident", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "termcolor" 1241 | version = "1.1.3" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 1244 | dependencies = [ 1245 | "winapi-util", 1246 | ] 1247 | 1248 | [[package]] 1249 | name = "thiserror" 1250 | version = "1.0.31" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" 1253 | dependencies = [ 1254 | "thiserror-impl", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "thiserror-impl" 1259 | version = "1.0.31" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" 1262 | dependencies = [ 1263 | "proc-macro2", 1264 | "quote", 1265 | "syn", 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "toml" 1270 | version = "0.5.9" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" 1273 | dependencies = [ 1274 | "serde", 1275 | ] 1276 | 1277 | [[package]] 1278 | name = "typenum" 1279 | version = "1.15.0" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 1282 | 1283 | [[package]] 1284 | name = "unicode-ident" 1285 | version = "1.0.0" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" 1288 | 1289 | [[package]] 1290 | name = "unicode-segmentation" 1291 | version = "1.9.0" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" 1294 | 1295 | [[package]] 1296 | name = "version_check" 1297 | version = "0.9.4" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1300 | 1301 | [[package]] 1302 | name = "wasi" 1303 | version = "0.9.0+wasi-snapshot-preview1" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1306 | 1307 | [[package]] 1308 | name = "wasi" 1309 | version = "0.10.2+wasi-snapshot-preview1" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1312 | 1313 | [[package]] 1314 | name = "wasm-bindgen" 1315 | version = "0.2.80" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" 1318 | dependencies = [ 1319 | "cfg-if", 1320 | "wasm-bindgen-macro", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "wasm-bindgen-backend" 1325 | version = "0.2.80" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" 1328 | dependencies = [ 1329 | "bumpalo", 1330 | "lazy_static", 1331 | "log", 1332 | "proc-macro2", 1333 | "quote", 1334 | "syn", 1335 | "wasm-bindgen-shared", 1336 | ] 1337 | 1338 | [[package]] 1339 | name = "wasm-bindgen-macro" 1340 | version = "0.2.80" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" 1343 | dependencies = [ 1344 | "quote", 1345 | "wasm-bindgen-macro-support", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "wasm-bindgen-macro-support" 1350 | version = "0.2.80" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" 1353 | dependencies = [ 1354 | "proc-macro2", 1355 | "quote", 1356 | "syn", 1357 | "wasm-bindgen-backend", 1358 | "wasm-bindgen-shared", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "wasm-bindgen-shared" 1363 | version = "0.2.80" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" 1366 | 1367 | [[package]] 1368 | name = "web-sys" 1369 | version = "0.3.57" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" 1372 | dependencies = [ 1373 | "js-sys", 1374 | "wasm-bindgen", 1375 | ] 1376 | 1377 | [[package]] 1378 | name = "winapi" 1379 | version = "0.3.9" 1380 | source = "registry+https://github.com/rust-lang/crates.io-index" 1381 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1382 | dependencies = [ 1383 | "winapi-i686-pc-windows-gnu", 1384 | "winapi-x86_64-pc-windows-gnu", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "winapi-i686-pc-windows-gnu" 1389 | version = "0.4.0" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1392 | 1393 | [[package]] 1394 | name = "winapi-util" 1395 | version = "0.1.5" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1398 | dependencies = [ 1399 | "winapi", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "winapi-x86_64-pc-windows-gnu" 1404 | version = "0.4.0" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1407 | 1408 | [[package]] 1409 | name = "yansi" 1410 | version = "0.5.1" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" 1413 | 1414 | [[package]] 1415 | name = "zeroize" 1416 | version = "1.3.0" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" 1419 | --------------------------------------------------------------------------------