Brought changes to structs and instructions across for new group/code v3.4.

This commit is contained in:
Geoff Taylor 2021-07-13 12:43:50 +01:00
parent 82405cfec1
commit bcd56301c9
10 changed files with 159 additions and 50 deletions

View File

@ -6,6 +6,66 @@
"testnet": "https://testnet.solana.com"
},
"groups": [
{
"cluster": "devnet",
"name": "mango_test_v3.4",
"publicKey": "CNd6bmeM1q7yS1C54xwT4fKpF3EquLWhFmF9xVweGjrM",
"quoteSymbol": "USDC",
"mangoProgramId": "32WeJ46tuY6QEkgydqzHYU5j85UT9m1cPJwFxPjuSVCt",
"serumProgramId": "DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY",
"tokens": [
{
"symbol": "USDC",
"mintKey": "EMjjdsqERN4wJUR9jMBax2pzqQPeGLNn5NeucbHpDUZK",
"decimals": 9,
"rootKey": "313wvMRvKN4BphP1qP3RG854KDzhu5Gg8wvi6VVsWp43",
"nodeKeys": [
"BXNs5nSef9eo16Sxxth5ed9WFjPBqkibxwdRmQVHPK4x"
]
},
{
"symbol": "BTC",
"mintKey": "bypQzRBaSDWiKhoAw3hNkf35eF3z3AZCU8Sxks6mTPP",
"decimals": 6,
"rootKey": "6b54SUFyXxnTUF9iQDDGQeB3m3F3vctkojwD2J4N3Gae",
"nodeKeys": [
"Drvtng3669H9F2KhmNbg8sB5SEnrBYo2L9t6Dug7JdZg"
]
}
],
"oracles": [
{
"symbol": "BTC",
"publicKey": "5c5T9996DKTqNcjFczz9MRASGubpxY2WfmCdpFdd5Di1"
}
],
"perpMarkets": [
{
"name": "BTC-PERP",
"publicKey": "Dgr3VDcjvwMoMPXw2Dqz3vuudGDCSwMM9vaV8LVnMYtk",
"baseSymbol": "BTC",
"baseDecimals": 6,
"quoteDecimals": 9,
"marketIndex": 0,
"bidsKey": "2mJw42YxF6bSi7NxgP1wLbc9J1NybX8Ms88xYiXAEQyc",
"asksKey": "FSczMHXhsorbiMXuGAhiY6yo2shRTFgbsmYMvZ8VCJPm",
"eventsKey": "41iaEsaJrcC5CDJJU85AvqMdrvASGgnCdHUs43gKCcoX"
}
],
"spotMarkets": [
{
"name": "BTC/USDC",
"publicKey": "E1mfsnnCcL24JcDQxr7F2BpWjkyy5x2WHys8EL2pnCj9",
"baseSymbol": "BTC",
"baseDecimals": 6,
"quoteDecimals": 9,
"marketIndex": 0,
"bidsKey": "8ovMqp4Tb7xe4r3bXdeyzzucMQfemcn2Wi2j55aYS2rR",
"asksKey": "GJ5PKrUkGrjHRhP1kNztgfHixYXyNpsRy8S2StBQ171n",
"eventsKey": "4xJ5T9c7m5wyt9Xw4PnP6yAU1sdqaegsiyGC6CvG2mUJ"
}
]
},
{
"cluster": "devnet",
"name": "mango_test_v3.3",

View File

@ -40,7 +40,8 @@ class Account(AddressableAccount):
meta_data: Metadata, group: Group, owner: PublicKey, in_margin_basket: typing.Sequence[Decimal],
deposits: typing.Sequence[typing.Optional[TokenValue]], borrows: typing.Sequence[typing.Optional[TokenValue]],
net_assets: typing.Sequence[typing.Optional[TokenValue]], spot_open_orders: typing.Sequence[PublicKey],
perp_accounts: typing.Sequence[typing.Any], is_bankrupt: bool):
perp_accounts: typing.Sequence[typing.Any], msrm_amount: Decimal, being_liquidated: bool,
is_bankrupt: bool):
super().__init__(account_info)
self.version: Version = version
@ -53,6 +54,8 @@ class Account(AddressableAccount):
self.net_assets: typing.Sequence[typing.Optional[TokenValue]] = net_assets
self.spot_open_orders: typing.Sequence[PublicKey] = spot_open_orders
self.perp_accounts: typing.Sequence[layouts.PERP_ACCOUNT] = perp_accounts
self.msrm_amount: Decimal = msrm_amount
self.being_liquidated: bool = being_liquidated
self.is_bankrupt: bool = is_bankrupt
@staticmethod
@ -79,9 +82,11 @@ class Account(AddressableAccount):
spot_open_orders: typing.Sequence[PublicKey] = layout.spot_open_orders
perp_accounts: typing.Sequence[typing.Any] = layout.perp_accounts
msrm_amount: Decimal = layout.msrm_amount
being_liquidated: bool = layout.being_liquidated
is_bankrupt: bool = layout.is_bankrupt
return Account(account_info, version, meta_data, group, owner, in_margin_basket, deposits, borrows, net_assets, spot_open_orders, perp_accounts, is_bankrupt)
return Account(account_info, version, meta_data, group, owner, in_margin_basket, deposits, borrows, net_assets, spot_open_orders, perp_accounts, msrm_amount, being_liquidated, is_bankrupt)
@staticmethod
def parse(context: Context, account_info: AccountInfo, group: Group) -> "Account":
@ -140,6 +145,8 @@ class Account(AddressableAccount):
group = f"{self.group}".replace("\n", "\n ")
return f"""« 𝙰𝚌𝚌𝚘𝚞𝚗𝚝 {self.version} [{self.address}]
{self.meta_data}
Bankrupt? {self.is_bankrupt}
Being Liquidated? {self.being_liquidated}
Owner: {self.owner}
{group}
Deposits:
@ -152,6 +159,7 @@ class Account(AddressableAccount):
{spot_open_orders}
Perp Accounts:
{perp_accounts}
MSRM: {self.msrm_amount}
»"""
def __repr__(self) -> str:

View File

@ -46,7 +46,7 @@ class Group(AddressableAccount):
perp_markets: typing.Sequence[typing.Optional[PerpMarketInfo]],
oracles: typing.Sequence[PublicKey], signer_nonce: Decimal, signer_key: PublicKey,
admin: PublicKey, dex_program_id: PublicKey, cache: PublicKey, valid_interval: Decimal,
dao_vault: typing.Optional[PublicKey]):
dao_vault: PublicKey, srm_vault: PublicKey, msrm_vault: PublicKey):
super().__init__(account_info)
self.version: Version = version
self.name: str = name
@ -62,7 +62,9 @@ class Group(AddressableAccount):
self.dex_program_id: PublicKey = dex_program_id
self.cache: PublicKey = cache
self.valid_interval: Decimal = valid_interval
self.dao_vault: typing.Optional[PublicKey] = dao_vault
self.dao_vault: PublicKey = dao_vault
self.srm_vault: PublicKey = srm_vault
self.msrm_vault: PublicKey = msrm_vault
@property
def shared_quote_token(self) -> TokenInfo:
@ -97,8 +99,10 @@ class Group(AddressableAccount):
cache: PublicKey = layout.cache
valid_interval: Decimal = layout.valid_interval
dao_vault: PublicKey = layout.dao_vault
srm_vault: PublicKey = layout.srm_vault
msrm_vault: PublicKey = layout.msrm_vault
return Group(account_info, version, name, meta_data, tokens, spot_markets, perp_markets, oracles, signer_nonce, signer_key, admin, dex_program_id, cache, valid_interval, dao_vault)
return Group(account_info, version, name, meta_data, tokens, spot_markets, perp_markets, oracles, signer_nonce, signer_key, admin, dex_program_id, cache, valid_interval, dao_vault, srm_vault, msrm_vault)
@staticmethod
def parse(context: Context, account_info: AccountInfo) -> "Group":
@ -160,6 +164,8 @@ class Group(AddressableAccount):
DEX Program ID: {self.dex_program_id}
Cache: {self.cache}
DAO Vault: {self.dao_vault}
SRM Vault: {self.srm_vault}
MSRM Vault: {self.msrm_vault}
Valid Interval: {self.valid_interval}
Tokens:
{tokens}

View File

@ -286,13 +286,12 @@ def build_cancel_perp_order_instructions(context: Context, wallet: Wallet, accou
})
# Accounts expected by this instruction (both CANCEL_PERP_ORDER and CANCEL_PERP_ORDER_BY_CLIENT_ID are the same):
# 0. `[]` mangoGroupPk
# 1. `[writable]` mangoAccountPk
# 2. `[signer]` ownerPk
# 3. `[writable]` perpMarketPk
# 4. `[writable]` bidsPk
# 5. `[writable]` asksPk
# 6. `[writable]` eventQueuePk
# { isSigner: false, isWritable: false, pubkey: mangoGroupPk },
# { isSigner: false, isWritable: true, pubkey: mangoAccountPk },
# { isSigner: true, isWritable: false, pubkey: ownerPk },
# { isSigner: false, isWritable: false, pubkey: perpMarketPk },
# { isSigner: false, isWritable: true, pubkey: bidsPk },
# { isSigner: false, isWritable: true, pubkey: asksPk },
instructions = [
TransactionInstruction(
@ -300,10 +299,9 @@ def build_cancel_perp_order_instructions(context: Context, wallet: Wallet, accou
AccountMeta(is_signer=False, is_writable=False, pubkey=account.group.address),
AccountMeta(is_signer=False, is_writable=True, pubkey=account.address),
AccountMeta(is_signer=True, is_writable=False, pubkey=wallet.address),
AccountMeta(is_signer=False, is_writable=True, pubkey=perp_market.address),
AccountMeta(is_signer=False, is_writable=False, pubkey=perp_market.address),
AccountMeta(is_signer=False, is_writable=True, pubkey=perp_market.bids),
AccountMeta(is_signer=False, is_writable=True, pubkey=perp_market.asks),
AccountMeta(is_signer=False, is_writable=True, pubkey=perp_market.event_queue)
AccountMeta(is_signer=False, is_writable=True, pubkey=perp_market.asks)
],
program_id=context.program_id,
data=data
@ -520,10 +518,11 @@ def build_spot_place_order_instructions(context: Context, wallet: Wallet, group:
# { isSigner: false, isWritable: false, pubkey: signerPk },
# { isSigner: false, isWritable: false, pubkey: SYSVAR_RENT_PUBKEY },
# { isSigner: false, isWritable: false, pubkey: dexSignerPk },
# ...openOrders.map((pubkey) => ({
# isSigner: false,
# isWritable: true, // TODO: only pass the one writable you are going to place the order on
# pubkey,
# { isSigner: false, isWritable: false, pubkey: msrmOrSrmVaultPk },
# ...openOrders.map(({ pubkey, isWritable }) => ({
# isSigner: false,
# isWritable,
# pubkey,
# })),
fee_discount_address_meta: typing.List[AccountMeta] = []
if fee_discount_address is not None:
@ -552,6 +551,7 @@ def build_spot_place_order_instructions(context: Context, wallet: Wallet, group:
AccountMeta(is_signer=False, is_writable=False, pubkey=group.signer_key),
AccountMeta(is_signer=False, is_writable=False, pubkey=SYSVAR_RENT_PUBKEY),
AccountMeta(is_signer=False, is_writable=False, pubkey=vault_signer),
AccountMeta(is_signer=False, is_writable=False, pubkey=group.srm_vault or SYSTEM_PROGRAM_ADDRESS),
*list([AccountMeta(is_signer=False, is_writable=(oo_address == open_orders_address),
pubkey=oo_address or SYSTEM_PROGRAM_ADDRESS) for oo_address in account.spot_open_orders]),
*fee_discount_address_meta
@ -610,9 +610,9 @@ def build_compound_spot_place_order_instructions(context: Context, wallet: Walle
return combined
# # 🥭 build_cancel_perp_order_instruction function
# # 🥭 build_cancel_spot_order_instruction function
#
# Builds the instructions necessary for cancelling a perp order.
# Builds the instructions necessary for cancelling a spot order.
#

View File

@ -452,7 +452,10 @@ PERP_MARKET_INFO = construct.Struct(
# pub mango_cache: Pubkey,
# pub valid_interval: u64,
#
# // DAO vault is funded by the Mango DAO with USDC and can be withdrawn by the DAO
# pub dao_vault: Pubkey,
# pub srm_vault: Pubkey,
# pub msrm_vault: Pubkey,
# }
# ```
GROUP = construct.Struct(
@ -468,7 +471,9 @@ GROUP = construct.Struct(
"dex_program_id" / PublicKeyAdapter(),
"cache" / PublicKeyAdapter(),
"valid_interval" / DecimalAdapter(),
"dao_vault" / PublicKeyAdapter()
"dao_vault" / PublicKeyAdapter(),
"srm_vault" / PublicKeyAdapter(),
"msrm_vault" / PublicKeyAdapter()
)
# # 🥭 ROOT_BANK
@ -593,7 +598,6 @@ PERP_ACCOUNT = construct.Struct(
# pub mango_group: Pubkey,
# pub owner: Pubkey,
#
# // pub in_basket: [bool; MAX_TOKENS],
# pub in_margin_basket: [bool; MAX_PAIRS],
# pub num_in_margin_basket: u8,
#
@ -605,6 +609,7 @@ PERP_ACCOUNT = construct.Struct(
# // Perps related data
# pub perp_accounts: [PerpAccount; MAX_PAIRS],
#
# pub msrm_amount: u64,
# /// This account cannot open new positions or borrow until `init_health >= 0`
# pub being_liquidated: bool,
#
@ -623,9 +628,10 @@ MANGO_ACCOUNT = construct.Struct(
"borrows" / construct.Array(MAX_TOKENS, FloatI80F48Adapter()),
"spot_open_orders" / construct.Array(MAX_PAIRS, PublicKeyAdapter()),
"perp_accounts" / construct.Array(MAX_PAIRS, PERP_ACCOUNT),
"msrm_amount" / DecimalAdapter(),
"being_liquidated" / DecimalAdapter(1),
"is_bankrupt" / DecimalAdapter(1),
"padding" / construct.Padding(6)
construct.Padding(6)
)
@ -661,6 +667,10 @@ MANGO_ACCOUNT = construct.Struct(
# pub max_depth_bps: I80F48,
# pub scaler: I80F48,
# pub total_liquidity_points: I80F48,
# pub points_per_mngo: I80F48, // how many points equal 1 native MNGO
#
# // mngo_vault holds mango tokens to be disbursed as liquidity incentives for this perp market
# pub mngo_vault: Pubkey,
# }
# ```
PERP_MARKET = construct.Struct(
@ -674,14 +684,19 @@ PERP_MARKET = construct.Struct(
"long_funding" / FloatI80F48Adapter(),
"short_funding" / FloatI80F48Adapter(),
"open_interest" / SignedDecimalAdapter(),
"last_updated" / DatetimeAdapter(),
"seq_num" / DecimalAdapter(),
"fees_accrued" / FloatI80F48Adapter(),
"max_depth_bips" / FloatI80F48Adapter(),
"scaler" / FloatI80F48Adapter(),
"total_liquidity_points" / FloatI80F48Adapter()
"total_liquidity_points" / FloatI80F48Adapter(),
"points_per_mngo" / FloatI80F48Adapter(),
"mngo_vault" / PublicKeyAdapter()
)

View File

@ -38,7 +38,7 @@ class PerpMarket(AddressableAccount):
event_queue: PublicKey, base_lot_size: Decimal, quote_lot_size: Decimal, long_funding: Decimal,
short_funding: Decimal, open_interest: Decimal, last_updated: datetime, seq_num: Decimal,
fees_accrued: Decimal, max_depth_bips: Decimal, scaler: PublicKey,
total_liquidity_points: Decimal):
total_liquidity_points: Decimal, points_per_mngo: Decimal, mngo_vault: PublicKey):
super().__init__(account_info)
self.version: Version = version
@ -58,6 +58,8 @@ class PerpMarket(AddressableAccount):
self.max_depth_bips: Decimal = max_depth_bips
self.scaler: PublicKey = scaler
self.total_liquidity_points: Decimal = total_liquidity_points
self.points_per_mngo: Decimal = points_per_mngo
self.mngo_vault: PublicKey = mngo_vault
self.market_index = group.find_perp_market_index(self.address)
@ -90,10 +92,13 @@ class PerpMarket(AddressableAccount):
max_depth_bips: Decimal = layout.max_depth_bips
scaler: PublicKey = layout.scaler
total_liquidity_points: Decimal = layout.total_liquidity_points
points_per_mngo: Decimal = layout.points_per_mngo
mngo_vault: PublicKey = layout.mngo_vault
return PerpMarket(account_info, version, meta_data, group, bids, asks, event_queue,
base_lot_size, quote_lot_size, long_funding, short_funding, open_interest,
last_updated, seq_num, fees_accrued, max_depth_bips, scaler, total_liquidity_points)
last_updated, seq_num, fees_accrued, max_depth_bips, scaler, total_liquidity_points,
points_per_mngo, mngo_vault)
@staticmethod
def parse(account_info: AccountInfo, group: Group) -> "PerpMarket":
@ -130,4 +135,6 @@ class PerpMarket(AddressableAccount):
Max Depth Bips: {self.max_depth_bips}
Scaler: {self.scaler}
Total Liquidity Points: {self.total_liquidity_points}
Points Per MNGO: {self.points_per_mngo}
MNGO Vault: {self.mngo_vault}
»"""

File diff suppressed because one or more lines are too long

View File

@ -16,13 +16,16 @@ def test_construction():
net_assets = [Decimal(10), Decimal(0), Decimal(5)]
spot_open_orders = [fake_seeded_public_key("spot1"), fake_seeded_public_key(
"spot2"), fake_seeded_public_key("spot3")]
msrm_amount = Decimal(0)
being_liquidated = False
is_bankrupt = False
# TODO - this isn't right.
perp_accounts = [fake_seeded_public_key("perp1"), fake_seeded_public_key("perp2"), fake_seeded_public_key("perp3")]
actual = mango.Account(account_info, mango.Version.V1, meta_data, group, owner, in_margin_basket,
deposits, borrows, net_assets, spot_open_orders, perp_accounts, is_bankrupt)
deposits, borrows, net_assets, spot_open_orders, perp_accounts, msrm_amount,
being_liquidated, is_bankrupt)
assert actual is not None
assert actual.logger is not None
@ -36,3 +39,6 @@ def test_construction():
assert actual.net_assets == net_assets
assert actual.spot_open_orders == spot_open_orders
assert actual.perp_accounts == perp_accounts
assert actual.msrm_amount == msrm_amount
assert actual.being_liquidated == being_liquidated
assert actual.is_bankrupt == is_bankrupt

View File

@ -8,8 +8,8 @@ def context_has_default_values(ctx):
assert ctx.cluster_url == "https://api.devnet.solana.com"
assert ctx.program_id == PublicKey("32WeJ46tuY6QEkgydqzHYU5j85UT9m1cPJwFxPjuSVCt")
assert ctx.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
assert ctx.group_name == "mango_test_v3.3"
assert ctx.group_id == PublicKey("Bio3MdqCwpEJ3rgCumci1h8WcMFFcwU6UMBsKcuT5kJp")
assert ctx.group_name == "mango_test_v3.4"
assert ctx.group_id == PublicKey("CNd6bmeM1q7yS1C54xwT4fKpF3EquLWhFmF9xVweGjrM")
def test_context_default_exists():
@ -28,8 +28,8 @@ def test_context_default_values():
# assert derived.cluster_url == "https://solana-api.projectserum.com"
# assert derived.program_id == PublicKey("32WeJ46tuY6QEkgydqzHYU5j85UT9m1cPJwFxPjuSVCt")
# assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
# assert derived.group_name == "mango_test_v3.3"
# assert derived.group_id == PublicKey("Bio3MdqCwpEJ3rgCumci1h8WcMFFcwU6UMBsKcuT5kJp")
# assert derived.group_name == "mango_test_v3.4"
# assert derived.group_id == PublicKey("CNd6bmeM1q7yS1C54xwT4fKpF3EquLWhFmF9xVweGjrM")
# context_has_default_values(mango.Context.default())
@ -40,34 +40,34 @@ def test_new_from_cluster_url():
assert derived.cluster_url == "https://some-dev-host"
assert derived.program_id == PublicKey("32WeJ46tuY6QEkgydqzHYU5j85UT9m1cPJwFxPjuSVCt")
assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
assert derived.group_name == "mango_test_v3.3"
assert derived.group_id == PublicKey("Bio3MdqCwpEJ3rgCumci1h8WcMFFcwU6UMBsKcuT5kJp")
assert derived.group_name == "mango_test_v3.4"
assert derived.group_id == PublicKey("CNd6bmeM1q7yS1C54xwT4fKpF3EquLWhFmF9xVweGjrM")
context_has_default_values(mango.Context.default())
def test_new_from_group_name():
context_has_default_values(mango.Context.default())
derived = mango.Context.default().new_from_group_name("mango_test_v3.3")
derived = mango.Context.default().new_from_group_name("mango_test_v3.4")
assert derived.cluster == "devnet"
assert derived.cluster_url == "https://api.devnet.solana.com"
assert derived.program_id == PublicKey("32WeJ46tuY6QEkgydqzHYU5j85UT9m1cPJwFxPjuSVCt")
assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
# Should update both of these values on new group name.
assert derived.group_name == "mango_test_v3.3"
assert derived.group_id == PublicKey("Bio3MdqCwpEJ3rgCumci1h8WcMFFcwU6UMBsKcuT5kJp")
assert derived.group_name == "mango_test_v3.4"
assert derived.group_id == PublicKey("CNd6bmeM1q7yS1C54xwT4fKpF3EquLWhFmF9xVweGjrM")
context_has_default_values(mango.Context.default())
def test_new_from_group_id():
context_has_default_values(mango.Context.default())
derived = mango.Context.default().new_from_group_id(PublicKey("Bio3MdqCwpEJ3rgCumci1h8WcMFFcwU6UMBsKcuT5kJp"))
derived = mango.Context.default().new_from_group_id(PublicKey("CNd6bmeM1q7yS1C54xwT4fKpF3EquLWhFmF9xVweGjrM"))
assert derived.cluster == "devnet"
assert derived.cluster_url == "https://api.devnet.solana.com"
assert derived.program_id == PublicKey("32WeJ46tuY6QEkgydqzHYU5j85UT9m1cPJwFxPjuSVCt")
assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
# Should update both of these values on new group ID.
assert derived.group_name == "mango_test_v3.3"
assert derived.group_id == PublicKey("Bio3MdqCwpEJ3rgCumci1h8WcMFFcwU6UMBsKcuT5kJp")
assert derived.group_name == "mango_test_v3.4"
assert derived.group_id == PublicKey("CNd6bmeM1q7yS1C54xwT4fKpF3EquLWhFmF9xVweGjrM")
context_has_default_values(mango.Context.default())

View File

@ -18,12 +18,15 @@ def test_construction():
admin_key = fake_seeded_public_key("admin key")
dex_program_id = fake_seeded_public_key("DEX program ID")
cache_key = fake_seeded_public_key("cache key")
dao_vault = fake_seeded_public_key("insurance vault")
valid_interval = Decimal(7)
dao_vault = fake_seeded_public_key("insurance vault")
srm_vault = fake_seeded_public_key("SRM vault")
msrm_vault = fake_seeded_public_key("MSRM vault")
actual = mango.Group(account_info, mango.Version.V1, name, meta_data, token_infos,
spot_markets, perp_markets, oracles, signer_nonce, signer_key,
admin_key, dex_program_id, cache_key, valid_interval, dao_vault)
admin_key, dex_program_id, cache_key, valid_interval, dao_vault,
srm_vault, msrm_vault)
assert actual is not None
assert actual.logger is not None
@ -40,6 +43,8 @@ def test_construction():
assert actual.cache == cache_key
assert actual.valid_interval == valid_interval
assert actual.dao_vault == dao_vault
assert actual.srm_vault == srm_vault
assert actual.msrm_vault == msrm_vault
# Need better stubs/fakes/mocks before reinstating this, now that Group loading tries to fetch the RootBanks.