├── .gitignore
├── .prettierignore
├── .vscode
└── settings.json
├── Anchor.toml
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── migrations
└── deploy.ts
├── package.json
├── programs
├── soundwork-bid
│ ├── Cargo.toml
│ ├── Xargo.toml
│ └── src
│ │ ├── constants.rs
│ │ ├── error.rs
│ │ ├── instructions
│ │ ├── accept_bid.rs
│ │ ├── edit_bid.rs
│ │ ├── make_bid.rs
│ │ ├── mod.rs
│ │ ├── reject_bid.rs
│ │ └── revoke_bid.rs
│ │ ├── lib.rs
│ │ └── state
│ │ ├── bid.rs
│ │ └── mod.rs
├── soundwork-create
│ ├── Cargo.toml
│ ├── Xargo.toml
│ └── src
│ │ ├── constants.rs
│ │ ├── error.rs
│ │ ├── instructions
│ │ ├── create.rs
│ │ └── mod.rs
│ │ ├── lib.rs
│ │ └── state
│ │ └── mod.rs
└── soundwork-list
│ ├── Cargo.toml
│ ├── Xargo.toml
│ └── src
│ ├── constants.rs
│ ├── error.rs
│ ├── helpers.rs
│ ├── instructions
│ ├── admin
│ │ ├── init_escrow.rs
│ │ ├── init_mp_config.rs
│ │ └── mod.rs
│ ├── buy_listing.rs
│ ├── escrow_ix
│ │ ├── deposit_sol.rs
│ │ ├── deposit_token.rs
│ │ ├── init_wallet.rs
│ │ ├── mod.rs
│ │ ├── withdraw_sol.rs
│ │ └── withdraw_token.rs
│ ├── list.rs
│ ├── mod.rs
│ ├── unlist.rs
│ └── update_listing.rs
│ ├── lib.rs
│ └── state
│ ├── escrow.rs
│ ├── listing.rs
│ ├── mod.rs
│ ├── protocol.rs
│ └── wallet.rs
├── tests
├── unit
│ ├── soundwork-bid.ts
│ ├── soundwork-create.ts
│ └── soundwork-list.ts
└── utils
│ ├── constants.ts
│ ├── helpers.ts
│ ├── pda.ts
│ └── programs.ts
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .anchor
3 | .DS_Store
4 | target
5 | **/*.rs.bk
6 | node_modules
7 | test-ledger
8 | .yarn
9 | .env
10 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 |
2 | .anchor
3 | .DS_Store
4 | target
5 | node_modules
6 | dist
7 | build
8 | test-ledger
9 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "Futari",
4 | "Hitori",
5 | "Ijichi",
6 | "Kessoku",
7 | "lamports",
8 | "Seika",
9 | "unlist"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/Anchor.toml:
--------------------------------------------------------------------------------
1 | [toolchain]
2 | anchor_version = "0.30.1"
3 | # solana_version = "1.18.11" system version. do not uncomment
4 | # solana_version = "1.17.28"
5 |
6 | [features]
7 | seeds = false
8 | skip-lint = false
9 |
10 | [programs.localnet]
11 | soundwork-bid = "4mFDYND4AVREYEJXCPhjq1LnbjELHHebJqG3NZechA7X"
12 | soundwork-create = "FegMMZtuFu8ZUTjdkt2yRR1TmGEAFZbjpDJWpQ4ueqyG"
13 | soundwork-list = "EA4ptgF3TYjDBGYJApAoZoyCbCYw6P5mGU5noCe1Z97"
14 |
15 | [registry]
16 | url = "https://api.apr.dev"
17 |
18 | [provider]
19 | cluster = "devnet"
20 | wallet = "~/.config/solana/id.json"
21 |
22 | [scripts]
23 | all = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
24 | create = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/soundwork-create.ts"
25 | list = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/soundwork-list.ts"
26 | bid = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/soundwork-bid.ts"
27 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 |
2 | [workspace]
3 | members = [
4 | "programs/*"
5 | ]
6 |
7 | [profile.release]
8 | overflow-checks = true
9 | lto = "fat"
10 | codegen-units = 1
11 | [profile.release.build-override]
12 | opt-level = 3
13 | incremental = false
14 | codegen-units = 1
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Soundwork
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
Soundwork Marketplace Contracts
4 |
5 | The Soundwork NFT Marketplace contracts.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | This repo contains the latest programs for [soundwork.io](https://soundwork.io/) protocol. Using the new [Metaplex core asset](https://developers.metaplex.com/core) users are able to perform all traditional operations of an NFT marketplace like list and bid operations trustlessly executed by our programs.
18 |
19 | ## Programs
20 |
21 | This project contains the following programs:
22 |
23 | **soundwork-list**
24 |
25 |
26 |
27 | - Devnet: `EA4ptgF3TYjDBGYJApAoZoyCbCYw6P5mGU5noCe1Z97`
28 |
29 | **soundwork-bid**
30 |
31 |
32 |
33 | - Devnet: `4mFDYND4AVREYEJXCPhjq1LnbjELHHebJqG3NZechA7X`
34 |
35 | ## Audits
36 |
37 | These programs are not audited, so fork, deploy and use them at your own risk.
38 |
39 | ## Developers
40 |
41 | You can interact with the list and bid programs via our SDK.
42 |
43 | Typescript SDK: [`@soundwork-oss/soundwork-sdk`](https://www.npmjs.com/package/@soundwork-oss/soundwork-sdk)
44 |
45 |
46 |
47 | ## Developing
48 |
49 | ### Environmental Setup
50 |
51 | 1. Install [Rust](https://rustup.rs/).
52 | 2. Install [Solana](https://docs.solana.com/cli/install-solana-cli-tools#use-solanas-install-tool).
53 | 3. Install [Anchor](https://www.anchor-lang.com/docs/installation).
54 |
55 | ### Install Dependencies
56 |
57 | ```
58 | yarn
59 | ```
60 |
61 | ### Build the Program
62 |
63 | ```
64 | anchor build
65 | ```
66 |
67 | ### Testing
68 |
69 | ```
70 | cargo clippy --all-targets -- -D warnings
71 | anchor test
72 | ```
73 |
74 | ### Patches
75 |
76 | Should you encounter `failed to select a version for the requirement toml_edit = "^0.21.0"`
77 |
78 | ```bash
79 | cargo update -p toml_edit@0.21.1 --precise 0.21.0
80 | ```
81 |
--------------------------------------------------------------------------------
/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("@coral-xyz/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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
4 | "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
5 | },
6 | "dependencies": {
7 | "@coral-xyz/anchor": "^0.30.1",
8 | "@solana/spl-token": "^0.4.6",
9 | "@solana/web3.js": "^1.91.4",
10 | "dotenv": "^16.4.5"
11 | },
12 | "devDependencies": {
13 | "@types/bn.js": "^5.1.0",
14 | "@types/chai": "^4.3.0",
15 | "@types/mocha": "^9.0.0",
16 | "chai": "^4.3.4",
17 | "mocha": "^9.0.3",
18 | "prettier": "^2.6.2",
19 | "ts-mocha": "^10.0.0",
20 | "typescript": "^4.3.5"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "soundwork-bid"
3 | version = "0.1.0"
4 | description = "Created with Anchor"
5 | edition = "2021"
6 |
7 | [lib]
8 | crate-type = ["cdylib", "lib"]
9 | name = "soundwork_bid"
10 |
11 | [features]
12 | no-entrypoint = []
13 | no-idl = []
14 | no-log-ix-name = []
15 | cpi = ["no-entrypoint"]
16 | default = []
17 | idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
18 |
19 | [dependencies]
20 | anchor-lang = "0.30.1"
21 | anchor-spl = "0.30.1"
22 | mpl-core = "0.7.2"
23 | solana-security-txt = "1.1.1"
24 | soundwork-create = { path = "../soundwork-create", features = ["cpi"] }
25 | soundwork-list = { path = "../soundwork-list", features = ["cpi"] }
26 | ahash="=0.8.7"
27 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/Xargo.toml:
--------------------------------------------------------------------------------
1 | [target.bpfel-unknown-unknown.dependencies.std]
2 | features = []
3 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/constants.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[constant]
4 | pub const SEED_PREFIX: &[u8] = b"Kessoku";
5 |
6 | #[constant]
7 | pub const SEED_BID_DATA: &[u8] = b"Futari";
8 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/error.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[error_code]
4 | pub enum BidErrorCode {
5 | #[msg("Signer address does not math the initializer address")]
6 | UnrecognizedSigner,
7 | #[msg("Bid TimeStamp Expired")]
8 | BidExpired,
9 | #[msg("Insufficient Funds to make bid for item")]
10 | InsufficientFunds,
11 | #[msg("An account required for this operation is missing.")]
12 | MissingAccount,
13 | #[msg("The mint address provided does not match seller's provided mint address.")]
14 | PaymentMintAddressMismatch,
15 | #[msg("Operations resulted in an overflow.")]
16 | Overflow,
17 | }
18 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/instructions/accept_bid.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use anchor_spl::{
3 | associated_token::AssociatedToken,
4 | token::{Mint, Token, TokenAccount},
5 | };
6 |
7 | use soundwork_create::Core;
8 | use soundwork_list::{
9 | cpi::{accounts::BuyAsset, buy_asset},
10 | program::SoundworkList,
11 | state::ListingData,
12 | AssetManager, BuyAssetParams, MarketPlaceConfig, PaymentOption,
13 | };
14 |
15 | use crate::{error::BidErrorCode, BidData};
16 |
17 | /// Accept a placed Bid
18 |
19 | /// ### Accounts:
20 | ///
21 | /// 1. `[writeable, signer]` seller
22 | /// 2. `[writeable]` bidder
23 | /// 3. `[writeable]` asset
24 | /// 4. `[writeable]` collection
25 | /// 5. `[writeable]` bid data account
26 | /// 6. `[writeable]` bidder escrow wallet
27 | /// 7. `[writeable]` listing data account
28 | /// 8. `[writeable, optional]` bidder token account
29 | /// 9. `[writeable, optional]` seller token account
30 | /// 10. `[writeable, optional]` wallet token account
31 | /// 11. `[writeable, optional]` treasury token account
32 | /// 12. `[writeable]` treasury
33 | /// 13. `[writeable]` asset manager
34 | /// 14. `[writeable]` marketplace config account
35 | /// 15. `[writeable]` payment mint
36 | /// 16. `[]` soundwork list program
37 | /// 17. `[]` core program
38 | /// 18. `[]` token program
39 | /// 19. `[]` associated token program
40 | /// 20. `[]` system program
41 | ///
42 | #[derive(Accounts)]
43 | pub struct AcceptBid<'info> {
44 | #[account(
45 | mut,
46 | address = listing_data.authority @ BidErrorCode::UnrecognizedSigner
47 | )]
48 | pub seller: Signer<'info>,
49 |
50 | #[account(
51 | mut,
52 | address = bid_data.authority @ BidErrorCode::UnrecognizedSigner
53 | )]
54 | pub bidder: SystemAccount<'info>,
55 |
56 | /// CHECK: checked by us
57 | #[account(mut)]
58 | pub asset: AccountInfo<'info>,
59 |
60 | /// CHECK: checked by us
61 | #[account(mut)]
62 | pub collection: Option>,
63 |
64 | #[account(
65 | mut,
66 | close = bidder,
67 | )]
68 | pub bid_data: Account<'info, BidData>,
69 |
70 | /// CHECK: initialized by list program through the CPI
71 | #[account(
72 | mut,
73 | owner = soundwork_list.key()
74 | )]
75 | pub bidder_escrow_wallet: UncheckedAccount<'info>,
76 |
77 | #[account(mut)]
78 | pub listing_data: Account<'info, ListingData>,
79 |
80 | #[account(mut)]
81 | pub payment_mint: Option>>,
82 |
83 | #[account(mut)]
84 | pub bidder_token_account: Option>>,
85 |
86 | // unchecked because this might be uninitialized
87 | #[account(mut)]
88 | pub seller_token_account: Option>,
89 |
90 | // unchecked because this might be uninitialized
91 | #[account(mut)]
92 | pub wallet_token_account: Option>>,
93 |
94 | // unchecked because this might be uninitialized
95 | #[account(mut)]
96 | pub treasury_token_account: Option>,
97 |
98 | #[account(
99 | mut,
100 | address = marketplace_config.treasury_address
101 | )]
102 | pub treasury: SystemAccount<'info>,
103 |
104 | pub asset_manager: Box>,
105 |
106 | pub marketplace_config: Box>,
107 |
108 | pub soundwork_list: Program<'info, SoundworkList>,
109 |
110 | pub core_program: Program<'info, Core>,
111 |
112 | pub token_program: Program<'info, Token>,
113 |
114 | pub associated_token_program: Program<'info, AssociatedToken>,
115 |
116 | pub system_program: Program<'info, System>,
117 | }
118 |
119 | impl AcceptBid<'_> {
120 | /// validation helper for our IX
121 | pub fn validate(&self) -> Result<()> {
122 | match self.listing_data.payment_option {
123 | PaymentOption::Native => {} // default anchor account checks
124 |
125 | PaymentOption::Token { mint: _ } => {
126 | let payment_mint = self.payment_mint.as_ref();
127 | let bidder_token_account = self.bidder_token_account.as_ref();
128 | let wallet_token_account = self.wallet_token_account.as_ref();
129 | let treasury_token_account = self.treasury_token_account.as_ref();
130 | let seller_token_account = self.seller_token_account.as_ref();
131 |
132 | if bidder_token_account.is_none()
133 | || payment_mint.is_none()
134 | || wallet_token_account.is_none()
135 | || seller_token_account.is_none()
136 | || treasury_token_account.is_none()
137 | {
138 | return Err(error!(BidErrorCode::MissingAccount));
139 | }
140 | } //
141 | }
142 |
143 | return Ok(());
144 | }
145 |
146 | /// Accept placed bid for an MPL core asset on the marketplace
147 | ///
148 | #[access_control(ctx.accounts.validate())]
149 | pub fn accept_bid(ctx: Context) -> Result<()> {
150 | let bid_data = &mut ctx.accounts.bid_data;
151 | let list_data = &mut ctx.accounts.listing_data;
152 | let cpi_program = ctx.accounts.soundwork_list.to_account_info();
153 |
154 | // transfer sol or tokens back to bidders wallet
155 |
156 | match list_data.payment_option {
157 | PaymentOption::Native => {
158 | let buy_asset_cpi_accounts = BuyAsset {
159 | payer: ctx.accounts.seller.to_account_info(),
160 | buyer: ctx.accounts.bidder.to_account_info(),
161 | seller: ctx.accounts.seller.to_account_info(),
162 | wallet_as_buyer: ctx.accounts.bidder_escrow_wallet.to_account_info().into(),
163 | asset: ctx.accounts.asset.to_account_info(),
164 | collection: ctx.accounts.collection.clone(),
165 | payment_mint: None, // safe to unwrap
166 | wallet_token_account: None, // safe to unwrap
167 | buyer_token_account: None,
168 | seller_token_account: None,
169 | treasury_token_account: None,
170 | treasury: ctx.accounts.treasury.to_account_info(),
171 | listing_data: ctx.accounts.listing_data.to_account_info(),
172 | asset_manager: ctx.accounts.asset_manager.to_account_info(),
173 | marketplace_config: ctx.accounts.marketplace_config.to_account_info(),
174 | core_program: ctx.accounts.core_program.to_account_info(),
175 | token_program: ctx.accounts.token_program.to_account_info(),
176 | associated_token_program: ctx
177 | .accounts
178 | .associated_token_program
179 | .to_account_info(),
180 | system_program: ctx.accounts.system_program.to_account_info(),
181 | };
182 |
183 | let buy_asset_ctx = CpiContext::new(cpi_program, buy_asset_cpi_accounts);
184 |
185 | buy_asset(buy_asset_ctx, None)?;
186 | }
187 |
188 | PaymentOption::Token { mint: _ } => {
189 | let buy_listing_cpi_accounts = BuyAsset {
190 | payer: ctx.accounts.seller.to_account_info(),
191 | buyer: ctx.accounts.bidder.to_account_info(),
192 | seller: ctx.accounts.seller.to_account_info(),
193 | wallet_as_buyer: ctx.accounts.bidder_escrow_wallet.to_account_info().into(),
194 | asset: ctx.accounts.asset.to_account_info(),
195 | collection: ctx.accounts.collection.clone(),
196 | payment_mint: Some(
197 | ctx.accounts.payment_mint.clone().unwrap().to_account_info(),
198 | ), // safe to unwrap
199 | wallet_token_account: Some(
200 | ctx.accounts
201 | .wallet_token_account
202 | .clone()
203 | .unwrap()
204 | .to_account_info(),
205 | ), // safe to unwrap
206 | buyer_token_account: Some(
207 | ctx.accounts
208 | .bidder_token_account
209 | .clone()
210 | .unwrap()
211 | .to_account_info(),
212 | ),
213 | seller_token_account: Some(
214 | ctx.accounts
215 | .seller_token_account
216 | .clone()
217 | .unwrap()
218 | .to_account_info(),
219 | ),
220 | treasury_token_account: Some(
221 | ctx.accounts
222 | .treasury_token_account
223 | .clone()
224 | .unwrap()
225 | .to_account_info(),
226 | ),
227 | treasury: ctx.accounts.treasury.to_account_info(),
228 | listing_data: ctx.accounts.listing_data.to_account_info(),
229 | asset_manager: ctx.accounts.asset_manager.to_account_info(),
230 | marketplace_config: ctx.accounts.marketplace_config.to_account_info(),
231 | core_program: ctx.accounts.core_program.to_account_info(),
232 | token_program: ctx.accounts.token_program.to_account_info(),
233 | associated_token_program: ctx
234 | .accounts
235 | .associated_token_program
236 | .to_account_info(),
237 | system_program: ctx.accounts.system_program.to_account_info(),
238 | };
239 |
240 | let buy_asset_ctx = CpiContext::new(cpi_program, buy_listing_cpi_accounts);
241 |
242 | buy_asset(
243 | buy_asset_ctx,
244 | BuyAssetParams {
245 | bid_amount: bid_data.amount,
246 | }
247 | .into(),
248 | )?;
249 | }
250 | }
251 |
252 | Ok(())
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/instructions/edit_bid.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use anchor_spl::{
3 | associated_token::AssociatedToken,
4 | token::{Mint, Token, TokenAccount},
5 | };
6 | use soundwork_list::{
7 | cpi::{
8 | accounts::{DepositSol, DepositToken},
9 | deposit_sol, deposit_token,
10 | },
11 | program::SoundworkList,
12 | state::{ListingData, Wallet},
13 | DepositSolParams, DepositTokenParams, PaymentOption,
14 | };
15 |
16 | use crate::{error::BidErrorCode, BidData};
17 |
18 | #[derive(AnchorSerialize, AnchorDeserialize)]
19 | pub struct EditBidParams {
20 | /// bid amount/price in lamports
21 | pub amount: Option,
22 |
23 | /// expiry timestamp
24 | pub expiry_ts: Option,
25 | }
26 |
27 | /// Edit Bid
28 | ///
29 | /// ### Accounts:
30 | ///
31 | /// 1. `[writeable, signer]` bidder
32 | /// 2. `[writeable]` asset
33 | /// 3. `[writeable]` bid data account
34 | /// 4. `[writeable]` bidder escrow wallet
35 | /// 5. `[writeable]` listing data account
36 | /// 6. `[writeable]` payment mint
37 | /// 7. `[writeable, optional]` bidder token account
38 | /// 8. `[writeable, options]` wallet token account
39 | /// 9. `[]` soundwork list program
40 | /// 10. `[]` token program
41 | /// 11. `[]` associated token program
42 | /// 12. `[]` system program
43 | ///
44 | /// ### Parameter
45 | /// 1. params: [EditBidParams]
46 | ///
47 | #[derive(Accounts)]
48 | #[instruction(params: EditBidParams)]
49 | pub struct EditBid<'info> {
50 | #[account(mut)]
51 | pub bidder: Signer<'info>,
52 |
53 | /// CHECK: checked by us
54 | #[account(mut)]
55 | pub asset: AccountInfo<'info>,
56 |
57 | /// CHECK: checked by us
58 | #[account(mut)]
59 | pub bid_data: Account<'info, BidData>,
60 |
61 | #[account(mut)]
62 | pub bidder_escrow_wallet: Box>,
63 |
64 | #[account(mut)]
65 | pub listing_data: Account<'info, ListingData>,
66 |
67 | #[account(mut)]
68 | pub payment_mint: Option>>,
69 |
70 | #[account(mut)]
71 | pub bidder_token_account: Option>>,
72 |
73 | #[account(mut)]
74 | pub wallet_token_account: Option>>,
75 |
76 | pub soundwork_list: Program<'info, SoundworkList>,
77 |
78 | pub token_program: Program<'info, Token>,
79 |
80 | pub associated_token_program: Program<'info, AssociatedToken>,
81 |
82 | pub system_program: Program<'info, System>,
83 | }
84 |
85 | impl EditBid<'_> {
86 | /// validation helper for our IX
87 | pub fn validate(&self, params: &EditBidParams) -> Result<()> {
88 | // check if bidder has enough amount
89 |
90 | if let Some(amt) = params.amount {
91 | let diff = amt.checked_sub(self.bid_data.amount);
92 | if diff.is_none() {
93 | return Err(error!(BidErrorCode::Overflow));
94 | }
95 |
96 | match self.listing_data.payment_option {
97 | PaymentOption::Native => {
98 | if self.bidder.get_lamports() < diff.unwrap() {
99 | msg!("insufficient lamports");
100 | return Err(error!(BidErrorCode::InsufficientFunds));
101 | }
102 | }
103 |
104 | PaymentOption::Token { mint } => {
105 | let payment_mint = self.payment_mint.as_ref();
106 | let bidder_token_account = self.bidder_token_account.as_ref();
107 |
108 | if bidder_token_account.is_none() || payment_mint.is_none() {
109 | return Err(error!(BidErrorCode::MissingAccount));
110 | }
111 |
112 | if mint != payment_mint.unwrap().key() {
113 | return Err(error!(BidErrorCode::PaymentMintAddressMismatch));
114 | }
115 |
116 | if bidder_token_account.unwrap().amount < diff.unwrap() {
117 | msg!("insufficient tokens");
118 | return Err(error!(BidErrorCode::InsufficientFunds));
119 | }
120 | } //
121 | }
122 | }
123 |
124 | // todo: sanity checks for expiry timestamp
125 |
126 | return Ok(());
127 | }
128 |
129 | /// Edit MPL core asset on the marketplace
130 | ///
131 | #[access_control(ctx.accounts.validate(¶ms))]
132 | pub fn edit_bid(ctx: Context, params: EditBidParams) -> Result<()> {
133 | let bid_data = &mut ctx.accounts.bid_data;
134 | let list_data = &mut ctx.accounts.listing_data;
135 | let cpi_program = ctx.accounts.soundwork_list.to_account_info();
136 |
137 | let EditBidParams { amount, expiry_ts } = params;
138 |
139 | // update expiry
140 | if let Some(expire_ts) = expiry_ts {
141 | bid_data.expiry_ts = expire_ts;
142 | }
143 |
144 | // check if bidder increased his bid amt and if true, transfer the
145 | // difference with new price to escrow wallet to be able to cover buying
146 | // nft if seller accepts offer
147 | if let Some(amt) = amount {
148 | if amt > bid_data.amount {
149 | let diff = amt.checked_sub(bid_data.amount);
150 | if diff.is_none() {
151 | return Err(error!(BidErrorCode::Overflow));
152 | }
153 |
154 | match list_data.payment_option {
155 | PaymentOption::Native => {
156 | let deposit_sol_cpi_accounts = DepositSol {
157 | authority: ctx.accounts.bidder.to_account_info(),
158 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
159 | system_program: ctx.accounts.system_program.to_account_info(),
160 | };
161 |
162 | let deposit_sol_ctx =
163 | CpiContext::new(cpi_program, deposit_sol_cpi_accounts);
164 |
165 | deposit_sol(
166 | deposit_sol_ctx,
167 | DepositSolParams {
168 | amount: diff.unwrap(),
169 | },
170 | )?;
171 | }
172 |
173 | PaymentOption::Token { mint: _ } => {
174 | let diff = amt.checked_sub(bid_data.amount);
175 | if diff.is_none() {
176 | return Err(error!(BidErrorCode::Overflow));
177 | }
178 |
179 | let deposit_token_cpi_accounts = DepositToken {
180 | authority: ctx.accounts.bidder.to_account_info(),
181 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
182 | mint: ctx
183 | .accounts
184 | .payment_mint
185 | .as_ref()
186 | .unwrap()
187 | .to_account_info(), // safe to unwrap. checked in validator constraint
188 | authority_token_account: ctx
189 | .accounts
190 | .bidder_token_account
191 | .as_ref()
192 | .unwrap()
193 | .to_account_info(), // safe to unwrap here too
194 | wallet_token_account: ctx
195 | .accounts
196 | .wallet_token_account
197 | .as_ref()
198 | .unwrap()
199 | .to_account_info(),
200 | token_program: ctx.accounts.token_program.to_account_info(),
201 | associated_token_program: ctx
202 | .accounts
203 | .associated_token_program
204 | .to_account_info(),
205 | system_program: ctx.accounts.system_program.to_account_info(),
206 | };
207 |
208 | let deposit_token_ctx =
209 | CpiContext::new(cpi_program, deposit_token_cpi_accounts);
210 |
211 | deposit_token(
212 | deposit_token_ctx,
213 | DepositTokenParams {
214 | amount: diff.unwrap(),
215 | },
216 | )?;
217 | }
218 | }
219 |
220 | bid_data.amount += diff.unwrap(); // ! test me
221 | }
222 |
223 | // do nothing. escrow wallet has enough funds to purchase asset if accepted
224 | msg!("escrow wallet balance remains unchanged");
225 | }
226 |
227 | Ok(())
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/instructions/make_bid.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use anchor_spl::{
3 | associated_token::AssociatedToken,
4 | token::{Mint, Token, TokenAccount},
5 | };
6 | use soundwork_list::{
7 | cpi::{
8 | accounts::{DepositSol, DepositToken},
9 | deposit_sol, deposit_token,
10 | },
11 | program::SoundworkList,
12 | state::{ListingData, Wallet},
13 | DepositSolParams, DepositTokenParams, PaymentOption,
14 | };
15 |
16 | use crate::{
17 | constants::{SEED_BID_DATA, SEED_PREFIX},
18 | // helpers::Core,
19 | // AssetManager, ListingData, PaymentOption,
20 | error::BidErrorCode,
21 | BidData,
22 | };
23 |
24 | #[derive(AnchorSerialize, AnchorDeserialize)]
25 | pub struct MakeBidParams {
26 | /// bid amount/price in lamports
27 | pub amount: u64,
28 |
29 | /// expiry timestamp
30 | pub expiry_ts: i64,
31 | }
32 |
33 | /// Make a bid for an MPL core asset listed soundwork
34 | ///
35 | /// ### Accounts:
36 | ///
37 | /// 1. `[writeable, signer]` bidder
38 | /// 2. `[writeable]` asset
39 | /// 3. `[writeable]` bid data account
40 | /// 4. `[writeable]` bidder escrow wallet
41 | /// 5. `[writeable]` listing data account
42 | /// 6. `[writeable]` payment mint
43 | /// 7. `[writeable, optional]` bidder token account
44 | /// 8. `[writeable, options]` wallet token account
45 | /// 9. `[]` soundwork list program
46 | /// 10. `[]` token program
47 | /// 11. `[]` associated token program
48 | /// 12. `[]` system program
49 | ///
50 | /// ### Parameters
51 | ///
52 | /// 1. params: [MakeBidParams]
53 | ///
54 | #[derive(Accounts)]
55 | #[instruction(params: MakeBidParams)]
56 | pub struct MakeBid<'info> {
57 | #[account(mut)]
58 | pub bidder: Signer<'info>,
59 |
60 | /// CHECK: checked by us
61 | #[account(mut)]
62 | pub asset: AccountInfo<'info>,
63 |
64 | /// CHECK: checked by us
65 | #[account(
66 | init,
67 | payer = bidder,
68 | space = BidData::LEN,
69 | seeds = [SEED_PREFIX, SEED_BID_DATA, asset.key().as_ref()],
70 | bump
71 | )]
72 | pub bid_data: Account<'info, BidData>,
73 |
74 | #[account(mut)]
75 | pub bidder_escrow_wallet: Box>,
76 |
77 | #[account(mut)]
78 | pub listing_data: Account<'info, ListingData>,
79 |
80 | #[account(mut)]
81 | pub payment_mint: Option>>,
82 |
83 | #[account(mut)]
84 | pub bidder_token_account: Option>>,
85 |
86 | #[account(
87 | init_if_needed,
88 | payer = bidder,
89 | associated_token::mint = payment_mint,
90 | associated_token::authority = bidder_escrow_wallet,
91 | )]
92 | pub wallet_token_account: Option>>,
93 |
94 | pub soundwork_list: Program<'info, SoundworkList>,
95 |
96 | pub token_program: Program<'info, Token>,
97 |
98 | pub associated_token_program: Program<'info, AssociatedToken>,
99 |
100 | pub system_program: Program<'info, System>,
101 | }
102 |
103 | impl MakeBid<'_> {
104 | /// validation helper for our IX
105 | pub fn validate(&self, params: &MakeBidParams) -> Result<()> {
106 | // check if bidder has enough amount specified by the payment options
107 |
108 | match self.listing_data.payment_option {
109 | PaymentOption::Native => {
110 | if self.bidder.get_lamports() < params.amount {
111 | msg!("insufficient lamports");
112 | return Err(error!(BidErrorCode::InsufficientFunds));
113 | }
114 | }
115 |
116 | PaymentOption::Token { mint } => {
117 | let payment_mint = self.payment_mint.as_ref();
118 | let bidder_token_account = self.bidder_token_account.as_ref();
119 |
120 | if bidder_token_account.is_none() || payment_mint.is_none() {
121 | return Err(error!(BidErrorCode::MissingAccount));
122 | }
123 |
124 | if mint != payment_mint.unwrap().key() {
125 | return Err(error!(BidErrorCode::PaymentMintAddressMismatch));
126 | }
127 |
128 | if bidder_token_account.unwrap().amount < params.amount {
129 | msg!("insufficient tokens");
130 | return Err(error!(BidErrorCode::InsufficientFunds));
131 | }
132 | } //
133 | }
134 |
135 | // todo(Jimii): check expiry
136 |
137 | return Ok(());
138 | }
139 |
140 | /// place bid for an MPL core asset on the marketplace
141 | ///
142 | #[access_control(ctx.accounts.validate(¶ms))]
143 | pub fn make_bid(ctx: Context, params: MakeBidParams) -> Result<()> {
144 | let bid_data = &mut ctx.accounts.bid_data;
145 | let list_data = &mut ctx.accounts.listing_data;
146 |
147 | **bid_data = BidData::new(
148 | ctx.bumps.bid_data,
149 | params.amount,
150 | ctx.accounts.bidder.key(),
151 | params.expiry_ts,
152 | );
153 |
154 | // transfer sol or tokens
155 |
156 | match list_data.payment_option {
157 | PaymentOption::Native => {
158 | let cpi_program = ctx.accounts.soundwork_list.to_account_info();
159 |
160 | let deposit_sol_cpi_accounts = DepositSol {
161 | authority: ctx.accounts.bidder.to_account_info(),
162 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
163 | system_program: ctx.accounts.system_program.to_account_info(),
164 | };
165 |
166 | let deposit_sol_ctx = CpiContext::new(cpi_program, deposit_sol_cpi_accounts);
167 |
168 | deposit_sol(
169 | deposit_sol_ctx,
170 | DepositSolParams {
171 | amount: params.amount,
172 | },
173 | )?;
174 | }
175 |
176 | PaymentOption::Token { mint: _ } => {
177 | let cpi_program = ctx.accounts.soundwork_list.to_account_info();
178 |
179 | let deposit_token_cpi_accounts = DepositToken {
180 | authority: ctx.accounts.bidder.to_account_info(),
181 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
182 | mint: ctx
183 | .accounts
184 | .payment_mint
185 | .as_ref()
186 | .unwrap()
187 | .to_account_info(), // safe to unwrap. checked in validator constraint
188 | authority_token_account: ctx
189 | .accounts
190 | .bidder_token_account
191 | .as_ref()
192 | .unwrap()
193 | .to_account_info(), // safe to unwrap here too
194 | wallet_token_account: ctx
195 | .accounts
196 | .wallet_token_account
197 | .as_ref()
198 | .unwrap()
199 | .to_account_info(),
200 | token_program: ctx.accounts.token_program.to_account_info(),
201 | associated_token_program: ctx
202 | .accounts
203 | .associated_token_program
204 | .to_account_info(),
205 | system_program: ctx.accounts.system_program.to_account_info(),
206 | };
207 |
208 | let deposit_token_ctx = CpiContext::new(cpi_program, deposit_token_cpi_accounts);
209 |
210 | deposit_token(
211 | deposit_token_ctx,
212 | DepositTokenParams {
213 | amount: params.amount,
214 | },
215 | )?;
216 | }
217 | }
218 |
219 | Ok(())
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/instructions/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod accept_bid;
2 | pub mod edit_bid;
3 | pub mod make_bid;
4 | pub mod reject_bid;
5 | pub mod revoke_bid;
6 |
7 | pub use accept_bid::*;
8 | pub use edit_bid::*;
9 | pub use make_bid::*;
10 | pub use reject_bid::*;
11 | pub use revoke_bid::*;
12 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/instructions/reject_bid.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use anchor_spl::{
3 | associated_token::AssociatedToken,
4 | token::{Mint, Token, TokenAccount},
5 | };
6 |
7 | use soundwork_list::{
8 | cpi::{
9 | accounts::{WithdrawSol, WithdrawToken},
10 | withdraw_sol, withdraw_token,
11 | },
12 | program::SoundworkList,
13 | state::ListingData,
14 | PaymentOption, WithdrawSolParams, WithdrawTokenParams,
15 | };
16 |
17 | use crate::{error::BidErrorCode, BidData};
18 |
19 | /// Reject a placed Bid
20 |
21 | /// ### Accounts:
22 | ///
23 | /// 1. `[writeable, signer]` seller
24 | /// 2. `[writeable]` bidder
25 | /// 3. `[writeable]` asset
26 | /// 4. `[writeable]` bid data account
27 | /// 5. `[writeable]` bidder escrow wallet
28 | /// 6. `[writeable]` listing data account
29 | /// 7. `[writeable, optional]` bidder token account
30 | /// 8. `[writeable, optional]` wallet token account
31 | /// 9. `[writeable]` payment mint
32 | /// 10. `[]` soundwork list program
33 | /// 11. `[]` token program
34 | /// 12. `[]` associated token program
35 | /// 13. `[]` system program
36 | ///
37 | #[derive(Accounts)]
38 | pub struct RejectBid<'info> {
39 | #[account(mut)]
40 | pub seller: Signer<'info>,
41 |
42 | #[account(
43 | mut,
44 | address = bid_data.authority @ BidErrorCode::UnrecognizedSigner
45 | )]
46 | pub bidder: SystemAccount<'info>,
47 |
48 | /// CHECK: checked by us
49 | #[account(mut)]
50 | pub asset: AccountInfo<'info>,
51 |
52 | #[account(
53 | mut,
54 | close = bidder,
55 | )]
56 | pub bid_data: Account<'info, BidData>,
57 |
58 | /// CHECK: initialized by list program through the CPI
59 | #[account(
60 | mut,
61 | owner = soundwork_list.key()
62 | )]
63 | pub bidder_escrow_wallet: UncheckedAccount<'info>,
64 |
65 | #[account(mut)]
66 | pub listing_data: Account<'info, ListingData>,
67 |
68 | #[account(mut)]
69 | pub payment_mint: Option>>,
70 |
71 | #[account(mut)]
72 | pub bidder_token_account: Option>>,
73 |
74 | #[account(mut)]
75 | pub wallet_token_account: Option>>,
76 |
77 | pub soundwork_list: Program<'info, SoundworkList>,
78 |
79 | pub token_program: Program<'info, Token>,
80 |
81 | pub associated_token_program: Program<'info, AssociatedToken>,
82 |
83 | pub system_program: Program<'info, System>,
84 | }
85 |
86 | impl RejectBid<'_> {
87 | /// validation helper for our IX
88 | pub fn validate(&self) -> Result<()> {
89 | match self.listing_data.payment_option {
90 | PaymentOption::Native => {} // default anchor account checks
91 |
92 | PaymentOption::Token { mint: _ } => {
93 | let payment_mint = self.payment_mint.as_ref();
94 | let bidder_token_account = self.bidder_token_account.as_ref();
95 |
96 | if bidder_token_account.is_none() || payment_mint.is_none() {
97 | return Err(error!(BidErrorCode::MissingAccount));
98 | }
99 | } //
100 | }
101 |
102 | return Ok(());
103 | }
104 |
105 | /// reject previously placed bid for an MPL core asset on the marketplace
106 | ///
107 | #[access_control(ctx.accounts.validate())]
108 | pub fn reject_bid(ctx: Context) -> Result<()> {
109 | let bid_data = &mut ctx.accounts.bid_data;
110 | let list_data = &mut ctx.accounts.listing_data;
111 | let cpi_program = ctx.accounts.soundwork_list.to_account_info();
112 |
113 | // transfer sol or tokens back to bidders wallet
114 |
115 | match list_data.payment_option {
116 | PaymentOption::Native => {
117 | let withdraw_sol_cpi_accounts = WithdrawSol {
118 | payer: ctx.accounts.bidder.to_account_info(),
119 | authority: ctx.accounts.bidder.to_account_info(),
120 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
121 | system_program: ctx.accounts.system_program.to_account_info(),
122 | };
123 |
124 | let withdraw_sol_ctx = CpiContext::new(cpi_program, withdraw_sol_cpi_accounts);
125 |
126 | withdraw_sol(
127 | withdraw_sol_ctx,
128 | WithdrawSolParams {
129 | amount: bid_data.amount,
130 | }
131 | .into(),
132 | )?;
133 | }
134 |
135 | PaymentOption::Token { mint: _ } => {
136 | let withdraw_token_cpi_accounts = WithdrawToken {
137 | payer: ctx.accounts.bidder.to_account_info(),
138 | authority: ctx.accounts.bidder.to_account_info(),
139 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
140 | mint: ctx
141 | .accounts
142 | .payment_mint
143 | .as_ref()
144 | .unwrap()
145 | .to_account_info(), // safe to unwrap. checked in validator constraint
146 | authority_token_account: ctx
147 | .accounts
148 | .bidder_token_account
149 | .as_ref()
150 | .unwrap()
151 | .to_account_info(), // safe to unwrap here too
152 | wallet_token_account: ctx
153 | .accounts
154 | .wallet_token_account
155 | .as_ref()
156 | .unwrap()
157 | .to_account_info(),
158 | token_program: ctx.accounts.token_program.to_account_info(),
159 | associated_token_program: ctx
160 | .accounts
161 | .associated_token_program
162 | .to_account_info(),
163 | system_program: ctx.accounts.system_program.to_account_info(),
164 | };
165 |
166 | let withdraw_token_ctx = CpiContext::new(cpi_program, withdraw_token_cpi_accounts);
167 |
168 | withdraw_token(
169 | withdraw_token_ctx,
170 | WithdrawTokenParams {
171 | amount: bid_data.amount,
172 | }
173 | .into(),
174 | )?;
175 | }
176 | }
177 |
178 | Ok(())
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/instructions/revoke_bid.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use anchor_spl::{
3 | associated_token::AssociatedToken,
4 | token::{Mint, Token, TokenAccount},
5 | };
6 |
7 | use soundwork_list::{
8 | cpi::{
9 | accounts::{WithdrawSol, WithdrawToken},
10 | withdraw_sol, withdraw_token,
11 | },
12 | program::SoundworkList,
13 | state::ListingData,
14 | PaymentOption, WithdrawSolParams, WithdrawTokenParams,
15 | };
16 |
17 | use crate::{error::BidErrorCode, BidData};
18 |
19 | /// Revoke placed Bid
20 | ///
21 | /// ### Accounts:
22 | /// 1. `[writeable, signer]` bidder
23 | /// 2. `[writeable]` asset
24 | /// 3. `[writeable]` bid data account
25 | /// 4. `[writeable]` bidder escrow wallet
26 | /// 5. `[writeable]` listing data account
27 | /// 6. `[writeable]` payment mint
28 | /// 7. `[writeable, optional]` bidder token account
29 | /// 8. `[writeable, options]` wallet token account
30 | /// 9. `[]` soundwork list program
31 | /// 10. `[]` token program
32 | /// 11. `[]` associated token program
33 | /// 12. `[]` system program
34 | ///
35 | #[derive(Accounts)]
36 | pub struct RevokeBid<'info> {
37 | #[account(
38 | mut,
39 | address = bid_data.authority @ BidErrorCode::UnrecognizedSigner
40 | )]
41 | pub bidder: Signer<'info>,
42 |
43 | /// CHECK: checked by us
44 | #[account(mut)]
45 | pub asset: AccountInfo<'info>,
46 |
47 | #[account(
48 | mut,
49 | close = bidder,
50 | )]
51 | pub bid_data: Account<'info, BidData>,
52 |
53 | /// CHECK: initialized by list program through the CPI
54 | #[account(
55 | mut,
56 | owner = soundwork_list.key()
57 | )]
58 | pub bidder_escrow_wallet: UncheckedAccount<'info>,
59 |
60 | #[account(mut)]
61 | pub listing_data: Account<'info, ListingData>,
62 |
63 | #[account(mut)]
64 | pub payment_mint: Option>>,
65 |
66 | #[account(mut)]
67 | pub bidder_token_account: Option>>,
68 |
69 | #[account(mut)]
70 | pub wallet_token_account: Option>>,
71 |
72 | pub soundwork_list: Program<'info, SoundworkList>,
73 |
74 | pub token_program: Program<'info, Token>,
75 |
76 | pub associated_token_program: Program<'info, AssociatedToken>,
77 |
78 | pub system_program: Program<'info, System>,
79 | }
80 |
81 | impl RevokeBid<'_> {
82 | /// validation helper for our IX
83 | pub fn validate(&self) -> Result<()> {
84 | match self.listing_data.payment_option {
85 | PaymentOption::Native => {}
86 |
87 | PaymentOption::Token { mint: _ } => {
88 | let payment_mint = self.payment_mint.as_ref();
89 | let bidder_token_account = self.bidder_token_account.as_ref();
90 |
91 | if bidder_token_account.is_none() || payment_mint.is_none() {
92 | return Err(error!(BidErrorCode::MissingAccount));
93 | }
94 | } //
95 | }
96 |
97 | return Ok(());
98 | }
99 |
100 | /// revoke previously placed bid for an MPL core asset on the marketplace
101 | ///
102 | #[access_control(ctx.accounts.validate())]
103 | pub fn revoke_bid(ctx: Context) -> Result<()> {
104 | let bid_data = &mut ctx.accounts.bid_data;
105 | let list_data = &mut ctx.accounts.listing_data;
106 | let cpi_program = ctx.accounts.soundwork_list.to_account_info();
107 |
108 | // transfer sol or tokens back to bidders wallet
109 |
110 | match list_data.payment_option {
111 | PaymentOption::Native => {
112 | let withdraw_sol_cpi_accounts = WithdrawSol {
113 | payer: ctx.accounts.bidder.to_account_info(),
114 | authority: ctx.accounts.bidder.to_account_info(),
115 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
116 | system_program: ctx.accounts.system_program.to_account_info(),
117 | };
118 |
119 | let withdraw_sol_ctx = CpiContext::new(cpi_program, withdraw_sol_cpi_accounts);
120 |
121 | withdraw_sol(
122 | withdraw_sol_ctx,
123 | WithdrawSolParams {
124 | amount: bid_data.amount,
125 | }
126 | .into(),
127 | )?;
128 | }
129 |
130 | PaymentOption::Token { mint: _ } => {
131 | let withdraw_token_cpi_accounts = WithdrawToken {
132 | payer: ctx.accounts.bidder.to_account_info(),
133 | authority: ctx.accounts.bidder.to_account_info(),
134 | wallet: ctx.accounts.bidder_escrow_wallet.to_account_info(),
135 | mint: ctx
136 | .accounts
137 | .payment_mint
138 | .as_ref()
139 | .unwrap()
140 | .to_account_info(), // safe to unwrap. checked in validator constraint
141 | authority_token_account: ctx
142 | .accounts
143 | .bidder_token_account
144 | .as_ref()
145 | .unwrap()
146 | .to_account_info(), // safe to unwrap here too
147 | wallet_token_account: ctx
148 | .accounts
149 | .wallet_token_account
150 | .as_ref()
151 | .unwrap()
152 | .to_account_info(),
153 | token_program: ctx.accounts.token_program.to_account_info(),
154 | associated_token_program: ctx
155 | .accounts
156 | .associated_token_program
157 | .to_account_info(),
158 | system_program: ctx.accounts.system_program.to_account_info(),
159 | };
160 |
161 | let withdraw_token_ctx = CpiContext::new(cpi_program, withdraw_token_cpi_accounts);
162 |
163 | withdraw_token(
164 | withdraw_token_ctx,
165 | WithdrawTokenParams {
166 | amount: bid_data.amount,
167 | }
168 | .into(),
169 | )?;
170 | }
171 | }
172 |
173 | Ok(())
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod constants;
2 | pub mod error;
3 | pub mod instructions;
4 | pub mod state;
5 |
6 | use anchor_lang::prelude::*;
7 |
8 | #[allow(unused_imports)]
9 | use solana_security_txt::security_txt;
10 |
11 | pub use constants::*;
12 | pub use instructions::*;
13 | pub use state::*;
14 |
15 | declare_id!("4mFDYND4AVREYEJXCPhjq1LnbjELHHebJqG3NZechA7X");
16 |
17 | #[cfg(not(feature = "no-entrypoint"))]
18 | security_txt! {
19 | name: "Soundwork Bid Program",
20 | project_url: "https://soundwork.io",
21 | contacts: "email:info@soundwork.io, twitter:@SoundworkSounds",
22 | policy: "https://github.com/SoundWorkLabs/marketplace-contracts/blob/master/SECURITY.md",
23 | preferred_languages: "en",
24 | source_code: "https://github.com/SoundWorkLabs/marketplace-contracts"
25 | }
26 |
27 | /// SOUNDWORK BID
28 | ///
29 | #[program]
30 | pub mod soundwork_bid {
31 | use super::*;
32 |
33 | /// Place a bid for a listed MPL Core asset on Soundwork
34 | ///
35 | pub fn make_bid(ctx: Context, params: MakeBidParams) -> Result<()> {
36 | MakeBid::make_bid(ctx, params)
37 | }
38 |
39 | /// Edit a placed bid on Soundwork
40 | ///
41 | pub fn edit_bid(ctx: Context, params: EditBidParams) -> Result<()> {
42 | EditBid::edit_bid(ctx, params)
43 | }
44 |
45 | /// Revoke placed bid
46 | ///
47 | pub fn revoke_bid(ctx: Context) -> Result<()> {
48 | RevokeBid::revoke_bid(ctx)
49 | }
50 |
51 | /// Accept placed bid
52 | ///
53 | pub fn accept_bid(ctx: Context) -> Result<()> {
54 | AcceptBid::accept_bid(ctx)
55 | }
56 |
57 | /// Reject placed bid
58 | ///
59 | pub fn reject_bid(ctx: Context) -> Result<()> {
60 | RejectBid::reject_bid(ctx)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/state/bid.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[account]
4 | pub struct BidData {
5 | /// PDA bump
6 | pub bump: u8,
7 |
8 | /// amount in lamports asset is being listed for
9 | pub amount: u64,
10 |
11 | /// asset owner
12 | pub authority: Pubkey,
13 |
14 | /// unix timestamp listing expires
15 | pub expiry_ts: i64,
16 |
17 | /// Unused reserved byte space for additive future changes.
18 | pub _reserved: [u8; 128],
19 | }
20 |
21 | impl BidData {
22 | pub const LEN: usize = 8 // anchor discriminator
23 | + 1 // bump
24 | + 8 // amount
25 | + 32 // authority address
26 | + 8 // expiry timestamp
27 | + 128; // reserved
28 |
29 | /// instantiate the bid data account with provided args
30 | pub fn new(bump: u8, amount: u64, authority: Pubkey, expiry_ts: i64) -> Self {
31 | Self {
32 | bump,
33 | amount,
34 | authority,
35 | expiry_ts,
36 | _reserved: [0; 128],
37 | }
38 | }
39 |
40 | /// update bid data account
41 | pub fn update(
42 | &mut self,
43 | updated_amount: Option,
44 | updated_expiry_ts: Option,
45 | ) -> (u64, i64) {
46 | let amount = updated_amount.unwrap_or(self.amount);
47 |
48 | let expiry_ts = updated_expiry_ts.unwrap_or(self.expiry_ts);
49 |
50 | (amount, expiry_ts)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/programs/soundwork-bid/src/state/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod bid;
2 |
3 | pub use bid::*;
4 |
--------------------------------------------------------------------------------
/programs/soundwork-create/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "soundwork-create"
3 | version = "0.1.0"
4 | description = "Created with Anchor"
5 | edition = "2021"
6 |
7 | [lib]
8 | crate-type = ["cdylib", "lib"]
9 | name = "soundwork_create"
10 |
11 | [features]
12 | no-entrypoint = []
13 | no-idl = []
14 | no-log-ix-name = []
15 | cpi = ["no-entrypoint"]
16 | default = []
17 | idl-build = ["anchor-lang/idl-build"]
18 |
19 | [dependencies]
20 | anchor-lang = "0.30.1"
21 | mpl-core = "0.7.2"
22 | solana-security-txt = "1.1.1"
23 | solana-program = "1.18.20"
24 | ahash="=0.8.7"
25 |
--------------------------------------------------------------------------------
/programs/soundwork-create/Xargo.toml:
--------------------------------------------------------------------------------
1 | [target.bpfel-unknown-unknown.dependencies.std]
2 | features = []
3 |
--------------------------------------------------------------------------------
/programs/soundwork-create/src/constants.rs:
--------------------------------------------------------------------------------
1 | // use anchor_lang::{prelude::*, solana_program::pubkey};
2 |
--------------------------------------------------------------------------------
/programs/soundwork-create/src/error.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[error_code]
4 | pub enum ErrorCode {
5 | #[msg("Custom error message")]
6 | CustomError,
7 | }
8 |
--------------------------------------------------------------------------------
/programs/soundwork-create/src/instructions/create.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use mpl_core::instructions::CreateV1CpiBuilder;
3 |
4 | // todo: remove and use SPL typed account
5 | #[derive(Clone)]
6 | pub struct Core;
7 |
8 | impl anchor_lang::Id for Core {
9 | fn id() -> Pubkey {
10 | mpl_core::ID
11 | }
12 | }
13 |
14 | /// Create MPL Core Asset context
15 | ///
16 | /// Expects the following accounts:
17 | /// 1. `[writeable, signer]` payer
18 | /// 2. `[writeable, signer]` asset
19 | /// 3. `[]` core program
20 | /// 4. `[]` `system program`
21 | ///
22 | /// Expects the following arguments
23 | /// 1. name: string
24 | /// 2. uri: string
25 | #[derive(Accounts)]
26 | pub struct CreateAsset<'info> {
27 | pub payer: Signer<'info>,
28 |
29 | /// CHECK: we are passing this in ourselves
30 | #[account(mut, signer)]
31 | pub asset: UncheckedAccount<'info>,
32 |
33 | pub core_program: Program<'info, Core>,
34 |
35 | pub system_program: Program<'info, System>,
36 | }
37 |
38 | impl CreateAsset<'_> {
39 | /// validation helper for our IX
40 | pub fn validate(&self) -> Result<()> {
41 | return Ok(());
42 | }
43 |
44 | /// CPI into mpl_core program and mint our asset.
45 | ///
46 | /// * name - the title of the asset being minted
47 | /// * uri – off-chain URI of the metadata
48 | ///
49 | #[access_control(ctx.accounts.validate())]
50 | pub fn create_asset(ctx: Context, name: String, uri: String) -> Result<()> {
51 | CreateV1CpiBuilder::new(&ctx.accounts.core_program)
52 | .asset(&ctx.accounts.asset)
53 | .collection(None)
54 | .authority(Some(&ctx.accounts.payer))
55 | .payer(&ctx.accounts.payer)
56 | .owner(Some(&ctx.accounts.payer))
57 | .update_authority(Some(&ctx.accounts.payer))
58 | .system_program(&ctx.accounts.system_program)
59 | .name(name)
60 | .uri(uri)
61 | .invoke()?;
62 |
63 | Ok(())
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/programs/soundwork-create/src/instructions/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod create;
2 |
3 | pub use create::*;
4 |
--------------------------------------------------------------------------------
/programs/soundwork-create/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod constants;
2 | pub mod error;
3 | pub mod instructions;
4 | pub mod state;
5 |
6 | use anchor_lang::prelude::*;
7 |
8 | #[allow(unused_imports)]
9 | use solana_security_txt::security_txt;
10 |
11 | pub use instructions::*;
12 |
13 | declare_id!("FegMMZtuFu8ZUTjdkt2yRR1TmGEAFZbjpDJWpQ4ueqyG");
14 |
15 | #[cfg(not(feature = "no-entrypoint"))]
16 | security_txt! {
17 | name: "Soundwork Create Program",
18 | project_url: "https://soundwork.io",
19 | contacts: "email:info@soundwork.io, twitter:@SoundworkSounds",
20 | policy: "https://github.com/SoundWorkLabs/marketplace-contracts/blob/master/SECURITY.md",
21 | preferred_languages: "en",
22 | source_code: "https://github.com/SoundWorkLabs/marketplace-contracts"
23 | }
24 |
25 | /// SOUNDWORK CREATE
26 | ///
27 | /// admin IXs to interact with the soundwork programs
28 | #[program]
29 | pub mod soundwork_create {
30 | use super::*;
31 |
32 | /// Create MPL Core Asset
33 | ///
34 | /// Expect
35 | /// 1. name - title of the asset
36 | /// 2. uri - off chain metadata uri
37 | pub fn create(ctx: Context, name: String, uri: String) -> Result<()> {
38 | CreateAsset::create_asset(ctx, name, uri)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/programs/soundwork-create/src/state/mod.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/programs/soundwork-list/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "soundwork-list"
3 | version = "0.1.0"
4 | description = "Created with Anchor"
5 | edition = "2021"
6 |
7 | [lib]
8 | crate-type = ["cdylib", "lib"]
9 | name = "soundwork_list"
10 |
11 | [features]
12 | no-entrypoint = []
13 | no-idl = []
14 | no-log-ix-name = []
15 | cpi = ["no-entrypoint"]
16 | default = []
17 | idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
18 |
19 | [dependencies]
20 | anchor-lang = { version = "0.30.1", features = ["init-if-needed"] }
21 | anchor-spl = "0.30.1"
22 | mpl-core = "0.7.2"
23 | solana-security-txt = "1.1.1"
24 | solana-program = "1.18.20"
25 | ahash="=0.8.7"
26 |
--------------------------------------------------------------------------------
/programs/soundwork-list/Xargo.toml:
--------------------------------------------------------------------------------
1 | [target.bpfel-unknown-unknown.dependencies.std]
2 | features = []
3 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/constants.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::{prelude::*, solana_program::pubkey};
2 |
3 | #[constant]
4 | pub const SEED_PREFIX: &[u8] = b"Kessoku";
5 |
6 | #[constant]
7 | pub const SEED_ASSET_MANAGER: &[u8] = b"Seika";
8 |
9 | #[constant]
10 | pub const SEED_MARKETPLACE_CONFIG: &[u8] = b"Ijichi";
11 |
12 | #[constant]
13 | pub const SEED_LISTING_DATA: &[u8] = b"Hitori";
14 |
15 | #[constant]
16 | pub const SEED_WALLET: &[u8] = b"Yamada";
17 |
18 | #[constant]
19 | pub const ADMIN_ADDRESS: Pubkey = pubkey!("4kg8oh3jdNtn7j2wcS7TrUua31AgbLzDVkBZgTAe44aF");
20 |
21 | #[constant]
22 | pub const TREASURY_ADDRESS: Pubkey = pubkey!("4kg8oh3jdNtn7j2wcS7TrUua31AgbLzDVkBZgTAe44aF");
23 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/error.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[error_code]
4 | pub enum ListErrorCode {
5 | #[msg("Insufficient funds to purchase asset")]
6 | InsufficientFunds,
7 | #[msg("Invalid operation!")]
8 | InvalidOperation,
9 | #[msg("You do no have authority to perform the requested operation!")]
10 | InvalidAuthority,
11 | #[msg("The value provided should not be zero.")]
12 | ZeroValueNotAllowed,
13 | #[msg("The mint address provided does not match seller's provided mint address.")]
14 | PaymentMintAddressMismatch,
15 | #[msg("An account required for this operation is missing.")]
16 | MissingAccount,
17 | }
18 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/helpers.rs:
--------------------------------------------------------------------------------
1 | use std::result::Result as StdResult;
2 |
3 | use solana_program::pubkey::Pubkey;
4 |
5 | // todo(Jimii): use royalty plugin
6 | // selling price + protocol fee + royalty
7 | pub fn calculate_total_buy_fee(amount: u64, taker_fee_bps: u8) -> StdResult {
8 | let fee = amount
9 | .checked_mul(taker_fee_bps as u64)
10 | .ok_or("fee calculation overflow")?
11 | .checked_div(10000)
12 | .ok_or("fee calculation overflow")?;
13 |
14 | // todo: royalty
15 |
16 | let total = amount.checked_add(fee).ok_or("")?;
17 |
18 | Ok(total)
19 | }
20 |
21 | // export core program type
22 | // todo: remove and use SPL typed account
23 | #[derive(Clone)]
24 | pub struct Core;
25 |
26 | impl anchor_lang::Id for Core {
27 | fn id() -> Pubkey {
28 | mpl_core::ID
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/admin/init_escrow.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | use crate::{AssetManager, constants::{SEED_ASSET_MANAGER, SEED_PREFIX, ADMIN_ADDRESS}, helpers::Core};
4 |
5 | /// Initialize AssetManager escrow account
6 | ///
7 | /// ### Accounts:
8 | ///
9 | /// 1. `[writeable, signer]` payer
10 | /// 2. `[writeable, signer]` assetManager
11 | /// 3. `[]` core program
12 | /// 4. `[]` `system program`
13 |
14 | #[derive(Accounts)]
15 | pub struct InitEscrow<'info> {
16 | // todo: move this admin address check to the validate functions
17 | // find out a way to do this using a slice or vector of verified addresses
18 | #[account(mut, address = ADMIN_ADDRESS)]
19 | pub payer: Signer<'info>,
20 |
21 | #[account(
22 | init,
23 | payer=payer,
24 | space=AssetManager::LEN,
25 | seeds = [SEED_PREFIX, SEED_ASSET_MANAGER],
26 | bump
27 | )]
28 | pub asset_manager: Account<'info, AssetManager>,
29 |
30 | pub core_program: Program<'info, Core>,
31 |
32 | pub system_program: Program<'info, System>,
33 | }
34 |
35 | impl InitEscrow<'_> {
36 | /// validation helper for our IX
37 | pub fn validate(&self) -> Result<()> {
38 | return Ok(());
39 | }
40 |
41 | /// Initialize the Asset Manager escrow account
42 | ///
43 | #[access_control(ctx.accounts.validate())]
44 | pub fn init_escrow(ctx: Context) -> Result<()> {
45 | msg!("initialized escrow account");
46 |
47 | let asset_manager = &mut ctx.accounts.asset_manager;
48 | asset_manager.bump = ctx.bumps.asset_manager; // ? is this safe
49 |
50 | Ok(())
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/admin/init_mp_config.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | use crate::{
4 | constants::{ADMIN_ADDRESS, SEED_MARKETPLACE_CONFIG, SEED_PREFIX},
5 | MarketPlaceConfig,
6 | };
7 |
8 | #[derive(AnchorSerialize, AnchorDeserialize)]
9 | pub struct InitMarketPlaceConfigParams {
10 | /// taker fee basis points, /100%
11 | pub taker_fee_bps: u8,
12 |
13 | /// treasury address
14 | pub treasury_address: Pubkey,
15 | }
16 |
17 | /// Initialize protocol state accounts
18 | ///
19 | /// ### Accounts:
20 | ///
21 | /// 1. `[writeable, signer]` payer
22 | /// 2. `[writeable, signer]` assetManager
23 | /// 3. `[]` `system program`
24 | ///
25 | /// ### Parameters
26 | /// 1. params: [InitMarketPlaceConfigParams]
27 | ///
28 | #[derive(Accounts)]
29 | #[instruction(params: InitMarketPlaceConfigParams)]
30 | pub struct InitMarketplaceConfig<'info> {
31 | // todo: move this admin address check to the validate functions
32 | // find out a way to do this using a slice or vector of verified addresses
33 | #[account(mut, address = ADMIN_ADDRESS)]
34 | pub payer: Signer<'info>,
35 |
36 | #[account(
37 | init,
38 | payer = payer,
39 | space = MarketPlaceConfig::LEN,
40 | seeds = [SEED_PREFIX, SEED_MARKETPLACE_CONFIG],
41 | bump
42 | )]
43 | pub marketplace_config: Account<'info, MarketPlaceConfig>,
44 |
45 | pub system_program: Program<'info, System>,
46 | }
47 |
48 | impl InitMarketplaceConfig<'_> {
49 | /// validation helper for our IX
50 | pub fn validate(&self) -> Result<()> {
51 | return Ok(());
52 | }
53 |
54 | /// Initialize the marketplace config account
55 | ///
56 | #[access_control(ctx.accounts.validate())]
57 | pub fn init_marketplace_config(
58 | ctx: Context,
59 | params: InitMarketPlaceConfigParams,
60 | ) -> Result<()> {
61 | msg!("initialized marketplace config account");
62 |
63 | let marketplace_config = &mut ctx.accounts.marketplace_config;
64 | **marketplace_config = MarketPlaceConfig::new(
65 | ctx.bumps.marketplace_config,
66 | params.treasury_address,
67 | params.taker_fee_bps,
68 | );
69 |
70 | Ok(())
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/admin/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod init_escrow;
2 | pub mod init_mp_config;
3 |
4 | pub use init_escrow::*;
5 | pub use init_mp_config::*;
6 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/buy_listing.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::{
2 | prelude::*,
3 | system_program::{self, Transfer as SOLTransfer},
4 | };
5 | use anchor_spl::{
6 | associated_token::AssociatedToken,
7 | token::{transfer_checked, Mint, Token, TokenAccount, TransferChecked as SPLTransferChecked},
8 | };
9 | use mpl_core::instructions::TransferV1CpiBuilder;
10 |
11 | use crate::{
12 | constants::{SEED_ASSET_MANAGER, SEED_PREFIX},
13 | error::ListErrorCode,
14 | helpers::{calculate_total_buy_fee, Core},
15 | AssetManager, ListingData, MarketPlaceConfig, PaymentOption, Wallet, SEED_WALLET,
16 | };
17 |
18 | #[derive(AnchorSerialize, AnchorDeserialize)]
19 | pub struct BuyAssetParams {
20 | /// only used when buying using a bid amount
21 | pub bid_amount: u64,
22 | }
23 |
24 | /// Buy a listed MPL core asset on Soundwork
25 | ///
26 | /// ### Accounts:
27 | ///
28 | /// 1. `[writeable, signer]` payer
29 | /// 2. `[writeable]` buyer
30 | /// 3. `[writeable]` seller
31 | /// 4. `[writeable, optional]` wallet as buyer
32 | /// 5. `[writeable]` asset
33 | /// 6. `[writeable]` collection
34 | /// 7. `[writeable, optional]` payment mint
35 | /// 8. `[writeable, optional]` wallet token account
36 | /// 9. `[writeable, optional]` buyer token account
37 | /// 10. `[writeable, optional]` seller token account
38 | /// 11. `[writeable, optional]` treasury token account
39 | /// 12. `[writeable]` treasury
40 | /// 13. `[writeable]` listing data account
41 | /// 14. `[]` asset manager
42 | /// 15. `[]` marketplace config
43 | /// 16. `[]` core program
44 | /// 17. `[]` token program
45 | /// 18. `[]` associated token program
46 | /// 19. `[]` system program
47 | ///
48 | /// ### Parameters
49 | ///
50 | /// 1. params: [BuyAssetParams]
51 | ///
52 | #[derive(Accounts)]
53 | pub struct BuyAsset<'info> {
54 | #[account(mut)]
55 | pub payer: Signer<'info>,
56 |
57 | #[account(mut)]
58 | pub buyer: SystemAccount<'info>,
59 |
60 | #[account(mut)]
61 | pub seller: SystemAccount<'info>,
62 |
63 | #[account(mut)]
64 | pub wallet_as_buyer: Option>>,
65 |
66 | /// CHECK: checked by us
67 | #[account(mut)]
68 | pub asset: UncheckedAccount<'info>,
69 |
70 | #[account(mut)]
71 | pub collection: Option>,
72 |
73 | #[account(mut)]
74 | pub payment_mint: Option>>,
75 |
76 | // we expect this to be initialized because this is used only for bids
77 | // a check before placing a bid, makes sure bidder has enough funds to make bid
78 | #[account(mut)]
79 | pub wallet_token_account: Option>>,
80 |
81 | #[account(mut)]
82 | pub buyer_token_account: Option>>,
83 |
84 | // maybe we offered seller a list of tokens to chose from,
85 | // hence seller token account might not be initialized
86 | #[account(
87 | init_if_needed,
88 | payer = buyer,
89 | associated_token::mint = payment_mint,
90 | associated_token::authority = seller,
91 | )]
92 | pub seller_token_account: Option>>,
93 |
94 | #[account(
95 | init_if_needed,
96 | payer = buyer,
97 | associated_token::mint = payment_mint,
98 | associated_token::authority = treasury,
99 | )]
100 | pub treasury_token_account: Option>>,
101 |
102 | #[account(
103 | mut,
104 | address = marketplace_config.treasury_address
105 | )]
106 | pub treasury: SystemAccount<'info>,
107 |
108 | #[account(mut, close = seller)]
109 | pub listing_data: Box>,
110 |
111 | pub asset_manager: Box>,
112 |
113 | pub marketplace_config: Box>,
114 |
115 | pub core_program: Program<'info, Core>,
116 |
117 | pub token_program: Program<'info, Token>,
118 |
119 | pub associated_token_program: Program<'info, AssociatedToken>,
120 |
121 | pub system_program: Program<'info, System>,
122 | }
123 |
124 | impl BuyAsset<'_> {
125 | /// validation helper for our IX
126 | pub fn validate(&self) -> Result<()> {
127 | return Ok(());
128 | }
129 |
130 | /// buy a MPL core asset listed on the marketplace
131 | ///
132 | #[access_control(ctx.accounts.validate())]
133 | pub fn buy_asset(ctx: Context, params: Option) -> Result<()> {
134 | let listing_data = &mut ctx.accounts.listing_data;
135 | let asset_manager = &ctx.accounts.asset_manager;
136 | let escrow_wallet = &mut ctx.accounts.wallet_as_buyer;
137 |
138 | // using the optional escrow_wallet_as buyer account to check who will be paying for the NFT
139 | // if escrow wallet is provided, use to pay for the asset, else use payer
140 | match (escrow_wallet, params) {
141 | // only use escrow wallet to buy asset if both the account and bid_amount is provided
142 | (Some(wallet), Some(params)) => {
143 | let taker_fee_bps = ctx.accounts.marketplace_config.taker_fee_bps;
144 | let total_cost = calculate_total_buy_fee(params.bid_amount, taker_fee_bps).unwrap();
145 | let protocol_take = total_cost.checked_sub(params.bid_amount).unwrap(); // if fee calculation OK, assume safe to unwrap here
146 |
147 | // if use wanted to pay with tokens
148 | match listing_data.payment_option {
149 | PaymentOption::Native => {
150 | if wallet.get_lamports() < total_cost {
151 | return Err(error!(ListErrorCode::InsufficientFunds));
152 | }
153 |
154 | // transfer to seller
155 | wallet.sub_lamports(params.bid_amount)?;
156 | ctx.accounts.seller.add_lamports(params.bid_amount)?;
157 |
158 | // transfer to protocol treasury
159 | wallet.sub_lamports(protocol_take)?;
160 | ctx.accounts.treasury.add_lamports(protocol_take)?;
161 | }
162 | PaymentOption::Token { mint } => {
163 | let payment_mint = &ctx.accounts.payment_mint.as_ref();
164 | let wallet_token_account = &ctx.accounts.wallet_token_account.as_ref();
165 | let seller_token_account = &ctx.accounts.seller_token_account.as_ref();
166 | let treasury_token_account = &ctx.accounts.treasury_token_account.as_ref();
167 |
168 | // allow us to use unwrap() safely
169 | if payment_mint.is_none()
170 | || wallet_token_account.is_none()
171 | || seller_token_account.is_none()
172 | || treasury_token_account.is_none()
173 | {
174 | return Err(error!(ListErrorCode::MissingAccount));
175 | }
176 |
177 | if payment_mint.unwrap().key() != mint {
178 | return Err(error!(ListErrorCode::PaymentMintAddressMismatch));
179 | }
180 |
181 | if wallet_token_account.unwrap().amount < total_cost {
182 | return Err(error!(ListErrorCode::InsufficientFunds));
183 | }
184 |
185 | // signer seeds
186 | let bump = &[wallet.bump];
187 | let signer_seeds = &[&[
188 | SEED_PREFIX,
189 | SEED_WALLET,
190 | ctx.accounts.buyer.key.as_ref(), // owns escrow wallet on soundwork
191 | bump,
192 | ][..]];
193 |
194 | let cpi_program = ctx.accounts.token_program.to_account_info();
195 |
196 | let seller_cpi_accounts = SPLTransferChecked {
197 | from: wallet_token_account.unwrap().to_account_info(),
198 | mint: payment_mint.unwrap().to_account_info(),
199 | to: seller_token_account.unwrap().to_account_info(),
200 | authority: wallet.to_account_info(),
201 | };
202 |
203 | let seller_cpi_ctx = CpiContext::new_with_signer(
204 | cpi_program.clone(),
205 | seller_cpi_accounts,
206 | signer_seeds,
207 | );
208 |
209 | transfer_checked(
210 | seller_cpi_ctx,
211 | params.bid_amount,
212 | payment_mint.unwrap().decimals,
213 | )?;
214 |
215 | // transfer to protocol
216 | let protocol_cpi_accounts = SPLTransferChecked {
217 | from: wallet_token_account.unwrap().to_account_info(),
218 | mint: payment_mint.unwrap().to_account_info(),
219 | to: treasury_token_account.unwrap().to_account_info(),
220 | authority: wallet.to_account_info(),
221 | };
222 |
223 | let protocol_cpi_ctx = CpiContext::new_with_signer(
224 | cpi_program.clone(),
225 | protocol_cpi_accounts,
226 | signer_seeds,
227 | );
228 |
229 | transfer_checked(
230 | protocol_cpi_ctx,
231 | protocol_take,
232 | payment_mint.unwrap().decimals,
233 | )?;
234 | }
235 | };
236 | }
237 |
238 | // use buyers account to buy asset
239 | (None, None) => {
240 | // price calc
241 | let taker_fee_bps = ctx.accounts.marketplace_config.taker_fee_bps;
242 | let total_cost =
243 | calculate_total_buy_fee(listing_data.amount, taker_fee_bps).unwrap();
244 | let protocol_take = total_cost.checked_sub(listing_data.amount).unwrap(); // if fee calculation OK, assume safe to unwrap here
245 |
246 | match listing_data.payment_option {
247 | PaymentOption::Native => {
248 | // accounts
249 | let buyer = ctx.accounts.buyer.as_ref();
250 | let seller = ctx.accounts.seller.as_ref();
251 |
252 | if buyer.get_lamports() < total_cost {
253 | return Err(error!(ListErrorCode::InsufficientFunds));
254 | }
255 |
256 | // transfers
257 | let cpi_program = ctx.accounts.system_program.to_account_info();
258 |
259 | // transfer to seller
260 | let seller_cpi_accounts = SOLTransfer {
261 | from: buyer.to_account_info(),
262 | to: seller.to_account_info(),
263 | };
264 |
265 | let seller_cpi_context =
266 | CpiContext::new(cpi_program.clone(), seller_cpi_accounts);
267 |
268 | system_program::transfer(seller_cpi_context, listing_data.amount)?;
269 |
270 | // protocol take
271 | let protocol_cpi_accounts = SOLTransfer {
272 | from: buyer.to_account_info(),
273 | to: seller.to_account_info(),
274 | };
275 |
276 | let protocol_cpi_context =
277 | CpiContext::new(cpi_program.clone(), protocol_cpi_accounts);
278 |
279 | system_program::transfer(protocol_cpi_context, protocol_take)?;
280 | }
281 | PaymentOption::Token { mint } => {
282 | // accounts
283 | let payment_mint = &ctx.accounts.payment_mint.as_ref();
284 | let buyer = ctx.accounts.buyer.as_ref();
285 | let buyer_token_account = ctx.accounts.buyer_token_account.as_ref();
286 | let seller_token_account = ctx.accounts.seller_token_account.as_ref();
287 | let treasury_token_account = ctx.accounts.treasury_token_account.as_ref();
288 |
289 | // check if optional accounts exist so that we can safely `unwrap()`
290 | if payment_mint.is_none()
291 | || buyer_token_account.is_none()
292 | || seller_token_account.is_none()
293 | || treasury_token_account.is_none()
294 | {
295 | return Err(error!(ListErrorCode::MissingAccount));
296 | }
297 |
298 | // check payment mint
299 | if payment_mint.unwrap().key() != mint {
300 | return Err(error!(ListErrorCode::PaymentMintAddressMismatch));
301 | }
302 |
303 | // check buyer amount
304 | if buyer_token_account.unwrap().amount < total_cost {
305 | return Err(error!(ListErrorCode::InsufficientFunds));
306 | }
307 |
308 | // transfers
309 | let cpi_program = ctx.accounts.token_program.to_account_info();
310 |
311 | // seller
312 | let seller_cpi_accounts = SPLTransferChecked {
313 | from: buyer_token_account.unwrap().to_account_info(),
314 | mint: payment_mint.unwrap().to_account_info(),
315 | to: seller_token_account.unwrap().to_account_info(),
316 | authority: buyer.to_account_info(),
317 | };
318 |
319 | let seller_cpi_ctx =
320 | CpiContext::new(cpi_program.clone(), seller_cpi_accounts);
321 |
322 | transfer_checked(
323 | seller_cpi_ctx,
324 | listing_data.amount,
325 | payment_mint.unwrap().decimals,
326 | )?;
327 |
328 | // protocol take
329 | let buyer_cpi_accounts = SPLTransferChecked {
330 | from: buyer_token_account.unwrap().to_account_info(),
331 | mint: payment_mint.unwrap().to_account_info(),
332 | to: treasury_token_account.unwrap().to_account_info(),
333 | authority: buyer.to_account_info(),
334 | };
335 |
336 | let seller_cpi_ctx =
337 | CpiContext::new(cpi_program.clone(), buyer_cpi_accounts);
338 |
339 | transfer_checked(
340 | seller_cpi_ctx,
341 | protocol_take,
342 | payment_mint.unwrap().decimals,
343 | )?;
344 | }
345 | }
346 | }
347 |
348 | // invalid, panic
349 | (None, Some(_)) => todo!("Create suitable error message for this"),
350 |
351 | // invalid, panic
352 | (Some(_), None) => todo!("Create suitable error message for this"),
353 | };
354 |
355 | // transfer to buyer
356 | let bump = &[asset_manager.bump];
357 | let signer_seeds = &[&[SEED_PREFIX, SEED_ASSET_MANAGER, bump][..]];
358 |
359 | TransferV1CpiBuilder::new(&ctx.accounts.core_program)
360 | .asset(&ctx.accounts.asset)
361 | .collection(ctx.accounts.collection.as_ref())
362 | .payer(&ctx.accounts.payer)
363 | .authority(Some(&asset_manager.to_account_info()))
364 | .new_owner(&ctx.accounts.payer.to_account_info())
365 | .system_program(Some(&ctx.accounts.system_program))
366 | .invoke_signed(signer_seeds)?;
367 |
368 | Ok(())
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/escrow_ix/deposit_sol.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::{
2 | prelude::*,
3 | system_program::{self, System, Transfer},
4 | };
5 |
6 | use crate::Wallet;
7 |
8 | #[derive(AnchorSerialize, AnchorDeserialize)]
9 | pub struct DepositSolParams {
10 | /// amount to deposit in lamports
11 | pub amount: u64,
12 | }
13 |
14 | /// Deposit Sol into escrow wallet managed by the list program
15 | ///
16 | /// ### Accounts:
17 | ///
18 | /// 1. `[writeable, signer]` authority
19 | /// 2. `[writeable]` wallet
20 | /// 3. `[]` system program
21 | ///
22 | /// ### Parameters
23 | /// 1. params: [DepositSolParams]
24 | ///
25 | #[derive(Accounts)]
26 | pub struct DepositSol<'info> {
27 | #[account(mut)]
28 | pub authority: Signer<'info>,
29 |
30 | #[account(mut)]
31 | pub wallet: Account<'info, Wallet>,
32 |
33 | pub system_program: Program<'info, System>,
34 | }
35 |
36 | impl DepositSol<'_> {
37 | /// validation helper for our IX
38 | pub fn validate(&self) -> Result<()> {
39 | return Ok(());
40 | }
41 |
42 | /// Deposit native sol into user's wallet
43 | ///
44 | #[access_control(ctx.accounts.validate())]
45 | pub fn deposit_sol(ctx: Context, params: DepositSolParams) -> Result<()> {
46 | let cpi_accounts = Transfer {
47 | from: ctx.accounts.authority.to_account_info(),
48 | to: ctx.accounts.wallet.to_account_info(),
49 | };
50 | let cpi_program = ctx.accounts.system_program.to_account_info();
51 |
52 | let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
53 |
54 | system_program::transfer(cpi_context, params.amount)?;
55 |
56 | Ok(())
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/escrow_ix/deposit_token.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use anchor_spl::{
3 | associated_token::AssociatedToken,
4 | token::{transfer_checked, Mint, Token, TokenAccount, TransferChecked},
5 | };
6 |
7 | use crate::Wallet;
8 |
9 | #[derive(AnchorSerialize, AnchorDeserialize)]
10 | pub struct DepositTokenParams {
11 | /// amount to deposit in lamports
12 | pub amount: u64,
13 | }
14 |
15 | /// Deposit Tokens into escrow wallet managed by the list program
16 | ///
17 | /// ### Accounts:
18 | /// 1. `[writeable, signer]` authority
19 | /// 2. `[writeable]` wallet
20 | /// 3. `[writeable, optional]` mint
21 | /// 4. `[writeable, optional]` authority associated token address
22 | /// 5. `[writeable, optional]` wallet associated token address
23 | /// 6. `[]` token program
24 | /// 7. `[]` associated token program
25 | /// 8. `[]` system program
26 | ///
27 | /// ### Parameters
28 | /// 1. params: [DepositTokenParams]
29 | ///
30 | #[derive(Accounts)]
31 | pub struct DepositToken<'info> {
32 | #[account(mut)]
33 | pub authority: Signer<'info>,
34 |
35 | #[account(mut)]
36 | pub wallet: Account<'info, Wallet>,
37 |
38 | #[account(mut)]
39 | pub mint: Account<'info, Mint>,
40 |
41 | #[account(mut)]
42 | pub authority_token_account: Account<'info, TokenAccount>,
43 |
44 | #[account(
45 | init_if_needed,
46 | payer = authority,
47 | associated_token::mint = mint,
48 | associated_token::authority = wallet,
49 | )]
50 | pub wallet_token_account: Account<'info, TokenAccount>,
51 | pub token_program: Program<'info, Token>,
52 | pub associated_token_program: Program<'info, AssociatedToken>,
53 | pub system_program: Program<'info, System>,
54 | }
55 |
56 | impl DepositToken<'_> {
57 | /// validation helper for our IX
58 | pub fn validate(&self) -> Result<()> {
59 | return Ok(());
60 | }
61 |
62 | /// Deposit native sol into user's wallet
63 | ///
64 | #[access_control(ctx.accounts.validate())]
65 | pub fn deposit_token(ctx: Context, params: DepositTokenParams) -> Result<()> {
66 | let DepositTokenParams { amount } = params;
67 |
68 | let cpi_program = ctx.accounts.token_program.to_account_info();
69 | let cpi_accounts = TransferChecked {
70 | from: ctx.accounts.authority_token_account.to_account_info(),
71 | mint: ctx.accounts.mint.to_account_info(),
72 | to: ctx.accounts.wallet_token_account.to_account_info(),
73 | authority: ctx.accounts.authority.to_account_info(),
74 | };
75 |
76 | let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
77 |
78 | transfer_checked(cpi_ctx, amount, ctx.accounts.mint.decimals)?;
79 |
80 | Ok(())
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/escrow_ix/init_wallet.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | use crate::{
4 | constants::{SEED_PREFIX, SEED_WALLET},
5 | Wallet,
6 | };
7 |
8 | /// Initialize user escrow wallet
9 | ///
10 | /// ### Accounts:
11 | ///
12 | /// 1. `[writeable, signer]` authority
13 | /// 2. `[writeable]` wallet
14 | /// 3. `[]` system program
15 | ///
16 | #[derive(Accounts)]
17 | pub struct InitWallet<'info> {
18 | #[account(mut)]
19 | pub authority: Signer<'info>,
20 |
21 | #[account(
22 | init,
23 | payer = authority,
24 | space = Wallet::LEN,
25 | seeds = [SEED_PREFIX, SEED_WALLET, authority.key().as_ref()],
26 | bump
27 | )]
28 | pub wallet: Account<'info, Wallet>,
29 |
30 | pub system_program: Program<'info, System>,
31 | }
32 |
33 | impl InitWallet<'_> {
34 | /// validation helper for our IX
35 | pub fn validate(&self) -> Result<()> {
36 | return Ok(());
37 | }
38 |
39 | /// Initialize our escrow marketplace wallet
40 | ///
41 | #[access_control(ctx.accounts.validate())]
42 | pub fn init_wallet(ctx: Context) -> Result<()> {
43 | let wallet = &mut ctx.accounts.wallet;
44 |
45 | **wallet = Wallet::new(&ctx.accounts.authority.key(), ctx.bumps.wallet);
46 |
47 | Ok(())
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/escrow_ix/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod deposit_sol;
2 | pub mod deposit_token;
3 | pub mod init_wallet;
4 | pub mod withdraw_sol;
5 | pub mod withdraw_token;
6 |
7 | pub use deposit_sol::*;
8 | pub use deposit_token::*;
9 | pub use init_wallet::*;
10 | pub use withdraw_sol::*;
11 | pub use withdraw_token::*;
12 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/escrow_ix/withdraw_sol.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::{prelude::*, system_program::System};
2 |
3 | use crate::{error::ListErrorCode, Wallet};
4 |
5 | #[derive(AnchorSerialize, AnchorDeserialize)]
6 | pub struct WithdrawSolParams {
7 | /// amount to withdraw in lamports
8 | pub amount: u64,
9 | }
10 |
11 | /// Withdraw SOL from escrow wallet managed by the program.
12 | ///
13 | /// ### Accounts:
14 | ///
15 | /// 1. `[writeable, signer]` payer
16 | /// 2. `[writeable]` authority
17 | /// 3. `[writeable]` wallet
18 | /// 4. `[]` system program
19 | ///
20 | /// ### Parameters
21 | ///
22 | /// 1. params: [WithdrawSolParams]
23 | ///
24 | #[derive(Accounts)]
25 | pub struct WithdrawSol<'info> {
26 | #[account(mut)]
27 | pub payer: Signer<'info>,
28 |
29 | /// CHECK: checked in the ix
30 | #[account(
31 | mut,
32 | address = wallet.authority @ ListErrorCode::InvalidAuthority
33 | )]
34 | pub authority: UncheckedAccount<'info>,
35 |
36 | #[account(mut)]
37 | pub wallet: Account<'info, Wallet>,
38 |
39 | pub system_program: Program<'info, System>,
40 | }
41 |
42 | impl WithdrawSol<'_> {
43 | /// validation helper for our IX
44 | pub fn validate(&self) -> Result<()> {
45 | return Ok(());
46 | }
47 |
48 | /// Deposit native sol into user's wallet
49 | ///
50 | /// todo(Jimii): withdraw to another wallet per user's request
51 | #[access_control(ctx.accounts.validate())]
52 | pub fn withdraw_sol(
53 | ctx: Context,
54 | params: Option,
55 | ) -> Result<()> {
56 | let wallet = &mut ctx.accounts.wallet;
57 |
58 | if let Some(WithdrawSolParams { amount }) = params {
59 | if amount > wallet.get_lamports() {
60 | return Err(error!(ListErrorCode::InsufficientFunds));
61 | }
62 |
63 | // transfer requested amount
64 | wallet.sub_lamports(amount)?;
65 | ctx.accounts.authority.add_lamports(amount)?;
66 |
67 | return Ok(());
68 | }
69 |
70 | // else close account and return everything to user
71 | wallet.close(ctx.accounts.authority.to_account_info())?;
72 |
73 | Ok(())
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/escrow_ix/withdraw_token.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use anchor_spl::{
3 | associated_token::AssociatedToken,
4 | token::{transfer_checked, Mint, Token, TokenAccount, TransferChecked},
5 | };
6 |
7 | use crate::{
8 | constants::{SEED_PREFIX, SEED_WALLET},
9 | error::ListErrorCode,
10 | Wallet,
11 | };
12 |
13 | #[derive(AnchorSerialize, AnchorDeserialize)]
14 | pub struct WithdrawTokenParams {
15 | /// amount to withdraw in lamports
16 | pub amount: u64,
17 | }
18 |
19 | /// Withdraw Tokens from escrow wallet managed by the list program
20 | ///
21 | /// ### Accounts:
22 | /// 1. `[writeable, signer]` payer
23 | /// 2. `[writeable]` authority
24 | /// 3. `[writeable]` wallet
25 | /// 4. `[writeable, optional]` mint
26 | /// 5. `[writeable, optional]` authority associated token address
27 | /// 6. `[writeable, optional]` wallet associated token address
28 | /// 7. `[]` token program
29 | /// 8. `[]` associated token program
30 | /// 9. `[]` system program
31 | ///
32 | /// ### Parameters
33 | ///
34 | /// 1. params: [WithdrawTokenParams]
35 | ///
36 | #[derive(Accounts)]
37 | pub struct WithdrawToken<'info> {
38 | #[account(mut)]
39 | pub payer: Signer<'info>,
40 |
41 | /// CHECK: checked in the ix
42 | #[account(
43 | mut,
44 | address = wallet.authority @ ListErrorCode::InvalidAuthority
45 | )]
46 | pub authority: UncheckedAccount<'info>,
47 |
48 | #[account(mut)]
49 | pub wallet: Account<'info, Wallet>,
50 |
51 | #[account(mut)]
52 | pub mint: Account<'info, Mint>,
53 |
54 | #[account(mut)]
55 | pub authority_token_account: Account<'info, TokenAccount>,
56 |
57 | #[account(mut)]
58 | pub wallet_token_account: Account<'info, TokenAccount>,
59 |
60 | pub token_program: Program<'info, Token>,
61 | pub associated_token_program: Program<'info, AssociatedToken>,
62 | pub system_program: Program<'info, System>,
63 | }
64 |
65 | impl WithdrawToken<'_> {
66 | /// validation helper for our IX
67 | pub fn validate(&self) -> Result<()> {
68 | return Ok(());
69 | }
70 |
71 | /// Deposit native sol into user's wallet
72 | ///
73 | /// todo(Jimii): withdraw to another wallet per user's request
74 | #[access_control(ctx.accounts.validate())]
75 | pub fn withdraw_token(ctx: Context, params: WithdrawTokenParams) -> Result<()> {
76 | let wallet = &mut ctx.accounts.wallet;
77 | let authority = &mut ctx.accounts.authority;
78 | let WithdrawTokenParams { amount } = params;
79 |
80 | // sanity check
81 | if amount == 0 {
82 | return Err(error!(ListErrorCode::ZeroValueNotAllowed));
83 | }
84 |
85 | let bump = &[wallet.bump];
86 | let signer_seeds = &[&[SEED_PREFIX, SEED_WALLET, authority.key.as_ref(), bump][..]];
87 |
88 | let cpi_program = ctx.accounts.token_program.to_account_info();
89 | let cpi_accounts = TransferChecked {
90 | from: ctx.accounts.wallet_token_account.to_account_info(),
91 | mint: ctx.accounts.mint.to_account_info(),
92 | to: ctx.accounts.authority_token_account.to_account_info(),
93 | authority: wallet.to_account_info(),
94 | };
95 |
96 | let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds);
97 |
98 | transfer_checked(cpi_ctx, amount, ctx.accounts.mint.decimals)?;
99 |
100 | Ok(())
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/list.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use mpl_core::instructions::TransferV1CpiBuilder;
3 |
4 | use crate::{
5 | constants::{SEED_LISTING_DATA, SEED_PREFIX},
6 | helpers::Core,
7 | AssetManager, ListingData, PaymentOption,
8 | };
9 |
10 | #[derive(AnchorSerialize, AnchorDeserialize)]
11 | pub struct ListAssetParams {
12 | /// listing amount/price in lamports
13 | pub amount: u64,
14 |
15 | /// which method can be used to purchase the listed asset
16 | pub payment_option: PaymentOption,
17 | }
18 |
19 | /// LIST an MPL core asset on soundwork
20 | ///
21 | /// ### Accounts:
22 | ///
23 | /// 1. `[writeable, signer]` payer
24 | /// 2. `[writeable]` asset
25 | /// 3. `[writeable]` listing data account
26 | /// 4. `[]` asset manager
27 | /// 5. `[]` core program
28 | /// 6. `[]` system program
29 | ///
30 | /// ### Parameters
31 | ///
32 | /// 1. params: [ListTokenParams]
33 | ///
34 | #[derive(Accounts)]
35 | #[instruction(params: ListAssetParams)]
36 | pub struct ListAsset<'info> {
37 | #[account(mut)]
38 | pub payer: Signer<'info>,
39 |
40 | /// CHECK: checked by us
41 | #[account(mut)]
42 | pub asset: AccountInfo<'info>,
43 |
44 | /// CHECK: checked by us
45 | #[account(
46 | init,
47 | payer = payer,
48 | space = ListingData::LEN,
49 | seeds = [SEED_PREFIX, SEED_LISTING_DATA, asset.key().as_ref()],
50 | bump
51 | )]
52 | pub listing_data: Account<'info, ListingData>,
53 |
54 | pub asset_manager: Account<'info, AssetManager>,
55 |
56 | /// CHECK: checked by us
57 | #[account(mut)]
58 | pub collection: Option>,
59 |
60 | pub core_program: Program<'info, Core>,
61 |
62 | pub system_program: Program<'info, System>,
63 | }
64 |
65 | impl ListAsset<'_> {
66 | /// validation helper for our IX
67 | pub fn validate(&self) -> Result<()> {
68 | return Ok(());
69 | }
70 |
71 | /// list MPL core asset on the marketplace
72 | ///
73 | #[access_control(ctx.accounts.validate())]
74 | pub fn list_asset(ctx: Context, params: ListAssetParams) -> Result<()> {
75 | let listing_data = &mut ctx.accounts.listing_data;
76 |
77 | **listing_data = ListingData::new(
78 | ctx.bumps.listing_data,
79 | params.amount,
80 | ctx.accounts.payer.key(),
81 | ctx.accounts.asset.key(),
82 | params.payment_option,
83 | );
84 |
85 | // transfer to assetManager
86 |
87 | TransferV1CpiBuilder::new(&ctx.accounts.core_program)
88 | .asset(&ctx.accounts.asset)
89 | .payer(&ctx.accounts.payer)
90 | .authority(Some(&ctx.accounts.payer))
91 | .collection(ctx.accounts.collection.as_ref())
92 | .new_owner(&ctx.accounts.asset_manager.to_account_info())
93 | .system_program(Some(&ctx.accounts.system_program))
94 | .invoke()?;
95 |
96 | Ok(())
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod admin;
2 | pub mod buy_listing;
3 | pub mod escrow_ix;
4 | pub mod list;
5 | pub mod unlist;
6 | pub mod update_listing;
7 |
8 | pub use admin::*;
9 | pub use buy_listing::*;
10 | pub use escrow_ix::*;
11 | pub use list::*;
12 | pub use unlist::*;
13 | pub use update_listing::*;
14 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/unlist.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 | use mpl_core::instructions::TransferV1CpiBuilder;
3 |
4 | use crate::{constants::SEED_PREFIX, helpers::Core, AssetManager, ListingData, SEED_ASSET_MANAGER};
5 |
6 | /// Un-list an MPL core asset on soundwork
7 | ///
8 | /// ### Accounts
9 | ///
10 | /// 1. `[writable, signer]` payer
11 | /// 2. `[writable]` asset
12 | /// 3. `[writable]` collection
13 | /// 4. `[writable]` listing data account
14 | /// 5. `[]` asset manager
15 | /// 6. `[]` core program
16 | /// 7. `[]` system program
17 | ///
18 | #[derive(Accounts)]
19 | pub struct UnListAsset<'info> {
20 | #[account(mut, address = listing_data.authority)]
21 | pub payer: Signer<'info>,
22 |
23 | /// CHECK: checked by us
24 | #[account(mut)]
25 | pub asset: AccountInfo<'info>,
26 |
27 | /// CHECK: checked by us
28 | #[account(mut)]
29 | pub collection: Option>,
30 |
31 | #[account(mut, close = payer)]
32 | pub listing_data: Account<'info, ListingData>,
33 |
34 | pub asset_manager: Account<'info, AssetManager>,
35 |
36 | pub core_program: Program<'info, Core>,
37 |
38 | pub system_program: Program<'info, System>,
39 | }
40 |
41 | impl UnListAsset<'_> {
42 | /// validation helper for our IX
43 | pub fn validate(&self, ctx: &Context) -> Result<()> {
44 | let asset_manager = Pubkey::create_program_address(
45 | &[
46 | SEED_PREFIX,
47 | SEED_ASSET_MANAGER,
48 | &[ctx.accounts.asset_manager.bump],
49 | ],
50 | &ctx.program_id,
51 | )
52 | .unwrap();
53 |
54 | assert_eq!(asset_manager, ctx.accounts.asset_manager.key());
55 |
56 | return Ok(());
57 | }
58 |
59 | /// un-list MPL core asset on the marketplace
60 | ///
61 | #[access_control(ctx.accounts.validate(&ctx))]
62 | pub fn unlist(ctx: Context) -> Result<()> {
63 | let asset_manager = &ctx.accounts.asset_manager;
64 | // asset manager signer seeds
65 | let bump = &[asset_manager.bump];
66 | let signer_seeds = &[&[SEED_PREFIX, SEED_ASSET_MANAGER, bump][..]];
67 |
68 | // transfer asset back to owner
69 | TransferV1CpiBuilder::new(&ctx.accounts.core_program)
70 | .asset(&ctx.accounts.asset)
71 | .collection(ctx.accounts.collection.as_ref())
72 | .payer(&ctx.accounts.payer)
73 | .authority(Some(&asset_manager.to_account_info()))
74 | .new_owner(&ctx.accounts.payer.to_account_info())
75 | .system_program(Some(&ctx.accounts.system_program))
76 | .invoke_signed(signer_seeds)?;
77 |
78 | Ok(())
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/instructions/update_listing.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | use crate::{helpers::Core, AssetManager, ListingData};
4 |
5 | #[derive(AnchorSerialize, AnchorDeserialize)]
6 | pub struct UpdateListingParams {
7 | /// edit listing amount/price in lamports
8 | pub amount: u64,
9 | }
10 |
11 | /// update a listed MPL core asset
12 | ///
13 | /// ### Accounts:
14 | ///
15 | /// 1. `[writeable, signer]` payer
16 | /// 2. `[writeable]` asset
17 | /// 3. `[writeable]` listing data account
18 | /// 4. `[]` asset manager
19 | /// 5. `[]` core program
20 | /// 6. `[]` system program
21 | ///
22 | /// ### Params
23 | ///
24 | /// 1. params: [UpdateListingParams]
25 | ///
26 | #[derive(Accounts)]
27 | #[instruction(params: UpdateListingParams)]
28 | pub struct UpdateListing<'info> {
29 | #[account(mut)]
30 | pub payer: Signer<'info>,
31 |
32 | /// CHECK: checked by us
33 | #[account(mut)]
34 | pub asset: AccountInfo<'info>,
35 |
36 | /// CHECK: checked by us
37 | #[account(mut)]
38 | pub listing_data: Account<'info, ListingData>,
39 |
40 | pub asset_manager: Account<'info, AssetManager>,
41 |
42 | pub core_program: Program<'info, Core>,
43 |
44 | pub system_program: Program<'info, System>,
45 | }
46 |
47 | impl UpdateListing<'_> {
48 | /// validation helper for our IX
49 | pub fn validate(&self) -> Result<()> {
50 | return Ok(());
51 | }
52 |
53 | /// list MPL core asset on the marketplace
54 | ///
55 | #[access_control(ctx.accounts.validate())]
56 | pub fn update_listing(ctx: Context, params: UpdateListingParams) -> Result<()> {
57 | let listing_data = &mut ctx.accounts.listing_data;
58 |
59 | listing_data.amount = ListingData::update_amount(params.amount);
60 |
61 | Ok(())
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod constants;
2 | pub mod error;
3 | pub mod helpers;
4 | pub mod instructions;
5 | pub mod state;
6 |
7 | use anchor_lang::prelude::*;
8 |
9 | #[allow(unused_imports)]
10 | use solana_security_txt::security_txt;
11 |
12 | pub use constants::*;
13 | pub use instructions::*;
14 | pub use state::*;
15 |
16 | declare_id!("EA4ptgF3TYjDBGYJApAoZoyCbCYw6P5mGU5noCe1Z97");
17 |
18 | #[cfg(not(feature = "no-entrypoint"))]
19 | security_txt! {
20 | name: "Soundwork List Program",
21 | project_url: "https://soundwork.io",
22 | contacts: "email:info@soundwork.io, twitter:@SoundworkSounds",
23 | policy: "https://github.com/SoundWorkLabs/marketplace-contracts/blob/master/SECURITY.md",
24 | preferred_languages: "en",
25 | source_code: "https://github.com/SoundWorkLabs/marketplace-contracts"
26 | }
27 |
28 | /// SOUNDWORK LIST
29 | ///
30 | #[program]
31 | pub mod soundwork_list {
32 |
33 | use super::*;
34 |
35 | /// Initialize asset manager escrow account.
36 | ///
37 | /// Note: Only admin address can call this function
38 | ///
39 | pub fn init_escrow_account(ctx: Context) -> Result<()> {
40 | InitEscrow::init_escrow(ctx)
41 | }
42 |
43 | /// Initialize marketplace config account.
44 | ///
45 | /// Note: Only admin address can call this function
46 | ///
47 | pub fn init_marketplace_config_account(
48 | ctx: Context,
49 | params: InitMarketPlaceConfigParams,
50 | ) -> Result<()> {
51 | InitMarketplaceConfig::init_marketplace_config(ctx, params)
52 | }
53 |
54 | /// Initialize user escrow wallet.
55 | ///
56 | pub fn init_user_escrow_wallet(ctx: Context) -> Result<()> {
57 | InitWallet::init_wallet(ctx)
58 | }
59 |
60 | /// Deposit SOL into the user escrow wallet.
61 | ///
62 | pub fn deposit_sol(ctx: Context, params: DepositSolParams) -> Result<()> {
63 | DepositSol::deposit_sol(ctx, params)
64 | }
65 |
66 | /// Withdraw SOL into the user's escrow wallet.
67 | ///
68 | pub fn withdraw_sol(
69 | ctx: Context,
70 | params: Option,
71 | ) -> Result<()> {
72 | WithdrawSol::withdraw_sol(ctx, params)
73 | }
74 |
75 | /// Deposit SOL into the user escrow wallet.
76 | ///
77 | pub fn deposit_token(ctx: Context, params: DepositTokenParams) -> Result<()> {
78 | DepositToken::deposit_token(ctx, params)
79 | }
80 |
81 | /// Withdraw tokens from the user escrow wallet.
82 | ///
83 | pub fn withdraw_token(ctx: Context, params: WithdrawTokenParams) -> Result<()> {
84 | WithdrawToken::withdraw_token(ctx, params)
85 | }
86 |
87 | /// List an MPL Core asset on Soundwork
88 | ///
89 | pub fn list_asset(ctx: Context, params: ListAssetParams) -> Result<()> {
90 | ListAsset::list_asset(ctx, params)
91 | }
92 |
93 | /// Remove MPL Core asset listed on our marketplace
94 | ///
95 | pub fn update_listing_amount(
96 | ctx: Context,
97 | params: UpdateListingParams,
98 | ) -> Result<()> {
99 | UpdateListing::update_listing(ctx, params)
100 | }
101 |
102 | /// Remove MPL Core asset listed on our marketplace
103 | ///
104 | pub fn unlist_asset(ctx: Context) -> Result<()> {
105 | UnListAsset::unlist(ctx)
106 | }
107 |
108 | /// Buy MPL Core asset listed on our marketplace
109 | ///
110 | pub fn buy_asset(ctx: Context, params: Option) -> Result<()> {
111 | BuyAsset::buy_asset(ctx, params)
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/state/escrow.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[account]
4 | pub struct AssetManager {
5 | /// PDA bump
6 | pub bump: u8,
7 |
8 | /// Unused reserved byte space for additive future changes.
9 | pub _reserved: [u8; 128],
10 | }
11 |
12 | impl AssetManager {
13 | pub const LEN: usize =
14 | 8 + // anchor account discriminator
15 | 1 + // PDA bump
16 | 130 // reserved space
17 | ;
18 | }
--------------------------------------------------------------------------------
/programs/soundwork-list/src/state/listing.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | /// When listed, how does the user want to receive funds
4 | ///
5 | #[derive(AnchorSerialize, AnchorDeserialize, Default, Clone)]
6 | pub enum PaymentOption {
7 | #[default]
8 | Native,
9 | Token {
10 | mint: Pubkey,
11 | },
12 | // todo(both) a combination of tokens and sol
13 | }
14 |
15 | #[account]
16 | pub struct ListingData {
17 | /// PDA bump
18 | pub bump: u8,
19 |
20 | /// amount in lamports asset is being listed for
21 | pub amount: u64,
22 |
23 | /// asset owner
24 | pub authority: Pubkey,
25 |
26 | /// asset address
27 | pub asset_address: Pubkey,
28 |
29 | /// type of way user wants to get paid when listing is bought / bid made for asset
30 | pub payment_option: PaymentOption,
31 |
32 | /// Unused reserved byte space for additive future changes.
33 | pub _reserved: [u8; 128],
34 | }
35 |
36 | impl ListingData {
37 | pub const LEN: usize = 8 // anchor discriminator
38 | + 1 // bump
39 | + 8 // amount
40 | + 32 // authority address
41 | + 32 // asset address
42 | + 33 // payment option
43 | + 128; // reserved
44 |
45 | /// instantiate the listing data account with provided args
46 | pub fn new(
47 | bump: u8,
48 | amount: u64,
49 | authority: Pubkey,
50 | asset_address: Pubkey,
51 | payment_option: PaymentOption,
52 | ) -> Self {
53 | Self {
54 | bump,
55 | amount,
56 | authority,
57 | asset_address,
58 | payment_option,
59 | _reserved: [0; 128],
60 | }
61 | }
62 |
63 | // update listing data account
64 | pub fn update_amount(amount: u64) -> u64 {
65 | amount
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/state/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod escrow;
2 | pub mod listing;
3 | pub mod protocol;
4 | pub mod wallet;
5 |
6 | pub use escrow::*;
7 | pub use listing::*;
8 | pub use protocol::*;
9 | pub use wallet::*;
10 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/state/protocol.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[account]
4 | pub struct MarketPlaceConfig {
5 | /// PDA bump
6 | pub bump: u8,
7 |
8 | /// Taker fee percentage
9 | pub treasury_address: Pubkey,
10 |
11 | /// Taker fee basis points
12 | pub taker_fee_bps: u8,
13 |
14 | /// Unused reserved byte space for additive future changes.
15 | pub _reserved: [u8; 128],
16 | }
17 |
18 | impl MarketPlaceConfig {
19 | pub const LEN: usize = 8 + // anchor account discriminator
20 | 1 + // PDA bump
21 | 32 + // treasury address
22 | 1 + // taker fee percentage
23 | 130; // reserved space
24 |
25 | pub fn new(bump: u8, treasury_address: Pubkey, taker_fee_bps: u8) -> Self {
26 | Self {
27 | bump,
28 | treasury_address,
29 | taker_fee_bps,
30 | _reserved: [0; 128],
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/programs/soundwork-list/src/state/wallet.rs:
--------------------------------------------------------------------------------
1 | use anchor_lang::prelude::*;
2 |
3 | #[account]
4 | pub struct Wallet {
5 | pub authority: Pubkey,
6 | pub bump: u8,
7 | pub _reserved: [u8; 128],
8 | }
9 |
10 | impl Wallet {
11 | pub const LEN: usize = 8 // discriminator
12 | + 32 // owner address
13 | + 1 // wallet bump
14 | + 130; // reserved space
15 |
16 | // todo: (Jimii) should size be changed to accommodate paying with tokens"
17 | pub fn new(authority: &Pubkey, bump: u8) -> Self {
18 | Self {
19 | authority: authority.to_owned(),
20 | bump,
21 | _reserved: [0; 128],
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/unit/soundwork-bid.ts:
--------------------------------------------------------------------------------
1 | import { AnchorProvider, setProvider } from "@coral-xyz/anchor";
2 |
3 | import {
4 | ASSOCIATED_TOKEN_PROGRAM_ID,
5 | getAssociatedTokenAddressSync,
6 | TOKEN_PROGRAM_ID,
7 | } from "@solana/spl-token";
8 | import {
9 | Keypair,
10 | LAMPORTS_PER_SOL,
11 | sendAndConfirmTransaction,
12 | SystemProgram,
13 | Transaction,
14 | } from "@solana/web3.js";
15 | import { BN } from "bn.js";
16 | import {
17 | asset,
18 | CORE_PROGRAM_ID,
19 | PAYMENT_MINT,
20 | SOUNDWORK_LIST_ID,
21 | } from "../utils/constants";
22 | import { KeyPairFile, loadKeypair } from "../utils/helpers";
23 | import {
24 | findAssetManagerAddress,
25 | findBidDataAddress,
26 | findListingDataAddress,
27 | findMarketplaceConfigAddress,
28 | findWalletAddress,
29 | } from "../utils/pda";
30 | import { BidProgram, ListProgram } from "../utils/programs";
31 |
32 | describe("BID PROGRAM", () => {
33 | // get the signer keypairs
34 | let signer = loadKeypair(KeyPairFile.main); // used as treasury
35 |
36 | let seller = loadKeypair(KeyPairFile.main);
37 | let bidder = loadKeypair(KeyPairFile.secondary);
38 |
39 | // instantiate List Program,
40 | const listProgram = new ListProgram().getProgram();
41 | // const program = listProgram.getProgram();
42 |
43 | // instantiate BID Program,
44 | const bidProgram = new BidProgram();
45 | const program = bidProgram.getProgram();
46 |
47 | // --------------------------------------------------------------------------BID IXs
48 |
49 | // wants to be paid using tokens
50 | // it("Makes a bid on a listed asset!", async () => {
51 | // let expiryTs = new BN(new Date().getTime());
52 |
53 | // /* const initWalletIX = await listProgram.methods
54 | // .initUserEscrowWallet()
55 | // .accountsStrict({
56 | // authority: bidder.publicKey,
57 | // wallet: findWalletAddress(bidder.publicKey),
58 | // systemProgram: SystemProgram.programId,
59 | // })
60 | // .instruction();
61 | // */
62 | // const bidIX = await program.methods
63 | // .makeBid({
64 | // amount: new BN(1 * LAMPORTS_PER_SOL),
65 | // expiryTs,
66 | // })
67 | // .accountsStrict({
68 | // bidder: bidder.publicKey,
69 | // asset,
70 | // bidData: findBidDataAddress(asset),
71 | // bidderEscrowWallet: findWalletAddress(bidder.publicKey),
72 | // listingData: findListingDataAddress(asset),
73 | // paymentMint: PAYMENT_MINT,
74 | // bidderTokenAccount: getAssociatedTokenAddressSync(
75 | // PAYMENT_MINT,
76 | // bidder.publicKey
77 | // ),
78 | // // in sdk check that this is initialized and if not, call initialize wallet
79 | // // initializeBidderWalletAndBid()
80 | // walletTokenAccount: getAssociatedTokenAddressSync(
81 | // PAYMENT_MINT,
82 | // findWalletAddress(bidder.publicKey),
83 | // true
84 | // ),
85 | // soundworkList: SOUNDWORK_LIST_ID,
86 | // tokenProgram: TOKEN_PROGRAM_ID,
87 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
88 | // systemProgram: SystemProgram.programId,
89 | // })
90 | // .instruction();
91 |
92 | // const tx = new Transaction() /* .add(initWalletIX) */
93 | // .add(bidIX);
94 |
95 | // let txHash = await sendAndConfirmTransaction(
96 | // program.provider.connection,
97 | // tx,
98 | // [bidder],
99 | // {
100 | // skipPreflight: true,
101 | // }
102 | // );
103 |
104 | // console.log(
105 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
106 | // );
107 | // });
108 |
109 | // it("Edits a bid for a listed asset!", async () => {
110 | // let ix = await program.methods
111 | // .editBid({ amount: new BN(1000), expiryTs: null })
112 | // .accountsStrict({
113 | // bidder: bidder.publicKey,
114 | // asset,
115 | // bidData: findBidDataAddress(asset),
116 | // bidderEscrowWallet: findWalletAddress(bidder.publicKey),
117 | // listingData: findListingDataAddress(asset),
118 | // paymentMint: PAYMENT_MINT,
119 | // bidderTokenAccount: getAssociatedTokenAddressSync(
120 | // PAYMENT_MINT,
121 | // bidder.publicKey
122 | // ),
123 | // walletTokenAccount: getAssociatedTokenAddressSync(
124 | // PAYMENT_MINT,
125 | // findWalletAddress(bidder.publicKey),
126 | // true
127 | // ),
128 | // soundworkList: SOUNDWORK_LIST_ID,
129 | // tokenProgram: TOKEN_PROGRAM_ID,
130 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
131 | // systemProgram: SystemProgram.programId,
132 | // })
133 | // .instruction();
134 |
135 | // const tx = new Transaction().add(ix);
136 |
137 | // let txHash = await sendAndConfirmTransaction(
138 | // program.provider.connection,
139 | // tx,
140 | // [bidder],
141 | // {
142 | // skipPreflight: true,
143 | // }
144 | // );
145 |
146 | // console.log(
147 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
148 | // );
149 | // });
150 |
151 | // it("Revoked bid on a listed asset!", async () => {
152 | // let ix = await program.methods
153 | // .revokeBid()
154 | // .accountsStrict({
155 | // bidder: bidder.publicKey,
156 | // asset,
157 | // bidData: findBidDataAddress(asset),
158 | // bidderEscrowWallet: findWalletAddress(bidder.publicKey),
159 | // listingData: findListingDataAddress(asset),
160 | // paymentMint: PAYMENT_MINT,
161 | // bidderTokenAccount: getAssociatedTokenAddressSync(
162 | // PAYMENT_MINT,
163 | // bidder.publicKey
164 | // ),
165 | // walletTokenAccount: getAssociatedTokenAddressSync(
166 | // PAYMENT_MINT,
167 | // findWalletAddress(bidder.publicKey),
168 | // true
169 | // ),
170 | // soundworkList: SOUNDWORK_LIST_ID,
171 | // tokenProgram: TOKEN_PROGRAM_ID,
172 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
173 | // systemProgram: SystemProgram.programId,
174 | // })
175 | // .instruction();
176 |
177 | // const tx = new Transaction().add(ix);
178 |
179 | // let txHash = await sendAndConfirmTransaction(
180 | // program.provider.connection,
181 | // tx,
182 | // [bidder],
183 | // {
184 | // skipPreflight: true,
185 | // }
186 | // );
187 |
188 | // console.log(
189 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
190 | // );
191 | // });
192 |
193 | // it("Accepts a bid for a listed asset!", async () => {
194 | // let txHash = await program.methods
195 | // .acceptBid()
196 | // .accountsStrict({
197 | // seller: seller.publicKey,
198 | // bidder: bidder.publicKey,
199 | // asset,
200 | // bidData: findBidDataAddress(asset),
201 | // bidderEscrowWallet: findWalletAddress(bidder.publicKey),
202 | // listingData: findListingDataAddress(asset),
203 | // paymentMint: PAYMENT_MINT,
204 | // bidderTokenAccount: getAssociatedTokenAddressSync(
205 | // PAYMENT_MINT,
206 | // bidder.publicKey
207 | // ),
208 | // sellerTokenAccount: getAssociatedTokenAddressSync(
209 | // PAYMENT_MINT,
210 | // seller.publicKey
211 | // ),
212 | // walletTokenAccount: getAssociatedTokenAddressSync(
213 | // PAYMENT_MINT,
214 | // findWalletAddress(bidder.publicKey),
215 | // true
216 | // ),
217 | // treasuryTokenAccount: getAssociatedTokenAddressSync(
218 | // PAYMENT_MINT,
219 | // signer.publicKey
220 | // ),
221 | // treasury: signer.publicKey,
222 | // assetManager: findAssetManagerAddress(),
223 | // marketplaceConfig: findMarketplaceConfigAddress(),
224 | // soundworkList: SOUNDWORK_LIST_ID,
225 | // coreProgram: CORE_PROGRAM_ID,
226 | // tokenProgram: TOKEN_PROGRAM_ID,
227 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
228 | // systemProgram: SystemProgram.programId,
229 | // })
230 | // .rpc({ skipPreflight: true });
231 |
232 | // console.log(
233 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
234 | // );
235 | // });
236 |
237 | // it("Seller rejects bid on listed asset!", async () => {
238 | // let ix = await program.methods
239 | // .rejectBid()
240 | // .accountsStrict({
241 | // seller: seller.publicKey,
242 | // bidder: bidder.publicKey,
243 | // asset,
244 | // bidData: findBidDataAddress(asset),
245 | // bidderEscrowWallet: findWalletAddress(bidder.publicKey),
246 | // listingData: findListingDataAddress(asset),
247 | // paymentMint: PAYMENT_MINT,
248 | // bidderTokenAccount: getAssociatedTokenAddressSync(
249 | // PAYMENT_MINT,
250 | // bidder.publicKey
251 | // ),
252 | // walletTokenAccount: getAssociatedTokenAddressSync(
253 | // PAYMENT_MINT,
254 | // findWalletAddress(bidder.publicKey),
255 | // true
256 | // ),
257 | // soundworkList: SOUNDWORK_LIST_ID,
258 | // tokenProgram: TOKEN_PROGRAM_ID,
259 | // associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
260 | // systemProgram: SystemProgram.programId,
261 | // })
262 | // .rpc();
263 |
264 | // console.log(
265 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
266 | // );
267 | // });
268 | });
269 |
--------------------------------------------------------------------------------
/tests/unit/soundwork-create.ts:
--------------------------------------------------------------------------------
1 | import { Keypair, SystemProgram } from "@solana/web3.js";
2 | import { CORE_PROGRAM_ID } from "../utils/constants";
3 | import { KeyPairFile, loadKeypair } from "../utils/helpers";
4 | import { CreateProgram } from "../utils/programs";
5 |
6 | describe("CREATE PROGRAM", () => {
7 | // get the signer keypair
8 | let signer = loadKeypair(KeyPairFile.main);
9 |
10 | // instantiate CREATE Program, using default provider
11 | const createProgram = new CreateProgram();
12 | const program = createProgram.getProgram();
13 |
14 | it("Is Mints a Core Asset!", async () => {
15 | const asset = Keypair.generate();
16 |
17 | const metadata = {
18 | name: "Kobeni Supremacy",
19 | uri: "https://raw.githubusercontent.com/687c/solana-nft-native-client/main/metadata.json",
20 | };
21 |
22 | const txHash = await program.methods
23 | .create(metadata.name, metadata.uri)
24 | .accountsStrict({
25 | payer: signer.publicKey,
26 | systemProgram: SystemProgram.programId,
27 | asset: asset.publicKey,
28 | coreProgram: CORE_PROGRAM_ID,
29 | })
30 | .signers([asset])
31 | .rpc();
32 |
33 | console.log(
34 | `mint Address: https://explorer.solana.com/address/${asset.publicKey}?cluster=devnet\n`
35 | );
36 | console.log(
37 | `mint tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet`
38 | );
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/tests/unit/soundwork-list.ts:
--------------------------------------------------------------------------------
1 | import { AnchorProvider, setProvider } from "@coral-xyz/anchor";
2 |
3 | import { ASSOCIATED_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token";
4 | import {
5 | getAssociatedTokenAddressSync,
6 | TOKEN_PROGRAM_ID,
7 | } from "@solana/spl-token";
8 | import {
9 | Keypair,
10 | LAMPORTS_PER_SOL,
11 | PublicKey,
12 | SystemProgram,
13 | } from "@solana/web3.js";
14 | import { BN } from "bn.js";
15 | import { asset, CORE_PROGRAM_ID, PAYMENT_MINT } from "../utils/constants";
16 | import { KeyPairFile, loadKeypair } from "../utils/helpers";
17 | import {
18 | findAssetManagerAddress,
19 | findListingDataAddress,
20 | findMarketplaceConfigAddress,
21 | findWalletAddress,
22 | } from "../utils/pda";
23 | import { ListProgram } from "../utils/programs";
24 |
25 | describe("LIST PROGRAM", () => {
26 | // get the signer keypair
27 | let signer = loadKeypair(KeyPairFile.main);
28 |
29 | let seller = loadKeypair(KeyPairFile.main);
30 | let buyer = loadKeypair(KeyPairFile.secondary);
31 |
32 | // instantiate LIST Program, using default provider
33 | const listProgram = new ListProgram();
34 | const program = listProgram.getProgram();
35 |
36 | // ! get rid of me below
37 | // let asset = new PublicKey("H4gutS7fRDgb4c4sDhULvQ23PaN81d5qgQpkaapC7N8t");
38 |
39 | // --------------------------------------------------------------------------ADMIN IXs
40 |
41 | it("Initializes asset manager escrow account!", async () => {
42 | // const txHash = await program.methods
43 | // .initEscrowAccount()
44 | // .accountsStrict({
45 | // payer: signer.publicKey,
46 | // systemProgram: SystemProgram.programId,
47 | // assetManager: findAssetManagerAddress(),
48 | // coreProgram: CORE_PROGRAM_ID,
49 | // })
50 | // .rpc({skipPreflight: true});
51 | // console.log(
52 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
53 | // );
54 | });
55 |
56 | // it("Initializes Marketplace config account!", async () => {
57 | // const txHash = await program.methods
58 | // .initMarketplaceConfigAccount({
59 | // takerFeeBps: 1,
60 | // treasuryAddress: signer.publicKey, // todo: update me
61 | // })
62 | // .accountsStrict({
63 | // payer: signer.publicKey,
64 | // marketplaceConfig: findMarketplaceConfigAddress(),
65 | // systemProgram: SystemProgram.programId,
66 | // })
67 | // .rpc();
68 |
69 | // console.log(
70 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
71 | // );
72 | // });
73 |
74 | // --------------------------------------------------------------------------USER IXs
75 |
76 | // it("Initializes buyer wallet escrow account!", async () => {
77 | // const txHash = await program.methods
78 | // .initUserEscrowWallet()
79 | // .accountsStrict({
80 | // authority: buyer.publicKey,
81 | // wallet: findWalletAddress(buyer.publicKey),
82 | // systemProgram: SystemProgram.programId,
83 | // })
84 | // .signers([buyer])
85 | // .rpc();
86 |
87 | // console.log(
88 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
89 | // );
90 | // });
91 |
92 | // it("Deposits SOL to buyer escrow wallet!", async () => {
93 | // const txHash = await program.methods
94 | // .depositSol({ amount: new BN(1 * LAMPORTS_PER_SOL) })
95 | // .accountsStrict({
96 | // authority: buyer.publicKey,
97 | // wallet: findWalletAddress(buyer.publicKey),
98 | // systemProgram: SystemProgram.programId,
99 | // })
100 | // .signers([buyer])
101 | // .rpc();
102 |
103 | // console.log(
104 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
105 | // );
106 | // });
107 |
108 | // it("Withdraws SOL from buyer escrow wallet!", async () => {
109 | // const txHash = await program.methods
110 | // .withdrawSol({ amount: new BN(0.01 * LAMPORTS_PER_SOL) })
111 | // .accountsStrict({
112 | // payer: buyer.publicKey,
113 | // authority: buyer.publicKey,
114 | // wallet: findWalletAddress(buyer.publicKey),
115 | // systemProgram: SystemProgram.programId,
116 | // })
117 | // .signers([buyer])
118 | // .rpc();
119 |
120 | // console.log(
121 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
122 | // );
123 | // });
124 |
125 | // it("Deposits Tokens to buyer escrow wallet!", async () => {
126 | // const txHash = await program.methods
127 | // .depositToken({ amount: new BN(1_000_000) }) // with 6 decimals, this is 1 USDC dev coin
128 | // .accountsStrict({
129 | // authority: buyer.publicKey,
130 | // wallet: findWalletAddress(buyer.publicKey),
131 | // mint: PAYMENT_MINT,
132 | // authorityTokenAccount: getAssociatedTokenAddressSync(
133 | // PAYMENT_MINT,
134 | // buyer.publicKey
135 | // ),
136 | // walletTokenAccount: getAssociatedTokenAddressSync(
137 | // PAYMENT_MINT,
138 | // findWalletAddress(buyer.publicKey),
139 | // true
140 | // ),
141 | // tokenProgram: TOKEN_PROGRAM_ID,
142 | // associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
143 | // systemProgram: SystemProgram.programId,
144 | // })
145 | // .signers([buyer])
146 | // .rpc({ skipPreflight: true });
147 |
148 | // console.log(
149 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
150 | // );
151 | // });
152 |
153 | // it("Withdraws Tokens from buyer escrow wallet", async () => {
154 | // const txHash = await program.methods
155 | // .withdrawToken({ amount: new BN(1) })
156 | // .accountsStrict({
157 | // payer: buyer.publicKey,
158 | // authority: buyer.publicKey,
159 | // wallet: findWalletAddress(buyer.publicKey),
160 | // mint: PAYMENT_MINT,
161 | // authorityTokenAccount: getAssociatedTokenAddressSync(
162 | // PAYMENT_MINT,
163 | // buyer.publicKey
164 | // ),
165 | // walletTokenAccount: getAssociatedTokenAddressSync(
166 | // PAYMENT_MINT,
167 | // findWalletAddress(buyer.publicKey),
168 | // true
169 | // ),
170 | // tokenProgram: TOKEN_PROGRAM_ID,
171 | // associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
172 | // systemProgram: SystemProgram.programId,
173 | // })
174 | // .signers([buyer])
175 | // .rpc({ skipPreflight: true });
176 |
177 | // console.log(
178 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
179 | // );
180 | // });
181 |
182 | // --------------------------------------------------------------------------LIST IXs
183 |
184 | // it("Lists an MPL core asset with native payment option!", async () => {
185 | // const txHash = await program.methods
186 | // .listAsset({
187 | // amount: new BN(1_0000_000),
188 | // paymentOption: { native: {} },
189 | // })
190 | // .accountsStrict({
191 | // payer: signer.publicKey,
192 | // asset,
193 | // collection: null,
194 | // listingData: findListingDataAddress(asset),
195 | // assetManager: findAssetManagerAddress(),
196 | // coreProgram: CORE_PROGRAM_ID,
197 | // systemProgram: SystemProgram.programId,
198 | // })
199 | // .rpc({ skipPreflight: true });
200 |
201 | // console.log(
202 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
203 | // );
204 | // });
205 |
206 | // it("Lists an MPL core asset and uses tokens as payment option!", async () => {
207 | // const txHash = await program.methods
208 | // .listAsset({
209 | // amount: new BN(1_000_000), // 1 USDC dev
210 | // paymentOption: { token: { mint: PAYMENT_MINT } },
211 | // })
212 | // .accountsStrict({
213 | // payer: signer.publicKey,
214 | // asset,
215 | // collection: null,
216 | // listingData: findListingDataAddress(asset),
217 | // assetManager: findAssetManagerAddress(),
218 | // coreProgram: CORE_PROGRAM_ID,
219 | // systemProgram: SystemProgram.programId,
220 | // })
221 | // .rpc({ skipPreflight: true });
222 |
223 | // console.log(
224 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
225 | // );
226 | // });
227 |
228 | // it("UnLists an MPL core asset!", async () => {
229 | // const txHash = await program.methods
230 | // .unlistAsset()
231 | // .accountsStrict({
232 | // payer: signer.publicKey,
233 | // asset,
234 | // collection: null,
235 | // listingData: findListingDataAddress(asset),
236 | // assetManager: findAssetManagerAddress(),
237 | // coreProgram: CORE_PROGRAM_ID,
238 | // systemProgram: SystemProgram.programId,
239 | // })
240 | // .rpc({ skipPreflight: true });
241 |
242 | // console.log(
243 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
244 | // );
245 | // });
246 |
247 | // it("Buys a listed NFT using Native SOL!", async () => {
248 | // const txHash = await program.methods
249 | // .buyAsset(null) // ! fails as expected
250 | // .accountsStrict({
251 | // payer: buyer.publicKey,
252 | // buyer: buyer.publicKey,
253 | // seller: seller.publicKey,
254 | // walletAsBuyer: null,
255 | // asset,
256 | // collection: null,
257 | // paymentMint: null,
258 | // walletTokenAccount: null,
259 | // buyerTokenAccount: null,
260 | // sellerTokenAccount: null,
261 | // treasuryTokenAccount: null, // ! update to correct address
262 | // treasury: signer.publicKey, // ! update to correct address
263 | // listingData: findListingDataAddress(asset),
264 | // assetManager: findAssetManagerAddress(),
265 | // marketplaceConfig: findMarketplaceConfigAddress(),
266 | // coreProgram: CORE_PROGRAM_ID,
267 | // tokenProgram: TOKEN_PROGRAM_ID,
268 | // associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
269 | // systemProgram: SystemProgram.programId,
270 | // })
271 | // .signers([buyer])
272 | // .rpc({ skipPreflight: true });
273 |
274 | // console.log(
275 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
276 | // );
277 | // });
278 |
279 | // it("Buys a listed NFT using Tokens using Escrow Wallet!", async () => {
280 | // const txHash = await program.methods
281 | // .buyAsset(null) // ! fails as expected
282 | // // .buyAsset({ bidAmount: new BN(1_000_000) }) // ! works, but this is for seller when accepting bids
283 | // .accountsStrict({
284 | // payer: buyer.publicKey,
285 | // buyer: buyer.publicKey,
286 | // seller: seller.publicKey,
287 | // walletAsBuyer: findWalletAddress(buyer.publicKey),
288 | // asset,
289 | // collection: null,
290 | // paymentMint: PAYMENT_MINT,
291 | // walletTokenAccount: getAssociatedTokenAddressSync(
292 | // PAYMENT_MINT,
293 | // findWalletAddress(buyer.publicKey),
294 | // true
295 | // ),
296 | // buyerTokenAccount: getAssociatedTokenAddressSync(
297 | // PAYMENT_MINT,
298 | // buyer.publicKey
299 | // ),
300 | // sellerTokenAccount: getAssociatedTokenAddressSync(
301 | // PAYMENT_MINT,
302 | // seller.publicKey
303 | // ),
304 | // treasuryTokenAccount: getAssociatedTokenAddressSync(
305 | // PAYMENT_MINT,
306 | // signer.publicKey
307 | // ), // ! update to correct address
308 | // treasury: signer.publicKey, // ! update to correct address
309 | // listingData: findListingDataAddress(asset),
310 | // assetManager: findAssetManagerAddress(),
311 | // marketplaceConfig: findMarketplaceConfigAddress(),
312 | // coreProgram: CORE_PROGRAM_ID,
313 | // tokenProgram: TOKEN_PROGRAM_ID,
314 | // associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
315 | // systemProgram: SystemProgram.programId,
316 | // })
317 | // .signers([buyer])
318 | // .rpc({ skipPreflight: true });
319 |
320 | // console.log(
321 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
322 | // );
323 | // });
324 |
325 | // it("Buys a listed NFT using Tokens!", async () => {
326 | // const txHash = await program.methods
327 | // .buyAsset(null) // ! fails as expected
328 | // .accountsStrict({
329 | // payer: buyer.publicKey,
330 | // buyer: buyer.publicKey,
331 | // seller: seller.publicKey,
332 | // walletAsBuyer: null,
333 |
334 | // asset,
335 | // paymentMint: PAYMENT_MINT,
336 | // walletTokenAccount: null,
337 | // buyerTokenAccount: getAssociatedTokenAddressSync(
338 | // PAYMENT_MINT,
339 | // buyer.publicKey
340 | // ),
341 | // sellerTokenAccount: getAssociatedTokenAddressSync(
342 | // PAYMENT_MINT,
343 | // seller.publicKey
344 | // ),
345 | // treasuryTokenAccount: getAssociatedTokenAddressSync(
346 | // PAYMENT_MINT,
347 | // signer.publicKey
348 | // ), // ! update to correct address
349 | // treasury: signer.publicKey, // ! update to correct address
350 | // listingData: findListingDataAddress(asset),
351 | // assetManager: findAssetManagerAddress(),
352 | // marketplaceConfig: findMarketplaceConfigAddress(),
353 | // coreProgram: CORE_PROGRAM_ID,
354 | // tokenProgram: TOKEN_PROGRAM_ID,
355 | // associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
356 | // systemProgram: SystemProgram.programId,
357 | // })
358 | // .signers([buyer])
359 | // .rpc({ skipPreflight: true });
360 |
361 | // console.log(
362 | // `tx: https://explorer.solana.com/tx/${txHash}?cluster=devnet\n`
363 | // );
364 | // });
365 | });
366 |
--------------------------------------------------------------------------------
/tests/utils/constants.ts:
--------------------------------------------------------------------------------
1 | import { AnchorProvider, Provider } from "@coral-xyz/anchor";
2 | import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
3 | import dotenv from "dotenv";
4 |
5 | dotenv.config();
6 |
7 | // const connection = new Connection(
8 | // `https://devnet.helius-rpc.com/?api-key=${process.env.HELIUS_API_KEY}`
9 | // );
10 |
11 | // eclipse endpoint
12 | const connection = new Connection(clusterApiUrl("devnet"));
13 |
14 | // default provider provided by Anchor.toml
15 | export const defaultProvider: Provider = new AnchorProvider(
16 | connection,
17 | AnchorProvider.env().wallet,
18 | AnchorProvider.defaultOptions()
19 | );
20 |
21 | // ------------------------------------------- programs
22 |
23 | export const SOUNDWORK_BID_ID = new PublicKey(
24 | "4mFDYND4AVREYEJXCPhjq1LnbjELHHebJqG3NZechA7X"
25 | );
26 | export const SOUNDWORK_CREATE_ID = new PublicKey(
27 | "4iraDthfMHkgrvWsLz4mfCyHJY4JKc31TTxGMZKrc6r8"
28 | );
29 | export const SOUNDWORK_LIST_ID = new PublicKey(
30 | "EA4ptgF3TYjDBGYJApAoZoyCbCYw6P5mGU5noCe1Z97"
31 | );
32 |
33 | // external programs
34 | export const CORE_PROGRAM_ID = new PublicKey(
35 | "CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d"
36 | );
37 |
38 | // ------------------------------------------- seeds
39 | export const SEED_PREFIX = "Kessoku";
40 |
41 | export const ASSET_MANAGER_PREFIX = "Seika";
42 |
43 | export const SEED_LISTING_DATA = "Hitori";
44 |
45 | export const SEED_MARKETPLACE_CONFIG = "Ijichi";
46 |
47 | export const SEED_WALLET = "Yamada";
48 |
49 | export const SEED_BID_DATA = "Futari";
50 |
51 | // --------------------------------------------------- accounts
52 | export const PAYMENT_MINT = new PublicKey(
53 | "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr"
54 | ); // USDC - dev
55 |
56 | // ------------------------------------------------------- testing
57 | export let asset = new PublicKey(
58 | "AWASHVbTkP4rHhPgeKUJwEf3J4ngoqZsCv7VRZSW4ERf"
59 | );
60 |
--------------------------------------------------------------------------------
/tests/utils/helpers.ts:
--------------------------------------------------------------------------------
1 | import { Idl } from "@coral-xyz/anchor";
2 | import { Keypair } from "@solana/web3.js";
3 | import { readFileSync } from "fs";
4 | import { homedir } from "os";
5 |
6 | export function loadProgramIdl(program: SupportedPrograms): Idl {
7 | switch (program) {
8 | case "bid": {
9 | return JSON.parse(
10 | readFileSync(
11 | process.cwd() + "/target/idl/soundwork_bid.json",
12 | "utf8"
13 | )
14 | );
15 | }
16 | case "create": {
17 | return JSON.parse(
18 | readFileSync(
19 | process.cwd() + "/target/idl/soundwork_create.json",
20 | "utf8"
21 | )
22 | );
23 | }
24 | case "list": {
25 | return JSON.parse(
26 | readFileSync(
27 | process.cwd() + "/target/idl/soundwork_list.json",
28 | "utf8"
29 | )
30 | );
31 | }
32 | default: {
33 | console.log("error: unknown program");
34 | break;
35 | }
36 | }
37 | }
38 |
39 | type SupportedPrograms = "bid" | "create" | "list";
40 |
41 | export function loadKeypair(file: KeyPairFile): Keypair {
42 | const data = readFileSync(homedir() + `/.config/solana/${file}`, "utf-8");
43 |
44 | return Keypair.fromSecretKey(Buffer.from(JSON.parse(data)));
45 | }
46 |
47 | // ! change this accordingly
48 |
49 | export enum KeyPairFile {
50 | main = "id.json",
51 | secondary = "id-new.json",
52 | }
53 |
--------------------------------------------------------------------------------
/tests/utils/pda.ts:
--------------------------------------------------------------------------------
1 | import { PublicKey } from "@solana/web3.js";
2 | import {
3 | ASSET_MANAGER_PREFIX,
4 | SEED_BID_DATA,
5 | SEED_LISTING_DATA,
6 | SEED_MARKETPLACE_CONFIG,
7 | SEED_PREFIX,
8 | SEED_WALLET,
9 | SOUNDWORK_BID_ID,
10 | SOUNDWORK_LIST_ID,
11 | } from "./constants";
12 |
13 | /**
14 | * Derive the asset manager account address
15 | * @returns {PublicKey} The asset Manager Address.
16 | */
17 | export const findAssetManagerAddress = (): PublicKey => {
18 | return PublicKey.findProgramAddressSync(
19 | [Buffer.from(SEED_PREFIX), Buffer.from(ASSET_MANAGER_PREFIX)],
20 | SOUNDWORK_LIST_ID
21 | )[0];
22 | };
23 |
24 | /**
25 | * Derive the marketplace config account
26 | * @returns {PublicKey} listingData Address.
27 | */
28 | export const findMarketplaceConfigAddress = (): PublicKey => {
29 | return PublicKey.findProgramAddressSync(
30 | [Buffer.from(SEED_PREFIX), Buffer.from(SEED_MARKETPLACE_CONFIG)],
31 | SOUNDWORK_LIST_ID
32 | )[0];
33 | };
34 |
35 | /**
36 | * Derive the listing data account address
37 | * @param asset Asset address
38 | * @returns {PublicKey} listingData Address.
39 | */
40 | export const findListingDataAddress = (asset: PublicKey): PublicKey => {
41 | return PublicKey.findProgramAddressSync(
42 | [
43 | Buffer.from(SEED_PREFIX),
44 | Buffer.from(SEED_LISTING_DATA),
45 | asset.toBuffer(),
46 | ],
47 | SOUNDWORK_LIST_ID
48 | )[0];
49 | };
50 |
51 | /**
52 | * Derive the user wallet escrow address
53 | * @param authority user's address
54 | * @returns {PublicKey} listingData Address.
55 | */
56 | export const findWalletAddress = (authority: PublicKey): PublicKey => {
57 | return PublicKey.findProgramAddressSync(
58 | [
59 | Buffer.from(SEED_PREFIX),
60 | Buffer.from(SEED_WALLET),
61 | authority.toBuffer(),
62 | ],
63 | SOUNDWORK_LIST_ID
64 | )[0];
65 | };
66 |
67 | /**
68 | * Derive the bid data account address
69 | *
70 | * @param asset asset's address
71 | *
72 | * @returns {PublicKey} The bid data Address.
73 | */
74 | export const findBidDataAddress = (asset: PublicKey): PublicKey => {
75 | return PublicKey.findProgramAddressSync(
76 | [
77 | Buffer.from(SEED_PREFIX),
78 | Buffer.from(SEED_BID_DATA),
79 | asset.toBuffer(),
80 | ],
81 | SOUNDWORK_BID_ID
82 | )[0];
83 | };
84 |
--------------------------------------------------------------------------------
/tests/utils/programs.ts:
--------------------------------------------------------------------------------
1 | // our program instances
2 |
3 | import { AnchorProvider, Program, Provider } from "@coral-xyz/anchor";
4 |
5 | import type { SoundworkBid } from "../../target/types/soundwork_bid";
6 | import type { SoundworkCreate } from "../../target/types/soundwork_create";
7 | import type { SoundworkList } from "../../target/types/soundwork_list";
8 |
9 | // @ts-ignore
10 | import * as soundworkBidIDL from "../../target/idl/soundwork_bid.json";
11 | // @ts-ignore
12 | import * as soundworkCreateIDL from "../../target/idl/soundwork_create.json";
13 | // @ts-ignore
14 | import * as soundworkListIDL from "../../target/idl/soundwork_list.json";
15 |
16 | import {
17 | defaultProvider,
18 | SOUNDWORK_BID_ID,
19 | SOUNDWORK_CREATE_ID,
20 | SOUNDWORK_LIST_ID,
21 | } from "./constants";
22 | import { loadProgramIdl } from "./helpers";
23 |
24 | export class BidProgram {
25 | constructor(readonly provider: Provider = defaultProvider) {}
26 |
27 | getProgram(): Program {
28 | const idl = loadProgramIdl("bid");
29 |
30 | return new Program(
31 | soundworkBidIDL as unknown as soundworkBidIDL,
32 | this.provider
33 | );
34 | }
35 | }
36 |
37 | export class CreateProgram {
38 | constructor(readonly provider: Provider = defaultProvider) {}
39 |
40 | getProgram(): Program {
41 | return new Program(
42 | soundworkCreateIDL as unknown as SoundworkCreate,
43 | this.provider
44 | );
45 | }
46 | }
47 |
48 | export class ListProgram {
49 | constructor(readonly provider: Provider = defaultProvider) {}
50 |
51 | getProgram(): Program {
52 | return new Program(
53 | soundworkListIDL as unknown as SoundworkList,
54 | this.provider
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4":
6 | version "7.24.4"
7 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd"
8 | integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==
9 | dependencies:
10 | regenerator-runtime "^0.14.0"
11 |
12 | "@babel/runtime@^7.24.5":
13 | version "7.24.5"
14 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c"
15 | integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==
16 | dependencies:
17 | regenerator-runtime "^0.14.0"
18 |
19 | "@coral-xyz/anchor-errors@^0.30.1":
20 | version "0.30.1"
21 | resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30"
22 | integrity sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ==
23 |
24 | "@coral-xyz/anchor@^0.30.1":
25 | version "0.30.1"
26 | resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.30.1.tgz#17f3e9134c28cd0ea83574c6bab4e410bcecec5d"
27 | integrity sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ==
28 | dependencies:
29 | "@coral-xyz/anchor-errors" "^0.30.1"
30 | "@coral-xyz/borsh" "^0.30.1"
31 | "@noble/hashes" "^1.3.1"
32 | "@solana/web3.js" "^1.68.0"
33 | bn.js "^5.1.2"
34 | bs58 "^4.0.1"
35 | buffer-layout "^1.2.2"
36 | camelcase "^6.3.0"
37 | cross-fetch "^3.1.5"
38 | crypto-hash "^1.3.0"
39 | eventemitter3 "^4.0.7"
40 | pako "^2.0.3"
41 | snake-case "^3.0.4"
42 | superstruct "^0.15.4"
43 | toml "^3.0.0"
44 |
45 | "@coral-xyz/borsh@^0.30.1":
46 | version "0.30.1"
47 | resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.30.1.tgz#869d8833abe65685c72e9199b8688477a4f6b0e3"
48 | integrity sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ==
49 | dependencies:
50 | bn.js "^5.1.2"
51 | buffer-layout "^1.2.0"
52 |
53 | "@noble/curves@^1.2.0", "@noble/curves@^1.4.0":
54 | version "1.4.0"
55 | resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6"
56 | integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==
57 | dependencies:
58 | "@noble/hashes" "1.4.0"
59 |
60 | "@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3", "@noble/hashes@^1.4.0":
61 | version "1.4.0"
62 | resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426"
63 | integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==
64 |
65 | "@solana/buffer-layout-utils@^0.2.0":
66 | version "0.2.0"
67 | resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca"
68 | integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==
69 | dependencies:
70 | "@solana/buffer-layout" "^4.0.0"
71 | "@solana/web3.js" "^1.32.0"
72 | bigint-buffer "^1.1.5"
73 | bignumber.js "^9.0.1"
74 |
75 | "@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1":
76 | version "4.0.1"
77 | resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15"
78 | integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==
79 | dependencies:
80 | buffer "~6.0.3"
81 |
82 | "@solana/codecs-core@2.0.0-preview.2":
83 | version "2.0.0-preview.2"
84 | resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.2.tgz#689784d032fbc1fedbde40bb25d76cdcecf6553b"
85 | integrity sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg==
86 | dependencies:
87 | "@solana/errors" "2.0.0-preview.2"
88 |
89 | "@solana/codecs-data-structures@2.0.0-preview.2":
90 | version "2.0.0-preview.2"
91 | resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.2.tgz#e82cb1b6d154fa636cd5c8953ff3f32959cc0370"
92 | integrity sha512-Xf5vIfromOZo94Q8HbR04TbgTwzigqrKII0GjYr21K7rb3nba4hUW2ir8kguY7HWFBcjHGlU5x3MevKBOLp3Zg==
93 | dependencies:
94 | "@solana/codecs-core" "2.0.0-preview.2"
95 | "@solana/codecs-numbers" "2.0.0-preview.2"
96 | "@solana/errors" "2.0.0-preview.2"
97 |
98 | "@solana/codecs-numbers@2.0.0-preview.2":
99 | version "2.0.0-preview.2"
100 | resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.2.tgz#56995c27396cd8ee3bae8bd055363891b630bbd0"
101 | integrity sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw==
102 | dependencies:
103 | "@solana/codecs-core" "2.0.0-preview.2"
104 | "@solana/errors" "2.0.0-preview.2"
105 |
106 | "@solana/codecs-strings@2.0.0-preview.2":
107 | version "2.0.0-preview.2"
108 | resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.2.tgz#8bd01a4e48614d5289d72d743c3e81305d445c46"
109 | integrity sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g==
110 | dependencies:
111 | "@solana/codecs-core" "2.0.0-preview.2"
112 | "@solana/codecs-numbers" "2.0.0-preview.2"
113 | "@solana/errors" "2.0.0-preview.2"
114 |
115 | "@solana/codecs@2.0.0-preview.2":
116 | version "2.0.0-preview.2"
117 | resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.2.tgz#d6615fec98f423166fb89409f9a4ad5b74c10935"
118 | integrity sha512-4HHzCD5+pOSmSB71X6w9ptweV48Zj1Vqhe732+pcAQ2cMNnN0gMPMdDq7j3YwaZDZ7yrILVV/3+HTnfT77t2yA==
119 | dependencies:
120 | "@solana/codecs-core" "2.0.0-preview.2"
121 | "@solana/codecs-data-structures" "2.0.0-preview.2"
122 | "@solana/codecs-numbers" "2.0.0-preview.2"
123 | "@solana/codecs-strings" "2.0.0-preview.2"
124 | "@solana/options" "2.0.0-preview.2"
125 |
126 | "@solana/errors@2.0.0-preview.2":
127 | version "2.0.0-preview.2"
128 | resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.2.tgz#e0ea8b008c5c02528d5855bc1903e5e9bbec322e"
129 | integrity sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA==
130 | dependencies:
131 | chalk "^5.3.0"
132 | commander "^12.0.0"
133 |
134 | "@solana/options@2.0.0-preview.2":
135 | version "2.0.0-preview.2"
136 | resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.2.tgz#13ff008bf43a5056ef9a091dc7bb3f39321e867e"
137 | integrity sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w==
138 | dependencies:
139 | "@solana/codecs-core" "2.0.0-preview.2"
140 | "@solana/codecs-numbers" "2.0.0-preview.2"
141 |
142 | "@solana/spl-token-group@^0.0.4":
143 | version "0.0.4"
144 | resolved "https://registry.yarnpkg.com/@solana/spl-token-group/-/spl-token-group-0.0.4.tgz#4f45d9526c96a33b9a1929a264d0aa21c7e38a2d"
145 | integrity sha512-7+80nrEMdUKlK37V6kOe024+T7J4nNss0F8LQ9OOPYdWCCfJmsGUzVx2W3oeizZR4IHM6N4yC9v1Xqwc3BTPWw==
146 | dependencies:
147 | "@solana/codecs" "2.0.0-preview.2"
148 | "@solana/spl-type-length-value" "0.1.0"
149 |
150 | "@solana/spl-token-metadata@^0.1.4":
151 | version "0.1.4"
152 | resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.4.tgz#5cdc3b857a8c4a6877df24e24a8648c4132d22ba"
153 | integrity sha512-N3gZ8DlW6NWDV28+vCCDJoTqaCZiF/jDUnk3o8GRkAFzHObiR60Bs1gXHBa8zCPdvOwiG6Z3dg5pg7+RW6XNsQ==
154 | dependencies:
155 | "@solana/codecs" "2.0.0-preview.2"
156 | "@solana/spl-type-length-value" "0.1.0"
157 |
158 | "@solana/spl-token@^0.4.6":
159 | version "0.4.6"
160 | resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.6.tgz#eb44e5080ea7b6fc976abcb39457223211bd9076"
161 | integrity sha512-1nCnUqfHVtdguFciVWaY/RKcQz1IF4b31jnKgAmjU9QVN1q7dRUkTEWJZgTYIEtsULjVnC9jRqlhgGN39WbKKA==
162 | dependencies:
163 | "@solana/buffer-layout" "^4.0.0"
164 | "@solana/buffer-layout-utils" "^0.2.0"
165 | "@solana/spl-token-group" "^0.0.4"
166 | "@solana/spl-token-metadata" "^0.1.4"
167 | buffer "^6.0.3"
168 |
169 | "@solana/spl-type-length-value@0.1.0":
170 | version "0.1.0"
171 | resolved "https://registry.yarnpkg.com/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz#b5930cf6c6d8f50c7ff2a70463728a4637a2f26b"
172 | integrity sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==
173 | dependencies:
174 | buffer "^6.0.3"
175 |
176 | "@solana/web3.js@^1.32.0":
177 | version "1.91.8"
178 | resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.91.8.tgz#0d5eb69626a92c391b53e15bfbb0bad3f6858e51"
179 | integrity sha512-USa6OS1jbh8zOapRJ/CBZImZ8Xb7AJjROZl5adql9TpOoBN9BUzyyouS5oPuZHft7S7eB8uJPuXWYjMi6BHgOw==
180 | dependencies:
181 | "@babel/runtime" "^7.24.5"
182 | "@noble/curves" "^1.4.0"
183 | "@noble/hashes" "^1.4.0"
184 | "@solana/buffer-layout" "^4.0.1"
185 | agentkeepalive "^4.5.0"
186 | bigint-buffer "^1.1.5"
187 | bn.js "^5.2.1"
188 | borsh "^0.7.0"
189 | bs58 "^4.0.1"
190 | buffer "6.0.3"
191 | fast-stable-stringify "^1.0.0"
192 | jayson "^4.1.0"
193 | node-fetch "^2.7.0"
194 | rpc-websockets "^7.11.0"
195 | superstruct "^0.14.2"
196 |
197 | "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.91.4":
198 | version "1.91.4"
199 | resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.91.4.tgz#b80295ce72aa125930dfc5b41b4b4e3f85fd87fa"
200 | integrity sha512-zconqecIcBqEF6JiM4xYF865Xc4aas+iWK5qnu7nwKPq9ilRYcn+2GiwpYXqUqqBUe0XCO17w18KO0F8h+QATg==
201 | dependencies:
202 | "@babel/runtime" "^7.23.4"
203 | "@noble/curves" "^1.2.0"
204 | "@noble/hashes" "^1.3.3"
205 | "@solana/buffer-layout" "^4.0.1"
206 | agentkeepalive "^4.5.0"
207 | bigint-buffer "^1.1.5"
208 | bn.js "^5.2.1"
209 | borsh "^0.7.0"
210 | bs58 "^4.0.1"
211 | buffer "6.0.3"
212 | fast-stable-stringify "^1.0.0"
213 | jayson "^4.1.0"
214 | node-fetch "^2.7.0"
215 | rpc-websockets "^7.5.1"
216 | superstruct "^0.14.2"
217 |
218 | "@types/bn.js@^5.1.0":
219 | version "5.1.5"
220 | resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0"
221 | integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==
222 | dependencies:
223 | "@types/node" "*"
224 |
225 | "@types/chai@^4.3.0":
226 | version "4.3.14"
227 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.14.tgz#ae3055ea2be43c91c9fd700a36d67820026d96e6"
228 | integrity sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==
229 |
230 | "@types/connect@^3.4.33":
231 | version "3.4.38"
232 | resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858"
233 | integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==
234 | dependencies:
235 | "@types/node" "*"
236 |
237 | "@types/json5@^0.0.29":
238 | version "0.0.29"
239 | resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
240 | integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
241 |
242 | "@types/mocha@^9.0.0":
243 | version "9.1.1"
244 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4"
245 | integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==
246 |
247 | "@types/node@*":
248 | version "20.12.7"
249 | resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384"
250 | integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==
251 | dependencies:
252 | undici-types "~5.26.4"
253 |
254 | "@types/node@^12.12.54":
255 | version "12.20.55"
256 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
257 | integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
258 |
259 | "@types/ws@^7.4.4":
260 | version "7.4.7"
261 | resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702"
262 | integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==
263 | dependencies:
264 | "@types/node" "*"
265 |
266 | "@ungap/promise-all-settled@1.1.2":
267 | version "1.1.2"
268 | resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
269 | integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
270 |
271 | JSONStream@^1.3.5:
272 | version "1.3.5"
273 | resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
274 | integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
275 | dependencies:
276 | jsonparse "^1.2.0"
277 | through ">=2.2.7 <3"
278 |
279 | agentkeepalive@^4.5.0:
280 | version "4.5.0"
281 | resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923"
282 | integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
283 | dependencies:
284 | humanize-ms "^1.2.1"
285 |
286 | ansi-colors@4.1.1:
287 | version "4.1.1"
288 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
289 | integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
290 |
291 | ansi-regex@^5.0.1:
292 | version "5.0.1"
293 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
294 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
295 |
296 | ansi-styles@^4.0.0, ansi-styles@^4.1.0:
297 | version "4.3.0"
298 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
299 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
300 | dependencies:
301 | color-convert "^2.0.1"
302 |
303 | anymatch@~3.1.2:
304 | version "3.1.3"
305 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
306 | integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
307 | dependencies:
308 | normalize-path "^3.0.0"
309 | picomatch "^2.0.4"
310 |
311 | argparse@^2.0.1:
312 | version "2.0.1"
313 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
314 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
315 |
316 | arrify@^1.0.0:
317 | version "1.0.1"
318 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
319 | integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==
320 |
321 | assertion-error@^1.1.0:
322 | version "1.1.0"
323 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
324 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
325 |
326 | balanced-match@^1.0.0:
327 | version "1.0.2"
328 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
329 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
330 |
331 | base-x@^3.0.2:
332 | version "3.0.9"
333 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
334 | integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
335 | dependencies:
336 | safe-buffer "^5.0.1"
337 |
338 | base64-js@^1.3.1:
339 | version "1.5.1"
340 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
341 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
342 |
343 | bigint-buffer@^1.1.5:
344 | version "1.1.5"
345 | resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442"
346 | integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==
347 | dependencies:
348 | bindings "^1.3.0"
349 |
350 | bignumber.js@^9.0.1:
351 | version "9.1.2"
352 | resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c"
353 | integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==
354 |
355 | binary-extensions@^2.0.0:
356 | version "2.3.0"
357 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
358 | integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
359 |
360 | bindings@^1.3.0:
361 | version "1.5.0"
362 | resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
363 | integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
364 | dependencies:
365 | file-uri-to-path "1.0.0"
366 |
367 | bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1:
368 | version "5.2.1"
369 | resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
370 | integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
371 |
372 | borsh@^0.7.0:
373 | version "0.7.0"
374 | resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a"
375 | integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==
376 | dependencies:
377 | bn.js "^5.2.0"
378 | bs58 "^4.0.0"
379 | text-encoding-utf-8 "^1.0.2"
380 |
381 | brace-expansion@^1.1.7:
382 | version "1.1.11"
383 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
384 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
385 | dependencies:
386 | balanced-match "^1.0.0"
387 | concat-map "0.0.1"
388 |
389 | braces@~3.0.2:
390 | version "3.0.2"
391 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
392 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
393 | dependencies:
394 | fill-range "^7.0.1"
395 |
396 | browser-stdout@1.3.1:
397 | version "1.3.1"
398 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
399 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
400 |
401 | bs58@^4.0.0, bs58@^4.0.1:
402 | version "4.0.1"
403 | resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
404 | integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==
405 | dependencies:
406 | base-x "^3.0.2"
407 |
408 | buffer-from@^1.0.0, buffer-from@^1.1.0:
409 | version "1.1.2"
410 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
411 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
412 |
413 | buffer-layout@^1.2.0, buffer-layout@^1.2.2:
414 | version "1.2.2"
415 | resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5"
416 | integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==
417 |
418 | buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3:
419 | version "6.0.3"
420 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
421 | integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
422 | dependencies:
423 | base64-js "^1.3.1"
424 | ieee754 "^1.2.1"
425 |
426 | bufferutil@^4.0.1:
427 | version "4.0.8"
428 | resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea"
429 | integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==
430 | dependencies:
431 | node-gyp-build "^4.3.0"
432 |
433 | camelcase@^6.0.0, camelcase@^6.3.0:
434 | version "6.3.0"
435 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
436 | integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
437 |
438 | chai@^4.3.4:
439 | version "4.4.1"
440 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1"
441 | integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==
442 | dependencies:
443 | assertion-error "^1.1.0"
444 | check-error "^1.0.3"
445 | deep-eql "^4.1.3"
446 | get-func-name "^2.0.2"
447 | loupe "^2.3.6"
448 | pathval "^1.1.1"
449 | type-detect "^4.0.8"
450 |
451 | chalk@^4.1.0:
452 | version "4.1.2"
453 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
454 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
455 | dependencies:
456 | ansi-styles "^4.1.0"
457 | supports-color "^7.1.0"
458 |
459 | chalk@^5.3.0:
460 | version "5.3.0"
461 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
462 | integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
463 |
464 | check-error@^1.0.3:
465 | version "1.0.3"
466 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694"
467 | integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==
468 | dependencies:
469 | get-func-name "^2.0.2"
470 |
471 | chokidar@3.5.3:
472 | version "3.5.3"
473 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
474 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
475 | dependencies:
476 | anymatch "~3.1.2"
477 | braces "~3.0.2"
478 | glob-parent "~5.1.2"
479 | is-binary-path "~2.1.0"
480 | is-glob "~4.0.1"
481 | normalize-path "~3.0.0"
482 | readdirp "~3.6.0"
483 | optionalDependencies:
484 | fsevents "~2.3.2"
485 |
486 | cliui@^7.0.2:
487 | version "7.0.4"
488 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
489 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
490 | dependencies:
491 | string-width "^4.2.0"
492 | strip-ansi "^6.0.0"
493 | wrap-ansi "^7.0.0"
494 |
495 | color-convert@^2.0.1:
496 | version "2.0.1"
497 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
498 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
499 | dependencies:
500 | color-name "~1.1.4"
501 |
502 | color-name@~1.1.4:
503 | version "1.1.4"
504 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
505 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
506 |
507 | commander@^12.0.0:
508 | version "12.1.0"
509 | resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
510 | integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
511 |
512 | commander@^2.20.3:
513 | version "2.20.3"
514 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
515 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
516 |
517 | concat-map@0.0.1:
518 | version "0.0.1"
519 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
520 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
521 |
522 | cross-fetch@^3.1.5:
523 | version "3.1.8"
524 | resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82"
525 | integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
526 | dependencies:
527 | node-fetch "^2.6.12"
528 |
529 | crypto-hash@^1.3.0:
530 | version "1.3.0"
531 | resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247"
532 | integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==
533 |
534 | debug@4.3.3:
535 | version "4.3.3"
536 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
537 | integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
538 | dependencies:
539 | ms "2.1.2"
540 |
541 | decamelize@^4.0.0:
542 | version "4.0.0"
543 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
544 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
545 |
546 | deep-eql@^4.1.3:
547 | version "4.1.3"
548 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d"
549 | integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==
550 | dependencies:
551 | type-detect "^4.0.0"
552 |
553 | delay@^5.0.0:
554 | version "5.0.0"
555 | resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d"
556 | integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==
557 |
558 | diff@5.0.0:
559 | version "5.0.0"
560 | resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
561 | integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
562 |
563 | diff@^3.1.0:
564 | version "3.5.0"
565 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
566 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
567 |
568 | dot-case@^3.0.4:
569 | version "3.0.4"
570 | resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
571 | integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
572 | dependencies:
573 | no-case "^3.0.4"
574 | tslib "^2.0.3"
575 |
576 | dotenv@^16.4.5:
577 | version "16.4.5"
578 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
579 | integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
580 |
581 | emoji-regex@^8.0.0:
582 | version "8.0.0"
583 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
584 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
585 |
586 | es6-promise@^4.0.3:
587 | version "4.2.8"
588 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
589 | integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
590 |
591 | es6-promisify@^5.0.0:
592 | version "5.0.0"
593 | resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
594 | integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==
595 | dependencies:
596 | es6-promise "^4.0.3"
597 |
598 | escalade@^3.1.1:
599 | version "3.1.2"
600 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
601 | integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
602 |
603 | escape-string-regexp@4.0.0:
604 | version "4.0.0"
605 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
606 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
607 |
608 | eventemitter3@^4.0.7:
609 | version "4.0.7"
610 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
611 | integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
612 |
613 | eyes@^0.1.8:
614 | version "0.1.8"
615 | resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
616 | integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==
617 |
618 | fast-stable-stringify@^1.0.0:
619 | version "1.0.0"
620 | resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313"
621 | integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==
622 |
623 | file-uri-to-path@1.0.0:
624 | version "1.0.0"
625 | resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
626 | integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
627 |
628 | fill-range@^7.0.1:
629 | version "7.0.1"
630 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
631 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
632 | dependencies:
633 | to-regex-range "^5.0.1"
634 |
635 | find-up@5.0.0:
636 | version "5.0.0"
637 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
638 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
639 | dependencies:
640 | locate-path "^6.0.0"
641 | path-exists "^4.0.0"
642 |
643 | flat@^5.0.2:
644 | version "5.0.2"
645 | resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
646 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
647 |
648 | fs.realpath@^1.0.0:
649 | version "1.0.0"
650 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
651 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
652 |
653 | fsevents@~2.3.2:
654 | version "2.3.3"
655 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
656 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
657 |
658 | get-caller-file@^2.0.5:
659 | version "2.0.5"
660 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
661 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
662 |
663 | get-func-name@^2.0.1, get-func-name@^2.0.2:
664 | version "2.0.2"
665 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41"
666 | integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==
667 |
668 | glob-parent@~5.1.2:
669 | version "5.1.2"
670 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
671 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
672 | dependencies:
673 | is-glob "^4.0.1"
674 |
675 | glob@7.2.0:
676 | version "7.2.0"
677 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
678 | integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
679 | dependencies:
680 | fs.realpath "^1.0.0"
681 | inflight "^1.0.4"
682 | inherits "2"
683 | minimatch "^3.0.4"
684 | once "^1.3.0"
685 | path-is-absolute "^1.0.0"
686 |
687 | growl@1.10.5:
688 | version "1.10.5"
689 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
690 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
691 |
692 | has-flag@^4.0.0:
693 | version "4.0.0"
694 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
695 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
696 |
697 | he@1.2.0:
698 | version "1.2.0"
699 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
700 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
701 |
702 | humanize-ms@^1.2.1:
703 | version "1.2.1"
704 | resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
705 | integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
706 | dependencies:
707 | ms "^2.0.0"
708 |
709 | ieee754@^1.2.1:
710 | version "1.2.1"
711 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
712 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
713 |
714 | inflight@^1.0.4:
715 | version "1.0.6"
716 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
717 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
718 | dependencies:
719 | once "^1.3.0"
720 | wrappy "1"
721 |
722 | inherits@2:
723 | version "2.0.4"
724 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
725 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
726 |
727 | is-binary-path@~2.1.0:
728 | version "2.1.0"
729 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
730 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
731 | dependencies:
732 | binary-extensions "^2.0.0"
733 |
734 | is-extglob@^2.1.1:
735 | version "2.1.1"
736 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
737 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
738 |
739 | is-fullwidth-code-point@^3.0.0:
740 | version "3.0.0"
741 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
742 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
743 |
744 | is-glob@^4.0.1, is-glob@~4.0.1:
745 | version "4.0.3"
746 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
747 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
748 | dependencies:
749 | is-extglob "^2.1.1"
750 |
751 | is-number@^7.0.0:
752 | version "7.0.0"
753 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
754 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
755 |
756 | is-plain-obj@^2.1.0:
757 | version "2.1.0"
758 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
759 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
760 |
761 | is-unicode-supported@^0.1.0:
762 | version "0.1.0"
763 | resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
764 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
765 |
766 | isexe@^2.0.0:
767 | version "2.0.0"
768 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
769 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
770 |
771 | isomorphic-ws@^4.0.1:
772 | version "4.0.1"
773 | resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc"
774 | integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==
775 |
776 | jayson@^4.1.0:
777 | version "4.1.0"
778 | resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9"
779 | integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==
780 | dependencies:
781 | "@types/connect" "^3.4.33"
782 | "@types/node" "^12.12.54"
783 | "@types/ws" "^7.4.4"
784 | JSONStream "^1.3.5"
785 | commander "^2.20.3"
786 | delay "^5.0.0"
787 | es6-promisify "^5.0.0"
788 | eyes "^0.1.8"
789 | isomorphic-ws "^4.0.1"
790 | json-stringify-safe "^5.0.1"
791 | uuid "^8.3.2"
792 | ws "^7.4.5"
793 |
794 | js-yaml@4.1.0:
795 | version "4.1.0"
796 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
797 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
798 | dependencies:
799 | argparse "^2.0.1"
800 |
801 | json-stringify-safe@^5.0.1:
802 | version "5.0.1"
803 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
804 | integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
805 |
806 | json5@^1.0.2:
807 | version "1.0.2"
808 | resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
809 | integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
810 | dependencies:
811 | minimist "^1.2.0"
812 |
813 | jsonparse@^1.2.0:
814 | version "1.3.1"
815 | resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
816 | integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
817 |
818 | locate-path@^6.0.0:
819 | version "6.0.0"
820 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
821 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
822 | dependencies:
823 | p-locate "^5.0.0"
824 |
825 | log-symbols@4.1.0:
826 | version "4.1.0"
827 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
828 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
829 | dependencies:
830 | chalk "^4.1.0"
831 | is-unicode-supported "^0.1.0"
832 |
833 | loupe@^2.3.6:
834 | version "2.3.7"
835 | resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697"
836 | integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==
837 | dependencies:
838 | get-func-name "^2.0.1"
839 |
840 | lower-case@^2.0.2:
841 | version "2.0.2"
842 | resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
843 | integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
844 | dependencies:
845 | tslib "^2.0.3"
846 |
847 | make-error@^1.1.1:
848 | version "1.3.6"
849 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
850 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
851 |
852 | minimatch@4.2.1:
853 | version "4.2.1"
854 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4"
855 | integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==
856 | dependencies:
857 | brace-expansion "^1.1.7"
858 |
859 | minimatch@^3.0.4:
860 | version "3.1.2"
861 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
862 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
863 | dependencies:
864 | brace-expansion "^1.1.7"
865 |
866 | minimist@^1.2.0, minimist@^1.2.6:
867 | version "1.2.8"
868 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
869 | integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
870 |
871 | mkdirp@^0.5.1:
872 | version "0.5.6"
873 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
874 | integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
875 | dependencies:
876 | minimist "^1.2.6"
877 |
878 | mocha@^9.0.3:
879 | version "9.2.2"
880 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9"
881 | integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==
882 | dependencies:
883 | "@ungap/promise-all-settled" "1.1.2"
884 | ansi-colors "4.1.1"
885 | browser-stdout "1.3.1"
886 | chokidar "3.5.3"
887 | debug "4.3.3"
888 | diff "5.0.0"
889 | escape-string-regexp "4.0.0"
890 | find-up "5.0.0"
891 | glob "7.2.0"
892 | growl "1.10.5"
893 | he "1.2.0"
894 | js-yaml "4.1.0"
895 | log-symbols "4.1.0"
896 | minimatch "4.2.1"
897 | ms "2.1.3"
898 | nanoid "3.3.1"
899 | serialize-javascript "6.0.0"
900 | strip-json-comments "3.1.1"
901 | supports-color "8.1.1"
902 | which "2.0.2"
903 | workerpool "6.2.0"
904 | yargs "16.2.0"
905 | yargs-parser "20.2.4"
906 | yargs-unparser "2.0.0"
907 |
908 | ms@2.1.2:
909 | version "2.1.2"
910 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
911 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
912 |
913 | ms@2.1.3, ms@^2.0.0:
914 | version "2.1.3"
915 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
916 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
917 |
918 | nanoid@3.3.1:
919 | version "3.3.1"
920 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
921 | integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
922 |
923 | no-case@^3.0.4:
924 | version "3.0.4"
925 | resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
926 | integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
927 | dependencies:
928 | lower-case "^2.0.2"
929 | tslib "^2.0.3"
930 |
931 | node-fetch@^2.6.12, node-fetch@^2.7.0:
932 | version "2.7.0"
933 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
934 | integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
935 | dependencies:
936 | whatwg-url "^5.0.0"
937 |
938 | node-gyp-build@^4.3.0:
939 | version "4.8.0"
940 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd"
941 | integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==
942 |
943 | normalize-path@^3.0.0, normalize-path@~3.0.0:
944 | version "3.0.0"
945 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
946 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
947 |
948 | once@^1.3.0:
949 | version "1.4.0"
950 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
951 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
952 | dependencies:
953 | wrappy "1"
954 |
955 | p-limit@^3.0.2:
956 | version "3.1.0"
957 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
958 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
959 | dependencies:
960 | yocto-queue "^0.1.0"
961 |
962 | p-locate@^5.0.0:
963 | version "5.0.0"
964 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
965 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
966 | dependencies:
967 | p-limit "^3.0.2"
968 |
969 | pako@^2.0.3:
970 | version "2.1.0"
971 | resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
972 | integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
973 |
974 | path-exists@^4.0.0:
975 | version "4.0.0"
976 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
977 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
978 |
979 | path-is-absolute@^1.0.0:
980 | version "1.0.1"
981 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
982 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
983 |
984 | pathval@^1.1.1:
985 | version "1.1.1"
986 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
987 | integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
988 |
989 | picomatch@^2.0.4, picomatch@^2.2.1:
990 | version "2.3.1"
991 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
992 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
993 |
994 | prettier@^2.6.2:
995 | version "2.8.8"
996 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
997 | integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
998 |
999 | randombytes@^2.1.0:
1000 | version "2.1.0"
1001 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
1002 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
1003 | dependencies:
1004 | safe-buffer "^5.1.0"
1005 |
1006 | readdirp@~3.6.0:
1007 | version "3.6.0"
1008 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
1009 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
1010 | dependencies:
1011 | picomatch "^2.2.1"
1012 |
1013 | regenerator-runtime@^0.14.0:
1014 | version "0.14.1"
1015 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
1016 | integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
1017 |
1018 | require-directory@^2.1.1:
1019 | version "2.1.1"
1020 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
1021 | integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
1022 |
1023 | rpc-websockets@^7.11.0:
1024 | version "7.11.0"
1025 | resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.11.0.tgz#05451975963a7d1a4cf36d54e200bfc4402a56d7"
1026 | integrity sha512-IkLYjayPv6Io8C/TdCL5gwgzd1hFz2vmBZrjMw/SPEXo51ETOhnzgS4Qy5GWi2JQN7HKHa66J3+2mv0fgNh/7w==
1027 | dependencies:
1028 | eventemitter3 "^4.0.7"
1029 | uuid "^8.3.2"
1030 | ws "^8.5.0"
1031 | optionalDependencies:
1032 | bufferutil "^4.0.1"
1033 | utf-8-validate "^5.0.2"
1034 |
1035 | rpc-websockets@^7.5.1:
1036 | version "7.9.0"
1037 | resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.9.0.tgz#a3938e16d6f134a3999fdfac422a503731bf8973"
1038 | integrity sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw==
1039 | dependencies:
1040 | "@babel/runtime" "^7.17.2"
1041 | eventemitter3 "^4.0.7"
1042 | uuid "^8.3.2"
1043 | ws "^8.5.0"
1044 | optionalDependencies:
1045 | bufferutil "^4.0.1"
1046 | utf-8-validate "^5.0.2"
1047 |
1048 | safe-buffer@^5.0.1, safe-buffer@^5.1.0:
1049 | version "5.2.1"
1050 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
1051 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
1052 |
1053 | serialize-javascript@6.0.0:
1054 | version "6.0.0"
1055 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
1056 | integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
1057 | dependencies:
1058 | randombytes "^2.1.0"
1059 |
1060 | snake-case@^3.0.4:
1061 | version "3.0.4"
1062 | resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
1063 | integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
1064 | dependencies:
1065 | dot-case "^3.0.4"
1066 | tslib "^2.0.3"
1067 |
1068 | source-map-support@^0.5.6:
1069 | version "0.5.21"
1070 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
1071 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
1072 | dependencies:
1073 | buffer-from "^1.0.0"
1074 | source-map "^0.6.0"
1075 |
1076 | source-map@^0.6.0:
1077 | version "0.6.1"
1078 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
1079 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
1080 |
1081 | string-width@^4.1.0, string-width@^4.2.0:
1082 | version "4.2.3"
1083 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
1084 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
1085 | dependencies:
1086 | emoji-regex "^8.0.0"
1087 | is-fullwidth-code-point "^3.0.0"
1088 | strip-ansi "^6.0.1"
1089 |
1090 | strip-ansi@^6.0.0, strip-ansi@^6.0.1:
1091 | version "6.0.1"
1092 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
1093 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
1094 | dependencies:
1095 | ansi-regex "^5.0.1"
1096 |
1097 | strip-bom@^3.0.0:
1098 | version "3.0.0"
1099 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
1100 | integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
1101 |
1102 | strip-json-comments@3.1.1:
1103 | version "3.1.1"
1104 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
1105 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
1106 |
1107 | superstruct@^0.14.2:
1108 | version "0.14.2"
1109 | resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b"
1110 | integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==
1111 |
1112 | superstruct@^0.15.4:
1113 | version "0.15.5"
1114 | resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab"
1115 | integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==
1116 |
1117 | supports-color@8.1.1:
1118 | version "8.1.1"
1119 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
1120 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
1121 | dependencies:
1122 | has-flag "^4.0.0"
1123 |
1124 | supports-color@^7.1.0:
1125 | version "7.2.0"
1126 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
1127 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
1128 | dependencies:
1129 | has-flag "^4.0.0"
1130 |
1131 | text-encoding-utf-8@^1.0.2:
1132 | version "1.0.2"
1133 | resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13"
1134 | integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==
1135 |
1136 | "through@>=2.2.7 <3":
1137 | version "2.3.8"
1138 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
1139 | integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
1140 |
1141 | to-regex-range@^5.0.1:
1142 | version "5.0.1"
1143 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1144 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1145 | dependencies:
1146 | is-number "^7.0.0"
1147 |
1148 | toml@^3.0.0:
1149 | version "3.0.0"
1150 | resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
1151 | integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==
1152 |
1153 | tr46@~0.0.3:
1154 | version "0.0.3"
1155 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
1156 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
1157 |
1158 | ts-mocha@^10.0.0:
1159 | version "10.0.0"
1160 | resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.0.0.tgz#41a8d099ac90dbbc64b06976c5025ffaebc53cb9"
1161 | integrity sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==
1162 | dependencies:
1163 | ts-node "7.0.1"
1164 | optionalDependencies:
1165 | tsconfig-paths "^3.5.0"
1166 |
1167 | ts-node@7.0.1:
1168 | version "7.0.1"
1169 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf"
1170 | integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==
1171 | dependencies:
1172 | arrify "^1.0.0"
1173 | buffer-from "^1.1.0"
1174 | diff "^3.1.0"
1175 | make-error "^1.1.1"
1176 | minimist "^1.2.0"
1177 | mkdirp "^0.5.1"
1178 | source-map-support "^0.5.6"
1179 | yn "^2.0.0"
1180 |
1181 | tsconfig-paths@^3.5.0:
1182 | version "3.15.0"
1183 | resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
1184 | integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==
1185 | dependencies:
1186 | "@types/json5" "^0.0.29"
1187 | json5 "^1.0.2"
1188 | minimist "^1.2.6"
1189 | strip-bom "^3.0.0"
1190 |
1191 | tslib@^2.0.3:
1192 | version "2.6.2"
1193 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
1194 | integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
1195 |
1196 | type-detect@^4.0.0, type-detect@^4.0.8:
1197 | version "4.0.8"
1198 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
1199 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
1200 |
1201 | typescript@^4.3.5:
1202 | version "4.9.5"
1203 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
1204 | integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
1205 |
1206 | undici-types@~5.26.4:
1207 | version "5.26.5"
1208 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
1209 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
1210 |
1211 | utf-8-validate@^5.0.2:
1212 | version "5.0.10"
1213 | resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2"
1214 | integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==
1215 | dependencies:
1216 | node-gyp-build "^4.3.0"
1217 |
1218 | uuid@^8.3.2:
1219 | version "8.3.2"
1220 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
1221 | integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
1222 |
1223 | webidl-conversions@^3.0.0:
1224 | version "3.0.1"
1225 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
1226 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
1227 |
1228 | whatwg-url@^5.0.0:
1229 | version "5.0.0"
1230 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
1231 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
1232 | dependencies:
1233 | tr46 "~0.0.3"
1234 | webidl-conversions "^3.0.0"
1235 |
1236 | which@2.0.2:
1237 | version "2.0.2"
1238 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
1239 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
1240 | dependencies:
1241 | isexe "^2.0.0"
1242 |
1243 | workerpool@6.2.0:
1244 | version "6.2.0"
1245 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b"
1246 | integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==
1247 |
1248 | wrap-ansi@^7.0.0:
1249 | version "7.0.0"
1250 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
1251 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
1252 | dependencies:
1253 | ansi-styles "^4.0.0"
1254 | string-width "^4.1.0"
1255 | strip-ansi "^6.0.0"
1256 |
1257 | wrappy@1:
1258 | version "1.0.2"
1259 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
1260 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
1261 |
1262 | ws@^7.4.5:
1263 | version "7.5.9"
1264 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
1265 | integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
1266 |
1267 | ws@^8.5.0:
1268 | version "8.16.0"
1269 | resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4"
1270 | integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==
1271 |
1272 | y18n@^5.0.5:
1273 | version "5.0.8"
1274 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
1275 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
1276 |
1277 | yargs-parser@20.2.4:
1278 | version "20.2.4"
1279 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
1280 | integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
1281 |
1282 | yargs-parser@^20.2.2:
1283 | version "20.2.9"
1284 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
1285 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
1286 |
1287 | yargs-unparser@2.0.0:
1288 | version "2.0.0"
1289 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
1290 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
1291 | dependencies:
1292 | camelcase "^6.0.0"
1293 | decamelize "^4.0.0"
1294 | flat "^5.0.2"
1295 | is-plain-obj "^2.1.0"
1296 |
1297 | yargs@16.2.0:
1298 | version "16.2.0"
1299 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
1300 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
1301 | dependencies:
1302 | cliui "^7.0.2"
1303 | escalade "^3.1.1"
1304 | get-caller-file "^2.0.5"
1305 | require-directory "^2.1.1"
1306 | string-width "^4.2.0"
1307 | y18n "^5.0.5"
1308 | yargs-parser "^20.2.2"
1309 |
1310 | yn@^2.0.0:
1311 | version "2.0.0"
1312 | resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a"
1313 | integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==
1314 |
1315 | yocto-queue@^0.1.0:
1316 | version "0.1.0"
1317 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
1318 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
1319 |
--------------------------------------------------------------------------------