diff --git a/programs/mango-v4/src/instructions/create_account.rs b/programs/mango-v4/src/instructions/create_account.rs index ef80262db..03b3c6f93 100644 --- a/programs/mango-v4/src/instructions/create_account.rs +++ b/programs/mango-v4/src/instructions/create_account.rs @@ -2,6 +2,7 @@ use anchor_lang::prelude::*; use crate::error::*; use crate::state::*; +use crate::util::fill_from_str; #[derive(Accounts)] #[instruction(account_num: u8)] @@ -25,10 +26,11 @@ pub struct CreateAccount<'info> { pub system_program: Program<'info, System>, } -pub fn create_account(ctx: Context, account_num: u8) -> Result<()> { +pub fn create_account(ctx: Context, account_num: u8, name: String) -> Result<()> { let mut account = ctx.accounts.account.load_init()?; // TODO: dont init on stack *account = MangoAccount { + name: fill_from_str(name)?, group: ctx.accounts.group.key(), owner: ctx.accounts.owner.key(), delegate: Pubkey::default(), diff --git a/programs/mango-v4/src/instructions/register_token.rs b/programs/mango-v4/src/instructions/register_token.rs index 2a4e47095..828650ebf 100644 --- a/programs/mango-v4/src/instructions/register_token.rs +++ b/programs/mango-v4/src/instructions/register_token.rs @@ -8,6 +8,7 @@ use fixed_macro::types::I80F48; // TODO: ALTs are unavailable //use crate::address_lookup_table; use crate::state::*; +use crate::util::fill_from_str; const INDEX_START: I80F48 = I80F48!(1_000_000); @@ -80,6 +81,7 @@ pub struct RegisterToken<'info> { pub fn register_token( ctx: Context, token_index: TokenIndex, + name: String, util0: f32, rate0: f32, util1: f32, @@ -95,6 +97,7 @@ pub fn register_token( let mut bank = ctx.accounts.bank.load_init()?; *bank = Bank { + name: fill_from_str(name)?, group: ctx.accounts.group.key(), mint: ctx.accounts.mint.key(), vault: ctx.accounts.vault.key(), diff --git a/programs/mango-v4/src/instructions/serum3_register_market.rs b/programs/mango-v4/src/instructions/serum3_register_market.rs index a31cd12c9..0e89733cd 100644 --- a/programs/mango-v4/src/instructions/serum3_register_market.rs +++ b/programs/mango-v4/src/instructions/serum3_register_market.rs @@ -3,6 +3,7 @@ use anchor_lang::prelude::*; use crate::error::MangoError; use crate::serum3_cpi::{load_market_state, pubkey_from_u64_array}; use crate::state::*; +use crate::util::fill_from_str; #[derive(Accounts)] pub struct Serum3RegisterMarket<'info> { @@ -42,6 +43,7 @@ pub struct Serum3RegisterMarket<'info> { pub fn serum3_register_market( ctx: Context, market_index: Serum3MarketIndex, + name: String, ) -> Result<()> { // TODO: must guard against accidentally using the same market_index twice! @@ -62,6 +64,7 @@ pub fn serum3_register_market( let mut serum_market = ctx.accounts.serum_market.load_init()?; *serum_market = Serum3Market { + name: fill_from_str(name)?, group: ctx.accounts.group.key(), serum_program: ctx.accounts.serum_program.key(), serum_market_external: ctx.accounts.serum_market_external.key(), diff --git a/programs/mango-v4/src/lib.rs b/programs/mango-v4/src/lib.rs index aaf7178a6..7cb60975d 100644 --- a/programs/mango-v4/src/lib.rs +++ b/programs/mango-v4/src/lib.rs @@ -37,6 +37,7 @@ pub mod mango_v4 { pub fn register_token( ctx: Context, token_index: TokenIndex, + name: String, util0: f32, rate0: f32, util1: f32, @@ -51,6 +52,7 @@ pub mod mango_v4 { instructions::register_token( ctx, token_index, + name, util0, rate0, util1, @@ -68,8 +70,12 @@ pub mod mango_v4 { instructions::update_index(ctx) } - pub fn create_account(ctx: Context, account_num: u8) -> Result<()> { - instructions::create_account(ctx, account_num) + pub fn create_account( + ctx: Context, + account_num: u8, + name: String, + ) -> Result<()> { + instructions::create_account(ctx, account_num, name) } pub fn close_account(ctx: Context) -> Result<()> { @@ -112,8 +118,9 @@ pub mod mango_v4 { pub fn serum3_register_market( ctx: Context, market_index: Serum3MarketIndex, + name: String, ) -> Result<()> { - instructions::serum3_register_market(ctx, market_index) + instructions::serum3_register_market(ctx, market_index, name) } pub fn serum3_create_open_orders(ctx: Context) -> Result<()> { diff --git a/programs/mango-v4/src/state/bank.rs b/programs/mango-v4/src/state/bank.rs index d9916ea92..e08346462 100644 --- a/programs/mango-v4/src/state/bank.rs +++ b/programs/mango-v4/src/state/bank.rs @@ -10,6 +10,8 @@ pub const YEAR: I80F48 = I80F48!(31536000); #[account(zero_copy)] pub struct Bank { + pub name: [u8; 16], + pub group: Pubkey, pub mint: Pubkey, pub vault: Pubkey, @@ -52,7 +54,7 @@ pub struct Bank { pub reserved: [u8; 6], } -const_assert_eq!(size_of::(), 32 * 4 + 8 + 16 * 15 + 2 + 6); +const_assert_eq!(size_of::(), 16 + 32 * 4 + 8 + 16 * 15 + 2 + 6); const_assert_eq!(size_of::() % 8, 0); impl Bank { diff --git a/programs/mango-v4/src/state/mango_account.rs b/programs/mango-v4/src/state/mango_account.rs index f0e7af457..5b633fb34 100644 --- a/programs/mango-v4/src/state/mango_account.rs +++ b/programs/mango-v4/src/state/mango_account.rs @@ -512,6 +512,8 @@ impl Default for MangoAccountPerps { #[account(zero_copy)] pub struct MangoAccount { + pub name: [u8; 16], + pub group: Pubkey, pub owner: Pubkey, @@ -542,7 +544,7 @@ pub struct MangoAccount { } const_assert_eq!( size_of::(), - 3 * 32 + 16 + 3 * 32 + size_of::() + size_of::() + size_of::() diff --git a/programs/mango-v4/src/state/serum3_market.rs b/programs/mango-v4/src/state/serum3_market.rs index e9d51228a..6b0aac872 100644 --- a/programs/mango-v4/src/state/serum3_market.rs +++ b/programs/mango-v4/src/state/serum3_market.rs @@ -8,6 +8,7 @@ pub type Serum3MarketIndex = u16; #[account(zero_copy)] pub struct Serum3Market { + pub name: [u8; 16], pub group: Pubkey, pub serum_program: Pubkey, pub serum_market_external: Pubkey, @@ -19,7 +20,7 @@ pub struct Serum3Market { pub bump: u8, pub reserved: [u8; 1], } -const_assert_eq!(size_of::(), 32 * 3 + 3 * 2 + 1 + 1); +const_assert_eq!(size_of::(), 16 + 32 * 3 + 3 * 2 + 1 + 1); const_assert_eq!(size_of::() % 8, 0); #[macro_export] diff --git a/programs/mango-v4/src/util.rs b/programs/mango-v4/src/util.rs index 6e082ea18..0e70409bb 100644 --- a/programs/mango-v4/src/util.rs +++ b/programs/mango-v4/src/util.rs @@ -1,7 +1,7 @@ +use crate::error::MangoError; use anchor_lang::prelude::*; use anchor_lang::ZeroCopy; use arrayref::array_ref; -use fixed::types::I80F48; use std::cell::RefMut; use std::{cell::Ref, mem}; @@ -90,10 +90,10 @@ impl<'info> LoadZeroCopy for AccountInfo<'info> { } } -// Returns asset_weight and liab_weight -pub fn get_leverage_weights(leverage: I80F48) -> (I80F48, I80F48) { - ( - (leverage - I80F48::ONE).checked_div(leverage).unwrap(), - (leverage + I80F48::ONE).checked_div(leverage).unwrap(), - ) +pub fn fill_from_str(name: String) -> Result<[u8; 16]> { + let name_bytes = name.as_bytes(); + require!(name_bytes.len() < 16, MangoError::SomeError); + let mut name_ = [0u8; 16]; + name_[..name_bytes.len()].copy_from_slice(name_bytes); + Ok(name_) } diff --git a/programs/mango-v4/tests/program_test/mango_client.rs b/programs/mango-v4/tests/program_test/mango_client.rs index 781175a7f..37a9adbd4 100644 --- a/programs/mango-v4/tests/program_test/mango_client.rs +++ b/programs/mango-v4/tests/program_test/mango_client.rs @@ -472,6 +472,7 @@ impl<'keypair> ClientInstruction for RegisterTokenInstruction<'keypair> { ) -> (Self::Accounts, instruction::Instruction) { let program_id = mango_v4::id(); let instruction = Self::Instruction { + name: "some_ticker".to_string(), token_index: self.token_index, util0: self.util0, rate0: self.rate0, @@ -700,6 +701,7 @@ impl<'keypair> ClientInstruction for CreateAccountInstruction<'keypair> { let program_id = mango_v4::id(); let instruction = mango_v4::instruction::CreateAccount { account_num: self.account_num, + name: "my_mango_account".to_string(), }; let account = Pubkey::find_program_address( @@ -786,6 +788,7 @@ impl<'keypair> ClientInstruction for Serum3RegisterMarketInstruction<'keypair> { let program_id = mango_v4::id(); let instruction = Self::Instruction { market_index: self.market_index, + name: "some_ticker/usdc".to_string(), }; let serum_market = Pubkey::find_program_address( diff --git a/programs/mango-v4/tests/program_test/solana.rs b/programs/mango-v4/tests/program_test/solana.rs index cfb2d1a29..91a4d75bc 100644 --- a/programs/mango-v4/tests/program_test/solana.rs +++ b/programs/mango-v4/tests/program_test/solana.rs @@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock}; use anchor_lang::AccountDeserialize; use anchor_spl::token::TokenAccount; -use solana_program::clock::UnixTimestamp; use solana_program::{program_pack::Pack, rent::*, system_instruction}; use solana_program_test::*; use solana_sdk::{ @@ -15,8 +14,6 @@ use solana_sdk::{ }; use spl_token::*; -use super::mango_client::ClientAccountLoader; - pub struct SolanaCookie { pub context: RefCell, pub rent: Rent, diff --git a/ts/accounts/types/bank.ts b/ts/accounts/types/bank.ts index 37c8c74fb..ca8a4eaba 100644 --- a/ts/accounts/types/bank.ts +++ b/ts/accounts/types/bank.ts @@ -1,15 +1,18 @@ +import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes'; import { PublicKey } from '@solana/web3.js'; import bs58 from 'bs58'; import { MangoClient } from '../../client'; import { I80F48, I80F48Dto } from './I80F48'; export class Bank { + public name: string; public depositIndex: I80F48; public borrowIndex: I80F48; static from( publicKey: PublicKey, obj: { + name: number[]; group: PublicKey; mint: PublicKey; vault: PublicKey; @@ -29,6 +32,7 @@ export class Bank { ) { return new Bank( publicKey, + obj.name, obj.group, obj.mint, obj.vault, @@ -49,6 +53,7 @@ export class Bank { constructor( public publicKey: PublicKey, + name: number[], public group: PublicKey, public mint: PublicKey, public vault: PublicKey, @@ -65,6 +70,7 @@ export class Bank { dust: Object, public tokenIndex: number, ) { + this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0]; this.depositIndex = I80F48.from(depositIndex); this.borrowIndex = I80F48.from(borrowIndex); } diff --git a/ts/accounts/types/group.ts b/ts/accounts/types/group.ts index b78c9ffe9..6a3f47717 100644 --- a/ts/accounts/types/group.ts +++ b/ts/accounts/types/group.ts @@ -1,9 +1,5 @@ import { PublicKey } from '@solana/web3.js'; import { MangoClient } from '../../client'; -import { - DEVNET_MINTS_REVERSE, - DEVNET_SERUM3_MARKETS_REVERSE, -} from '../../constants'; import { Bank } from './bank'; import { Serum3Market } from './serum3'; @@ -32,20 +28,13 @@ export class Group { public async reloadBanks(client: MangoClient) { const banks = await client.getBanksForGroup(this); - this.banksMap = new Map( - banks.map((bank) => [DEVNET_MINTS_REVERSE[bank.mint.toBase58()], bank]), - ); + this.banksMap = new Map(banks.map((bank) => [bank.name, bank])); } public async reloadSerum3Markets(client: MangoClient) { const serum3Markets = await client.serum3GetMarket(this); this.serum3MarketsMap = new Map( - serum3Markets.map((serum3Market) => [ - DEVNET_SERUM3_MARKETS_REVERSE[ - serum3Market.serumMarketExternal.toBase58() - ], - serum3Market, - ]), + serum3Markets.map((serum3Market) => [serum3Market.name, serum3Market]), ); } } diff --git a/ts/accounts/types/mangoAccount.ts b/ts/accounts/types/mangoAccount.ts index 4c8f0e8fc..96b8f01be 100644 --- a/ts/accounts/types/mangoAccount.ts +++ b/ts/accounts/types/mangoAccount.ts @@ -1,14 +1,16 @@ +import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes'; import { PublicKey } from '@solana/web3.js'; import { Bank } from './bank'; import { I80F48, I80F48Dto } from './I80F48'; - export class MangoAccount { public tokens: TokenAccount[]; public serum3: Serum3Account[]; + public name: string; static from( publicKey: PublicKey, obj: { + name: number[]; group: PublicKey; owner: PublicKey; delegate: PublicKey; @@ -24,6 +26,7 @@ export class MangoAccount { ) { return new MangoAccount( publicKey, + obj.name, obj.group, obj.owner, obj.delegate, @@ -40,6 +43,7 @@ export class MangoAccount { constructor( public publicKey: PublicKey, + name: number[], public group: PublicKey, public owner: PublicKey, public delegate: PublicKey, @@ -52,6 +56,7 @@ export class MangoAccount { bump: number, reserved: number[], ) { + this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0]; this.tokens = tokens.values.map((dto) => TokenAccount.from(dto)); this.serum3 = serum3.values.map((dto) => Serum3Account.from(dto)); } diff --git a/ts/accounts/types/serum3.ts b/ts/accounts/types/serum3.ts index 63dfefa92..ac8dcb877 100644 --- a/ts/accounts/types/serum3.ts +++ b/ts/accounts/types/serum3.ts @@ -1,9 +1,12 @@ +import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes'; import { PublicKey } from '@solana/web3.js'; export class Serum3Market { + public name: string; static from( publicKey: PublicKey, obj: { + name: number[]; group: PublicKey; serumProgram: PublicKey; serumMarketExternal: PublicKey; @@ -16,6 +19,7 @@ export class Serum3Market { ): Serum3Market { return new Serum3Market( publicKey, + obj.name, obj.group, obj.serumProgram, obj.serumMarketExternal, @@ -27,13 +31,16 @@ export class Serum3Market { constructor( public publicKey: PublicKey, + name: number[], public group: PublicKey, public serumProgram: PublicKey, public serumMarketExternal: PublicKey, public marketIndex: number, public baseTokenIndex: number, public quoteTokenIndex: number, - ) {} + ) { + this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0]; + } } export class Serum3SelfTradeBehavior { diff --git a/ts/client.ts b/ts/client.ts index 07177807c..3381adbe6 100644 --- a/ts/client.ts +++ b/ts/client.ts @@ -76,6 +76,7 @@ export class MangoClient { mintPk: PublicKey, oraclePk: PublicKey, tokenIndex: number, + name: string, util0: number, rate0: number, util1: number, @@ -90,6 +91,7 @@ export class MangoClient { return await this.program.methods .registerToken( tokenIndex, + name, util0, rate0, util1, @@ -118,7 +120,7 @@ export class MangoClient { { memcmp: { bytes: group.publicKey.toBase58(), - offset: 8, + offset: 24, }, }, ]) @@ -188,10 +190,11 @@ export class MangoClient { group: Group, ownerPk: PublicKey, accountNumber?: number, + name?: string, ): Promise { let mangoAccounts = await this.getMangoAccountForOwner(group, ownerPk); if (mangoAccounts.length === 0) { - await this.createMangoAccount(group, accountNumber ?? 0); + await this.createMangoAccount(group, accountNumber ?? 0, name ?? ''); mangoAccounts = await this.getMangoAccountForOwner(group, ownerPk); } return mangoAccounts[0]; @@ -200,9 +203,10 @@ export class MangoClient { public async createMangoAccount( group: Group, accountNumber: number, + name?: string, ): Promise { return await this.program.methods - .createAccount(accountNumber) + .createAccount(accountNumber, name ?? '') .accounts({ group: group.publicKey, owner: this.program.provider.wallet.publicKey, @@ -227,13 +231,13 @@ export class MangoClient { { memcmp: { bytes: group.publicKey.toBase58(), - offset: 8, + offset: 24, }, }, { memcmp: { bytes: ownerPk.toBase58(), - offset: 40, + offset: 56, }, }, ]) @@ -335,9 +339,10 @@ export class MangoClient { baseBank: Bank, quoteBank: Bank, marketIndex: number, + name: string, ): Promise { return await this.program.methods - .serum3RegisterMarket(marketIndex) + .serum3RegisterMarket(marketIndex, name) .accounts({ group: group.publicKey, admin: this.program.provider.wallet.publicKey, @@ -362,7 +367,7 @@ export class MangoClient { { memcmp: { bytes: group.publicKey.toBase58(), - offset: 8, + offset: 24, }, }, ]; @@ -373,7 +378,7 @@ export class MangoClient { filters.push({ memcmp: { bytes: bs58.encode(bbuf), - offset: 106, + offset: 122, }, }); } @@ -384,7 +389,7 @@ export class MangoClient { filters.push({ memcmp: { bytes: bs58.encode(qbuf), - offset: 108, + offset: 124, }, }); } diff --git a/ts/constants.ts b/ts/constants.ts index cb1167a28..4b62d6b42 100644 --- a/ts/constants.ts +++ b/ts/constants.ts @@ -1,6 +1,6 @@ import { PublicKey } from '@solana/web3.js'; -export const DEVNET_GROUP = '882CDTXBMgqvD2ZzDcW2DxzMwEz1kD4eg7bzEBhFYejd'; +export const DEVNET_GROUP = 'EjDBeQkKQ1y68ki4YskWjSZc4v5hJ44KWH64uvMNubsg'; export const DEVNET_MINTS = new Map([ ['USDC', '8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN'], diff --git a/ts/example1-admin.ts b/ts/example1-admin.ts index 33266ec1c..ae777b832 100644 --- a/ts/example1-admin.ts +++ b/ts/example1-admin.ts @@ -47,6 +47,7 @@ async function main() { btcDevnetMint, btcDevnetOracle, 0, + 'btc', 0.4, 0.07, 0.8, @@ -73,6 +74,7 @@ async function main() { usdcDevnetMint, usdcDevnetOracle.publicKey, 1, + 'usdc', 0.4, 0.07, 0.8, @@ -107,6 +109,7 @@ async function main() { banks[0], banks[1], 0, + 'btc/usdc', ); } catch (error) {} const markets = await client.serum3GetMarket( diff --git a/ts/example1-user.ts b/ts/example1-user.ts index daaf5a6cd..f2704ef86 100644 --- a/ts/example1-user.ts +++ b/ts/example1-user.ts @@ -42,6 +42,7 @@ async function main() { group, user.publicKey, 0, + 'my_mango_account', ); console.log(`MangoAccount ${mangoAccount.publicKey}`); diff --git a/ts/mango_v4.ts b/ts/mango_v4.ts index 4beef6a64..67255304d 100644 --- a/ts/mango_v4.ts +++ b/ts/mango_v4.ts @@ -164,6 +164,10 @@ export type MangoV4 = { "name": "tokenIndex", "type": "u16" }, + { + "name": "name", + "type": "string" + }, { "name": "util0", "type": "f32" @@ -274,6 +278,10 @@ export type MangoV4 = { { "name": "accountNum", "type": "u8" + }, + { + "name": "name", + "type": "string" } ] }, @@ -599,6 +607,10 @@ export type MangoV4 = { { "name": "marketIndex", "type": "u16" + }, + { + "name": "name", + "type": "string" } ] }, @@ -1346,6 +1358,15 @@ export type MangoV4 = { "type": { "kind": "struct", "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, { "name": "group", "type": "publicKey" @@ -1557,6 +1578,15 @@ export type MangoV4 = { "type": { "kind": "struct", "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, { "name": "group", "type": "publicKey" @@ -1867,6 +1897,15 @@ export type MangoV4 = { "type": { "kind": "struct", "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, { "name": "group", "type": "publicKey" @@ -2627,6 +2666,10 @@ export const IDL: MangoV4 = { "name": "tokenIndex", "type": "u16" }, + { + "name": "name", + "type": "string" + }, { "name": "util0", "type": "f32" @@ -2737,6 +2780,10 @@ export const IDL: MangoV4 = { { "name": "accountNum", "type": "u8" + }, + { + "name": "name", + "type": "string" } ] }, @@ -3062,6 +3109,10 @@ export const IDL: MangoV4 = { { "name": "marketIndex", "type": "u16" + }, + { + "name": "name", + "type": "string" } ] }, @@ -3809,6 +3860,15 @@ export const IDL: MangoV4 = { "type": { "kind": "struct", "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, { "name": "group", "type": "publicKey" @@ -4020,6 +4080,15 @@ export const IDL: MangoV4 = { "type": { "kind": "struct", "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, { "name": "group", "type": "publicKey" @@ -4330,6 +4399,15 @@ export const IDL: MangoV4 = { "type": { "kind": "struct", "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, { "name": "group", "type": "publicKey"