Mango Markets

Mangoは、オンチェーンリスク エンジンを介して、取引暗号資産を貸与、借入、交換、および活用するための単一の場を提供します。 クライアントAPIライブラリを使用して、Mangoのオンチェーンプログラムに接続できます。Solana JavaScript APIライブラリも必要です。

"@blockworks-foundation/mango-client": "^3.3.27",
"@solana/web3.js": "^1.37.0"

Mango Groupの取得方法

Mango groupはクロスマージントークンのバスケットで、トークン、Serum dex market、perp market、Oracle、Insurance fund、Fees vaultに関する幅広い市場情報を保持しています。 Mango Markets の各バージョンは、異なるトークンを含む異なる Mango Group を使用します。現在の v3 グループはmainnet.1 です。さまざまなグループを示す表を次に示します:

GroupVersionCluster
mainnet.1v3mainnet
devnet.2v3devnet
devnet.3v3devnet
BTC_ETH_SOL_SRM_USDCv2mainnet & devnet
BTC_ETH_USDTv2devnet
BTC_ETH_USDCv2testnet

Note

v2 グループを使用する場合は、v2 クライアント ライブラリを使用する必要があります。ここopen in new windowで見つけることができます

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import {
  IDS,
  MangoClient,
  Config,
  I80F48,
} from "@blockworks-foundation/mango-client";

(async () => {
  const cluster = "devnet";
  const group = "devnet.3";

  const config = new Config(IDS);
  const groupConfig = config.getGroup(cluster, group);
  if (!groupConfig) {
    throw new Error("unable to get mango group config");
  }
  const mangoGroupKey = groupConfig.publicKey;

  const clusterData = IDS.groups.find((g) => {
    return g.name == group && g.cluster == cluster;
  });
  const mangoProgramIdPk = new PublicKey(clusterData.mangoProgramId);

  const clusterUrl = IDS.cluster_urls[cluster];
  const connection = new Connection(clusterUrl, "singleGossip");
  const client = new MangoClient(connection, mangoProgramIdPk);
  const mangoGroup = await client.getMangoGroup(mangoGroupKey);
})();

Mango Accountの作成方法

Mango Accountは Mango Groupに関連付けられており、トークンを保持し、そのグループの市場での取引を可能にします。こちらopen in new windowからリファレンスを確認できます。

Press </> button to view full source
import { useWallet } from "@solana/wallet-adapter-react";
import { Connection, PublicKey } from "@solana/web3.js";
import { IDS, MangoClient, Config } from "@blockworks-foundation/mango-client";

(async () => {
  const { wallet } = useWallet();

  const cluster = "devnet";
  const group = "devnet.3";

  const config = new Config(IDS);
  const groupConfig = config.getGroup(cluster, group);
  if (!groupConfig) {
    throw new Error("unable to get mango group config");
  }
  const mangoGroupKey = groupConfig.publicKey;

  const clusterData = IDS.groups.find((g) => {
    return g.name == group && g.cluster == cluster;
  });
  const mangoProgramIdPk = new PublicKey(clusterData.mangoProgramId);

  const clusterUrl = IDS.cluster_urls[cluster];
  const connection = new Connection(clusterUrl, "singleGossip");
  const client = new MangoClient(connection, mangoProgramIdPk);
  const mangoGroup = await client.getMangoGroup(mangoGroupKey);
  const mangoAccount = await client.createMangoAccount(
    mangoGroup,
    wallet?.adapter,
    23
  );
})();
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
  account_info::{next_account_info, AccountInfo},
  entrypoint::ProgramResult,
  msg,
  program::{invoke_signed},
  program_error::ProgramError,
  pubkey::Pubkey,
  system_instruction,
  system_program::ID as SYSTEM_PROGRAM_ID,
  sysvar::{rent::Rent, Sysvar},
};
// Add this to Cargo.toml to be able to use the mango program repository as a crate
// mango = { version = "3.4.2", git = "https://github.com/blockworks-foundation/mango-v3.git", default-features=false, features = ["no-entrypoint", "program"] }
use mango::instruction::MangoInstruction;

use crate::instruction::ProgramInstruction;

pub struct Processor {}

impl Processor {
  pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8]
  ) -> ProgramResult {
    let instruction = ProgramInstruction::try_from_slice(instruction_data)
      .map_err(|_| ProgramError::InvalidInstructionData)?;

    let accounts_iter = &mut accounts.iter();
    match instruction {
      ProgramInstruction::CreateMangoAccount { account_num } => {
        msg!("Instruction: CreateMangoAccount");
        let mango_group_ai = next_account_info(accounts_iter)?;
        let mango_account_ai = next_account_info(accounts_iter)?;
        let user = next_account_info(accounts_iter)?;
        let mango_program = next_account_info(accounts_iter)?;
        let system_program = next_account_info(accounts_iter)?;
        
        invoke(
          &mango::instruction::create_mango_account(
            *mango_program.key,
            *mango_account_ai.key,
            *user.key,
            *system_program.key,
            *user.key,
            *account_num
          ),
          &[
            mango_program.clone(),
            user.clone(),
            system_program.clone(),
            mango_account_ai.clone(),
          ]
        )?;
      }
    }
    Ok(())
  }
}

USDCをMango Accountに入金する方法

Mango accountアカウントを作成したら、取引用のトークンで資金を供給する必要があります。 入金方法のリファレンスはこちらopen in new window

Press </> button to view full source
import { useWallet } from "@solana/wallet-adapter-react";
import { Connection, PublicKey } from "@solana/web3.js";
import {
  IDS,
  MangoClient,
  Config,
  getTokenAccountsByOwnerWithWrappedSol,
} from "@blockworks-foundation/mango-client";

(async () => {
  const { wallet } = useWallet();

  const cluster = "devnet";
  const group = "devnet.3";

  const config = new Config(IDS);
  const groupConfig = config.getGroup(cluster, group);
  if (!groupConfig) {
    throw new Error("unable to get mango group config");
  }
  const mangoGroupKey = groupConfig.publicKey;

  const clusterData = IDS.groups.find((g) => {
    return g.name == group && g.cluster == cluster;
  });
  const mangoProgramIdPk = new PublicKey(clusterData.mangoProgramId);

  const clusterUrl = IDS.cluster_urls[cluster];
  const connection = new Connection(clusterUrl, "singleGossip");
  const client = new MangoClient(connection, mangoProgramIdPk);
  const mangoGroup = await client.getMangoGroup(mangoGroupKey);
  const mangoAccount = await client.createMangoAccount(
    mangoGroup,
    wallet?.adapter,
    23
  );
  const tokenAccounts = await getTokenAccountsByOwnerWithWrappedSol(
    connection,
    wallet.adapter.publicKey
  );
  const tokenAccount = tokenAccounts.find((account) =>
    account.mint.equals(
      new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
    )
  ); // USDC mint address
  const tokenIndex = mangoGroup.getTokenIndex(tokenAccount.mint);
  await client.deposit(
    mangoGroup,
    mangoAccount,
    wallet?.adapter,
    mangoGroup.tokens[tokenIndex].rootBank,
    mangoGroup.rootBankAccounts[tokenIndex].nodeBankAccounts[0].publicKey,
    mangoGroup.rootBankAccounts[tokenIndex].nodeBankAccounts[0].vault,
    tokenAccount.publicKey,
    Number(4)
  );
})();

スポット注文の方法

MangoはSerum Protocolと対話し、市場でスポット注文を出します。これにより、スポット注文を出すことができます。placeSpotOrder関数のリファレンスはこちらopen in new window。 Mangoには、グループ、マーケット、トークン、およびOracleに関する情報を含む構成ファイルがあります。 ここopen in new windowで見つけることができます。そのファイルの情報を使用して、適切なグループと市場を見つけます。

Press </> button to view full source
import { useWallet } from "@solana/wallet-adapter-react";
import { Connection, PublicKey } from "@solana/web3.js";
import { Market } from "@project-serum/serum";
import {
  IDS,
  MangoClient,
  Config,
  getSpotMarketByBaseSymbol,
} from "@blockworks-foundation/mango-client";

(async () => {
  const { wallet } = useWallet();

  const cluster = "devnet";
  const group = "devnet.3";

  const config = new Config(IDS);
  const groupConfig = config.getGroup(cluster, group);
  if (!groupConfig) {
    throw new Error("unable to get mango group config");
  }
  const mangoGroupKey = groupConfig.publicKey;

  const clusterData = IDS.groups.find((g) => {
    return g.name == group && g.cluster == cluster;
  });
  const mangoProgramIdPk = new PublicKey(clusterData.mangoProgramId);

  const clusterUrl = IDS.cluster_urls[cluster];
  const connection = new Connection(clusterUrl, "singleGossip");
  const client = new MangoClient(connection, mangoProgramIdPk);
  const mangoGroup = await client.getMangoGroup(mangoGroupKey);
  const mangoAccount = await client.createMangoAccount(
    mangoGroup,
    wallet?.adapter,
    23
  );
  const marketConfig = getSpotMarketByBaseSymbol(groupConfig, "SOL");
  const market = await Market.load(
    connection,
    marketConfig.publicKey,
    {},
    groupConfig.serumProgramId
  );
  await client.placeSpotOrder(
    mangoGroup,
    mangoAccount,
    mangoGroup.mangoCache,
    market,
    wallet?.adapter,
    "buy",
    3,
    3.5
  );
})();

売値の読込方法

MangoはSerum Protocolから得た市場情報を使用して売値を読み込みます。Serumから直接読み込み、Mangoで操作できます。Serumの市場に関しての より詳しい情報はこちらopen in new window

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Market } from "@project-serum/serum";
import {
  IDS,
  Config,
  getSpotMarketByBaseSymbol,
} from "@blockworks-foundation/mango-client";

(async () => {
  const cluster = "devnet";
  const group = "devnet.3";

  const config = new Config(IDS);
  const groupConfig = config.getGroup(cluster, group);
  if (!groupConfig) {
    throw new Error("unable to get mango group config");
  }

  const clusterUrl = IDS.cluster_urls[cluster];
  const connection = new Connection(clusterUrl, "singleGossip");
  const marketConfig = getSpotMarketByBaseSymbol(groupConfig, "SOL");
  const market = await Market.load(
    connection,
    marketConfig.publicKey,
    {},
    groupConfig.serumProgramId
  );
  const bids = market.loadBids(connection);
})();

買値の読込方法

MangoはSerum Protocolから得た市場情報を使用して買値を読み込みます。 Serumから直接読み込み、Mangoで操作できます。Serumの市場の詳しい情報はこちらopen in new window

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Market } from "@project-serum/serum";
import {
  IDS,
  MangoClient,
  Config,
  getSpotMarketByBaseSymbol,
} from "@blockworks-foundation/mango-client";

(async () => {
  const cluster = "devnet";
  const group = "devnet.3";

  const config = new Config(IDS);
  const groupConfig = config.getGroup(cluster, group);
  if (!groupConfig) {
    throw new Error("unable to get mango group config");
  }

  const clusterUrl = IDS.cluster_urls[cluster];
  const connection = new Connection(clusterUrl, "singleGossip");
  const marketConfig = getSpotMarketByBaseSymbol(groupConfig, "SOL");
  const market = await Market.load(
    connection,
    marketConfig.publicKey,
    {},
    groupConfig.serumProgramId
  );
  const asks = await market.loadBids(connection);
})();

その他参考資料

Last Updated:
Contributors: PokoPoko2ry