Ignore .idea

Bump version, rename root folder

Multiple misc. improvements

Bump version

Bump version

Update .gitignore
This commit is contained in:
waterquarks 2022-12-23 20:56:48 +00:00
commit 8463a434fc
145 changed files with 21426 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.venv/
build
.idea
id.json
config.json
.DS_Store
**/__pycache__/
dist/*
.swp

68
README.md Normal file
View File

@ -0,0 +1,68 @@
# mango-explorer-v4
Python client library for interacting with Mango Markets V4.
## 📦 Installation
![PyPI](https://img.shields.io/pypi/v/mango-explorer-v4)
`mango-explorer-v4` is available as a [Python package on PyPI](https://pypi.org/project/mango-explorer-v4) and can be installed as:
```
pip install mango-explorer-v4
```
## Example usage
Assuming that you have a SOL wallet already set up, visit https://app.mango.markets to create a Mango account and fund it so that you can place orders. You can find all available examples [here](./examples).
```python
import asyncio
from mango_explorer_v4 import MangoClient
async def main():
mango_client = await MangoClient.connect(
secret_key='YOUR_SECRET_KEY',
# Can be the output from Phantom's "Export Private Key"
# Or the byte array output from solana-keygen, as [173,143,69,111 ... 109]
mango_account_pk='YOUR_MANGO_ACCOUNT_PK'
)
print(await mango_client.symbols())
# [
# {
# 'name': 'SOL/USDC',
# 'baseCurrency': 'SOL',
# 'quoteCurrency': 'USDC',
# 'makerFees': -5e-05,
# 'takerFees': 0.0001
# }
# ...
# ]
print(await mango_client.place_order('SOL/USDC', 'bid', 10, 0.1, 'limit'))
# (Refresh the UI to see the newly opened order)
print(await mango_client.orderbook_l2('SOL/USDC', 3))
# {
# 'symbol': 'SOL/USDC',
# 'bids': [
# [11.826, 0.899],
# [11.824, 39.436],
# [11.82, 316.421],
# ],
# 'asks': [
# [11.839, 0.78],
# [11.84, 44.392],
# [11.841, 1.1],
# ]}
print(await mango_client.balances())
# [
# {'symbol': 'USDC', 'balance': 2.7435726906761744},
# {'symbol': 'SOL', 'balance': 0.1690007074236178},
# ...
# ]
asyncio.run(main())
```

4
config.example.json Normal file
View File

@ -0,0 +1,4 @@
{
"secret_key": "YOUR_SECRET_KEY",
"mango_account_pk": "MANGO_ACCOUNT_PK"
}

View File

@ -0,0 +1,56 @@
import asyncio
import json
import pathlib
from solana.transaction import Transaction
from mango_explorer_v4.mango_client import MangoClient
async def main():
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
symbol = 'SOL/USDC'
orderbook = await mango_client.orderbook_l2(symbol)
mid_price = (orderbook['bids'][0][0] + orderbook['asks'][0][0]) / 2
spread = 500 / 1e4 # bps
orders = [{
'symbol': symbol,
'side': 'bid',
'price': mid_price - (mid_price * spread),
'size': 1, # TODO: Have here the minimum contract size
}, {
'symbol': symbol,
'side': 'ask',
'price': mid_price + (mid_price * spread),
'size': 1,
}]
serum3_cancel_all_orders_ix = mango_client.make_serum3_cancel_all_orders_ix('SOL/USDC')
serum3_place_order_ixs = map(lambda order: mango_client.make_serum3_place_order_ix(**order), orders)
tx = Transaction()
tx.add(serum3_cancel_all_orders_ix, *serum3_place_order_ixs)
recent_blockhash = (await mango_client.provider.connection.get_latest_blockhash()).value.blockhash
tx.recent_blockhash = str(recent_blockhash)
tx.sign(mango_client.provider.wallet.payer)
print(await mango_client.provider.send(tx))
if __name__ == '__main__':
asyncio.run(main())

26
examples/balances.py Normal file
View File

@ -0,0 +1,26 @@
import asyncio
import json
import pathlib
from mango_explorer_v4.mango_client import MangoClient
async def main():
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
print(await mango_client.balances())
# [
# {'symbol': 'USDC', 'balance': 2.7435726906761744},
# {'symbol': 'SOL', 'balance': 0.1690007074236178},
# {'symbol': 'MSOL', 'balance': 0.0}
# ]
if __name__ == '__main__':
asyncio.run(main())

View File

@ -0,0 +1,33 @@
import argparse
import asyncio
import json
import pathlib
from mango_explorer_v4.mango_client import MangoClient
async def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--symbol',
required=True
)
args = parser.parse_args()
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
print(await mango_client.cancel_all_orders(args.symbol))
# 5B9Rq1sZAjtzXFbYh7wiV1thNGiaAC716ejPSBLE3EvTNgKC8CmFETdtMx8L5nfXHYZ3R8WyAqr9upfRbVYyGVg5
# (Check the UI)
if __name__ == '__main__':
asyncio.run(main())

61
examples/fills.py Normal file
View File

@ -0,0 +1,61 @@
import asyncio
import json
import re
import websockets
from mango_explorer_v4.accounts.event_queue import EventQueue
async def main():
async for connection in websockets.connect('wss://api.mngo.cloud/fills/v1/'):
await connection.send(json.dumps({
'command': 'getMarkets'
}))
markets = json.loads(await connection.recv())
# {
# "9Y8paZ5wUpzLFfQuHz8j2RtPrKsDtHx9sbgFmWb5abCw": "MNGO-PERP",
# "HwhVGkfsSQ9JSQeQYu2CbkRCLvsh3qRZxG6m4oMVwZpN": "BTC-PERP",
# "8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6": "SOL/USDC",
# "9Lyhks5bQQxb9EyyX55NtgKQzpM4WK7JCmeaWuQ5MoXD": "mSOL/USDC"
# }
print(markets)
await asyncio.gather(*[
connection.send(
json.dumps({
'command': 'subscribe',
'marketId': market_id
})
)
for market_id in markets.keys()
])
async for raw_message in connection:
message = json.loads(raw_message)
if not 'slot' in message:
continue
is_snapshot = 'events' in message
market_name = markets[message['market']]
market_type = {'PERP': 'perpetual', 'USDC': 'spot'}[re.split(r"[-|/]", market_name)[1]]
if is_snapshot:
match market_type:
case 'perpetual':
print(len(message['events']))
# print(EventQueue.decode(message['events']))
else:
pass
# print(message, market_name, market_type)
if __name__ == '__main__':
asyncio.run(main())

View File

@ -0,0 +1,83 @@
import argparse
import asyncio
import json
from operator import neg
import websockets
from sortedcontainers import SortedDict
class Orderbook:
def __init__(
self,
bids: [[float, float]] = None,
asks: [[float, float]] = None
):
self.bids = SortedDict(neg)
self.asks = SortedDict()
if bids: self.bids.update({price: quantity for price, quantity in bids})
if asks: self.asks.update({price: quantity for price, quantity in asks})
async def main():
async for connection in websockets.connect('wss://api.mngo.cloud/orderbook/v1/'):
await connection.send(json.dumps({
'command': 'getMarkets'
}))
markets = json.loads(await connection.recv())
# {
# "9Y8paZ5wUpzLFfQuHz8j2RtPrKsDtHx9sbgFmWb5abCw": "MNGO-PERP",
# "HwhVGkfsSQ9JSQeQYu2CbkRCLvsh3qRZxG6m4oMVwZpN": "BTC-PERP",
# "8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6": "SOL/USDC",
# "9Lyhks5bQQxb9EyyX55NtgKQzpM4WK7JCmeaWuQ5MoXD": "mSOL/USDC"
# }
orderbooks = {market_name: Orderbook() for market_name in markets.values()}
await asyncio.gather(*[
connection.send(
json.dumps({
'command': 'subscribe',
'marketId': market_id
})
)
for market_id in markets.keys()
])
async for raw_message in connection:
message = json.loads(raw_message)
if 'market' not in message:
continue
is_snapshot = 'side' not in message
market_name = markets[message['market']]
orderbook = orderbooks[market_name]
if is_snapshot:
for side in ['bids', 'asks']:
suborderbook = getattr(orderbook, side)
suborderbook.clear(); suborderbook.update({price: size for price, size in message[side]})
continue
suborderbook = getattr(orderbook, {'bid': 'bids', 'ask': 'asks'}[message['side']])
for price, size in message['update']:
if size == 0:
suborderbook.pop(price)
else:
suborderbook.update({price: size})
print({'symbol': market_name, 'bids': orderbook.bids, 'asks': orderbook.asks})
if __name__ == '__main__':
asyncio.run(main())

88
examples/market_maker.py Normal file
View File

@ -0,0 +1,88 @@
import asyncio
import json
import logging
import pathlib
import argparse
from solana.transaction import Transaction
from mango_explorer_v4.mango_client import MangoClient
async def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--symbol',
required=True
)
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
symbol = 'SOL/USDC'
state = {
'orderbook': None,
'recent_blockhash': None
}
async def poll_orderbook():
async for orderbook in mango_client.snapshots_l2(symbol, 5):
state['orderbook'] = orderbook
async def poll_blockhash():
# All transactions require a Blockhash attached as metadata - rather than do the RPC
# roundtrip on each transaction build just for this, poll it in the background
async def poll():
state['recent_blockhash'] = str((await mango_client.provider.connection.get_latest_blockhash()).value.blockhash)
while True: asyncio.ensure_future(poll()); await asyncio.sleep(1)
asyncio.ensure_future(poll_orderbook())
asyncio.ensure_future(poll_blockhash())
while True:
try:
mid_price = round((state['orderbook']['bids'][0][0] + state['orderbook']['asks'][0][0]) / 2, 3)
spread = 50 / 1e4 # 50 bps
orders = [{
'symbol': symbol,
'side': 'bid',
'price': round(mid_price - (mid_price * spread), 3),
'size': 1, # TODO: Have here the minimum contract size
}, {
'symbol': symbol,
'side': 'ask',
'price': round(mid_price + (mid_price * spread), 3),
'size': 1,
}]
serum3_cancel_all_orders_ix = mango_client.make_serum3_cancel_all_orders_ix('SOL/USDC')
serum3_place_order_ixs = map(lambda order: mango_client.make_serum3_place_order_ix(**order), orders)
tx = Transaction()
tx.add(serum3_cancel_all_orders_ix, *serum3_place_order_ixs)
tx.recent_blockhash = state['recent_blockhash']
tx.sign(mango_client.provider.wallet.payer)
response = await mango_client.provider.send(tx)
print(f"Quoted {json.dumps(orders)}: f{response}")
except Exception as exception:
logging.error(f"{exception}")
finally:
logging.info(f"Standby..."); await asyncio.sleep(1)
if __name__ == '__main__':
asyncio.run(main())

53
examples/orderbook_l2.py Normal file
View File

@ -0,0 +1,53 @@
import argparse
import asyncio
import json
import pathlib
from mango_explorer_v4.mango_client import MangoClient
async def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--symbol',
required=True
)
parser.add_argument(
'--depth',
default=50,
type=int
)
args = parser.parse_args()
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
print(await mango_client.orderbook_l2(args.symbol, args.depth))
# {
# 'symbol': 'SOL/USDC',
# 'slot': 168616506,
# 'bids': [
# [11.826, 0.899],
# [11.824, 39.436],
# [11.82, 316.421],
# [11.817, 1.43],
# [11.816, 1.21]
# ],
# 'asks': [
# [11.839, 0.78],
# [11.84, 44.392],
# [11.841, 1.1],
# [11.843, 300.89],
# [11.844, 355.131]
# ]}
if __name__ == '__main__':
asyncio.run(main())

51
examples/place_order.py Normal file
View File

@ -0,0 +1,51 @@
import argparse
import asyncio
import json
import pathlib
from mango_explorer_v4.mango_client import MangoClient
async def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--symbol',
required=True
)
parser.add_argument(
'--side',
required=True,
choices=['bids', 'asks']
)
parser.add_argument(
'--price',
type=float
)
parser.add_argument(
'--size',
type=float
)
args = parser.parse_args()
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
# print(await mango_client.place_order('SOL/USDC', 'bid', 10, 0.1))
print(await mango_client.place_order(args.symbol, args.side, args.price, args.size))
# 3VQA4zqmRPLtmeHBNV2dKZKhXYX3cHBiM1LpCrjgJZwZDF418GF6RQ9DihSZq6Zg4pjqcUjTMQwEDNLuybfL8mQT
# (Check the UI)
if __name__ == '__main__':
asyncio.run(main())

37
examples/snapshots_l2.py Normal file
View File

@ -0,0 +1,37 @@
import argparse
import asyncio
import json
import pathlib
from mango_explorer_v4.mango_client import MangoClient
async def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--symbol',
required=True
)
parser.add_argument(
'--depth',
default=50,
type=int
)
args = parser.parse_args()
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
async for snapshot in mango_client.snapshots_l2(args.symbol, args.depth):
print(snapshot)
if __name__ == '__main__':
asyncio.run(main())

27
examples/symbols.py Normal file
View File

@ -0,0 +1,27 @@
import argparse
import asyncio
import json
import pathlib
from mango_explorer_v4.mango_client import MangoClient
async def main():
config = json.load(open(pathlib.Path(__file__).parent.parent / 'config.json'))
mango_client = await MangoClient.connect(
secret_key=config['secret_key'],
mango_account_pk=config['mango_account_pk']
)
print(json.dumps(mango_client.symbols()))
# [
# {'name': 'SOL/USDC', 'baseCurrency': 'SOL', 'quoteCurrency': 'USDC', 'makerFees': -5e-05, 'takerFees': 0.0001},
# {'name': 'mSOL/USDC', 'baseCurrency': 'mSOL', 'quoteCurrency': 'USDC', 'makerFees': -5e-05, 'takerFees': 0.0001},
# {'name': 'ETH/USDC', 'baseCurrency': 'ETH', 'quoteCurrency': 'USDC', 'makerFees': -5e-05, 'takerFees': 0.0001}
# ]
if __name__ == '__main__':
asyncio.run(main())

7099
idl.json Normal file

File diff suppressed because it is too large Load Diff

View File

View File

@ -0,0 +1,13 @@
from .bank import Bank, BankJSON
from .group import Group, GroupJSON
from .mango_account import MangoAccount, MangoAccountJSON
from .mint_info import MintInfo, MintInfoJSON
from .stub_oracle import StubOracle, StubOracleJSON
from .book_side import BookSide, BookSideJSON
from .event_queue import EventQueue, EventQueueJSON
from .perp_market import PerpMarket, PerpMarketJSON
from .serum3_market import Serum3Market, Serum3MarketJSON
from .serum3_market_index_reservation import (
Serum3MarketIndexReservation,
Serum3MarketIndexReservationJSON,
)

View File

@ -0,0 +1,351 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
from .. import types
class BankJSON(typing.TypedDict):
group: str
name: list[int]
mint: str
vault: str
oracle: str
oracle_config: types.oracle_config.OracleConfigJSON
stable_price_model: types.stable_price_model.StablePriceModelJSON
deposit_index: types.i80f48.I80F48JSON
borrow_index: types.i80f48.I80F48JSON
indexed_deposits: types.i80f48.I80F48JSON
indexed_borrows: types.i80f48.I80F48JSON
index_last_updated: int
bank_rate_last_updated: int
avg_utilization: types.i80f48.I80F48JSON
adjustment_factor: types.i80f48.I80F48JSON
util0: types.i80f48.I80F48JSON
rate0: types.i80f48.I80F48JSON
util1: types.i80f48.I80F48JSON
rate1: types.i80f48.I80F48JSON
max_rate: types.i80f48.I80F48JSON
collected_fees_native: types.i80f48.I80F48JSON
loan_origination_fee_rate: types.i80f48.I80F48JSON
loan_fee_rate: types.i80f48.I80F48JSON
maint_asset_weight: types.i80f48.I80F48JSON
init_asset_weight: types.i80f48.I80F48JSON
maint_liab_weight: types.i80f48.I80F48JSON
init_liab_weight: types.i80f48.I80F48JSON
liquidation_fee: types.i80f48.I80F48JSON
dust: types.i80f48.I80F48JSON
flash_loan_token_account_initial: int
flash_loan_approved_amount: int
token_index: int
bump: int
mint_decimals: int
bank_num: int
min_vault_to_deposits_ratio: float
net_borrow_limit_window_size_ts: int
last_net_borrows_window_start_ts: int
net_borrow_limit_per_window_quote: int
net_borrows_in_window: int
borrow_weight_scale_start_quote: float
deposit_weight_scale_start_quote: float
reserved: list[int]
@dataclass
class Bank:
discriminator: typing.ClassVar = b"\x8e1\xa6\xf22Ba\xbc"
layout: typing.ClassVar = borsh.CStruct(
"group" / BorshPubkey,
"name" / borsh.U8[16],
"mint" / BorshPubkey,
"vault" / BorshPubkey,
"oracle" / BorshPubkey,
"oracle_config" / types.oracle_config.OracleConfig.layout,
"stable_price_model" / types.stable_price_model.StablePriceModel.layout,
"deposit_index" / types.i80f48.I80F48.layout,
"borrow_index" / types.i80f48.I80F48.layout,
"indexed_deposits" / types.i80f48.I80F48.layout,
"indexed_borrows" / types.i80f48.I80F48.layout,
"index_last_updated" / borsh.U64,
"bank_rate_last_updated" / borsh.U64,
"avg_utilization" / types.i80f48.I80F48.layout,
"adjustment_factor" / types.i80f48.I80F48.layout,
"util0" / types.i80f48.I80F48.layout,
"rate0" / types.i80f48.I80F48.layout,
"util1" / types.i80f48.I80F48.layout,
"rate1" / types.i80f48.I80F48.layout,
"max_rate" / types.i80f48.I80F48.layout,
"collected_fees_native" / types.i80f48.I80F48.layout,
"loan_origination_fee_rate" / types.i80f48.I80F48.layout,
"loan_fee_rate" / types.i80f48.I80F48.layout,
"maint_asset_weight" / types.i80f48.I80F48.layout,
"init_asset_weight" / types.i80f48.I80F48.layout,
"maint_liab_weight" / types.i80f48.I80F48.layout,
"init_liab_weight" / types.i80f48.I80F48.layout,
"liquidation_fee" / types.i80f48.I80F48.layout,
"dust" / types.i80f48.I80F48.layout,
"flash_loan_token_account_initial" / borsh.U64,
"flash_loan_approved_amount" / borsh.U64,
"token_index" / borsh.U16,
"bump" / borsh.U8,
"mint_decimals" / borsh.U8,
"bank_num" / borsh.U32,
"min_vault_to_deposits_ratio" / borsh.F64,
"net_borrow_limit_window_size_ts" / borsh.U64,
"last_net_borrows_window_start_ts" / borsh.U64,
"net_borrow_limit_per_window_quote" / borsh.I64,
"net_borrows_in_window" / borsh.I64,
"borrow_weight_scale_start_quote" / borsh.F64,
"deposit_weight_scale_start_quote" / borsh.F64,
"reserved" / borsh.U8[2120],
)
group: PublicKey
name: list[int]
mint: PublicKey
vault: PublicKey
oracle: PublicKey
oracle_config: types.oracle_config.OracleConfig
stable_price_model: types.stable_price_model.StablePriceModel
deposit_index: types.i80f48.I80F48
borrow_index: types.i80f48.I80F48
indexed_deposits: types.i80f48.I80F48
indexed_borrows: types.i80f48.I80F48
index_last_updated: int
bank_rate_last_updated: int
avg_utilization: types.i80f48.I80F48
adjustment_factor: types.i80f48.I80F48
util0: types.i80f48.I80F48
rate0: types.i80f48.I80F48
util1: types.i80f48.I80F48
rate1: types.i80f48.I80F48
max_rate: types.i80f48.I80F48
collected_fees_native: types.i80f48.I80F48
loan_origination_fee_rate: types.i80f48.I80F48
loan_fee_rate: types.i80f48.I80F48
maint_asset_weight: types.i80f48.I80F48
init_asset_weight: types.i80f48.I80F48
maint_liab_weight: types.i80f48.I80F48
init_liab_weight: types.i80f48.I80F48
liquidation_fee: types.i80f48.I80F48
dust: types.i80f48.I80F48
flash_loan_token_account_initial: int
flash_loan_approved_amount: int
token_index: int
bump: int
mint_decimals: int
bank_num: int
min_vault_to_deposits_ratio: float
net_borrow_limit_window_size_ts: int
last_net_borrows_window_start_ts: int
net_borrow_limit_per_window_quote: int
net_borrows_in_window: int
borrow_weight_scale_start_quote: float
deposit_weight_scale_start_quote: float
reserved: list[int]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["Bank"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["Bank"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["Bank"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "Bank":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = Bank.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
group=dec.group,
name=dec.name,
mint=dec.mint,
vault=dec.vault,
oracle=dec.oracle,
oracle_config=types.oracle_config.OracleConfig.from_decoded(
dec.oracle_config
),
stable_price_model=types.stable_price_model.StablePriceModel.from_decoded(
dec.stable_price_model
),
deposit_index=types.i80f48.I80F48.from_decoded(dec.deposit_index),
borrow_index=types.i80f48.I80F48.from_decoded(dec.borrow_index),
indexed_deposits=types.i80f48.I80F48.from_decoded(dec.indexed_deposits),
indexed_borrows=types.i80f48.I80F48.from_decoded(dec.indexed_borrows),
index_last_updated=dec.index_last_updated,
bank_rate_last_updated=dec.bank_rate_last_updated,
avg_utilization=types.i80f48.I80F48.from_decoded(dec.avg_utilization),
adjustment_factor=types.i80f48.I80F48.from_decoded(dec.adjustment_factor),
util0=types.i80f48.I80F48.from_decoded(dec.util0),
rate0=types.i80f48.I80F48.from_decoded(dec.rate0),
util1=types.i80f48.I80F48.from_decoded(dec.util1),
rate1=types.i80f48.I80F48.from_decoded(dec.rate1),
max_rate=types.i80f48.I80F48.from_decoded(dec.max_rate),
collected_fees_native=types.i80f48.I80F48.from_decoded(
dec.collected_fees_native
),
loan_origination_fee_rate=types.i80f48.I80F48.from_decoded(
dec.loan_origination_fee_rate
),
loan_fee_rate=types.i80f48.I80F48.from_decoded(dec.loan_fee_rate),
maint_asset_weight=types.i80f48.I80F48.from_decoded(dec.maint_asset_weight),
init_asset_weight=types.i80f48.I80F48.from_decoded(dec.init_asset_weight),
maint_liab_weight=types.i80f48.I80F48.from_decoded(dec.maint_liab_weight),
init_liab_weight=types.i80f48.I80F48.from_decoded(dec.init_liab_weight),
liquidation_fee=types.i80f48.I80F48.from_decoded(dec.liquidation_fee),
dust=types.i80f48.I80F48.from_decoded(dec.dust),
flash_loan_token_account_initial=dec.flash_loan_token_account_initial,
flash_loan_approved_amount=dec.flash_loan_approved_amount,
token_index=dec.token_index,
bump=dec.bump,
mint_decimals=dec.mint_decimals,
bank_num=dec.bank_num,
min_vault_to_deposits_ratio=dec.min_vault_to_deposits_ratio,
net_borrow_limit_window_size_ts=dec.net_borrow_limit_window_size_ts,
last_net_borrows_window_start_ts=dec.last_net_borrows_window_start_ts,
net_borrow_limit_per_window_quote=dec.net_borrow_limit_per_window_quote,
net_borrows_in_window=dec.net_borrows_in_window,
borrow_weight_scale_start_quote=dec.borrow_weight_scale_start_quote,
deposit_weight_scale_start_quote=dec.deposit_weight_scale_start_quote,
reserved=dec.reserved,
)
def to_json(self) -> BankJSON:
return {
"group": str(self.group),
"name": self.name,
"mint": str(self.mint),
"vault": str(self.vault),
"oracle": str(self.oracle),
"oracle_config": self.oracle_config.to_json(),
"stable_price_model": self.stable_price_model.to_json(),
"deposit_index": self.deposit_index.to_json(),
"borrow_index": self.borrow_index.to_json(),
"indexed_deposits": self.indexed_deposits.to_json(),
"indexed_borrows": self.indexed_borrows.to_json(),
"index_last_updated": self.index_last_updated,
"bank_rate_last_updated": self.bank_rate_last_updated,
"avg_utilization": self.avg_utilization.to_json(),
"adjustment_factor": self.adjustment_factor.to_json(),
"util0": self.util0.to_json(),
"rate0": self.rate0.to_json(),
"util1": self.util1.to_json(),
"rate1": self.rate1.to_json(),
"max_rate": self.max_rate.to_json(),
"collected_fees_native": self.collected_fees_native.to_json(),
"loan_origination_fee_rate": self.loan_origination_fee_rate.to_json(),
"loan_fee_rate": self.loan_fee_rate.to_json(),
"maint_asset_weight": self.maint_asset_weight.to_json(),
"init_asset_weight": self.init_asset_weight.to_json(),
"maint_liab_weight": self.maint_liab_weight.to_json(),
"init_liab_weight": self.init_liab_weight.to_json(),
"liquidation_fee": self.liquidation_fee.to_json(),
"dust": self.dust.to_json(),
"flash_loan_token_account_initial": self.flash_loan_token_account_initial,
"flash_loan_approved_amount": self.flash_loan_approved_amount,
"token_index": self.token_index,
"bump": self.bump,
"mint_decimals": self.mint_decimals,
"bank_num": self.bank_num,
"min_vault_to_deposits_ratio": self.min_vault_to_deposits_ratio,
"net_borrow_limit_window_size_ts": self.net_borrow_limit_window_size_ts,
"last_net_borrows_window_start_ts": self.last_net_borrows_window_start_ts,
"net_borrow_limit_per_window_quote": self.net_borrow_limit_per_window_quote,
"net_borrows_in_window": self.net_borrows_in_window,
"borrow_weight_scale_start_quote": self.borrow_weight_scale_start_quote,
"deposit_weight_scale_start_quote": self.deposit_weight_scale_start_quote,
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: BankJSON) -> "Bank":
return cls(
group=PublicKey(obj["group"]),
name=obj["name"],
mint=PublicKey(obj["mint"]),
vault=PublicKey(obj["vault"]),
oracle=PublicKey(obj["oracle"]),
oracle_config=types.oracle_config.OracleConfig.from_json(
obj["oracle_config"]
),
stable_price_model=types.stable_price_model.StablePriceModel.from_json(
obj["stable_price_model"]
),
deposit_index=types.i80f48.I80F48.from_json(obj["deposit_index"]),
borrow_index=types.i80f48.I80F48.from_json(obj["borrow_index"]),
indexed_deposits=types.i80f48.I80F48.from_json(obj["indexed_deposits"]),
indexed_borrows=types.i80f48.I80F48.from_json(obj["indexed_borrows"]),
index_last_updated=obj["index_last_updated"],
bank_rate_last_updated=obj["bank_rate_last_updated"],
avg_utilization=types.i80f48.I80F48.from_json(obj["avg_utilization"]),
adjustment_factor=types.i80f48.I80F48.from_json(obj["adjustment_factor"]),
util0=types.i80f48.I80F48.from_json(obj["util0"]),
rate0=types.i80f48.I80F48.from_json(obj["rate0"]),
util1=types.i80f48.I80F48.from_json(obj["util1"]),
rate1=types.i80f48.I80F48.from_json(obj["rate1"]),
max_rate=types.i80f48.I80F48.from_json(obj["max_rate"]),
collected_fees_native=types.i80f48.I80F48.from_json(
obj["collected_fees_native"]
),
loan_origination_fee_rate=types.i80f48.I80F48.from_json(
obj["loan_origination_fee_rate"]
),
loan_fee_rate=types.i80f48.I80F48.from_json(obj["loan_fee_rate"]),
maint_asset_weight=types.i80f48.I80F48.from_json(obj["maint_asset_weight"]),
init_asset_weight=types.i80f48.I80F48.from_json(obj["init_asset_weight"]),
maint_liab_weight=types.i80f48.I80F48.from_json(obj["maint_liab_weight"]),
init_liab_weight=types.i80f48.I80F48.from_json(obj["init_liab_weight"]),
liquidation_fee=types.i80f48.I80F48.from_json(obj["liquidation_fee"]),
dust=types.i80f48.I80F48.from_json(obj["dust"]),
flash_loan_token_account_initial=obj["flash_loan_token_account_initial"],
flash_loan_approved_amount=obj["flash_loan_approved_amount"],
token_index=obj["token_index"],
bump=obj["bump"],
mint_decimals=obj["mint_decimals"],
bank_num=obj["bank_num"],
min_vault_to_deposits_ratio=obj["min_vault_to_deposits_ratio"],
net_borrow_limit_window_size_ts=obj["net_borrow_limit_window_size_ts"],
last_net_borrows_window_start_ts=obj["last_net_borrows_window_start_ts"],
net_borrow_limit_per_window_quote=obj["net_borrow_limit_per_window_quote"],
net_borrows_in_window=obj["net_borrows_in_window"],
borrow_weight_scale_start_quote=obj["borrow_weight_scale_start_quote"],
deposit_weight_scale_start_quote=obj["deposit_weight_scale_start_quote"],
reserved=obj["reserved"],
)

View File

@ -0,0 +1,122 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from ..program_id import MANGO_PROGRAM_ID
from .. import types
class BookSideJSON(typing.TypedDict):
roots: list[types.order_tree_root.OrderTreeRootJSON]
reserved_roots: list[types.order_tree_root.OrderTreeRootJSON]
reserved: list[int]
nodes: types.order_tree_nodes.OrderTreeNodesJSON
@dataclass
class BookSide:
discriminator: typing.ClassVar = b"H,\xe1\x8d\xb2\x82a9"
layout: typing.ClassVar = borsh.CStruct(
"roots" / types.order_tree_root.OrderTreeRoot.layout[2],
"reserved_roots" / types.order_tree_root.OrderTreeRoot.layout[4],
"reserved" / borsh.U8[256],
"nodes" / types.order_tree_nodes.OrderTreeNodes.layout,
)
roots: list[types.order_tree_root.OrderTreeRoot]
reserved_roots: list[types.order_tree_root.OrderTreeRoot]
reserved: list[int]
nodes: types.order_tree_nodes.OrderTreeNodes
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["BookSide"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["BookSide"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["BookSide"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "BookSide":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = BookSide.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
roots=list(
map(
lambda item: types.order_tree_root.OrderTreeRoot.from_decoded(item),
dec.roots,
)
),
reserved_roots=list(
map(
lambda item: types.order_tree_root.OrderTreeRoot.from_decoded(item),
dec.reserved_roots,
)
),
reserved=dec.reserved,
nodes=types.order_tree_nodes.OrderTreeNodes.from_decoded(dec.nodes),
)
def to_json(self) -> BookSideJSON:
return {
"roots": list(map(lambda item: item.to_json(), self.roots)),
"reserved_roots": list(
map(lambda item: item.to_json(), self.reserved_roots)
),
"reserved": self.reserved,
"nodes": self.nodes.to_json(),
}
@classmethod
def from_json(cls, obj: BookSideJSON) -> "BookSide":
return cls(
roots=list(
map(
lambda item: types.order_tree_root.OrderTreeRoot.from_json(item),
obj["roots"],
)
),
reserved_roots=list(
map(
lambda item: types.order_tree_root.OrderTreeRoot.from_json(item),
obj["reserved_roots"],
)
),
reserved=obj["reserved"],
nodes=types.order_tree_nodes.OrderTreeNodes.from_json(obj["nodes"]),
)

View File

@ -0,0 +1,98 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from ..program_id import MANGO_PROGRAM_ID
from .. import types
class EventQueueJSON(typing.TypedDict):
header: types.event_queue_header.EventQueueHeaderJSON
buf: list[types.any_event.AnyEventJSON]
reserved: list[int]
@dataclass
class EventQueue:
discriminator: typing.ClassVar = b")\xd0t\xd1\xadt\x8dD"
layout: typing.ClassVar = borsh.CStruct(
"header" / types.event_queue_header.EventQueueHeader.layout,
"buf" / types.any_event.AnyEvent.layout[488],
"reserved" / borsh.U8[64],
)
header: types.event_queue_header.EventQueueHeader
buf: list[types.any_event.AnyEvent]
reserved: list[int]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["EventQueue"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["EventQueue"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["EventQueue"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "EventQueue":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = EventQueue.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
header=types.event_queue_header.EventQueueHeader.from_decoded(dec.header),
buf=list(
map(lambda item: types.any_event.AnyEvent.from_decoded(item), dec.buf)
),
reserved=dec.reserved,
)
def to_json(self) -> EventQueueJSON:
return {
"header": self.header.to_json(),
"buf": list(map(lambda item: item.to_json(), self.buf)),
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: EventQueueJSON) -> "EventQueue":
return cls(
header=types.event_queue_header.EventQueueHeader.from_json(obj["header"]),
buf=list(
map(lambda item: types.any_event.AnyEvent.from_json(item), obj["buf"])
),
reserved=obj["reserved"],
)

View File

@ -0,0 +1,158 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
class GroupJSON(typing.TypedDict):
creator: str
group_num: int
admin: str
fast_listing_admin: str
padding: list[int]
insurance_vault: str
insurance_mint: str
bump: int
testing: int
version: int
padding2: list[int]
address_lookup_tables: list[str]
reserved: list[int]
@dataclass
class Group:
discriminator: typing.ClassVar = b"\xd1\xf9\xd0?\xb6Y\xba\xfe"
layout: typing.ClassVar = borsh.CStruct(
"creator" / BorshPubkey,
"group_num" / borsh.U32,
"admin" / BorshPubkey,
"fast_listing_admin" / BorshPubkey,
"padding" / borsh.U8[4],
"insurance_vault" / BorshPubkey,
"insurance_mint" / BorshPubkey,
"bump" / borsh.U8,
"testing" / borsh.U8,
"version" / borsh.U8,
"padding2" / borsh.U8[5],
"address_lookup_tables" / BorshPubkey[20],
"reserved" / borsh.U8[1920],
)
creator: PublicKey
group_num: int
admin: PublicKey
fast_listing_admin: PublicKey
padding: list[int]
insurance_vault: PublicKey
insurance_mint: PublicKey
bump: int
testing: int
version: int
padding2: list[int]
address_lookup_tables: list[PublicKey]
reserved: list[int]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["Group"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["Group"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["Group"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "Group":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = Group.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
creator=dec.creator,
group_num=dec.group_num,
admin=dec.admin,
fast_listing_admin=dec.fast_listing_admin,
padding=dec.padding,
insurance_vault=dec.insurance_vault,
insurance_mint=dec.insurance_mint,
bump=dec.bump,
testing=dec.testing,
version=dec.version,
padding2=dec.padding2,
address_lookup_tables=dec.address_lookup_tables,
reserved=dec.reserved,
)
def to_json(self) -> GroupJSON:
return {
"creator": str(self.creator),
"group_num": self.group_num,
"admin": str(self.admin),
"fast_listing_admin": str(self.fast_listing_admin),
"padding": self.padding,
"insurance_vault": str(self.insurance_vault),
"insurance_mint": str(self.insurance_mint),
"bump": self.bump,
"testing": self.testing,
"version": self.version,
"padding2": self.padding2,
"address_lookup_tables": list(
map(lambda item: str(item), self.address_lookup_tables)
),
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: GroupJSON) -> "Group":
return cls(
creator=PublicKey(obj["creator"]),
group_num=obj["group_num"],
admin=PublicKey(obj["admin"]),
fast_listing_admin=PublicKey(obj["fast_listing_admin"]),
padding=obj["padding"],
insurance_vault=PublicKey(obj["insurance_vault"]),
insurance_mint=PublicKey(obj["insurance_mint"]),
bump=obj["bump"],
testing=obj["testing"],
version=obj["version"],
padding2=obj["padding2"],
address_lookup_tables=list(
map(lambda item: PublicKey(item), obj["address_lookup_tables"])
),
reserved=obj["reserved"],
)

View File

@ -0,0 +1,262 @@
import typing
from dataclasses import dataclass
from construct import Construct
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
from .. import types
class MangoAccountJSON(typing.TypedDict):
group: str
owner: str
name: list[int]
delegate: str
account_num: int
being_liquidated: int
in_health_region: int
bump: int
padding: list[int]
net_deposits: int
perp_spot_transfers: int
health_region_begin_init_health: int
reserved: list[int]
header_version: int
padding3: list[int]
padding4: int
tokens: list[types.token_position.TokenPositionJSON]
padding5: int
serum3: list[types.serum3_orders.Serum3OrdersJSON]
padding6: int
perps: list[types.perp_position.PerpPositionJSON]
padding7: int
perp_open_orders: list[types.perp_open_order.PerpOpenOrderJSON]
@dataclass
class MangoAccount:
discriminator: typing.ClassVar = b"\xf3\xe4\xf7\x03\xa94\xaf\x1f"
layout: typing.ClassVar = borsh.CStruct(
"group" / BorshPubkey,
"owner" / BorshPubkey,
"name" / borsh.U8[32],
"delegate" / BorshPubkey,
"account_num" / borsh.U32,
"being_liquidated" / borsh.U8,
"in_health_region" / borsh.U8,
"bump" / borsh.U8,
"padding" / borsh.U8[1],
"net_deposits" / borsh.I64,
"perp_spot_transfers" / borsh.I64,
"health_region_begin_init_health" / borsh.I64,
"reserved" / borsh.U8[240],
"header_version" / borsh.U8,
"padding3" / borsh.U8[7],
"padding4" / borsh.U32,
"tokens"
/ borsh.Vec(typing.cast(Construct, types.token_position.TokenPosition.layout)),
"padding5" / borsh.U32,
"serum3"
/ borsh.Vec(typing.cast(Construct, types.serum3_orders.Serum3Orders.layout)),
"padding6" / borsh.U32,
"perps"
/ borsh.Vec(typing.cast(Construct, types.perp_position.PerpPosition.layout)),
"padding7" / borsh.U32,
"perp_open_orders"
/ borsh.Vec(typing.cast(Construct, types.perp_open_order.PerpOpenOrder.layout)),
)
group: PublicKey
owner: PublicKey
name: list[int]
delegate: PublicKey
account_num: int
being_liquidated: int
in_health_region: int
bump: int
padding: list[int]
net_deposits: int
perp_spot_transfers: int
health_region_begin_init_health: int
reserved: list[int]
header_version: int
padding3: list[int]
padding4: int
tokens: list[types.token_position.TokenPosition]
padding5: int
serum3: list[types.serum3_orders.Serum3Orders]
padding6: int
perps: list[types.perp_position.PerpPosition]
padding7: int
perp_open_orders: list[types.perp_open_order.PerpOpenOrder]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["MangoAccount"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["MangoAccount"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["MangoAccount"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "MangoAccount":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = MangoAccount.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
group=dec.group,
owner=dec.owner,
name=dec.name,
delegate=dec.delegate,
account_num=dec.account_num,
being_liquidated=dec.being_liquidated,
in_health_region=dec.in_health_region,
bump=dec.bump,
padding=dec.padding,
net_deposits=dec.net_deposits,
perp_spot_transfers=dec.perp_spot_transfers,
health_region_begin_init_health=dec.health_region_begin_init_health,
reserved=dec.reserved,
header_version=dec.header_version,
padding3=dec.padding3,
padding4=dec.padding4,
tokens=list(
map(
lambda item: types.token_position.TokenPosition.from_decoded(item),
dec.tokens,
)
),
padding5=dec.padding5,
serum3=list(
map(
lambda item: types.serum3_orders.Serum3Orders.from_decoded(item),
dec.serum3,
)
),
padding6=dec.padding6,
perps=list(
map(
lambda item: types.perp_position.PerpPosition.from_decoded(item),
dec.perps,
)
),
padding7=dec.padding7,
perp_open_orders=list(
map(
lambda item: types.perp_open_order.PerpOpenOrder.from_decoded(item),
dec.perp_open_orders,
)
),
)
def to_json(self) -> MangoAccountJSON:
return {
"group": str(self.group),
"owner": str(self.owner),
"name": self.name,
"delegate": str(self.delegate),
"account_num": self.account_num,
"being_liquidated": self.being_liquidated,
"in_health_region": self.in_health_region,
"bump": self.bump,
"padding": self.padding,
"net_deposits": self.net_deposits,
"perp_spot_transfers": self.perp_spot_transfers,
"health_region_begin_init_health": self.health_region_begin_init_health,
"reserved": self.reserved,
"header_version": self.header_version,
"padding3": self.padding3,
"padding4": self.padding4,
"tokens": list(map(lambda item: item.to_json(), self.tokens)),
"padding5": self.padding5,
"serum3": list(map(lambda item: item.to_json(), self.serum3)),
"padding6": self.padding6,
"perps": list(map(lambda item: item.to_json(), self.perps)),
"padding7": self.padding7,
"perp_open_orders": list(
map(lambda item: item.to_json(), self.perp_open_orders)
),
}
@classmethod
def from_json(cls, obj: MangoAccountJSON) -> "MangoAccount":
return cls(
group=PublicKey(obj["group"]),
owner=PublicKey(obj["owner"]),
name=obj["name"],
delegate=PublicKey(obj["delegate"]),
account_num=obj["account_num"],
being_liquidated=obj["being_liquidated"],
in_health_region=obj["in_health_region"],
bump=obj["bump"],
padding=obj["padding"],
net_deposits=obj["net_deposits"],
perp_spot_transfers=obj["perp_spot_transfers"],
health_region_begin_init_health=obj["health_region_begin_init_health"],
reserved=obj["reserved"],
header_version=obj["header_version"],
padding3=obj["padding3"],
padding4=obj["padding4"],
tokens=list(
map(
lambda item: types.token_position.TokenPosition.from_json(item),
obj["tokens"],
)
),
padding5=obj["padding5"],
serum3=list(
map(
lambda item: types.serum3_orders.Serum3Orders.from_json(item),
obj["serum3"],
)
),
padding6=obj["padding6"],
perps=list(
map(
lambda item: types.perp_position.PerpPosition.from_json(item),
obj["perps"],
)
),
padding7=obj["padding7"],
perp_open_orders=list(
map(
lambda item: types.perp_open_order.PerpOpenOrder.from_json(item),
obj["perp_open_orders"],
)
),
)

View File

@ -0,0 +1,136 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
class MintInfoJSON(typing.TypedDict):
group: str
token_index: int
group_insurance_fund: int
padding1: list[int]
mint: str
banks: list[str]
vaults: list[str]
oracle: str
registration_time: int
reserved: list[int]
@dataclass
class MintInfo:
discriminator: typing.ClassVar = b"\xc7s\xd5\xdd\xdb\x1d\x87\xae"
layout: typing.ClassVar = borsh.CStruct(
"group" / BorshPubkey,
"token_index" / borsh.U16,
"group_insurance_fund" / borsh.U8,
"padding1" / borsh.U8[5],
"mint" / BorshPubkey,
"banks" / BorshPubkey[6],
"vaults" / BorshPubkey[6],
"oracle" / BorshPubkey,
"registration_time" / borsh.U64,
"reserved" / borsh.U8[2560],
)
group: PublicKey
token_index: int
group_insurance_fund: int
padding1: list[int]
mint: PublicKey
banks: list[PublicKey]
vaults: list[PublicKey]
oracle: PublicKey
registration_time: int
reserved: list[int]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["MintInfo"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["MintInfo"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["MintInfo"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "MintInfo":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = MintInfo.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
group=dec.group,
token_index=dec.token_index,
group_insurance_fund=dec.group_insurance_fund,
padding1=dec.padding1,
mint=dec.mint,
banks=dec.banks,
vaults=dec.vaults,
oracle=dec.oracle,
registration_time=dec.registration_time,
reserved=dec.reserved,
)
def to_json(self) -> MintInfoJSON:
return {
"group": str(self.group),
"token_index": self.token_index,
"group_insurance_fund": self.group_insurance_fund,
"padding1": self.padding1,
"mint": str(self.mint),
"banks": list(map(lambda item: str(item), self.banks)),
"vaults": list(map(lambda item: str(item), self.vaults)),
"oracle": str(self.oracle),
"registration_time": self.registration_time,
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: MintInfoJSON) -> "MintInfo":
return cls(
group=PublicKey(obj["group"]),
token_index=obj["token_index"],
group_insurance_fund=obj["group_insurance_fund"],
padding1=obj["padding1"],
mint=PublicKey(obj["mint"]),
banks=list(map(lambda item: PublicKey(item), obj["banks"])),
vaults=list(map(lambda item: PublicKey(item), obj["vaults"])),
oracle=PublicKey(obj["oracle"]),
registration_time=obj["registration_time"],
reserved=obj["reserved"],
)

View File

@ -0,0 +1,343 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
from .. import types
from ..constants import QUOTE_DECIMALS
from decimal import Decimal
class PerpMarketJSON(typing.TypedDict):
group: str
settle_token_index: int
perp_market_index: int
trusted_market: int
group_insurance_fund: int
bump: int
base_decimals: int
name: list[int]
bids: str
asks: str
event_queue: str
oracle: str
oracle_config: types.oracle_config.OracleConfigJSON
stable_price_model: types.stable_price_model.StablePriceModelJSON
quote_lot_size: int
base_lot_size: int
maint_asset_weight: types.i80f48.I80F48JSON
init_asset_weight: types.i80f48.I80F48JSON
maint_liab_weight: types.i80f48.I80F48JSON
init_liab_weight: types.i80f48.I80F48JSON
open_interest: int
seq_num: int
registration_time: int
min_funding: types.i80f48.I80F48JSON
max_funding: types.i80f48.I80F48JSON
impact_quantity: int
long_funding: types.i80f48.I80F48JSON
short_funding: types.i80f48.I80F48JSON
funding_last_updated: int
liquidation_fee: types.i80f48.I80F48JSON
maker_fee: types.i80f48.I80F48JSON
taker_fee: types.i80f48.I80F48JSON
fees_accrued: types.i80f48.I80F48JSON
fees_settled: types.i80f48.I80F48JSON
fee_penalty: float
settle_fee_flat: float
settle_fee_amount_threshold: float
settle_fee_fraction_low_health: float
settle_pnl_limit_factor: float
padding3: list[int]
settle_pnl_limit_window_size_ts: int
reserved: list[int]
@dataclass
class PerpMarket:
discriminator: typing.ClassVar = b"\n\xdf\x0c,k\xf57\xf7"
layout: typing.ClassVar = borsh.CStruct(
"group" / BorshPubkey,
"settle_token_index" / borsh.U16,
"perp_market_index" / borsh.U16,
"trusted_market" / borsh.U8,
"group_insurance_fund" / borsh.U8,
"bump" / borsh.U8,
"base_decimals" / borsh.U8,
"name" / borsh.U8[16],
"bids" / BorshPubkey,
"asks" / BorshPubkey,
"event_queue" / BorshPubkey,
"oracle" / BorshPubkey,
"oracle_config" / types.oracle_config.OracleConfig.layout,
"stable_price_model" / types.stable_price_model.StablePriceModel.layout,
"quote_lot_size" / borsh.I64,
"base_lot_size" / borsh.I64,
"maint_asset_weight" / types.i80f48.I80F48.layout,
"init_asset_weight" / types.i80f48.I80F48.layout,
"maint_liab_weight" / types.i80f48.I80F48.layout,
"init_liab_weight" / types.i80f48.I80F48.layout,
"open_interest" / borsh.I64,
"seq_num" / borsh.U64,
"registration_time" / borsh.U64,
"min_funding" / types.i80f48.I80F48.layout,
"max_funding" / types.i80f48.I80F48.layout,
"impact_quantity" / borsh.I64,
"long_funding" / types.i80f48.I80F48.layout,
"short_funding" / types.i80f48.I80F48.layout,
"funding_last_updated" / borsh.U64,
"liquidation_fee" / types.i80f48.I80F48.layout,
"maker_fee" / types.i80f48.I80F48.layout,
"taker_fee" / types.i80f48.I80F48.layout,
"fees_accrued" / types.i80f48.I80F48.layout,
"fees_settled" / types.i80f48.I80F48.layout,
"fee_penalty" / borsh.F32,
"settle_fee_flat" / borsh.F32,
"settle_fee_amount_threshold" / borsh.F32,
"settle_fee_fraction_low_health" / borsh.F32,
"settle_pnl_limit_factor" / borsh.F32,
"padding3" / borsh.U8[4],
"settle_pnl_limit_window_size_ts" / borsh.U64,
"reserved" / borsh.U8[1944],
)
group: PublicKey
settle_token_index: int
perp_market_index: int
trusted_market: int
group_insurance_fund: int
bump: int
base_decimals: int
name: list[int]
bids: PublicKey
asks: PublicKey
event_queue: PublicKey
oracle: PublicKey
oracle_config: types.oracle_config.OracleConfig
stable_price_model: types.stable_price_model.StablePriceModel
quote_lot_size: int
base_lot_size: int
maint_asset_weight: types.i80f48.I80F48
init_asset_weight: types.i80f48.I80F48
maint_liab_weight: types.i80f48.I80F48
init_liab_weight: types.i80f48.I80F48
open_interest: int
seq_num: int
registration_time: int
min_funding: types.i80f48.I80F48
max_funding: types.i80f48.I80F48
impact_quantity: int
long_funding: types.i80f48.I80F48
short_funding: types.i80f48.I80F48
funding_last_updated: int
liquidation_fee: types.i80f48.I80F48
maker_fee: types.i80f48.I80F48
taker_fee: types.i80f48.I80F48
fees_accrued: types.i80f48.I80F48
fees_settled: types.i80f48.I80F48
fee_penalty: float
settle_fee_flat: float
settle_fee_amount_threshold: float
settle_fee_fraction_low_health: float
settle_pnl_limit_factor: float
padding3: list[int]
settle_pnl_limit_window_size_ts: int
reserved: list[int]
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["PerpMarket"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["PerpMarket"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["PerpMarket"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "PerpMarket":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = PerpMarket.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
group=dec.group,
settle_token_index=dec.settle_token_index,
perp_market_index=dec.perp_market_index,
trusted_market=dec.trusted_market,
group_insurance_fund=dec.group_insurance_fund,
bump=dec.bump,
base_decimals=dec.base_decimals,
name=dec.name,
bids=dec.bids,
asks=dec.asks,
event_queue=dec.event_queue,
oracle=dec.oracle,
oracle_config=types.oracle_config.OracleConfig.from_decoded(
dec.oracle_config
),
stable_price_model=types.stable_price_model.StablePriceModel.from_decoded(
dec.stable_price_model
),
quote_lot_size=dec.quote_lot_size,
base_lot_size=dec.base_lot_size,
maint_asset_weight=types.i80f48.I80F48.from_decoded(dec.maint_asset_weight),
init_asset_weight=types.i80f48.I80F48.from_decoded(dec.init_asset_weight),
maint_liab_weight=types.i80f48.I80F48.from_decoded(dec.maint_liab_weight),
init_liab_weight=types.i80f48.I80F48.from_decoded(dec.init_liab_weight),
open_interest=dec.open_interest,
seq_num=dec.seq_num,
registration_time=dec.registration_time,
min_funding=types.i80f48.I80F48.from_decoded(dec.min_funding),
max_funding=types.i80f48.I80F48.from_decoded(dec.max_funding),
impact_quantity=dec.impact_quantity,
long_funding=types.i80f48.I80F48.from_decoded(dec.long_funding),
short_funding=types.i80f48.I80F48.from_decoded(dec.short_funding),
funding_last_updated=dec.funding_last_updated,
liquidation_fee=types.i80f48.I80F48.from_decoded(dec.liquidation_fee),
maker_fee=types.i80f48.I80F48.from_decoded(dec.maker_fee),
taker_fee=types.i80f48.I80F48.from_decoded(dec.taker_fee),
fees_accrued=types.i80f48.I80F48.from_decoded(dec.fees_accrued),
fees_settled=types.i80f48.I80F48.from_decoded(dec.fees_settled),
fee_penalty=dec.fee_penalty,
settle_fee_flat=dec.settle_fee_flat,
settle_fee_amount_threshold=dec.settle_fee_amount_threshold,
settle_fee_fraction_low_health=dec.settle_fee_fraction_low_health,
settle_pnl_limit_factor=dec.settle_pnl_limit_factor,
padding3=dec.padding3,
settle_pnl_limit_window_size_ts=dec.settle_pnl_limit_window_size_ts,
reserved=dec.reserved,
)
def to_json(self) -> PerpMarketJSON:
return {
"group": str(self.group),
"settle_token_index": self.settle_token_index,
"perp_market_index": self.perp_market_index,
"trusted_market": self.trusted_market,
"group_insurance_fund": self.group_insurance_fund,
"bump": self.bump,
"base_decimals": self.base_decimals,
"name": self.name,
"bids": str(self.bids),
"asks": str(self.asks),
"event_queue": str(self.event_queue),
"oracle": str(self.oracle),
"oracle_config": self.oracle_config.to_json(),
"stable_price_model": self.stable_price_model.to_json(),
"quote_lot_size": self.quote_lot_size,
"base_lot_size": self.base_lot_size,
"maint_asset_weight": self.maint_asset_weight.to_json(),
"init_asset_weight": self.init_asset_weight.to_json(),
"maint_liab_weight": self.maint_liab_weight.to_json(),
"init_liab_weight": self.init_liab_weight.to_json(),
"open_interest": self.open_interest,
"seq_num": self.seq_num,
"registration_time": self.registration_time,
"min_funding": self.min_funding.to_json(),
"max_funding": self.max_funding.to_json(),
"impact_quantity": self.impact_quantity,
"long_funding": self.long_funding.to_json(),
"short_funding": self.short_funding.to_json(),
"funding_last_updated": self.funding_last_updated,
"liquidation_fee": self.liquidation_fee.to_json(),
"maker_fee": self.maker_fee.to_json(),
"taker_fee": self.taker_fee.to_json(),
"fees_accrued": self.fees_accrued.to_json(),
"fees_settled": self.fees_settled.to_json(),
"fee_penalty": self.fee_penalty,
"settle_fee_flat": self.settle_fee_flat,
"settle_fee_amount_threshold": self.settle_fee_amount_threshold,
"settle_fee_fraction_low_health": self.settle_fee_fraction_low_health,
"settle_pnl_limit_factor": self.settle_pnl_limit_factor,
"padding3": self.padding3,
"settle_pnl_limit_window_size_ts": self.settle_pnl_limit_window_size_ts,
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: PerpMarketJSON) -> "PerpMarket":
return cls(
group=PublicKey(obj["group"]),
settle_token_index=obj["settle_token_index"],
perp_market_index=obj["perp_market_index"],
trusted_market=obj["trusted_market"],
group_insurance_fund=obj["group_insurance_fund"],
bump=obj["bump"],
base_decimals=obj["base_decimals"],
name=obj["name"],
bids=PublicKey(obj["bids"]),
asks=PublicKey(obj["asks"]),
event_queue=PublicKey(obj["event_queue"]),
oracle=PublicKey(obj["oracle"]),
oracle_config=types.oracle_config.OracleConfig.from_json(
obj["oracle_config"]
),
stable_price_model=types.stable_price_model.StablePriceModel.from_json(
obj["stable_price_model"]
),
quote_lot_size=obj["quote_lot_size"],
base_lot_size=obj["base_lot_size"],
maint_asset_weight=types.i80f48.I80F48.from_json(obj["maint_asset_weight"]),
init_asset_weight=types.i80f48.I80F48.from_json(obj["init_asset_weight"]),
maint_liab_weight=types.i80f48.I80F48.from_json(obj["maint_liab_weight"]),
init_liab_weight=types.i80f48.I80F48.from_json(obj["init_liab_weight"]),
open_interest=obj["open_interest"],
seq_num=obj["seq_num"],
registration_time=obj["registration_time"],
min_funding=types.i80f48.I80F48.from_json(obj["min_funding"]),
max_funding=types.i80f48.I80F48.from_json(obj["max_funding"]),
impact_quantity=obj["impact_quantity"],
long_funding=types.i80f48.I80F48.from_json(obj["long_funding"]),
short_funding=types.i80f48.I80F48.from_json(obj["short_funding"]),
funding_last_updated=obj["funding_last_updated"],
liquidation_fee=types.i80f48.I80F48.from_json(obj["liquidation_fee"]),
maker_fee=types.i80f48.I80F48.from_json(obj["maker_fee"]),
taker_fee=types.i80f48.I80F48.from_json(obj["taker_fee"]),
fees_accrued=types.i80f48.I80F48.from_json(obj["fees_accrued"]),
fees_settled=types.i80f48.I80F48.from_json(obj["fees_settled"]),
fee_penalty=obj["fee_penalty"],
settle_fee_flat=obj["settle_fee_flat"],
settle_fee_amount_threshold=obj["settle_fee_amount_threshold"],
settle_fee_fraction_low_health=obj["settle_fee_fraction_low_health"],
settle_pnl_limit_factor=obj["settle_pnl_limit_factor"],
padding3=obj["padding3"],
settle_pnl_limit_window_size_ts=obj["settle_pnl_limit_window_size_ts"],
reserved=obj["reserved"],
)
def __post_init__(self):
self.price_lots_to_ui_converter = (((Decimal(10) ** Decimal(self.base_decimals - QUOTE_DECIMALS)) * Decimal(self.quote_lot_size)) / Decimal(self.base_lot_size))
self.base_lots_to_ui_converter = (Decimal(self.base_lot_size) / (Decimal(10) ** Decimal(self.base_decimals)))
self.quote_lots_to_ui_converter = (Decimal(self.quote_lot_size) / (Decimal(10) ** Decimal(QUOTE_DECIMALS)))

View File

@ -0,0 +1,148 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
class Serum3MarketJSON(typing.TypedDict):
group: str
base_token_index: int
quote_token_index: int
padding1: list[int]
name: list[int]
serum_program: str
serum_market_external: str
market_index: int
bump: int
padding2: list[int]
registration_time: int
reserved: list[int]
@dataclass
class Serum3Market:
discriminator: typing.ClassVar = b"u\x07\xb6\xf6`h\x88\x84"
layout: typing.ClassVar = borsh.CStruct(
"group" / BorshPubkey,
"base_token_index" / borsh.U16,
"quote_token_index" / borsh.U16,
"padding1" / borsh.U8[4],
"name" / borsh.U8[16],
"serum_program" / BorshPubkey,
"serum_market_external" / BorshPubkey,
"market_index" / borsh.U16,
"bump" / borsh.U8,
"padding2" / borsh.U8[5],
"registration_time" / borsh.U64,
"reserved" / borsh.U8[128],
)
group: PublicKey
base_token_index: int
quote_token_index: int
padding1: list[int]
name: list[int]
serum_program: PublicKey
serum_market_external: PublicKey
market_index: int
bump: int
padding2: list[int]
registration_time: int
reserved: list[int]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["Serum3Market"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["Serum3Market"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["Serum3Market"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "Serum3Market":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = Serum3Market.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
group=dec.group,
base_token_index=dec.base_token_index,
quote_token_index=dec.quote_token_index,
padding1=dec.padding1,
name=dec.name,
serum_program=dec.serum_program,
serum_market_external=dec.serum_market_external,
market_index=dec.market_index,
bump=dec.bump,
padding2=dec.padding2,
registration_time=dec.registration_time,
reserved=dec.reserved,
)
def to_json(self) -> Serum3MarketJSON:
return {
"group": str(self.group),
"base_token_index": self.base_token_index,
"quote_token_index": self.quote_token_index,
"padding1": self.padding1,
"name": self.name,
"serum_program": str(self.serum_program),
"serum_market_external": str(self.serum_market_external),
"market_index": self.market_index,
"bump": self.bump,
"padding2": self.padding2,
"registration_time": self.registration_time,
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: Serum3MarketJSON) -> "Serum3Market":
return cls(
group=PublicKey(obj["group"]),
base_token_index=obj["base_token_index"],
quote_token_index=obj["quote_token_index"],
padding1=obj["padding1"],
name=obj["name"],
serum_program=PublicKey(obj["serum_program"]),
serum_market_external=PublicKey(obj["serum_market_external"]),
market_index=obj["market_index"],
bump=obj["bump"],
padding2=obj["padding2"],
registration_time=obj["registration_time"],
reserved=obj["reserved"],
)

View File

@ -0,0 +1,96 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
class Serum3MarketIndexReservationJSON(typing.TypedDict):
group: str
market_index: int
reserved: list[int]
@dataclass
class Serum3MarketIndexReservation:
discriminator: typing.ClassVar = b"\xf6\x10\xc6d\xefpx5"
layout: typing.ClassVar = borsh.CStruct(
"group" / BorshPubkey, "market_index" / borsh.U16, "reserved" / borsh.U8[38]
)
group: PublicKey
market_index: int
reserved: list[int]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["Serum3MarketIndexReservation"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["Serum3MarketIndexReservation"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["Serum3MarketIndexReservation"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "Serum3MarketIndexReservation":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = Serum3MarketIndexReservation.layout.parse(
data[ACCOUNT_DISCRIMINATOR_SIZE:]
)
return cls(
group=dec.group,
market_index=dec.market_index,
reserved=dec.reserved,
)
def to_json(self) -> Serum3MarketIndexReservationJSON:
return {
"group": str(self.group),
"market_index": self.market_index,
"reserved": self.reserved,
}
@classmethod
def from_json(
cls, obj: Serum3MarketIndexReservationJSON
) -> "Serum3MarketIndexReservation":
return cls(
group=PublicKey(obj["group"]),
market_index=obj["market_index"],
reserved=obj["reserved"],
)

View File

@ -0,0 +1,107 @@
import typing
from dataclasses import dataclass
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Commitment
import borsh_construct as borsh
from anchorpy.coder.accounts import ACCOUNT_DISCRIMINATOR_SIZE
from anchorpy.error import AccountInvalidDiscriminator
from anchorpy.utils.rpc import get_multiple_accounts
from anchorpy.borsh_extension import BorshPubkey
from ..program_id import MANGO_PROGRAM_ID
from .. import types
class StubOracleJSON(typing.TypedDict):
group: str
mint: str
price: types.i80f48.I80F48JSON
last_updated: int
reserved: list[int]
@dataclass
class StubOracle:
discriminator: typing.ClassVar = b"\xe0\xfb\xfec\xb1\xae\x89\x04"
layout: typing.ClassVar = borsh.CStruct(
"group" / BorshPubkey,
"mint" / BorshPubkey,
"price" / types.i80f48.I80F48.layout,
"last_updated" / borsh.I64,
"reserved" / borsh.U8[128],
)
group: PublicKey
mint: PublicKey
price: types.i80f48.I80F48
last_updated: int
reserved: list[int]
@classmethod
async def fetch(
cls,
conn: AsyncClient,
address: PublicKey,
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.Optional["StubOracle"]:
resp = await conn.get_account_info(address, commitment=commitment)
info = resp.value
if info is None:
return None
if info.owner != program_id.to_solders():
raise ValueError("Account does not belong to this program")
bytes_data = info.data
return cls.decode(bytes_data)
@classmethod
async def fetch_multiple(
cls,
conn: AsyncClient,
addresses: list[PublicKey],
commitment: typing.Optional[Commitment] = None,
program_id: PublicKey = MANGO_PROGRAM_ID,
) -> typing.List[typing.Optional["StubOracle"]]:
infos = await get_multiple_accounts(conn, addresses, commitment=commitment)
res: typing.List[typing.Optional["StubOracle"]] = []
for info in infos:
if info is None:
res.append(None)
continue
if info.account.owner != program_id:
raise ValueError("Account does not belong to this program")
res.append(cls.decode(info.account.data))
return res
@classmethod
def decode(cls, data: bytes) -> "StubOracle":
if data[:ACCOUNT_DISCRIMINATOR_SIZE] != cls.discriminator:
raise AccountInvalidDiscriminator(
"The discriminator for this account is invalid"
)
dec = StubOracle.layout.parse(data[ACCOUNT_DISCRIMINATOR_SIZE:])
return cls(
group=dec.group,
mint=dec.mint,
price=types.i80f48.I80F48.from_decoded(dec.price),
last_updated=dec.last_updated,
reserved=dec.reserved,
)
def to_json(self) -> StubOracleJSON:
return {
"group": str(self.group),
"mint": str(self.mint),
"price": self.price.to_json(),
"last_updated": self.last_updated,
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: StubOracleJSON) -> "StubOracle":
return cls(
group=PublicKey(obj["group"]),
mint=PublicKey(obj["mint"]),
price=types.i80f48.I80F48.from_json(obj["price"]),
last_updated=obj["last_updated"],
reserved=obj["reserved"],
)

View File

@ -0,0 +1,8 @@
RUST_U64_MAX = 18446744073709551615
RUST_I64_MAX = 9223372036854775807
RUST_I64_MIN = -9223372036854775807
QUOTE_DECIMALS = 6

View File

@ -0,0 +1,29 @@
import typing
import re
from solders.transaction_status import (
InstructionErrorCustom,
TransactionErrorInstructionError,
)
from solana.rpc.core import RPCException
from solders.rpc.errors import SendTransactionPreflightFailureMessage
from anchorpy.error import extract_code_and_logs
from ..program_id import MANGO_PROGRAM_ID
from . import anchor
from . import custom
def from_code(code: int) -> typing.Union[custom.CustomError, anchor.AnchorError, None]:
return custom.from_code(code) if code >= 6000 else anchor.from_code(code)
error_re = re.compile(r"Program (\w+) failed: custom program error: (\w+)")
def from_tx_error(
error: RPCException,
) -> typing.Union[anchor.AnchorError, custom.CustomError, None]:
err_info = error.args[0]
extracted = extract_code_and_logs(err_info, MANGO_PROGRAM_ID)
if extracted is None:
return None
return from_code(extracted[0])

View File

@ -0,0 +1,590 @@
import typing
from anchorpy.error import ProgramError
class InstructionMissing(ProgramError):
def __init__(self):
super().__init__(100, "8 byte instruction identifier not provided")
code = 100
name = "InstructionMissing"
msg = "8 byte instruction identifier not provided"
class InstructionFallbackNotFound(ProgramError):
def __init__(self):
super().__init__(101, "Fallback functions are not supported")
code = 101
name = "InstructionFallbackNotFound"
msg = "Fallback functions are not supported"
class InstructionDidNotDeserialize(ProgramError):
def __init__(self):
super().__init__(102, "The program could not deserialize the given instruction")
code = 102
name = "InstructionDidNotDeserialize"
msg = "The program could not deserialize the given instruction"
class InstructionDidNotSerialize(ProgramError):
def __init__(self):
super().__init__(103, "The program could not serialize the given instruction")
code = 103
name = "InstructionDidNotSerialize"
msg = "The program could not serialize the given instruction"
class IdlInstructionStub(ProgramError):
def __init__(self):
super().__init__(1000, "The program was compiled without idl instructions")
code = 1000
name = "IdlInstructionStub"
msg = "The program was compiled without idl instructions"
class IdlInstructionInvalidProgram(ProgramError):
def __init__(self):
super().__init__(
1001, "The transaction was given an invalid program for the IDL instruction"
)
code = 1001
name = "IdlInstructionInvalidProgram"
msg = "The transaction was given an invalid program for the IDL instruction"
class ConstraintMut(ProgramError):
def __init__(self):
super().__init__(2000, "A mut constraint was violated")
code = 2000
name = "ConstraintMut"
msg = "A mut constraint was violated"
class ConstraintHasOne(ProgramError):
def __init__(self):
super().__init__(2001, "A has_one constraint was violated")
code = 2001
name = "ConstraintHasOne"
msg = "A has_one constraint was violated"
class ConstraintSigner(ProgramError):
def __init__(self):
super().__init__(2002, "A signer constraint was violated")
code = 2002
name = "ConstraintSigner"
msg = "A signer constraint was violated"
class ConstraintRaw(ProgramError):
def __init__(self):
super().__init__(2003, "A raw constraint was violated")
code = 2003
name = "ConstraintRaw"
msg = "A raw constraint was violated"
class ConstraintOwner(ProgramError):
def __init__(self):
super().__init__(2004, "An owner constraint was violated")
code = 2004
name = "ConstraintOwner"
msg = "An owner constraint was violated"
class ConstraintRentExempt(ProgramError):
def __init__(self):
super().__init__(2005, "A rent exempt constraint was violated")
code = 2005
name = "ConstraintRentExempt"
msg = "A rent exempt constraint was violated"
class ConstraintSeeds(ProgramError):
def __init__(self):
super().__init__(2006, "A seeds constraint was violated")
code = 2006
name = "ConstraintSeeds"
msg = "A seeds constraint was violated"
class ConstraintExecutable(ProgramError):
def __init__(self):
super().__init__(2007, "An executable constraint was violated")
code = 2007
name = "ConstraintExecutable"
msg = "An executable constraint was violated"
class ConstraintState(ProgramError):
def __init__(self):
super().__init__(2008, "A state constraint was violated")
code = 2008
name = "ConstraintState"
msg = "A state constraint was violated"
class ConstraintAssociated(ProgramError):
def __init__(self):
super().__init__(2009, "An associated constraint was violated")
code = 2009
name = "ConstraintAssociated"
msg = "An associated constraint was violated"
class ConstraintAssociatedInit(ProgramError):
def __init__(self):
super().__init__(2010, "An associated init constraint was violated")
code = 2010
name = "ConstraintAssociatedInit"
msg = "An associated init constraint was violated"
class ConstraintClose(ProgramError):
def __init__(self):
super().__init__(2011, "A close constraint was violated")
code = 2011
name = "ConstraintClose"
msg = "A close constraint was violated"
class ConstraintAddress(ProgramError):
def __init__(self):
super().__init__(2012, "An address constraint was violated")
code = 2012
name = "ConstraintAddress"
msg = "An address constraint was violated"
class ConstraintZero(ProgramError):
def __init__(self):
super().__init__(2013, "Expected zero account discriminant")
code = 2013
name = "ConstraintZero"
msg = "Expected zero account discriminant"
class ConstraintTokenMint(ProgramError):
def __init__(self):
super().__init__(2014, "A token mint constraint was violated")
code = 2014
name = "ConstraintTokenMint"
msg = "A token mint constraint was violated"
class ConstraintTokenOwner(ProgramError):
def __init__(self):
super().__init__(2015, "A token owner constraint was violated")
code = 2015
name = "ConstraintTokenOwner"
msg = "A token owner constraint was violated"
class ConstraintMintMintAuthority(ProgramError):
def __init__(self):
super().__init__(2016, "A mint mint authority constraint was violated")
code = 2016
name = "ConstraintMintMintAuthority"
msg = "A mint mint authority constraint was violated"
class ConstraintMintFreezeAuthority(ProgramError):
def __init__(self):
super().__init__(2017, "A mint freeze authority constraint was violated")
code = 2017
name = "ConstraintMintFreezeAuthority"
msg = "A mint freeze authority constraint was violated"
class ConstraintMintDecimals(ProgramError):
def __init__(self):
super().__init__(2018, "A mint decimals constraint was violated")
code = 2018
name = "ConstraintMintDecimals"
msg = "A mint decimals constraint was violated"
class ConstraintSpace(ProgramError):
def __init__(self):
super().__init__(2019, "A space constraint was violated")
code = 2019
name = "ConstraintSpace"
msg = "A space constraint was violated"
class RequireViolated(ProgramError):
def __init__(self):
super().__init__(2500, "A require expression was violated")
code = 2500
name = "RequireViolated"
msg = "A require expression was violated"
class RequireEqViolated(ProgramError):
def __init__(self):
super().__init__(2501, "A require_eq expression was violated")
code = 2501
name = "RequireEqViolated"
msg = "A require_eq expression was violated"
class RequireKeysEqViolated(ProgramError):
def __init__(self):
super().__init__(2502, "A require_keys_eq expression was violated")
code = 2502
name = "RequireKeysEqViolated"
msg = "A require_keys_eq expression was violated"
class RequireNeqViolated(ProgramError):
def __init__(self):
super().__init__(2503, "A require_neq expression was violated")
code = 2503
name = "RequireNeqViolated"
msg = "A require_neq expression was violated"
class RequireKeysNeqViolated(ProgramError):
def __init__(self):
super().__init__(2504, "A require_keys_neq expression was violated")
code = 2504
name = "RequireKeysNeqViolated"
msg = "A require_keys_neq expression was violated"
class RequireGtViolated(ProgramError):
def __init__(self):
super().__init__(2505, "A require_gt expression was violated")
code = 2505
name = "RequireGtViolated"
msg = "A require_gt expression was violated"
class RequireGteViolated(ProgramError):
def __init__(self):
super().__init__(2506, "A require_gte expression was violated")
code = 2506
name = "RequireGteViolated"
msg = "A require_gte expression was violated"
class AccountDiscriminatorAlreadySet(ProgramError):
def __init__(self):
super().__init__(
3000, "The account discriminator was already set on this account"
)
code = 3000
name = "AccountDiscriminatorAlreadySet"
msg = "The account discriminator was already set on this account"
class AccountDiscriminatorNotFound(ProgramError):
def __init__(self):
super().__init__(3001, "No 8 byte discriminator was found on the account")
code = 3001
name = "AccountDiscriminatorNotFound"
msg = "No 8 byte discriminator was found on the account"
class AccountDiscriminatorMismatch(ProgramError):
def __init__(self):
super().__init__(3002, "8 byte discriminator did not match what was expected")
code = 3002
name = "AccountDiscriminatorMismatch"
msg = "8 byte discriminator did not match what was expected"
class AccountDidNotDeserialize(ProgramError):
def __init__(self):
super().__init__(3003, "Failed to deserialize the account")
code = 3003
name = "AccountDidNotDeserialize"
msg = "Failed to deserialize the account"
class AccountDidNotSerialize(ProgramError):
def __init__(self):
super().__init__(3004, "Failed to serialize the account")
code = 3004
name = "AccountDidNotSerialize"
msg = "Failed to serialize the account"
class AccountNotEnoughKeys(ProgramError):
def __init__(self):
super().__init__(3005, "Not enough account keys given to the instruction")
code = 3005
name = "AccountNotEnoughKeys"
msg = "Not enough account keys given to the instruction"
class AccountNotMutable(ProgramError):
def __init__(self):
super().__init__(3006, "The given account is not mutable")
code = 3006
name = "AccountNotMutable"
msg = "The given account is not mutable"
class AccountOwnedByWrongProgram(ProgramError):
def __init__(self):
super().__init__(
3007, "The given account is owned by a different program than expected"
)
code = 3007
name = "AccountOwnedByWrongProgram"
msg = "The given account is owned by a different program than expected"
class InvalidProgramId(ProgramError):
def __init__(self):
super().__init__(3008, "Program ID was not as expected")
code = 3008
name = "InvalidProgramId"
msg = "Program ID was not as expected"
class InvalidProgramExecutable(ProgramError):
def __init__(self):
super().__init__(3009, "Program account is not executable")
code = 3009
name = "InvalidProgramExecutable"
msg = "Program account is not executable"
class AccountNotSigner(ProgramError):
def __init__(self):
super().__init__(3010, "The given account did not sign")
code = 3010
name = "AccountNotSigner"
msg = "The given account did not sign"
class AccountNotSystemOwned(ProgramError):
def __init__(self):
super().__init__(3011, "The given account is not owned by the system program")
code = 3011
name = "AccountNotSystemOwned"
msg = "The given account is not owned by the system program"
class AccountNotInitialized(ProgramError):
def __init__(self):
super().__init__(
3012, "The program expected this account to be already initialized"
)
code = 3012
name = "AccountNotInitialized"
msg = "The program expected this account to be already initialized"
class AccountNotProgramData(ProgramError):
def __init__(self):
super().__init__(3013, "The given account is not a program data account")
code = 3013
name = "AccountNotProgramData"
msg = "The given account is not a program data account"
class AccountNotAssociatedTokenAccount(ProgramError):
def __init__(self):
super().__init__(3014, "The given account is not the associated token account")
code = 3014
name = "AccountNotAssociatedTokenAccount"
msg = "The given account is not the associated token account"
class AccountSysvarMismatch(ProgramError):
def __init__(self):
super().__init__(
3015, "The given public key does not match the required sysvar"
)
code = 3015
name = "AccountSysvarMismatch"
msg = "The given public key does not match the required sysvar"
class StateInvalidAddress(ProgramError):
def __init__(self):
super().__init__(
4000, "The given state account does not have the correct address"
)
code = 4000
name = "StateInvalidAddress"
msg = "The given state account does not have the correct address"
class Deprecated(ProgramError):
def __init__(self):
super().__init__(
5000, "The API being used is deprecated and should no longer be used"
)
code = 5000
name = "Deprecated"
msg = "The API being used is deprecated and should no longer be used"
AnchorError = typing.Union[
InstructionMissing,
InstructionFallbackNotFound,
InstructionDidNotDeserialize,
InstructionDidNotSerialize,
IdlInstructionStub,
IdlInstructionInvalidProgram,
ConstraintMut,
ConstraintHasOne,
ConstraintSigner,
ConstraintRaw,
ConstraintOwner,
ConstraintRentExempt,
ConstraintSeeds,
ConstraintExecutable,
ConstraintState,
ConstraintAssociated,
ConstraintAssociatedInit,
ConstraintClose,
ConstraintAddress,
ConstraintZero,
ConstraintTokenMint,
ConstraintTokenOwner,
ConstraintMintMintAuthority,
ConstraintMintFreezeAuthority,
ConstraintMintDecimals,
ConstraintSpace,
RequireViolated,
RequireEqViolated,
RequireKeysEqViolated,
RequireNeqViolated,
RequireKeysNeqViolated,
RequireGtViolated,
RequireGteViolated,
AccountDiscriminatorAlreadySet,
AccountDiscriminatorNotFound,
AccountDiscriminatorMismatch,
AccountDidNotDeserialize,
AccountDidNotSerialize,
AccountNotEnoughKeys,
AccountNotMutable,
AccountOwnedByWrongProgram,
InvalidProgramId,
InvalidProgramExecutable,
AccountNotSigner,
AccountNotSystemOwned,
AccountNotInitialized,
AccountNotProgramData,
AccountNotAssociatedTokenAccount,
AccountSysvarMismatch,
StateInvalidAddress,
Deprecated,
]
ANCHOR_ERROR_MAP: dict[int, AnchorError] = {
100: InstructionMissing(),
101: InstructionFallbackNotFound(),
102: InstructionDidNotDeserialize(),
103: InstructionDidNotSerialize(),
1000: IdlInstructionStub(),
1001: IdlInstructionInvalidProgram(),
2000: ConstraintMut(),
2001: ConstraintHasOne(),
2002: ConstraintSigner(),
2003: ConstraintRaw(),
2004: ConstraintOwner(),
2005: ConstraintRentExempt(),
2006: ConstraintSeeds(),
2007: ConstraintExecutable(),
2008: ConstraintState(),
2009: ConstraintAssociated(),
2010: ConstraintAssociatedInit(),
2011: ConstraintClose(),
2012: ConstraintAddress(),
2013: ConstraintZero(),
2014: ConstraintTokenMint(),
2015: ConstraintTokenOwner(),
2016: ConstraintMintMintAuthority(),
2017: ConstraintMintFreezeAuthority(),
2018: ConstraintMintDecimals(),
2019: ConstraintSpace(),
2500: RequireViolated(),
2501: RequireEqViolated(),
2502: RequireKeysEqViolated(),
2503: RequireNeqViolated(),
2504: RequireKeysNeqViolated(),
2505: RequireGtViolated(),
2506: RequireGteViolated(),
3000: AccountDiscriminatorAlreadySet(),
3001: AccountDiscriminatorNotFound(),
3002: AccountDiscriminatorMismatch(),
3003: AccountDidNotDeserialize(),
3004: AccountDidNotSerialize(),
3005: AccountNotEnoughKeys(),
3006: AccountNotMutable(),
3007: AccountOwnedByWrongProgram(),
3008: InvalidProgramId(),
3009: InvalidProgramExecutable(),
3010: AccountNotSigner(),
3011: AccountNotSystemOwned(),
3012: AccountNotInitialized(),
3013: AccountNotProgramData(),
3014: AccountNotAssociatedTokenAccount(),
3015: AccountSysvarMismatch(),
4000: StateInvalidAddress(),
5000: Deprecated(),
}
def from_code(code: int) -> typing.Optional[AnchorError]:
maybe_err = ANCHOR_ERROR_MAP.get(code)
if maybe_err is None:
return None
return maybe_err

View File

@ -0,0 +1,339 @@
import typing
from anchorpy.error import ProgramError
class SomeError(ProgramError):
def __init__(self) -> None:
super().__init__(6000, "")
code = 6000
name = "SomeError"
msg = ""
class NotImplementedError(ProgramError):
def __init__(self) -> None:
super().__init__(6001, "")
code = 6001
name = "NotImplementedError"
msg = ""
class MathError(ProgramError):
def __init__(self) -> None:
super().__init__(6002, "checked math error")
code = 6002
name = "MathError"
msg = "checked math error"
class UnexpectedOracle(ProgramError):
def __init__(self) -> None:
super().__init__(6003, "")
code = 6003
name = "UnexpectedOracle"
msg = ""
class UnknownOracleType(ProgramError):
def __init__(self) -> None:
super().__init__(6004, "oracle type cannot be determined")
code = 6004
name = "UnknownOracleType"
msg = "oracle type cannot be determined"
class InvalidFlashLoanTargetCpiProgram(ProgramError):
def __init__(self) -> None:
super().__init__(6005, "")
code = 6005
name = "InvalidFlashLoanTargetCpiProgram"
msg = ""
class HealthMustBePositive(ProgramError):
def __init__(self) -> None:
super().__init__(6006, "health must be positive")
code = 6006
name = "HealthMustBePositive"
msg = "health must be positive"
class HealthMustBePositiveOrIncrease(ProgramError):
def __init__(self) -> None:
super().__init__(6007, "health must be positive or increase")
code = 6007
name = "HealthMustBePositiveOrIncrease"
msg = "health must be positive or increase"
class HealthMustBeNegative(ProgramError):
def __init__(self) -> None:
super().__init__(6008, "health must be negative")
code = 6008
name = "HealthMustBeNegative"
msg = "health must be negative"
class IsBankrupt(ProgramError):
def __init__(self) -> None:
super().__init__(6009, "the account is bankrupt")
code = 6009
name = "IsBankrupt"
msg = "the account is bankrupt"
class IsNotBankrupt(ProgramError):
def __init__(self) -> None:
super().__init__(6010, "the account is not bankrupt")
code = 6010
name = "IsNotBankrupt"
msg = "the account is not bankrupt"
class NoFreeTokenPositionIndex(ProgramError):
def __init__(self) -> None:
super().__init__(6011, "no free token position index")
code = 6011
name = "NoFreeTokenPositionIndex"
msg = "no free token position index"
class NoFreeSerum3OpenOrdersIndex(ProgramError):
def __init__(self) -> None:
super().__init__(6012, "no free serum3 open orders index")
code = 6012
name = "NoFreeSerum3OpenOrdersIndex"
msg = "no free serum3 open orders index"
class NoFreePerpPositionIndex(ProgramError):
def __init__(self) -> None:
super().__init__(6013, "no free perp position index")
code = 6013
name = "NoFreePerpPositionIndex"
msg = "no free perp position index"
class Serum3OpenOrdersExistAlready(ProgramError):
def __init__(self) -> None:
super().__init__(6014, "serum3 open orders exist already")
code = 6014
name = "Serum3OpenOrdersExistAlready"
msg = "serum3 open orders exist already"
class InsufficentBankVaultFunds(ProgramError):
def __init__(self) -> None:
super().__init__(6015, "bank vault has insufficent funds")
code = 6015
name = "InsufficentBankVaultFunds"
msg = "bank vault has insufficent funds"
class BeingLiquidated(ProgramError):
def __init__(self) -> None:
super().__init__(6016, "account is currently being liquidated")
code = 6016
name = "BeingLiquidated"
msg = "account is currently being liquidated"
class InvalidBank(ProgramError):
def __init__(self) -> None:
super().__init__(6017, "invalid bank")
code = 6017
name = "InvalidBank"
msg = "invalid bank"
class ProfitabilityMismatch(ProgramError):
def __init__(self) -> None:
super().__init__(6018, "account profitability is mismatched")
code = 6018
name = "ProfitabilityMismatch"
msg = "account profitability is mismatched"
class CannotSettleWithSelf(ProgramError):
def __init__(self) -> None:
super().__init__(6019, "cannot settle with self")
code = 6019
name = "CannotSettleWithSelf"
msg = "cannot settle with self"
class PerpPositionDoesNotExist(ProgramError):
def __init__(self) -> None:
super().__init__(6020, "perp position does not exist")
code = 6020
name = "PerpPositionDoesNotExist"
msg = "perp position does not exist"
class MaxSettleAmountMustBeGreaterThanZero(ProgramError):
def __init__(self) -> None:
super().__init__(6021, "max settle amount must be greater than zero")
code = 6021
name = "MaxSettleAmountMustBeGreaterThanZero"
msg = "max settle amount must be greater than zero"
class HasOpenPerpOrders(ProgramError):
def __init__(self) -> None:
super().__init__(
6022, "the perp position has open orders or unprocessed fill events"
)
code = 6022
name = "HasOpenPerpOrders"
msg = "the perp position has open orders or unprocessed fill events"
class OracleConfidence(ProgramError):
def __init__(self) -> None:
super().__init__(6023, "an oracle does not reach the confidence threshold")
code = 6023
name = "OracleConfidence"
msg = "an oracle does not reach the confidence threshold"
class OracleStale(ProgramError):
def __init__(self) -> None:
super().__init__(6024, "an oracle is stale")
code = 6024
name = "OracleStale"
msg = "an oracle is stale"
class SettlementAmountMustBePositive(ProgramError):
def __init__(self) -> None:
super().__init__(6025, "settlement amount must always be positive")
code = 6025
name = "SettlementAmountMustBePositive"
msg = "settlement amount must always be positive"
class BankBorrowLimitReached(ProgramError):
def __init__(self) -> None:
super().__init__(6026, "bank utilization has reached limit")
code = 6026
name = "BankBorrowLimitReached"
msg = "bank utilization has reached limit"
class BankNetBorrowsLimitReached(ProgramError):
def __init__(self) -> None:
super().__init__(
6027,
"bank net borrows has reached limit - this is an intermittent error - the limit will reset regularly",
)
code = 6027
name = "BankNetBorrowsLimitReached"
msg = "bank net borrows has reached limit - this is an intermittent error - the limit will reset regularly"
class TokenPositionDoesNotExist(ProgramError):
def __init__(self) -> None:
super().__init__(6028, "token position does not exist")
code = 6028
name = "TokenPositionDoesNotExist"
msg = "token position does not exist"
CustomError = typing.Union[
SomeError,
NotImplementedError,
MathError,
UnexpectedOracle,
UnknownOracleType,
InvalidFlashLoanTargetCpiProgram,
HealthMustBePositive,
HealthMustBePositiveOrIncrease,
HealthMustBeNegative,
IsBankrupt,
IsNotBankrupt,
NoFreeTokenPositionIndex,
NoFreeSerum3OpenOrdersIndex,
NoFreePerpPositionIndex,
Serum3OpenOrdersExistAlready,
InsufficentBankVaultFunds,
BeingLiquidated,
InvalidBank,
ProfitabilityMismatch,
CannotSettleWithSelf,
PerpPositionDoesNotExist,
MaxSettleAmountMustBeGreaterThanZero,
HasOpenPerpOrders,
OracleConfidence,
OracleStale,
SettlementAmountMustBePositive,
BankBorrowLimitReached,
BankNetBorrowsLimitReached,
TokenPositionDoesNotExist,
]
CUSTOM_ERROR_MAP: dict[int, CustomError] = {
6000: SomeError(),
6001: NotImplementedError(),
6002: MathError(),
6003: UnexpectedOracle(),
6004: UnknownOracleType(),
6005: InvalidFlashLoanTargetCpiProgram(),
6006: HealthMustBePositive(),
6007: HealthMustBePositiveOrIncrease(),
6008: HealthMustBeNegative(),
6009: IsBankrupt(),
6010: IsNotBankrupt(),
6011: NoFreeTokenPositionIndex(),
6012: NoFreeSerum3OpenOrdersIndex(),
6013: NoFreePerpPositionIndex(),
6014: Serum3OpenOrdersExistAlready(),
6015: InsufficentBankVaultFunds(),
6016: BeingLiquidated(),
6017: InvalidBank(),
6018: ProfitabilityMismatch(),
6019: CannotSettleWithSelf(),
6020: PerpPositionDoesNotExist(),
6021: MaxSettleAmountMustBeGreaterThanZero(),
6022: HasOpenPerpOrders(),
6023: OracleConfidence(),
6024: OracleStale(),
6025: SettlementAmountMustBePositive(),
6026: BankBorrowLimitReached(),
6027: BankNetBorrowsLimitReached(),
6028: TokenPositionDoesNotExist(),
}
def from_code(code: int) -> typing.Optional[CustomError]:
maybe_err = CUSTOM_ERROR_MAP.get(code)
if maybe_err is None:
return None
return maybe_err

380
mango_explorer_v4/ids.json Normal file
View File

@ -0,0 +1,380 @@
{
"groups": [
{
"publicKey": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"cluster": "MAINNET",
"name": "MAINNET.0",
"mangoProgramId": "4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg",
"insuranceVault": "F1vqFqkZHh5jd5rf8BcEzT8kqfd1snB1adRkayJ9KPNY",
"insuranceMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"insuranceMintDecimals": 6,
"perpMarkets": [
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "HwhVGkfsSQ9JSQeQYu2CbkRCLvsh3qRZxG6m4oMVwZpN",
"marketIndex": 0,
"name": "BTC-PERP",
"baseDecimals": 6,
"baseLotSize": 100,
"quoteLotSize": 10,
"oracle": "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU",
"active": true,
"settleTokenIndex": 0
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "9Y8paZ5wUpzLFfQuHz8j2RtPrKsDtHx9sbgFmWb5abCw",
"marketIndex": 1,
"name": "MNGO-PERP",
"baseDecimals": 6,
"baseLotSize": 1000000,
"quoteLotSize": 100,
"oracle": "79wm3jjcPr6RaNQ4DGvP5KxG1mNd3gEBsg6FsNVFezK4",
"active": false,
"settleTokenIndex": 0
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "ESdnpnNLgTkBCZRuTJkZLi5wKEZ2z47SG3PJrhundSQ2",
"marketIndex": 2,
"name": "SOL-PERP",
"baseDecimals": 9,
"baseLotSize": 10000000,
"quoteLotSize": 100,
"oracle": "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG",
"active": true,
"settleTokenIndex": 0
}
],
"tokens": [
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"tokenIndex": 0,
"symbol": "USDC",
"decimals": 6,
"oracle": "7e7xcRkdb4uJ4A6xShYwBJrWJk5V4AmrEFqAPhSMvzSx",
"mintInfo": "9jPkVdufMKbg62ndJHv5CqCAkzssmstyDi9kxsvrjbSc",
"banks": [
{
"bankNum": 0,
"publicKey": "J6MsZiJUU6bjKSCkbfQsiHkd8gvJoddG2hsdSFsZQEZV"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac",
"tokenIndex": 6,
"symbol": "MNGO",
"decimals": 6,
"oracle": "79wm3jjcPr6RaNQ4DGvP5KxG1mNd3gEBsg6FsNVFezK4",
"mintInfo": "2rbDQ2E1kDK4SHPbr1VUzB6sKdxkcJxDq8jYf44R4oVi",
"banks": [
{
"bankNum": 0,
"publicKey": "5covW85GcCq3kHCJtcKCKYyQoxZLnHiz3zw5TEZEYgKj"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So",
"tokenIndex": 5,
"symbol": "MSOL",
"decimals": 9,
"oracle": "E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9",
"mintInfo": "HopzURnbkLPpQch37o5sN31knjpYGrENuwy9UASXkhfC",
"banks": [
{
"bankNum": 0,
"publicKey": "AL2BeApHWeHdzERdiCy13ZrmPXaiBWG8s11deHrZPuSt"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs",
"tokenIndex": 3,
"symbol": "ETH",
"decimals": 8,
"oracle": "JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB",
"mintInfo": "J8Mq6JQUqaKfWjn9fjaYq8S5haCJXuUGtavjtQHzW4Vm",
"banks": [
{
"bankNum": 0,
"publicKey": "5h2KcPQQijX1RR35yhBJPDzvrsLd4sUcTtXUq3PhVhY9"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
"tokenIndex": 1,
"symbol": "USDT",
"decimals": 6,
"oracle": "3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL",
"mintInfo": "HPmQ7dvQpZV7yoRo8NqMS9jVZBJXocE472b1bbGoLG1Q",
"banks": [
{
"bankNum": 0,
"publicKey": "3k87hyqCaFR2G4SVwsLNMyPmR1mFN6uo7dUytzKQYu9d"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o",
"tokenIndex": 2,
"symbol": "DAI",
"decimals": 8,
"oracle": "CtJ8EkqLmeYyGB8s4jevpeNsvmD4dxVR2krfsDLcvV8Y",
"mintInfo": "A2EmRoXjscbwzbWS84rTnsvWwF2S9T7cdUNwshLWJcbf",
"banks": [
{
"bankNum": 0,
"publicKey": "2AyZpjYWZf42ui1wzWJ642KWMCCY5YEU9GnKRWzQHLYW"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "So11111111111111111111111111111111111111112",
"tokenIndex": 4,
"symbol": "SOL",
"decimals": 9,
"oracle": "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG",
"mintInfo": "EzQYaAhP3mdL4C8VQAAYxec9idCe31yCyAmzxWHLR4QJ",
"banks": [
{
"bankNum": 0,
"publicKey": "FqEhSJSP3ao8RwRSekaAQ9sNQBSANhfb6EPtxQBByyh5"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh",
"tokenIndex": 8,
"symbol": "wBTC (Portal)",
"decimals": 8,
"oracle": "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU",
"mintInfo": "59rgC1pa45EziDPyFgJgE7gbv7Dd7VaGmd2D93i1dtFk",
"banks": [
{
"bankNum": 0,
"publicKey": "8gabXzwdPn5TvtuQvysh3CxVbjfNY3TZd5XEG5qnueUm"
}
],
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
"tokenIndex": 7,
"symbol": "BONK",
"decimals": 5,
"oracle": "4SZ1qb4MtSUrZcoeaeQ3BDzVCyqxw3VwSFpPiMTmn4GE",
"mintInfo": "HweVqvYPKwcxb1vsFxz3qMWKu4wqYWBpCraTFvinJrZZ",
"banks": [
{
"bankNum": 0,
"publicKey": "CwyxwCugWhWDMZTo2xCjVr3CqjLorpBMpqHKZCLYpPod"
}
],
"active": true
}
],
"stubOracles": [
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"publicKey": "7e7xcRkdb4uJ4A6xShYwBJrWJk5V4AmrEFqAPhSMvzSx"
}
],
"serum3Markets": [
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "8JTrmcsZYABLL2HQcNnFo7q7osCVAsRW7m9ggE9Dj9Dw",
"marketIndex": 0,
"name": "SOL/USDC",
"baseTokenIndex": 4,
"quoteTokenIndex": 0,
"serumProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX",
"serumMarketExternal": "8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6",
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "Dp6vp6PfK29gvUMxbjMLhZHiTTFuiStGqvLrZNovvk17",
"marketIndex": 5,
"name": "wBTCpo/USDC",
"baseTokenIndex": 8,
"quoteTokenIndex": 0,
"serumProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX",
"serumMarketExternal": "3BAKsQd3RuhZKES2DGysMhjBdwjZYKYmxRqnSMtZ4KSN",
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "6M7Zrd9UtWc8bhfa6zVnsuN9QULskY6x5bPcZ543hVUQ",
"marketIndex": 2,
"name": "mSOL/USDC",
"baseTokenIndex": 5,
"quoteTokenIndex": 0,
"serumProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX",
"serumMarketExternal": "9Lyhks5bQQxb9EyyX55NtgKQzpM4WK7JCmeaWuQ5MoXD",
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "CjjmHLg9tLFZ86jun4Gbi9c6r6ndZqEiVTevhAf3br7x",
"marketIndex": 1,
"name": "ETH/USDC",
"baseTokenIndex": 3,
"quoteTokenIndex": 0,
"serumProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX",
"serumMarketExternal": "FZxi3yWkE5mMjyaZj6utmYL54QQYfMCKMcLaQZq4UwnA",
"active": false
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "Da4TtMXAKv9uf8sNvhco3agbV9Bvj9S6otgG3Xf9yCv3",
"marketIndex": 3,
"name": "ETHpo/USDC",
"baseTokenIndex": 3,
"quoteTokenIndex": 0,
"serumProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX",
"serumMarketExternal": "BbJgE7HZMaDp5NTYvRh5jZSkQPVDTU8ubPFtpogUkEj4",
"active": true
},
{
"group": "78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX",
"publicKey": "4JptAVNgDYqn8XPcPQgVK8sy99bjyDuv5aTNnFuU8vC9",
"marketIndex": 4,
"name": "BONK/USDC",
"baseTokenIndex": 7,
"quoteTokenIndex": 0,
"serumProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX",
"serumMarketExternal": "8PhnCfgqpgFM7ZJvttGdBVMXHuU4Q23ACxCvWkbs1M71",
"active": true
}
]
},
{
"publicKey": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"cluster": "MAINNET",
"name": "MAINNET.200",
"mangoProgramId": "4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg",
"insuranceVault": "GuiM3jt34uuCQPNQkdaCJMZ5XeBHyemttRDBCY8HvxUV",
"insuranceMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"insuranceMintDecimals": 6,
"perpMarkets": [
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"publicKey": "GqmHjhyhgpYkPgu5NtEq6FHGraLop8d1FHcuCqvQMwgo",
"marketIndex": 0,
"name": "MNGO-PERP",
"baseDecimals": 6,
"baseLotSize": 100000,
"quoteLotSize": 10,
"oracle": "95HSiuPDcg18S2peG1XkftwUConMmphAAGkHzLJxXTVF",
"active": false,
"settleTokenIndex": 0
}
],
"tokens": [
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs",
"tokenIndex": 1,
"symbol": "ETH",
"decimals": 8,
"oracle": "6cNTNmN5JiiJRDDmT9jVETRQHFer6CPnLu5sB7sJa4SW",
"mintInfo": "B4pt1G25pyEWpUZ2qKytRpCaGk8XsWCXXDYnDCinjfiv",
"banks": [
{
"bankNum": 0,
"publicKey": "BXMgtNFW8w7H34MZaeavD45obZdLw2RA9A65LoifbMMg"
}
],
"active": false
},
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"mint": "So11111111111111111111111111111111111111112",
"tokenIndex": 2,
"symbol": "SOL",
"decimals": 9,
"oracle": "CUefdnSmmA2iesNXLhMGhSBueDCTSX4NQUnAMFtwknL6",
"mintInfo": "A2nLp6LdEz4hwADNrpccvwqPH2Qw4CuwU6W4ZnsrLCba",
"banks": [
{
"bankNum": 0,
"publicKey": "AW6BM2paRj7BhK26rLhTNeDT73YRdB1Eg78xNmd9WPJC"
}
],
"active": false
},
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"tokenIndex": 0,
"symbol": "USDC",
"decimals": 6,
"oracle": "4HxZ8spXvVKtuji4WNj1K4zEygUj8SPW3ZQnaCUFN11w",
"mintInfo": "8hW94pJYGCE1vYjinZtXgzy2FSFNLTaD9ckqG5ZXJ6Dk",
"banks": [
{
"bankNum": 0,
"publicKey": "5TX5f6UA4vEyHmxrfhAQzubB9so6k6ojmYCcyYTzN1qK"
}
],
"active": false
}
],
"stubOracles": [
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"mint": "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac",
"publicKey": "95HSiuPDcg18S2peG1XkftwUConMmphAAGkHzLJxXTVF"
},
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs",
"publicKey": "6cNTNmN5JiiJRDDmT9jVETRQHFer6CPnLu5sB7sJa4SW"
},
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"mint": "So11111111111111111111111111111111111111112",
"publicKey": "CUefdnSmmA2iesNXLhMGhSBueDCTSX4NQUnAMFtwknL6"
},
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"publicKey": "4HxZ8spXvVKtuji4WNj1K4zEygUj8SPW3ZQnaCUFN11w"
}
],
"serum3Markets": [
{
"group": "Czdh6uGt9x7EW7TAvN7ZwheSwYjiv29z6VD4yavkmHqe",
"publicKey": "6FCuSyVdekzM5yoVE47ndps7sXcbRgbbXv56d5yU38S2",
"marketIndex": 1,
"name": "SOL/USDC",
"baseTokenIndex": 2,
"quoteTokenIndex": 0,
"serumProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX",
"serumMarketExternal": "8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6",
"active": false
}
]
}
]
}

View File

@ -0,0 +1,176 @@
from .group_create import group_create, GroupCreateArgs, GroupCreateAccounts
from .group_edit import group_edit, GroupEditArgs, GroupEditAccounts
from .group_close import group_close, GroupCloseAccounts
from .token_register import token_register, TokenRegisterArgs, TokenRegisterAccounts
from .token_register_trustless import (
token_register_trustless,
TokenRegisterTrustlessArgs,
TokenRegisterTrustlessAccounts,
)
from .token_edit import token_edit, TokenEditArgs, TokenEditAccounts
from .token_add_bank import token_add_bank, TokenAddBankArgs, TokenAddBankAccounts
from .token_deregister import token_deregister, TokenDeregisterAccounts
from .token_update_index_and_rate import (
token_update_index_and_rate,
TokenUpdateIndexAndRateAccounts,
)
from .account_create import account_create, AccountCreateArgs, AccountCreateAccounts
from .account_expand import account_expand, AccountExpandArgs, AccountExpandAccounts
from .account_edit import account_edit, AccountEditArgs, AccountEditAccounts
from .account_close import account_close, AccountCloseArgs, AccountCloseAccounts
from .stub_oracle_create import (
stub_oracle_create,
StubOracleCreateArgs,
StubOracleCreateAccounts,
)
from .stub_oracle_close import stub_oracle_close, StubOracleCloseAccounts
from .stub_oracle_set import stub_oracle_set, StubOracleSetArgs, StubOracleSetAccounts
from .token_deposit import token_deposit, TokenDepositArgs, TokenDepositAccounts
from .token_deposit_into_existing import (
token_deposit_into_existing,
TokenDepositIntoExistingArgs,
TokenDepositIntoExistingAccounts,
)
from .token_withdraw import token_withdraw, TokenWithdrawArgs, TokenWithdrawAccounts
from .flash_loan_begin import (
flash_loan_begin,
FlashLoanBeginArgs,
FlashLoanBeginAccounts,
)
from .flash_loan_end import flash_loan_end, FlashLoanEndArgs, FlashLoanEndAccounts
from .health_region_begin import health_region_begin, HealthRegionBeginAccounts
from .health_region_end import health_region_end, HealthRegionEndAccounts
from .serum3_register_market import (
serum3_register_market,
Serum3RegisterMarketArgs,
Serum3RegisterMarketAccounts,
)
from .serum3_deregister_market import (
serum3_deregister_market,
Serum3DeregisterMarketAccounts,
)
from .serum3_create_open_orders import (
serum3_create_open_orders,
Serum3CreateOpenOrdersAccounts,
)
from .serum3_close_open_orders import (
serum3_close_open_orders,
Serum3CloseOpenOrdersAccounts,
)
from .serum3_place_order import (
serum3_place_order,
Serum3PlaceOrderArgs,
Serum3PlaceOrderAccounts,
)
from .serum3_cancel_order import (
serum3_cancel_order,
Serum3CancelOrderArgs,
Serum3CancelOrderAccounts,
)
from .serum3_cancel_all_orders import (
serum3_cancel_all_orders,
Serum3CancelAllOrdersArgs,
Serum3CancelAllOrdersAccounts,
)
from .serum3_settle_funds import serum3_settle_funds, Serum3SettleFundsAccounts
from .serum3_liq_force_cancel_orders import (
serum3_liq_force_cancel_orders,
Serum3LiqForceCancelOrdersArgs,
Serum3LiqForceCancelOrdersAccounts,
)
from .liq_token_with_token import (
liq_token_with_token,
LiqTokenWithTokenArgs,
LiqTokenWithTokenAccounts,
)
from .liq_token_bankruptcy import (
liq_token_bankruptcy,
LiqTokenBankruptcyArgs,
LiqTokenBankruptcyAccounts,
)
from .token_liq_with_token import (
token_liq_with_token,
TokenLiqWithTokenArgs,
TokenLiqWithTokenAccounts,
)
from .token_liq_bankruptcy import (
token_liq_bankruptcy,
TokenLiqBankruptcyArgs,
TokenLiqBankruptcyAccounts,
)
from .perp_create_market import (
perp_create_market,
PerpCreateMarketArgs,
PerpCreateMarketAccounts,
)
from .perp_edit_market import (
perp_edit_market,
PerpEditMarketArgs,
PerpEditMarketAccounts,
)
from .perp_close_market import perp_close_market, PerpCloseMarketAccounts
from .perp_deactivate_position import (
perp_deactivate_position,
PerpDeactivatePositionAccounts,
)
from .perp_place_order import (
perp_place_order,
PerpPlaceOrderArgs,
PerpPlaceOrderAccounts,
)
from .perp_place_order_pegged import (
perp_place_order_pegged,
PerpPlaceOrderPeggedArgs,
PerpPlaceOrderPeggedAccounts,
)
from .perp_cancel_order import (
perp_cancel_order,
PerpCancelOrderArgs,
PerpCancelOrderAccounts,
)
from .perp_cancel_order_by_client_order_id import (
perp_cancel_order_by_client_order_id,
PerpCancelOrderByClientOrderIdArgs,
PerpCancelOrderByClientOrderIdAccounts,
)
from .perp_cancel_all_orders import (
perp_cancel_all_orders,
PerpCancelAllOrdersArgs,
PerpCancelAllOrdersAccounts,
)
from .perp_cancel_all_orders_by_side import (
perp_cancel_all_orders_by_side,
PerpCancelAllOrdersBySideArgs,
PerpCancelAllOrdersBySideAccounts,
)
from .perp_consume_events import (
perp_consume_events,
PerpConsumeEventsArgs,
PerpConsumeEventsAccounts,
)
from .perp_update_funding import perp_update_funding, PerpUpdateFundingAccounts
from .perp_settle_pnl import perp_settle_pnl, PerpSettlePnlAccounts
from .perp_settle_fees import (
perp_settle_fees,
PerpSettleFeesArgs,
PerpSettleFeesAccounts,
)
from .perp_liq_base_position import (
perp_liq_base_position,
PerpLiqBasePositionArgs,
PerpLiqBasePositionAccounts,
)
from .perp_liq_force_cancel_orders import (
perp_liq_force_cancel_orders,
PerpLiqForceCancelOrdersArgs,
PerpLiqForceCancelOrdersAccounts,
)
from .perp_liq_bankruptcy import (
perp_liq_bankruptcy,
PerpLiqBankruptcyArgs,
PerpLiqBankruptcyAccounts,
)
from .alt_set import alt_set, AltSetArgs, AltSetAccounts
from .alt_extend import alt_extend, AltExtendArgs, AltExtendAccounts
from .compute_account_data import compute_account_data, ComputeAccountDataAccounts
from .benchmark import benchmark

View File

@ -0,0 +1,48 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class AccountCloseArgs(typing.TypedDict):
force_close: bool
layout = borsh.CStruct("force_close" / borsh.Bool)
class AccountCloseAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
sol_destination: PublicKey
def account_close(
args: AccountCloseArgs,
accounts: AccountCloseAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["sol_destination"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"s\x05\xc0\x1cV\xdd\x89f"
encoded_args = layout.build(
{
"force_close": args["force_close"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,63 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class AccountCreateArgs(typing.TypedDict):
account_num: int
token_count: int
serum3_count: int
perp_count: int
perp_oo_count: int
name: str
layout = borsh.CStruct(
"account_num" / borsh.U32,
"token_count" / borsh.U8,
"serum3_count" / borsh.U8,
"perp_count" / borsh.U8,
"perp_oo_count" / borsh.U8,
"name" / borsh.String,
)
class AccountCreateAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
payer: PublicKey
def account_create(
args: AccountCreateArgs,
accounts: AccountCreateAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xc6_'\xc5)\xd6\x9d\x12"
encoded_args = layout.build(
{
"account_num": args["account_num"],
"token_count": args["token_count"],
"serum3_count": args["serum3_count"],
"perp_count": args["perp_count"],
"perp_oo_count": args["perp_oo_count"],
"name": args["name"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,47 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from anchorpy.borsh_extension import BorshPubkey
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class AccountEditArgs(typing.TypedDict):
name_opt: typing.Optional[str]
delegate_opt: typing.Optional[PublicKey]
layout = borsh.CStruct(
"name_opt" / borsh.Option(borsh.String), "delegate_opt" / borsh.Option(BorshPubkey)
)
class AccountEditAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
def account_edit(
args: AccountEditArgs,
accounts: AccountEditAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xba\xd3\xcd\xb7s]\x18\xa1"
encoded_args = layout.build(
{
"name_opt": args["name_opt"],
"delegate_opt": args["delegate_opt"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,57 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class AccountExpandArgs(typing.TypedDict):
token_count: int
serum3_count: int
perp_count: int
perp_oo_count: int
layout = borsh.CStruct(
"token_count" / borsh.U8,
"serum3_count" / borsh.U8,
"perp_count" / borsh.U8,
"perp_oo_count" / borsh.U8,
)
class AccountExpandAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
payer: PublicKey
def account_expand(
args: AccountExpandArgs,
accounts: AccountExpandAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"X\xd4\x1ft\xfd\xc9Q\x01"
encoded_args = layout.build(
{
"token_count": args["token_count"],
"serum3_count": args["serum3_count"],
"perp_count": args["perp_count"],
"perp_oo_count": args["perp_oo_count"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,52 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from anchorpy.borsh_extension import BorshPubkey
from construct import Construct
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class AltExtendArgs(typing.TypedDict):
index: int
new_addresses: list[PublicKey]
layout = borsh.CStruct(
"index" / borsh.U8, "new_addresses" / borsh.Vec(typing.cast(Construct, BorshPubkey))
)
class AltExtendAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
payer: PublicKey
address_lookup_table: PublicKey
def alt_extend(
args: AltExtendArgs,
accounts: AltExtendAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["address_lookup_table"], is_signer=False, is_writable=True
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"|3/ZDB\x19b"
encoded_args = layout.build(
{
"index": args["index"],
"new_addresses": args["new_addresses"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,44 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class AltSetArgs(typing.TypedDict):
index: int
layout = borsh.CStruct("index" / borsh.U8)
class AltSetAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
address_lookup_table: PublicKey
def alt_set(
args: AltSetArgs,
accounts: AltSetAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["address_lookup_table"], is_signer=False, is_writable=True
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xebD\x91 ;i7\x19"
encoded_args = layout.build(
{
"index": args["index"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,18 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
def benchmark(
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = []
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"yv;\xdcV\x8d\xa6z"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,27 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class ComputeAccountDataAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
def compute_account_data(
accounts: ComputeAccountDataAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"6F\xbeb\xf6\xf2ct"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,47 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
from construct import Construct
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class FlashLoanBeginArgs(typing.TypedDict):
loan_amounts: list[int]
layout = borsh.CStruct("loan_amounts" / borsh.Vec(typing.cast(Construct, borsh.U64)))
class FlashLoanBeginAccounts(typing.TypedDict):
account: PublicKey
owner: PublicKey
instructions: PublicKey
def flash_loan_begin(
args: FlashLoanBeginArgs,
accounts: FlashLoanBeginAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(
pubkey=accounts["instructions"], is_signer=False, is_writable=False
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"QN\xe0<\xf48Z\xef"
encoded_args = layout.build(
{
"loan_amounts": args["loan_amounts"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,43 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class FlashLoanEndArgs(typing.TypedDict):
flash_loan_type: types.flash_loan_type.FlashLoanTypeKind
layout = borsh.CStruct("flash_loan_type" / types.flash_loan_type.layout)
class FlashLoanEndAccounts(typing.TypedDict):
account: PublicKey
owner: PublicKey
def flash_loan_end(
args: FlashLoanEndArgs,
accounts: FlashLoanEndAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xb2\xaa\x02N\xf0\x17\xbe\xb2"
encoded_args = layout.build(
{
"flash_loan_type": args["flash_loan_type"].to_encodable(),
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,37 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class GroupCloseAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
insurance_vault: PublicKey
sol_destination: PublicKey
def group_close(
accounts: GroupCloseAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["insurance_vault"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["sol_destination"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"C~\n\xe0\tyb|"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,62 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.sysvar import SYSVAR_RENT_PUBKEY
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class GroupCreateArgs(typing.TypedDict):
group_num: int
testing: int
version: int
layout = borsh.CStruct(
"group_num" / borsh.U32, "testing" / borsh.U8, "version" / borsh.U8
)
class GroupCreateAccounts(typing.TypedDict):
group: PublicKey
creator: PublicKey
insurance_mint: PublicKey
insurance_vault: PublicKey
payer: PublicKey
def group_create(
args: GroupCreateArgs,
accounts: GroupCreateAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["creator"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["insurance_mint"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["insurance_vault"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xe2R\xefwk\x88\xa6\xf0"
encoded_args = layout.build(
{
"group_num": args["group_num"],
"testing": args["testing"],
"version": args["version"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,52 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from anchorpy.borsh_extension import BorshPubkey
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class GroupEditArgs(typing.TypedDict):
admin_opt: typing.Optional[PublicKey]
fast_listing_admin_opt: typing.Optional[PublicKey]
testing_opt: typing.Optional[int]
version_opt: typing.Optional[int]
layout = borsh.CStruct(
"admin_opt" / borsh.Option(BorshPubkey),
"fast_listing_admin_opt" / borsh.Option(BorshPubkey),
"testing_opt" / borsh.Option(borsh.U8),
"version_opt" / borsh.Option(borsh.U8),
)
class GroupEditAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
def group_edit(
args: GroupEditArgs,
accounts: GroupEditAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x08X\xb7\xf9\xa6s7\xe3"
encoded_args = layout.build(
{
"admin_opt": args["admin_opt"],
"fast_listing_admin_opt": args["fast_listing_admin_opt"],
"testing_opt": args["testing_opt"],
"version_opt": args["version_opt"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,29 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class HealthRegionBeginAccounts(typing.TypedDict):
instructions: PublicKey
account: PublicKey
def health_region_begin(
accounts: HealthRegionBeginAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(
pubkey=accounts["instructions"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"=C5\xc6\x8b\x84\xd3,"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,25 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class HealthRegionEndAccounts(typing.TypedDict):
account: PublicKey
def health_region_end(
accounts: HealthRegionEndAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True)
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x1a\xb4\xeap:A\x08\xf6"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,57 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class LiqTokenBankruptcyArgs(typing.TypedDict):
max_liab_transfer: types.i80f48.I80F48
layout = borsh.CStruct("max_liab_transfer" / types.i80f48.I80F48.layout)
class LiqTokenBankruptcyAccounts(typing.TypedDict):
group: PublicKey
liqor: PublicKey
liqor_owner: PublicKey
liqee: PublicKey
liab_mint_info: PublicKey
quote_vault: PublicKey
insurance_vault: PublicKey
def liq_token_bankruptcy(
args: LiqTokenBankruptcyArgs,
accounts: LiqTokenBankruptcyAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["liqor"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["liqor_owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["liqee"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["liab_mint_info"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["insurance_vault"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"i\xab\xdfDk>\x0c\xf3"
encoded_args = layout.build(
{
"max_liab_transfer": args["max_liab_transfer"].to_encodable(),
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,53 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class LiqTokenWithTokenArgs(typing.TypedDict):
asset_token_index: int
liab_token_index: int
max_liab_transfer: types.i80f48.I80F48
layout = borsh.CStruct(
"asset_token_index" / borsh.U16,
"liab_token_index" / borsh.U16,
"max_liab_transfer" / types.i80f48.I80F48.layout,
)
class LiqTokenWithTokenAccounts(typing.TypedDict):
group: PublicKey
liqor: PublicKey
liqor_owner: PublicKey
liqee: PublicKey
def liq_token_with_token(
args: LiqTokenWithTokenArgs,
accounts: LiqTokenWithTokenAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["liqor"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["liqor_owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["liqee"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"C\x7f\x98\x98\xd3\xd0\xfb\xe2"
encoded_args = layout.build(
{
"asset_token_index": args["asset_token_index"],
"liab_token_index": args["liab_token_index"],
"max_liab_transfer": args["max_liab_transfer"].to_encodable(),
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,48 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpCancelAllOrdersArgs(typing.TypedDict):
limit: int
layout = borsh.CStruct("limit" / borsh.U8)
class PerpCancelAllOrdersAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
def perp_cancel_all_orders(
args: PerpCancelAllOrdersArgs,
accounts: PerpCancelAllOrdersAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"`\x10\xe2\xb5k\x91\xe0\xd5"
encoded_args = layout.build(
{
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,57 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class PerpCancelAllOrdersBySideArgs(typing.TypedDict):
side_option: typing.Optional[types.side.SideKind]
limit: int
layout = borsh.CStruct(
"side_option" / borsh.Option(types.side.layout), "limit" / borsh.U8
)
class PerpCancelAllOrdersBySideAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
def perp_cancel_all_orders_by_side(
args: PerpCancelAllOrdersBySideArgs,
accounts: PerpCancelAllOrdersBySideAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"3\xf8\xcc}e\xb6k\x92"
encoded_args = layout.build(
{
"side_option": (
None
if args["side_option"] is None
else args["side_option"].to_encodable()
),
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,48 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpCancelOrderArgs(typing.TypedDict):
order_id: int
layout = borsh.CStruct("order_id" / borsh.U128)
class PerpCancelOrderAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
def perp_cancel_order(
args: PerpCancelOrderArgs,
accounts: PerpCancelOrderAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xe9\t\xbdD\xe0\xa3\xf5\xc1"
encoded_args = layout.build(
{
"order_id": args["order_id"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,48 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpCancelOrderByClientOrderIdArgs(typing.TypedDict):
client_order_id: int
layout = borsh.CStruct("client_order_id" / borsh.U64)
class PerpCancelOrderByClientOrderIdAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
def perp_cancel_order_by_client_order_id(
args: PerpCancelOrderByClientOrderIdArgs,
accounts: PerpCancelOrderByClientOrderIdAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"J\xfa8O\xce\xad\xa3f"
encoded_args = layout.build(
{
"client_order_id": args["client_order_id"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,41 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class PerpCloseMarketAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
event_queue: PublicKey
sol_destination: PublicKey
def perp_close_market(
accounts: PerpCloseMarketAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["sol_destination"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xe2\xee\xbb\x11\xa0\x99\xfe\xa0"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,42 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpConsumeEventsArgs(typing.TypedDict):
limit: int
layout = borsh.CStruct("limit" / borsh.U64)
class PerpConsumeEventsAccounts(typing.TypedDict):
group: PublicKey
perp_market: PublicKey
event_queue: PublicKey
def perp_consume_events(
args: PerpConsumeEventsArgs,
accounts: PerpConsumeEventsAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x9eU\x1d\xd18\xeb %"
encoded_args = layout.build(
{
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,129 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class PerpCreateMarketArgs(typing.TypedDict):
perp_market_index: int
name: str
oracle_config: types.oracle_config_params.OracleConfigParams
base_decimals: int
quote_lot_size: int
base_lot_size: int
maint_asset_weight: float
init_asset_weight: float
maint_liab_weight: float
init_liab_weight: float
liquidation_fee: float
maker_fee: float
taker_fee: float
min_funding: float
max_funding: float
impact_quantity: int
group_insurance_fund: bool
trusted_market: bool
fee_penalty: float
settle_fee_flat: float
settle_fee_amount_threshold: float
settle_fee_fraction_low_health: float
settle_token_index: int
settle_pnl_limit_factor: float
settle_pnl_limit_window_size_ts: int
layout = borsh.CStruct(
"perp_market_index" / borsh.U16,
"name" / borsh.String,
"oracle_config" / types.oracle_config_params.OracleConfigParams.layout,
"base_decimals" / borsh.U8,
"quote_lot_size" / borsh.I64,
"base_lot_size" / borsh.I64,
"maint_asset_weight" / borsh.F32,
"init_asset_weight" / borsh.F32,
"maint_liab_weight" / borsh.F32,
"init_liab_weight" / borsh.F32,
"liquidation_fee" / borsh.F32,
"maker_fee" / borsh.F32,
"taker_fee" / borsh.F32,
"min_funding" / borsh.F32,
"max_funding" / borsh.F32,
"impact_quantity" / borsh.I64,
"group_insurance_fund" / borsh.Bool,
"trusted_market" / borsh.Bool,
"fee_penalty" / borsh.F32,
"settle_fee_flat" / borsh.F32,
"settle_fee_amount_threshold" / borsh.F32,
"settle_fee_fraction_low_health" / borsh.F32,
"settle_token_index" / borsh.U16,
"settle_pnl_limit_factor" / borsh.F32,
"settle_pnl_limit_window_size_ts" / borsh.U64,
)
class PerpCreateMarketAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
oracle: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
event_queue: PublicKey
payer: PublicKey
def perp_create_market(
args: PerpCreateMarketArgs,
accounts: PerpCreateMarketAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b']/-\xc3>\xfc "'
encoded_args = layout.build(
{
"perp_market_index": args["perp_market_index"],
"name": args["name"],
"oracle_config": args["oracle_config"].to_encodable(),
"base_decimals": args["base_decimals"],
"quote_lot_size": args["quote_lot_size"],
"base_lot_size": args["base_lot_size"],
"maint_asset_weight": args["maint_asset_weight"],
"init_asset_weight": args["init_asset_weight"],
"maint_liab_weight": args["maint_liab_weight"],
"init_liab_weight": args["init_liab_weight"],
"liquidation_fee": args["liquidation_fee"],
"maker_fee": args["maker_fee"],
"taker_fee": args["taker_fee"],
"min_funding": args["min_funding"],
"max_funding": args["max_funding"],
"impact_quantity": args["impact_quantity"],
"group_insurance_fund": args["group_insurance_fund"],
"trusted_market": args["trusted_market"],
"fee_penalty": args["fee_penalty"],
"settle_fee_flat": args["settle_fee_flat"],
"settle_fee_amount_threshold": args["settle_fee_amount_threshold"],
"settle_fee_fraction_low_health": args["settle_fee_fraction_low_health"],
"settle_token_index": args["settle_token_index"],
"settle_pnl_limit_factor": args["settle_pnl_limit_factor"],
"settle_pnl_limit_window_size_ts": args["settle_pnl_limit_window_size_ts"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,31 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class PerpDeactivatePositionAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
perp_market: PublicKey
def perp_deactivate_position(
accounts: PerpDeactivatePositionAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x8cT\xf3\xf9\x1d\x94\x12\x1d"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,128 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from anchorpy.borsh_extension import BorshPubkey
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class PerpEditMarketArgs(typing.TypedDict):
oracle_opt: typing.Optional[PublicKey]
oracle_config_opt: typing.Optional[types.oracle_config_params.OracleConfigParams]
base_decimals_opt: typing.Optional[int]
maint_asset_weight_opt: typing.Optional[float]
init_asset_weight_opt: typing.Optional[float]
maint_liab_weight_opt: typing.Optional[float]
init_liab_weight_opt: typing.Optional[float]
liquidation_fee_opt: typing.Optional[float]
maker_fee_opt: typing.Optional[float]
taker_fee_opt: typing.Optional[float]
min_funding_opt: typing.Optional[float]
max_funding_opt: typing.Optional[float]
impact_quantity_opt: typing.Optional[int]
group_insurance_fund_opt: typing.Optional[bool]
trusted_market_opt: typing.Optional[bool]
fee_penalty_opt: typing.Optional[float]
settle_fee_flat_opt: typing.Optional[float]
settle_fee_amount_threshold_opt: typing.Optional[float]
settle_fee_fraction_low_health_opt: typing.Optional[float]
stable_price_delay_interval_seconds_opt: typing.Optional[int]
stable_price_delay_growth_limit_opt: typing.Optional[float]
stable_price_growth_limit_opt: typing.Optional[float]
settle_pnl_limit_factor_opt: typing.Optional[float]
settle_pnl_limit_window_size_ts: typing.Optional[int]
layout = borsh.CStruct(
"oracle_opt" / borsh.Option(BorshPubkey),
"oracle_config_opt"
/ borsh.Option(types.oracle_config_params.OracleConfigParams.layout),
"base_decimals_opt" / borsh.Option(borsh.U8),
"maint_asset_weight_opt" / borsh.Option(borsh.F32),
"init_asset_weight_opt" / borsh.Option(borsh.F32),
"maint_liab_weight_opt" / borsh.Option(borsh.F32),
"init_liab_weight_opt" / borsh.Option(borsh.F32),
"liquidation_fee_opt" / borsh.Option(borsh.F32),
"maker_fee_opt" / borsh.Option(borsh.F32),
"taker_fee_opt" / borsh.Option(borsh.F32),
"min_funding_opt" / borsh.Option(borsh.F32),
"max_funding_opt" / borsh.Option(borsh.F32),
"impact_quantity_opt" / borsh.Option(borsh.I64),
"group_insurance_fund_opt" / borsh.Option(borsh.Bool),
"trusted_market_opt" / borsh.Option(borsh.Bool),
"fee_penalty_opt" / borsh.Option(borsh.F32),
"settle_fee_flat_opt" / borsh.Option(borsh.F32),
"settle_fee_amount_threshold_opt" / borsh.Option(borsh.F32),
"settle_fee_fraction_low_health_opt" / borsh.Option(borsh.F32),
"stable_price_delay_interval_seconds_opt" / borsh.Option(borsh.U32),
"stable_price_delay_growth_limit_opt" / borsh.Option(borsh.F32),
"stable_price_growth_limit_opt" / borsh.Option(borsh.F32),
"settle_pnl_limit_factor_opt" / borsh.Option(borsh.F32),
"settle_pnl_limit_window_size_ts" / borsh.Option(borsh.U64),
)
class PerpEditMarketAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
perp_market: PublicKey
oracle: PublicKey
def perp_edit_market(
args: PerpEditMarketArgs,
accounts: PerpEditMarketAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"|r\xa0\xe7E\xdfLQ"
encoded_args = layout.build(
{
"oracle_opt": args["oracle_opt"],
"oracle_config_opt": (
None
if args["oracle_config_opt"] is None
else args["oracle_config_opt"].to_encodable()
),
"base_decimals_opt": args["base_decimals_opt"],
"maint_asset_weight_opt": args["maint_asset_weight_opt"],
"init_asset_weight_opt": args["init_asset_weight_opt"],
"maint_liab_weight_opt": args["maint_liab_weight_opt"],
"init_liab_weight_opt": args["init_liab_weight_opt"],
"liquidation_fee_opt": args["liquidation_fee_opt"],
"maker_fee_opt": args["maker_fee_opt"],
"taker_fee_opt": args["taker_fee_opt"],
"min_funding_opt": args["min_funding_opt"],
"max_funding_opt": args["max_funding_opt"],
"impact_quantity_opt": args["impact_quantity_opt"],
"group_insurance_fund_opt": args["group_insurance_fund_opt"],
"trusted_market_opt": args["trusted_market_opt"],
"fee_penalty_opt": args["fee_penalty_opt"],
"settle_fee_flat_opt": args["settle_fee_flat_opt"],
"settle_fee_amount_threshold_opt": args["settle_fee_amount_threshold_opt"],
"settle_fee_fraction_low_health_opt": args[
"settle_fee_fraction_low_health_opt"
],
"stable_price_delay_interval_seconds_opt": args[
"stable_price_delay_interval_seconds_opt"
],
"stable_price_delay_growth_limit_opt": args[
"stable_price_delay_growth_limit_opt"
],
"stable_price_growth_limit_opt": args["stable_price_growth_limit_opt"],
"settle_pnl_limit_factor_opt": args["settle_pnl_limit_factor_opt"],
"settle_pnl_limit_window_size_ts": args["settle_pnl_limit_window_size_ts"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,60 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpLiqBankruptcyArgs(typing.TypedDict):
max_liab_transfer: int
layout = borsh.CStruct("max_liab_transfer" / borsh.U64)
class PerpLiqBankruptcyAccounts(typing.TypedDict):
group: PublicKey
perp_market: PublicKey
liqor: PublicKey
liqor_owner: PublicKey
liqee: PublicKey
settle_bank: PublicKey
settle_vault: PublicKey
settle_oracle: PublicKey
insurance_vault: PublicKey
def perp_liq_bankruptcy(
args: PerpLiqBankruptcyArgs,
accounts: PerpLiqBankruptcyAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["liqor"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["liqor_owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["liqee"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["settle_bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["settle_vault"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["settle_oracle"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["insurance_vault"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x8b\xcc\xdd\x02\xe9\x05\xb5|"
encoded_args = layout.build(
{
"max_liab_transfer": args["max_liab_transfer"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,48 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpLiqBasePositionArgs(typing.TypedDict):
max_base_transfer: int
layout = borsh.CStruct("max_base_transfer" / borsh.I64)
class PerpLiqBasePositionAccounts(typing.TypedDict):
group: PublicKey
perp_market: PublicKey
oracle: PublicKey
liqor: PublicKey
liqor_owner: PublicKey
liqee: PublicKey
def perp_liq_base_position(
args: PerpLiqBasePositionArgs,
accounts: PerpLiqBasePositionAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["liqor"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["liqor_owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["liqee"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xa8L\xc9uH5Ak"
encoded_args = layout.build(
{
"max_base_transfer": args["max_base_transfer"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,46 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpLiqForceCancelOrdersArgs(typing.TypedDict):
limit: int
layout = borsh.CStruct("limit" / borsh.U8)
class PerpLiqForceCancelOrdersAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
def perp_liq_force_cancel_orders(
args: PerpLiqForceCancelOrdersArgs,
accounts: PerpLiqForceCancelOrdersAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"m\xcb\xba\x10\xe9[\x01\x8d"
encoded_args = layout.build(
{
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,79 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class PerpPlaceOrderArgs(typing.TypedDict):
side: types.side.SideKind
price_lots: int
max_base_lots: int
max_quote_lots: int
client_order_id: int
order_type: types.place_order_type.PlaceOrderTypeKind
reduce_only: bool
expiry_timestamp: int
limit: int
layout = borsh.CStruct(
"side" / types.side.layout,
"price_lots" / borsh.I64,
"max_base_lots" / borsh.I64,
"max_quote_lots" / borsh.I64,
"client_order_id" / borsh.U64,
"order_type" / types.place_order_type.layout,
"reduce_only" / borsh.Bool,
"expiry_timestamp" / borsh.U64,
"limit" / borsh.U8,
)
class PerpPlaceOrderAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
event_queue: PublicKey
oracle: PublicKey
def perp_place_order(
args: PerpPlaceOrderArgs,
accounts: PerpPlaceOrderAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xbd\xc4\xe1\xc9r\xac\x19\xa6"
encoded_args = layout.build(
{
"side": args["side"].to_encodable(),
"price_lots": args["price_lots"],
"max_base_lots": args["max_base_lots"],
"max_quote_lots": args["max_quote_lots"],
"client_order_id": args["client_order_id"],
"order_type": args["order_type"].to_encodable(),
"reduce_only": args["reduce_only"],
"expiry_timestamp": args["expiry_timestamp"],
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,85 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class PerpPlaceOrderPeggedArgs(typing.TypedDict):
side: types.side.SideKind
price_offset_lots: int
peg_limit: int
max_base_lots: int
max_quote_lots: int
client_order_id: int
order_type: types.place_order_type.PlaceOrderTypeKind
reduce_only: bool
expiry_timestamp: int
limit: int
max_oracle_staleness_slots: int
layout = borsh.CStruct(
"side" / types.side.layout,
"price_offset_lots" / borsh.I64,
"peg_limit" / borsh.I64,
"max_base_lots" / borsh.I64,
"max_quote_lots" / borsh.I64,
"client_order_id" / borsh.U64,
"order_type" / types.place_order_type.layout,
"reduce_only" / borsh.Bool,
"expiry_timestamp" / borsh.U64,
"limit" / borsh.U8,
"max_oracle_staleness_slots" / borsh.I32,
)
class PerpPlaceOrderPeggedAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
event_queue: PublicKey
oracle: PublicKey
def perp_place_order_pegged(
args: PerpPlaceOrderPeggedArgs,
accounts: PerpPlaceOrderPeggedAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["event_queue"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xc0<\x99\xa2\xf6\xc82W"
encoded_args = layout.build(
{
"side": args["side"].to_encodable(),
"price_offset_lots": args["price_offset_lots"],
"peg_limit": args["peg_limit"],
"max_base_lots": args["max_base_lots"],
"max_quote_lots": args["max_quote_lots"],
"client_order_id": args["client_order_id"],
"order_type": args["order_type"].to_encodable(),
"reduce_only": args["reduce_only"],
"expiry_timestamp": args["expiry_timestamp"],
"limit": args["limit"],
"max_oracle_staleness_slots": args["max_oracle_staleness_slots"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,50 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class PerpSettleFeesArgs(typing.TypedDict):
max_settle_amount: int
layout = borsh.CStruct("max_settle_amount" / borsh.U64)
class PerpSettleFeesAccounts(typing.TypedDict):
group: PublicKey
perp_market: PublicKey
account: PublicKey
oracle: PublicKey
settle_bank: PublicKey
settle_oracle: PublicKey
def perp_settle_fees(
args: PerpSettleFeesArgs,
accounts: PerpSettleFeesAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["settle_bank"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["settle_oracle"], is_signer=False, is_writable=False
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xdf\xed\xe3H\x98\xb9\xeas"
encoded_args = layout.build(
{
"max_settle_amount": args["max_settle_amount"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,45 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class PerpSettlePnlAccounts(typing.TypedDict):
group: PublicKey
settler: PublicKey
settler_owner: PublicKey
perp_market: PublicKey
account_a: PublicKey
account_b: PublicKey
oracle: PublicKey
settle_bank: PublicKey
settle_oracle: PublicKey
def perp_settle_pnl(
accounts: PerpSettlePnlAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["settler"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["settler_owner"], is_signer=True, is_writable=False
),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account_a"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["account_b"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["settle_bank"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["settle_oracle"], is_signer=False, is_writable=False
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xf5bU\xb3\xe6\xd7\x829"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,33 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class PerpUpdateFundingAccounts(typing.TypedDict):
group: PublicKey
perp_market: PublicKey
bids: PublicKey
asks: PublicKey
oracle: PublicKey
def perp_update_funding(
accounts: PerpUpdateFundingAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["perp_market"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["asks"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x1c\x12\xb8F\x07\xf5\x0e."
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,64 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class Serum3CancelAllOrdersArgs(typing.TypedDict):
limit: int
layout = borsh.CStruct("limit" / borsh.U8)
class Serum3CancelAllOrdersAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
open_orders: PublicKey
serum_market: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
market_bids: PublicKey
market_asks: PublicKey
market_event_queue: PublicKey
def serum3_cancel_all_orders(
args: Serum3CancelAllOrdersArgs,
accounts: Serum3CancelAllOrdersAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["serum_market"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=accounts["market_bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["market_asks"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["market_event_queue"], is_signer=False, is_writable=True
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xf1\xfc\x0e\x05\xf5\x80\x02\xac"
encoded_args = layout.build(
{
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,67 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class Serum3CancelOrderArgs(typing.TypedDict):
side: types.serum3_side.Serum3SideKind
order_id: int
layout = borsh.CStruct("side" / types.serum3_side.layout, "order_id" / borsh.U128)
class Serum3CancelOrderAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
open_orders: PublicKey
serum_market: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
market_bids: PublicKey
market_asks: PublicKey
market_event_queue: PublicKey
def serum3_cancel_order(
args: Serum3CancelOrderArgs,
accounts: Serum3CancelOrderAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["serum_market"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=accounts["market_bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["market_asks"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["market_event_queue"], is_signer=False, is_writable=True
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"~rm\x16\xc6\x0c|K"
encoded_args = layout.build(
{
"side": args["side"].to_encodable(),
"order_id": args["order_id"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,47 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class Serum3CloseOpenOrdersAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
serum_market: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
open_orders: PublicKey
sol_destination: PublicKey
def serum3_close_open_orders(
accounts: Serum3CloseOpenOrdersAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["serum_market"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["sol_destination"], is_signer=False, is_writable=True
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xff\x89z\xfd\xf1&\xee\x88"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,49 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.sysvar import SYSVAR_RENT_PUBKEY
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class Serum3CreateOpenOrdersAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
serum_market: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
open_orders: PublicKey
payer: PublicKey
def serum3_create_open_orders(
accounts: Serum3CreateOpenOrdersAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["serum_market"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x04\xf4#(US\xcb\xfa"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,39 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class Serum3DeregisterMarketAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
serum_market: PublicKey
index_reservation: PublicKey
sol_destination: PublicKey
def serum3_deregister_market(
accounts: Serum3DeregisterMarketAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["serum_market"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["index_reservation"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["sol_destination"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x11\xa4*\xde\x97\xa0\x18\xb5"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,84 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class Serum3LiqForceCancelOrdersArgs(typing.TypedDict):
limit: int
layout = borsh.CStruct("limit" / borsh.U8)
class Serum3LiqForceCancelOrdersAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
open_orders: PublicKey
serum_market: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
market_bids: PublicKey
market_asks: PublicKey
market_event_queue: PublicKey
market_base_vault: PublicKey
market_quote_vault: PublicKey
market_vault_signer: PublicKey
quote_bank: PublicKey
quote_vault: PublicKey
base_bank: PublicKey
base_vault: PublicKey
def serum3_liq_force_cancel_orders(
args: Serum3LiqForceCancelOrdersArgs,
accounts: Serum3LiqForceCancelOrdersAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["serum_market"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=accounts["market_bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["market_asks"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["market_event_queue"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_base_vault"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_quote_vault"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_vault_signer"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["quote_bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["base_bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["base_vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x1f\xaa_]X6\t\xe7"
encoded_args = layout.build(
{
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,116 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID, SERUM_PROGRAM_ID
class Serum3PlaceOrderArgs(typing.TypedDict):
side: types.serum3_side.Serum3SideKind
limit_price: int
max_base_qty: int
max_native_quote_qty_including_fees: int
self_trade_behavior: types.serum3_self_trade_behavior.Serum3SelfTradeBehaviorKind
order_type: types.serum3_order_type.Serum3OrderTypeKind
client_order_id: int
limit: int
layout = borsh.CStruct(
"side" / types.serum3_side.layout,
"limit_price" / borsh.U64,
"max_base_qty" / borsh.U64,
"max_native_quote_qty_including_fees" / borsh.U64,
"self_trade_behavior" / types.serum3_self_trade_behavior.layout,
"order_type" / types.serum3_order_type.layout,
"client_order_id" / borsh.U64,
"limit" / borsh.U16,
)
class Serum3PlaceOrderAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
open_orders: PublicKey
serum_market: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
market_bids: PublicKey
market_asks: PublicKey
market_event_queue: PublicKey
market_request_queue: PublicKey
market_base_vault: PublicKey
market_quote_vault: PublicKey
market_vault_signer: PublicKey
payer_bank: PublicKey
payer_vault: PublicKey
payer_oracle: PublicKey
def serum3_place_order(
args: Serum3PlaceOrderArgs,
accounts: Serum3PlaceOrderAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["serum_market"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=accounts["market_bids"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["market_asks"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["market_event_queue"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_request_queue"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_base_vault"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_quote_vault"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_vault_signer"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["payer_bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["payer_vault"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["payer_oracle"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"a\x1d{\xc7\xe4\x14\xb8\xfc"
encoded_args = layout.build(
{
"side": args["side"].to_encodable(),
"limit_price": args["limit_price"],
"max_base_qty": args["max_base_qty"],
"max_native_quote_qty_including_fees": args[
"max_native_quote_qty_including_fees"
],
"self_trade_behavior": args["self_trade_behavior"].to_encodable(),
"order_type": args["order_type"].to_encodable(),
"client_order_id": args["client_order_id"],
"limit": args["limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,64 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class Serum3RegisterMarketArgs(typing.TypedDict):
market_index: int
name: str
layout = borsh.CStruct("market_index" / borsh.U16, "name" / borsh.String)
class Serum3RegisterMarketAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
serum_market: PublicKey
index_reservation: PublicKey
quote_bank: PublicKey
base_bank: PublicKey
payer: PublicKey
def serum3_register_market(
args: Serum3RegisterMarketArgs,
accounts: Serum3RegisterMarketAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["serum_market"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["index_reservation"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=accounts["quote_bank"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["base_bank"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"(\x0emx\xde\x9c\xd1\x00"
encoded_args = layout.build(
{
"market_index": args["market_index"],
"name": args["name"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,65 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class Serum3SettleFundsAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
open_orders: PublicKey
serum_market: PublicKey
serum_program: PublicKey
serum_market_external: PublicKey
market_base_vault: PublicKey
market_quote_vault: PublicKey
market_vault_signer: PublicKey
quote_bank: PublicKey
quote_vault: PublicKey
base_bank: PublicKey
base_vault: PublicKey
def serum3_settle_funds(
accounts: Serum3SettleFundsAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["open_orders"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["serum_market"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_program"], is_signer=False, is_writable=False
),
AccountMeta(
pubkey=accounts["serum_market_external"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_base_vault"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_quote_vault"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["market_vault_signer"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["quote_bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["base_bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["base_vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"U<i\xe5\xe23%k"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,35 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class StubOracleCloseAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
oracle: PublicKey
sol_destination: PublicKey
def stub_oracle_close(
accounts: StubOracleCloseAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["sol_destination"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\\\x89-\x03-<u\xe0"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,49 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class StubOracleCreateArgs(typing.TypedDict):
price: types.i80f48.I80F48
layout = borsh.CStruct("price" / types.i80f48.I80F48.layout)
class StubOracleCreateAccounts(typing.TypedDict):
group: PublicKey
oracle: PublicKey
admin: PublicKey
mint: PublicKey
payer: PublicKey
def stub_oracle_create(
args: StubOracleCreateArgs,
accounts: StubOracleCreateAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xac?eS\x8dL\xc7\xd8"
encoded_args = layout.build(
{
"price": args["price"].to_encodable(),
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,43 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class StubOracleSetArgs(typing.TypedDict):
price: types.i80f48.I80F48
layout = borsh.CStruct("price" / types.i80f48.I80F48.layout)
class StubOracleSetAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
oracle: PublicKey
def stub_oracle_set(
args: StubOracleSetArgs,
accounts: StubOracleSetAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"m\xc6OyA\xca\xa1\x8e"
encoded_args = layout.build(
{
"price": args["price"].to_encodable(),
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,62 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.sysvar import SYSVAR_RENT_PUBKEY
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class TokenAddBankArgs(typing.TypedDict):
token_index: int
bank_num: int
layout = borsh.CStruct("token_index" / borsh.U16, "bank_num" / borsh.U32)
class TokenAddBankAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
mint: PublicKey
existing_bank: PublicKey
bank: PublicKey
vault: PublicKey
mint_info: PublicKey
payer: PublicKey
def token_add_bank(
args: TokenAddBankArgs,
accounts: TokenAddBankAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False),
AccountMeta(
pubkey=accounts["existing_bank"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["mint_info"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\xa3X\xea\x1f\x81\xde\x03$"
encoded_args = layout.build(
{
"token_index": args["token_index"],
"bank_num": args["bank_num"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,58 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class TokenDepositArgs(typing.TypedDict):
amount: int
layout = borsh.CStruct("amount" / borsh.U64)
class TokenDepositAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
bank: PublicKey
vault: PublicKey
oracle: PublicKey
token_account: PublicKey
token_authority: PublicKey
def token_deposit(
args: TokenDepositArgs,
accounts: TokenDepositAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(
pubkey=accounts["token_account"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["token_authority"], is_signer=True, is_writable=False
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"u\xff\x9aG\xf5:_Y"
encoded_args = layout.build(
{
"amount": args["amount"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,56 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class TokenDepositIntoExistingArgs(typing.TypedDict):
amount: int
layout = borsh.CStruct("amount" / borsh.U64)
class TokenDepositIntoExistingAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
bank: PublicKey
vault: PublicKey
oracle: PublicKey
token_account: PublicKey
token_authority: PublicKey
def token_deposit_into_existing(
args: TokenDepositIntoExistingArgs,
accounts: TokenDepositIntoExistingAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(
pubkey=accounts["token_account"], is_signer=False, is_writable=True
),
AccountMeta(
pubkey=accounts["token_authority"], is_signer=True, is_writable=False
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\r%\xdcD\x17\x15*\x89"
encoded_args = layout.build(
{
"amount": args["amount"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,37 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class TokenDeregisterAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
mint_info: PublicKey
dust_vault: PublicKey
sol_destination: PublicKey
def token_deregister(
accounts: TokenDeregisterAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["mint_info"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["dust_vault"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["sol_destination"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"Rf&C\x87\xc7\x84."
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,132 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from anchorpy.borsh_extension import BorshPubkey
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class TokenEditArgs(typing.TypedDict):
oracle_opt: typing.Optional[PublicKey]
oracle_config_opt: typing.Optional[types.oracle_config_params.OracleConfigParams]
group_insurance_fund_opt: typing.Optional[bool]
interest_rate_params_opt: typing.Optional[
types.interest_rate_params.InterestRateParams
]
loan_fee_rate_opt: typing.Optional[float]
loan_origination_fee_rate_opt: typing.Optional[float]
maint_asset_weight_opt: typing.Optional[float]
init_asset_weight_opt: typing.Optional[float]
maint_liab_weight_opt: typing.Optional[float]
init_liab_weight_opt: typing.Optional[float]
liquidation_fee_opt: typing.Optional[float]
stable_price_delay_interval_seconds_opt: typing.Optional[int]
stable_price_delay_growth_limit_opt: typing.Optional[float]
stable_price_growth_limit_opt: typing.Optional[float]
min_vault_to_deposits_ratio_opt: typing.Optional[float]
net_borrow_limit_per_window_quote_opt: typing.Optional[int]
net_borrow_limit_window_size_ts_opt: typing.Optional[int]
borrow_weight_scale_start_quote_opt: typing.Optional[float]
deposit_weight_scale_start_quote_opt: typing.Optional[float]
reset_stable_price: bool
reset_net_borrow_limit: bool
layout = borsh.CStruct(
"oracle_opt" / borsh.Option(BorshPubkey),
"oracle_config_opt"
/ borsh.Option(types.oracle_config_params.OracleConfigParams.layout),
"group_insurance_fund_opt" / borsh.Option(borsh.Bool),
"interest_rate_params_opt"
/ borsh.Option(types.interest_rate_params.InterestRateParams.layout),
"loan_fee_rate_opt" / borsh.Option(borsh.F32),
"loan_origination_fee_rate_opt" / borsh.Option(borsh.F32),
"maint_asset_weight_opt" / borsh.Option(borsh.F32),
"init_asset_weight_opt" / borsh.Option(borsh.F32),
"maint_liab_weight_opt" / borsh.Option(borsh.F32),
"init_liab_weight_opt" / borsh.Option(borsh.F32),
"liquidation_fee_opt" / borsh.Option(borsh.F32),
"stable_price_delay_interval_seconds_opt" / borsh.Option(borsh.U32),
"stable_price_delay_growth_limit_opt" / borsh.Option(borsh.F32),
"stable_price_growth_limit_opt" / borsh.Option(borsh.F32),
"min_vault_to_deposits_ratio_opt" / borsh.Option(borsh.F64),
"net_borrow_limit_per_window_quote_opt" / borsh.Option(borsh.I64),
"net_borrow_limit_window_size_ts_opt" / borsh.Option(borsh.U64),
"borrow_weight_scale_start_quote_opt" / borsh.Option(borsh.F64),
"deposit_weight_scale_start_quote_opt" / borsh.Option(borsh.F64),
"reset_stable_price" / borsh.Bool,
"reset_net_borrow_limit" / borsh.Bool,
)
class TokenEditAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
mint_info: PublicKey
oracle: PublicKey
def token_edit(
args: TokenEditArgs,
accounts: TokenEditAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["mint_info"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x91\xcc\x0b\xd1\xae\x86O>"
encoded_args = layout.build(
{
"oracle_opt": args["oracle_opt"],
"oracle_config_opt": (
None
if args["oracle_config_opt"] is None
else args["oracle_config_opt"].to_encodable()
),
"group_insurance_fund_opt": args["group_insurance_fund_opt"],
"interest_rate_params_opt": (
None
if args["interest_rate_params_opt"] is None
else args["interest_rate_params_opt"].to_encodable()
),
"loan_fee_rate_opt": args["loan_fee_rate_opt"],
"loan_origination_fee_rate_opt": args["loan_origination_fee_rate_opt"],
"maint_asset_weight_opt": args["maint_asset_weight_opt"],
"init_asset_weight_opt": args["init_asset_weight_opt"],
"maint_liab_weight_opt": args["maint_liab_weight_opt"],
"init_liab_weight_opt": args["init_liab_weight_opt"],
"liquidation_fee_opt": args["liquidation_fee_opt"],
"stable_price_delay_interval_seconds_opt": args[
"stable_price_delay_interval_seconds_opt"
],
"stable_price_delay_growth_limit_opt": args[
"stable_price_delay_growth_limit_opt"
],
"stable_price_growth_limit_opt": args["stable_price_growth_limit_opt"],
"min_vault_to_deposits_ratio_opt": args["min_vault_to_deposits_ratio_opt"],
"net_borrow_limit_per_window_quote_opt": args[
"net_borrow_limit_per_window_quote_opt"
],
"net_borrow_limit_window_size_ts_opt": args[
"net_borrow_limit_window_size_ts_opt"
],
"borrow_weight_scale_start_quote_opt": args[
"borrow_weight_scale_start_quote_opt"
],
"deposit_weight_scale_start_quote_opt": args[
"deposit_weight_scale_start_quote_opt"
],
"reset_stable_price": args["reset_stable_price"],
"reset_net_borrow_limit": args["reset_net_borrow_limit"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,57 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class TokenLiqBankruptcyArgs(typing.TypedDict):
max_liab_transfer: types.i80f48.I80F48
layout = borsh.CStruct("max_liab_transfer" / types.i80f48.I80F48.layout)
class TokenLiqBankruptcyAccounts(typing.TypedDict):
group: PublicKey
liqor: PublicKey
liqor_owner: PublicKey
liqee: PublicKey
liab_mint_info: PublicKey
quote_vault: PublicKey
insurance_vault: PublicKey
def token_liq_bankruptcy(
args: TokenLiqBankruptcyArgs,
accounts: TokenLiqBankruptcyAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["liqor"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["liqor_owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["liqee"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["liab_mint_info"], is_signer=False, is_writable=False
),
AccountMeta(pubkey=accounts["quote_vault"], is_signer=False, is_writable=True),
AccountMeta(
pubkey=accounts["insurance_vault"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"zn\xcb\x0f\x08u\xa4F"
encoded_args = layout.build(
{
"max_liab_transfer": args["max_liab_transfer"].to_encodable(),
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,53 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class TokenLiqWithTokenArgs(typing.TypedDict):
asset_token_index: int
liab_token_index: int
max_liab_transfer: types.i80f48.I80F48
layout = borsh.CStruct(
"asset_token_index" / borsh.U16,
"liab_token_index" / borsh.U16,
"max_liab_transfer" / types.i80f48.I80F48.layout,
)
class TokenLiqWithTokenAccounts(typing.TypedDict):
group: PublicKey
liqor: PublicKey
liqor_owner: PublicKey
liqee: PublicKey
def token_liq_with_token(
args: TokenLiqWithTokenArgs,
accounts: TokenLiqWithTokenAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["liqor"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["liqor_owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["liqee"], is_signer=False, is_writable=True),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x064S\x14\xd8\x7f@f"
encoded_args = layout.build(
{
"asset_token_index": args["asset_token_index"],
"liab_token_index": args["liab_token_index"],
"max_liab_transfer": args["max_liab_transfer"].to_encodable(),
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,102 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.sysvar import SYSVAR_RENT_PUBKEY
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from .. import types
from ..program_id import MANGO_PROGRAM_ID
class TokenRegisterArgs(typing.TypedDict):
token_index: int
name: str
oracle_config: types.oracle_config_params.OracleConfigParams
interest_rate_params: types.interest_rate_params.InterestRateParams
loan_fee_rate: float
loan_origination_fee_rate: float
maint_asset_weight: float
init_asset_weight: float
maint_liab_weight: float
init_liab_weight: float
liquidation_fee: float
min_vault_to_deposits_ratio: float
net_borrow_limit_window_size_ts: int
net_borrow_limit_per_window_quote: int
layout = borsh.CStruct(
"token_index" / borsh.U16,
"name" / borsh.String,
"oracle_config" / types.oracle_config_params.OracleConfigParams.layout,
"interest_rate_params" / types.interest_rate_params.InterestRateParams.layout,
"loan_fee_rate" / borsh.F32,
"loan_origination_fee_rate" / borsh.F32,
"maint_asset_weight" / borsh.F32,
"init_asset_weight" / borsh.F32,
"maint_liab_weight" / borsh.F32,
"init_liab_weight" / borsh.F32,
"liquidation_fee" / borsh.F32,
"min_vault_to_deposits_ratio" / borsh.F64,
"net_borrow_limit_window_size_ts" / borsh.U64,
"net_borrow_limit_per_window_quote" / borsh.I64,
)
class TokenRegisterAccounts(typing.TypedDict):
group: PublicKey
admin: PublicKey
mint: PublicKey
bank: PublicKey
vault: PublicKey
mint_info: PublicKey
oracle: PublicKey
payer: PublicKey
def token_register(
args: TokenRegisterArgs,
accounts: TokenRegisterAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["admin"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["mint_info"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"m\x1c\x87:\xa2\xd6q&"
encoded_args = layout.build(
{
"token_index": args["token_index"],
"name": args["name"],
"oracle_config": args["oracle_config"].to_encodable(),
"interest_rate_params": args["interest_rate_params"].to_encodable(),
"loan_fee_rate": args["loan_fee_rate"],
"loan_origination_fee_rate": args["loan_origination_fee_rate"],
"maint_asset_weight": args["maint_asset_weight"],
"init_asset_weight": args["init_asset_weight"],
"maint_liab_weight": args["maint_liab_weight"],
"init_liab_weight": args["init_liab_weight"],
"liquidation_fee": args["liquidation_fee"],
"min_vault_to_deposits_ratio": args["min_vault_to_deposits_ratio"],
"net_borrow_limit_window_size_ts": args["net_borrow_limit_window_size_ts"],
"net_borrow_limit_per_window_quote": args[
"net_borrow_limit_per_window_quote"
],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,62 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.system_program import SYS_PROGRAM_ID
from solana.sysvar import SYSVAR_RENT_PUBKEY
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class TokenRegisterTrustlessArgs(typing.TypedDict):
token_index: int
name: str
layout = borsh.CStruct("token_index" / borsh.U16, "name" / borsh.String)
class TokenRegisterTrustlessAccounts(typing.TypedDict):
group: PublicKey
fast_listing_admin: PublicKey
mint: PublicKey
bank: PublicKey
vault: PublicKey
mint_info: PublicKey
oracle: PublicKey
payer: PublicKey
def token_register_trustless(
args: TokenRegisterTrustlessArgs,
accounts: TokenRegisterTrustlessAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(
pubkey=accounts["fast_listing_admin"], is_signer=True, is_writable=False
),
AccountMeta(pubkey=accounts["mint"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["mint_info"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["payer"], is_signer=True, is_writable=True),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False),
AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"8-#\r\xfd\xfe:P"
encoded_args = layout.build(
{
"token_index": args["token_index"],
"name": args["name"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,33 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from solana.transaction import TransactionInstruction, AccountMeta
from ..program_id import MANGO_PROGRAM_ID
class TokenUpdateIndexAndRateAccounts(typing.TypedDict):
group: PublicKey
mint_info: PublicKey
oracle: PublicKey
instructions: PublicKey
def token_update_index_and_rate(
accounts: TokenUpdateIndexAndRateAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["mint_info"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(
pubkey=accounts["instructions"], is_signer=False, is_writable=False
),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"\x83\x88\xc2'\x0b2\n\xc6"
encoded_args = b""
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,56 @@
from __future__ import annotations
import typing
from solana.publickey import PublicKey
from spl.token.constants import TOKEN_PROGRAM_ID
from solana.transaction import TransactionInstruction, AccountMeta
import borsh_construct as borsh
from ..program_id import MANGO_PROGRAM_ID
class TokenWithdrawArgs(typing.TypedDict):
amount: int
allow_borrow: bool
layout = borsh.CStruct("amount" / borsh.U64, "allow_borrow" / borsh.Bool)
class TokenWithdrawAccounts(typing.TypedDict):
group: PublicKey
account: PublicKey
owner: PublicKey
bank: PublicKey
vault: PublicKey
oracle: PublicKey
token_account: PublicKey
def token_withdraw(
args: TokenWithdrawArgs,
accounts: TokenWithdrawAccounts,
program_id: PublicKey = MANGO_PROGRAM_ID,
remaining_accounts: typing.Optional[typing.List[AccountMeta]] = None,
) -> TransactionInstruction:
keys: list[AccountMeta] = [
AccountMeta(pubkey=accounts["group"], is_signer=False, is_writable=False),
AccountMeta(pubkey=accounts["account"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["owner"], is_signer=True, is_writable=False),
AccountMeta(pubkey=accounts["bank"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["vault"], is_signer=False, is_writable=True),
AccountMeta(pubkey=accounts["oracle"], is_signer=False, is_writable=False),
AccountMeta(
pubkey=accounts["token_account"], is_signer=False, is_writable=True
),
AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False),
]
if remaining_accounts is not None:
keys += remaining_accounts
identifier = b"?\xdf*;\x0f\x80fB"
encoded_args = layout.build(
{
"amount": args["amount"],
"allow_borrow": args["allow_borrow"],
}
)
data = identifier + encoded_args
return TransactionInstruction(keys, program_id, data)

View File

@ -0,0 +1,913 @@
import asyncio
import sys
import json
import logging
import pathlib
import re
import time
from dataclasses import dataclass
from decimal import Decimal
from typing import Literal, Any
from .constants import RUST_I64_MIN, RUST_U64_MAX, RUST_I64_MAX, QUOTE_DECIMALS
import base58
from anchorpy import Provider, Wallet
from pyserum.market import AsyncMarket, OrderBook
from solana.keypair import Keypair
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Processed
from solana.rpc.websocket_api import connect
from solana.transaction import AccountMeta, Transaction
from solders.rpc.responses import AccountNotification
from mango_explorer_v4.types.side import Bid, Ask
from mango_explorer_v4.accounts.bank import Bank
from mango_explorer_v4.accounts.book_side import BookSide
from mango_explorer_v4.accounts.mango_account import MangoAccount
from mango_explorer_v4.accounts.mint_info import MintInfo
from mango_explorer_v4.accounts.serum3_market import Serum3Market
from mango_explorer_v4.accounts.perp_market import PerpMarket
from mango_explorer_v4.types.inner_node import InnerNode
from mango_explorer_v4.types.leaf_node import LeafNode
from mango_explorer_v4.types.perp_open_order import PerpOpenOrder
from mango_explorer_v4.instructions.serum3_cancel_all_orders import Serum3CancelAllOrdersAccounts, Serum3CancelAllOrdersArgs, serum3_cancel_all_orders
from mango_explorer_v4.instructions.serum3_create_open_orders import Serum3CreateOpenOrdersAccounts, serum3_create_open_orders
from mango_explorer_v4.instructions.serum3_place_order import Serum3PlaceOrderArgs, Serum3PlaceOrderAccounts, serum3_place_order
from mango_explorer_v4.instructions.perp_place_order import PerpPlaceOrderArgs, PerpPlaceOrderAccounts, perp_place_order
from mango_explorer_v4.instructions.perp_cancel_all_orders import PerpCancelAllOrdersArgs, PerpCancelAllOrdersAccounts, perp_cancel_all_orders
from mango_explorer_v4.program_id import SERUM_PROGRAM_ID, MANGO_PROGRAM_ID
from mango_explorer_v4.types import serum3_side, serum3_self_trade_behavior, serum3_order_type
from mango_explorer_v4.types import place_order_type
logging.basicConfig(
level=logging.INFO
)
@dataclass
class MangoClient():
provider: Provider
mango_account_pk: str
group_config: dict
mango_account: MangoAccount
serum_market_configs: [dict]
perp_market_configs: [dict]
serum_markets: [Serum3Market]
serum_markets_external: [AsyncMarket]
banks: [Bank]
mint_infos: [MintInfo]
perp_markets: [PerpMarket]
rpc_url: str
@staticmethod
async def connect(
secret_key: str | bytes,
# ^ Can be the output from Phantom's "Export Private Key" - this for easy onboarding
# as with the V3 lib folks used to get confused about how to turn it into something
# like the output from `solana-keygen new -o scratch.json`, which is also supported
mango_account_pk: str,
# ^ A SOL wallet can have multiple Mango accounts - let the user pick the one he's
# looking to use. Specifying it beforehand spares a lot of redundancy
rpc_url: str = 'https://mango.rpcpool.com/0f9acc0d45173b51bf7d7e09c1e5'
# ^ Can use the default RPC endpoint or whichever so desired
):
# TODO: There's a bunch of asynchronous calls here, which could reasonably be parallelized
# to shorten the lib's init time, which is now sitting at around 2 seconds - annoying
provider = Provider(
AsyncClient(rpc_url, Processed),
Wallet(
Keypair.from_secret_key(
base58.b58decode(secret_key)
if type(secret_key == str) else
Wallet(Keypair.from_secret_key(secret_key))
)
)
if secret_key is not None else Wallet.dummy()
)
mango_account = await MangoAccount.fetch(
provider.connection,
PublicKey(mango_account_pk)
)
if mango_account.owner != provider.wallet.public_key:
raise ValueError('Mango account is not owned by the secret key entered')
ids = json.loads(open(pathlib.Path(__file__).parent / 'ids.json').read())
# TODO: ^ Make this fetch from https://mango-transaction-log.herokuapp.com/v4/group-metadata instead
group_config = [group_config for group_config in ids['groups'] if PublicKey(group_config['publicKey']) == mango_account.group][0]
perp_market_configs = [
perp_market_config for perp_market_config in group_config['perpMarkets'] if perp_market_config['active']
]
serum_market_configs = [
serum_market_config for serum_market_config in group_config['serum3Markets'] if serum_market_config['active']
]
serum_markets = await Serum3Market.fetch_multiple(
provider.connection,
[
PublicKey(serum3_market_config['publicKey']) for serum3_market_config in serum_market_configs
]
)
serum_markets_external = await asyncio.gather(*[
AsyncMarket.load(provider.connection, serum_market.serum_market_external, SERUM_PROGRAM_ID)
for serum_market in serum_markets
])
banks_config = [
{
'tokenIndex': token_config['tokenIndex'],
'publicKey': PublicKey(token_config['banks'][0]['publicKey'])
}
for token_config in group_config['tokens']
if token_config['active']
]
banks = await Bank.fetch_multiple(
provider.connection,
[bank_config['publicKey'] for bank_config in banks_config]
)
mint_infos_configs = [
{
'tokenIndex': token_config['tokenIndex'],
'publicKey': PublicKey(token_config['mintInfo'])
}
for token_config in group_config['tokens']
if token_config['active']
if token_config['tokenIndex'] in [token.token_index for token in mango_account.tokens if token.token_index != 65535]
]
mint_infos_configs = list(sorted(mint_infos_configs, key=lambda mint_info_config: mint_info_config['tokenIndex']))
mint_infos = await MintInfo.fetch_multiple(
provider.connection,
[mint_info_config['publicKey'] for mint_info_config in mint_infos_configs]
)
perp_markets = await PerpMarket.fetch_multiple(
provider.connection,
[perp_market_config['publicKey'] for perp_market_config in perp_market_configs]
)
return MangoClient(
provider,
mango_account_pk,
mango_account=mango_account,
group_config=group_config,
serum_market_configs=serum_market_configs,
perp_market_configs=perp_market_configs,
serum_markets=serum_markets,
serum_markets_external=serum_markets_external,
banks=banks,
mint_infos=mint_infos,
perp_markets=perp_markets,
rpc_url=rpc_url
)
def symbols(self):
# Can't make it a static / class function yet because need to know
# which group to use, and group is inferred from the Mango account
# This might not be the best format for keeping symbols organized,
# as it presumes that perpetual and spot market names would never
# conflict, but it works for now
# TODO: Add minimum order size, tick size, lot size and liquidation fee
return [
*[
{
'name': perp_market_config['name'],
'type': 'perpetual',
'base_currency': perp_market_config['name'].split('-')[0],
'quote_currency': perp_market_config['name'].split('-')[1],
'maker_fees': - (1 / 1e4),
'taker_fees': (4 / 1e4)
}
for perp_market_config in self.perp_market_configs
],
*[
{
'name': serum3_market_config['name'],
'type': 'spot',
'base_currency': serum3_market_config['name'].split('/')[0],
'quote_currency': serum3_market_config['name'].split('/')[1],
'maker_fees': - (0.5 / 1e4),
'taker_fees': (1 / 1e4)
}
for serum3_market_config in self.serum_market_configs
]
]
async def orderbook_l2(self, symbol: str, depth: int = 100):
# TODO: Validate that the symbol entered is valid
market_type = {'PERP': 'perpetual', 'USDC': 'spot'}[re.split(r"[-|/]", symbol)[1]]
match market_type:
case 'spot':
serum_market_config = [serum3_market_config for serum3_market_config in self.group_config['serum3Markets'] if serum3_market_config['name'] == symbol][0]
serum_market_index = serum_market_config['marketIndex']
serum_market = [
serum_market
for serum_market in self.serum_markets
if serum_market.market_index == serum_market_index
][0]
serum_market_external = [
serum_market_external
for serum_market_external in self.serum_markets_external
if serum_market_external.state.public_key() == serum_market.serum_market_external
][0]
response = await self.provider.connection.get_multiple_accounts([
serum_market_external.state.bids(),
serum_market_external.state.asks()
])
[raw_bids, raw_asks] = response.value
[bids, asks] = [
OrderBook.from_bytes(serum_market_external.state, raw_bids.data),
OrderBook.from_bytes(serum_market_external.state, raw_asks.data)
]
orderbook = {
'symbol': symbol,
'bids': [[bid.price, bid.size] for bid in bids.get_l2(depth)],
'asks': [[ask.price, ask.size] for ask in asks.get_l2(depth)]
}
return orderbook
case 'perpetual':
@dataclass
class PerpOrder:
seq_num: int
order_id: int
owner: PublicKey
open_orders_slot: int
fee_tier: 0
ui_price: float
price: int
ui_size: float
size: int
side: Literal['bids', 'asks']
timestamp: int
expiry_timestamp: int
perp_market_index: int
is_expired: bool
is_oracle_pegged: bool
oracle_pegged_properties: Any
@staticmethod
def build(
perp_market: PerpMarket,
leaf_node: LeafNode,
side: Literal['bids', 'asks'],
is_oracle_pegged: bool = False
):
if is_oracle_pegged:
price_lots = leaf_node.key >> 64
else:
price_lots = leaf_node.key >> 64
now = int(time.time())
expiry_timestamp = leaf_node.timestamp + leaf_node.time_in_force if leaf_node.time_in_force else sys.maxsize
is_expired = now > expiry_timestamp
return PerpOrder(
{
'bids': RUST_U64_MAX - (leaf_node.key & ((1 << 64) - 1)),
'asks': leaf_node.key & ((1 << 64) - 1)
}[side],
leaf_node.key,
leaf_node.owner,
leaf_node.owner_slot,
0,
float(Decimal(price_lots) * Decimal(perp_market.price_lots_to_ui_converter)),
price_lots,
float(Decimal(leaf_node.quantity) * Decimal(perp_market.base_lots_to_ui_converter)),
leaf_node.quantity,
side,
leaf_node.timestamp,
expiry_timestamp,
perp_market.perp_market_index,
is_expired,
is_oracle_pegged,
None
)
perp_market_config = [perp_market_config for perp_market_config in self.group_config['perpMarkets'] if perp_market_config['name'] == symbol][0]
perp_market = [perp_market for perp_market in self.perp_markets if perp_market.perp_market_index == perp_market_config['marketIndex']][0]
[bids, asks] = await BookSide.fetch_multiple(self.provider.connection, [perp_market.bids, perp_market.asks])
# TODO: Abstract away the pretty much the same body in fixed_items() and oracle_pegged_items()
def items(book_side: BookSide, side: Literal['bids', 'asks']):
def fixed_items():
if book_side.roots[0].leaf_count == 0:
return
stack = [book_side.roots[0].maybe_node]
[left, right] = [1, 0] if side == 'bids' else [0, 1]
while len(stack) > 0:
index = stack.pop()
node = book_side.nodes.nodes[index]
match node.tag:
case 1:
inner_node = InnerNode.layout.parse(bytes([1] + node.data))
stack.extend([inner_node.children[right], inner_node.children[left]])
case 2:
leaf_node: LeafNode = LeafNode.layout.parse(bytes([2] + node.data))
yield PerpOrder.build(
perp_market,
leaf_node,
side
)
def oracle_pegged_items():
if book_side.roots[1].leaf_count == 0:
return
stack = [book_side.roots[1].maybe_node]
[left, right] = [1, 0] if side == 'bids' else [0, 1]
while len(stack) > 0:
index = stack.pop()
node = book_side.nodes.nodes[index]
match node.tag:
case 1:
inner_node = InnerNode.layout.parse(bytes([1] + node.data))
stack.extend([inner_node.children[right], inner_node.children[left]])
case 2:
leaf_node: LeafNode = LeafNode.layout.parse(bytes([2] + node.data))
yield PerpOrder.build(
perp_market,
leaf_node,
side,
True
)
return [
list(fixed_items()),
list(oracle_pegged_items())
]
return items(bids, 'bids')
async def snapshots_l2(self, symbol: str, depth: int = 50):
serum_market_config = [serum3_market_config for serum3_market_config in self.group_config['serum3Markets'] if serum3_market_config['name'] == symbol][0]
serum_market_index = serum_market_config['marketIndex']
serum_market = [
serum_market
for serum_market in self.serum_markets
if serum_market.market_index == serum_market_index
][0]
serum_market_external = [
serum_market_external
for serum_market_external in self.serum_markets_external
if serum_market_external.state.public_key() == serum_market.serum_market_external
][0]
orderbook = {
'symbol': symbol,
'bids': None,
'asks': None
}
yield await self.orderbook_l2(symbol, depth)
# async with connect(self.rpc_url.replace('https://', 'wss://')) as websocket:
async with connect('wss://mango.rpcpool.com/0f9acc0d45173b51bf7d7e09c1e5') as websocket:
remap = {}
await websocket.account_subscribe(serum_market_external.state.bids(), Processed, 'jsonParsed')
remap[(await websocket.recv())[0].result] = 'bids'
await websocket.account_subscribe(serum_market_external.state.asks(), Processed, 'jsonParsed')
remap[(await websocket.recv())[0].result] = 'asks'
async for message in websocket:
for submessage in message:
if not isinstance(submessage, AccountNotification):
continue
side = OrderBook.from_bytes(serum_market_external.state, submessage.result.value.data)
orderbook[remap[submessage.subscription]] = [[order.price, order.size] for order in side.get_l2(depth)]
if not all([orderbook['bids'], orderbook['asks']]):
continue
yield orderbook
def _health_remaining_accounts(
self,
retriever: Literal['fixed', 'scanning'],
banks: [Bank],
perp_markets: [PerpMarket]
) -> [AccountMeta]:
health_remaining_account_pks = []
match retriever:
case 'fixed':
token_indices = [token.token_index for token in self.mango_account.tokens]
if len(banks) > 0:
for bank in banks:
if bank.token_index not in token_indices:
index = [
idx for idx, token in enumerate(self.mango_account.tokens)
if token.token_index == 65535
if token_indices[idx] == 65535
][0]
token_indices[index] = bank.token_index
mint_infos = [
mint_info for mint_info in self.mint_infos
if mint_info.token_index in [token_index for token_index in token_indices if token_index != 65535]
]
health_remaining_account_pks.extend([mint_info.banks[0] for mint_info in mint_infos])
health_remaining_account_pks.extend([mint_info.oracle for mint_info in mint_infos])
perp_market_indices = [perp.market_index for perp in self.mango_account.perps]
if len(perp_markets) > 0:
for perp_market in perp_markets:
if perp_market.perp_market_index not in perp_market_indices:
index = [
idx for idx, perp in enumerate(self.mango_account.perps)
if perp.market_index == 65535
if perp_market_indices[idx] == 65535
][0] = perp_market.perp_market_index
perp_market_indices[index] = perp_market.perp_market_index
perp_markets = [
perp_market for perp_market in self.perp_markets
if perp_market.perp_market_index in [perp_index for perp_index in perp_market_indices if perp_index != 65535]
]
perp_market_pks = [
PublicKey(perp_market_config['publicKey']) for perp_market_config in self.group_config['perpMarkets']
if perp_market_config['marketIndex'] in [perp_market.perp_market_index for perp_market in perp_markets]
]
health_remaining_account_pks.extend(perp_market_pks)
health_remaining_account_pks.extend([perp_market.oracle for perp_market in perp_markets])
health_remaining_account_pks.extend([serum3.open_orders for serum3 in self.mango_account.serum3 if serum3.market_index != 65535])
case 'scanning':
raise NotImplementedError()
remaining_accounts: [AccountMeta] = [
AccountMeta(pubkey=remaining_account_pk, is_writable=False, is_signer=False)
for remaining_account_pk in health_remaining_account_pks
]
return remaining_accounts
def make_serum3_place_order_ix(self, symbol: str, side: Literal['bids', 'asks'], price: float, size: float):
serum_market_config = [serum3_market_config for serum3_market_config in self.group_config['serum3Markets'] if serum3_market_config['name'] == symbol][0]
serum_market_index = serum_market_config['marketIndex']
serum_market = [
serum_market
for serum_market in self.serum_markets
if serum_market.market_index == serum_market_index
][0]
serum_market_external = [
serum_market_external
for serum_market_external in self.serum_markets_external
if serum_market_external.state.public_key() == serum_market.serum_market_external
][0]
limit_price = serum_market_external.state.price_number_to_lots(price)
max_base_qty = serum_market_external.state.base_size_number_to_lots(size)
order_type = {'limit': serum3_order_type.Limit(), 'immediate_or_cancel': serum3_order_type.ImmediateOrCancel()}['limit']
max_native_quote_qty_without_fees = limit_price * max_base_qty
is_maker = order_type == serum3_order_type.PostOnly()
fees = {True: - (0.5 / 1e4), False: (1 / 1e4)}[is_maker]
max_native_quote_qty_including_fees = max_native_quote_qty_without_fees + round(max_native_quote_qty_without_fees * fees)
client_order_id = round(time.time_ns() / 1e6)
serum3_place_order_args: Serum3PlaceOrderArgs = {
'side': {'bids': serum3_side.Bid(), 'asks': serum3_side.Ask()}[side],
'limit_price': limit_price,
'max_base_qty': max_base_qty,
'max_native_quote_qty_including_fees': max_native_quote_qty_including_fees,
'self_trade_behavior': serum3_self_trade_behavior.DecrementTake(),
'order_type': order_type,
'client_order_id': client_order_id,
'limit': 10
}
serum3 = [serum3 for serum3 in self.mango_account.serum3 if serum3.market_index == serum_market_index][0]
if serum3 is None:
raise Exception('serum3 account not found')
payer_token_index = {
'bids': serum_market.quote_token_index,
'asks': serum_market.base_token_index
}[side]
bank = [bank for bank in self.banks if bank.token_index == payer_token_index][0]
banks_config = [
{
'tokenIndex': token_config['tokenIndex'],
'publicKey': PublicKey(token_config['banks'][0]['publicKey'])
}
for token_config in self.group_config['tokens']
if token_config['active']
]
bank_config = [bank_config for bank_config in banks_config if bank_config['tokenIndex'] == bank.token_index][0]
serum_market_external_vault_signer_address = PublicKey.create_program_address([
bytes(serum_market.serum_market_external),
serum_market_external.state.vault_signer_nonce().to_bytes(8, 'little')
], SERUM_PROGRAM_ID)
serum3_place_order_accounts: Serum3PlaceOrderAccounts = {
'group': self.mango_account.group,
'account': PublicKey(self.mango_account_pk),
'owner': self.mango_account.owner,
'open_orders': serum3.open_orders,
'serum_market': PublicKey(serum_market_config['publicKey']),
'serum_program': SERUM_PROGRAM_ID,
'serum_market_external': serum_market.serum_market_external,
'market_bids': serum_market_external.state.bids(),
'market_asks': serum_market_external.state.asks(),
'market_event_queue': serum_market_external.state.event_queue(),
'market_request_queue': serum_market_external.state.request_queue(),
'market_base_vault': serum_market_external.state.base_vault(),
'market_quote_vault': serum_market_external.state.quote_vault(),
'market_vault_signer': serum_market_external_vault_signer_address,
'payer_bank': bank_config['publicKey'],
'payer_vault': bank.vault,
'payer_oracle': bank.oracle
}
remaining_accounts = self._health_remaining_accounts('fixed', [], [])
serum3_place_order_ix = serum3_place_order(
serum3_place_order_args,
serum3_place_order_accounts,
remaining_accounts=remaining_accounts
)
return serum3_place_order_ix
def make_serum3_create_open_orders_ix(self, symbol):
serum_market_config = [serum3_market_config for serum3_market_config in self.group_config['serum3Markets'] if serum3_market_config['name'] == symbol][0]
serum_market_index = serum_market_config['marketIndex']
serum_market = [
serum_market
for serum_market in self.serum_markets
if serum_market.market_index == serum_market_index
][0]
[open_orders_pk, nonce] = PublicKey.find_program_address(
[
bytes('Serum3OO', 'utf-8'),
bytes(PublicKey(self.mango_account_pk)),
bytes(PublicKey(serum_market_config['publicKey']))
],
MANGO_PROGRAM_ID
)
serum3_create_open_orders_accounts: Serum3CreateOpenOrdersAccounts = {
'group': self.mango_account.group,
'account': PublicKey(self.mango_account_pk),
'owner': self.provider.wallet.public_key,
'serum_market': PublicKey(serum_market_config['publicKey']),
'serum_program': serum_market.serum_program,
'serum_market_external': serum_market.serum_market_external,
'open_orders': open_orders_pk,
'payer': self.provider.wallet.public_key,
}
serum3_create_open_orders_ix = serum3_create_open_orders(serum3_create_open_orders_accounts)
return serum3_create_open_orders_ix
def make_perp_place_order_ix(self, symbol, side, price, size):
perp_market_config = [perp_market_config for perp_market_config in self.group_config['perpMarkets'] if perp_market_config['name'] == symbol][0]
perp_market = [perp_market for perp_market in self.perp_markets if perp_market.perp_market_index == perp_market_config['marketIndex']][0]
quote_decimals = 6
def to_native(ui_amount: float, decimals: float) -> int:
return int(ui_amount * 10 ** decimals)
def ui_price_to_lots(perp_market: PerpMarket, price: float) -> int:
return int(to_native(price, quote_decimals) * perp_market.base_lot_size / (perp_market.quote_lot_size * 10 ** perp_market.base_decimals))
def ui_base_to_lots(perp_market: PerpMarket, size: float) -> int:
return int(to_native(size, perp_market.base_decimals) // perp_market.base_lot_size)
perp_place_order_args: PerpPlaceOrderArgs = {
'side': {'bids': Bid, 'asks': Ask}[side],
'price_lots': ui_price_to_lots(perp_market, price),
'max_base_lots': ui_base_to_lots(perp_market, size),
'max_quote_lots': sys.maxsize,
'client_order_id': int(time.time() * 1e3),
'order_type': place_order_type.Limit(),
'reduce_only': False,
'expiry_timestamp': 0,
'limit': 10
}
perp_place_order_accounts: PerpPlaceOrderAccounts = {
'group': perp_market.group,
'account': PublicKey(self.mango_account_pk),
'owner': self.provider.wallet.public_key,
'perp_market': PublicKey(perp_market_config['publicKey']),
'bids': perp_market.bids,
'asks': perp_market.asks,
'event_queue': perp_market.event_queue,
'oracle': perp_market.oracle
}
remaining_accounts = self._health_remaining_accounts('fixed', [[bank for bank in self.banks if bank.token_index == 0][0]], [perp_market])
perp_place_order_ix = perp_place_order(
perp_place_order_args,
perp_place_order_accounts,
remaining_accounts=remaining_accounts
)
return perp_place_order_ix
async def place_order(
self,
symbol: str,
side: Literal['bids', 'asks'],
price: float,
size: float
):
market_type = {'PERP': 'perpetual', 'USDC': 'spot'}[re.split(r"[-|/]", symbol)[1]]
match market_type:
case 'spot':
serum_market_config = [serum3_market_config for serum3_market_config in self.group_config['serum3Markets'] if serum3_market_config['name'] == symbol][0]
serum_market_index = serum_market_config['marketIndex']
try:
serum3 = [serum3 for serum3 in self.mango_account.serum3 if serum3.market_index == serum_market_index][0]
except IndexError:
logging.error(f"Open orders account for {symbol} not found, creating one...")
serum3_create_open_orders_ix = self.make_serum3_create_open_orders_ix('SOL/USDC')
recent_blockhash = (await self.provider.connection.get_latest_blockhash()).value.blockhash
tx = Transaction()
tx.recent_blockhash = str(recent_blockhash)
tx.add(serum3_create_open_orders_ix)
tx.sign(self.provider.wallet.payer)
response = await self.provider.send(tx)
logging.error(f"Waiting for Open Orders account creation confirmation...")
await self.provider.connection.confirm_transaction(response)
logging.error(f"Open orders account created for {symbol}.")
self.mango_account = await MangoAccount.fetch(
self.provider.connection,
PublicKey(self.mango_account_pk)
)
serum3_place_order_ix = self.make_serum3_place_order_ix(
symbol,
side,
price,
size
)
tx = Transaction()
recent_blockhash = (await self.provider.connection.get_latest_blockhash()).value.blockhash
tx.recent_blockhash = str(recent_blockhash)
tx.add(serum3_place_order_ix)
tx.sign(self.provider.wallet.payer)
response = await self.provider.send(tx)
return response
case 'perpetual':
tx = Transaction()
recent_blockhash = (await self.provider.connection.get_latest_blockhash()).value.blockhash
tx.recent_blockhash = str(recent_blockhash)
perp_place_order_ix = self.make_perp_place_order_ix(symbol, side, price, size)
tx.add(perp_place_order_ix)
tx.sign(self.provider.wallet.payer)
response = await self.provider.send(tx)
return response
def make_serum3_cancel_all_orders_ix(self, symbol: str):
serum_market_config = [serum3_market_config for serum3_market_config in self.group_config['serum3Markets'] if serum3_market_config['name'] == symbol][0]
serum_market_index = serum_market_config['marketIndex']
serum_market = [
serum_market
for serum_market in self.serum_markets
if serum_market.market_index == serum_market_index
][0]
try:
serum3 = [serum3 for serum3 in self.mango_account.serum3 if serum3.market_index == serum_market_index][0]
except IndexError as error:
print(error)
serum_market_external = [
serum_market_external
for serum_market_external in self.serum_markets_external
if serum_market_external.state.public_key() == serum_market.serum_market_external
][0]
serum3_cancel_all_orders_args: Serum3CancelAllOrdersArgs = {
'limit': 10
}
serum3_cancel_all_orders_accounts: Serum3CancelAllOrdersAccounts = {
'group': self.mango_account.group,
'account': PublicKey(self.mango_account_pk),
'owner': self.provider.wallet.public_key,
'open_orders': serum3.open_orders,
'serum_market': PublicKey(serum_market_config['publicKey']),
'serum_program': serum_market.serum_program,
'serum_market_external': serum_market.serum_market_external,
'market_bids': serum_market_external.state.bids(),
'market_asks': serum_market_external.state.asks(),
'market_event_queue': serum_market_external.state.event_queue()
}
serum3_cancel_all_orders_ix = serum3_cancel_all_orders(
serum3_cancel_all_orders_args,
serum3_cancel_all_orders_accounts
)
return serum3_cancel_all_orders_ix
def make_perp_cancel_all_orders_ix(self, symbol: str):
perp_market_config = [perp_market_config for perp_market_config in self.group_config['perpMarkets'] if perp_market_config['name'] == symbol][0]
perp_market = [perp_market for perp_market in self.perp_markets if perp_market.perp_market_index == perp_market_config['marketIndex']][0]
perp_cancel_all_orders_args: PerpCancelAllOrdersArgs = {
'limit': 10
}
perp_cancel_all_orders_accounts: PerpCancelAllOrdersAccounts = {
'group': perp_market.group,
'account': PublicKey(self.mango_account_pk),
'owner': self.provider.wallet.public_key,
'perp_market': PublicKey(perp_market_config['publicKey']),
'bids': perp_market.bids,
'asks': perp_market.asks
}
perp_cancel_all_orders_ix = perp_cancel_all_orders(perp_cancel_all_orders_args, perp_cancel_all_orders_accounts)
return perp_cancel_all_orders_ix
async def cancel_all_orders(self, symbol: str):
market_type = {'PERP': 'perpetual', 'USDC': 'spot'}[re.split(r"[-|/]", symbol)[1]]
match market_type:
case 'spot':
tx = Transaction()
recent_blockhash = (await self.provider.connection.get_latest_blockhash()).value.blockhash
tx.recent_blockhash = str(recent_blockhash)
serum3_cancel_all_orders_ix = self.make_serum3_cancel_all_orders_ix(symbol)
tx.add(serum3_cancel_all_orders_ix)
tx.sign(self.provider.wallet.payer)
response = await self.provider.send(tx)
return response
case 'perpetual':
tx = Transaction()
recent_blockhash = (await self.provider.connection.get_latest_blockhash()).value.blockhash
tx.recent_blockhash = str(recent_blockhash)
perp_cancel_all_orders_ix = self.make_perp_cancel_all_orders_ix(symbol)
tx.add(perp_cancel_all_orders_ix)
tx.sign(self.provider.wallet.payer)
response = await self.provider.send(tx)
return response
async def balances(self):
# TODO: Clean up this mess
return [
{
'symbol': meta['symbol'],
'balance': float(
meta['token_indexed_position'] * (
meta['bank_deposit_index'] if meta['token_indexed_position'] > 0
else meta['bank_borrow_index']
)
/
meta['bank_mint_decimals']
)
}
for meta in
[
{
'symbol': token_config['symbol'],
'token_indexed_position': Decimal(token.indexed_position.val) / divider,
'bank_mint_decimals': 10 ** bank.mint_decimals,
'bank_deposit_index': Decimal(bank.deposit_index.val) / divider,
'bank_borrow_index': Decimal(bank.borrow_index.val) / divider,
}
for token, bank, token_config, divider in
[
[
token,
[bank for bank in self.banks if bank.token_index == token.token_index][0],
[token_config for token_config in self.group_config['tokens'] if token_config['tokenIndex'] == token.token_index][0],
Decimal(2 ** (8 * 6))
]
for token in self.mango_account.tokens
if token.token_index != 65535
]
]
]

View File

@ -0,0 +1,4 @@
from solana.publickey import PublicKey
MANGO_PROGRAM_ID = PublicKey("4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg")
SERUM_PROGRAM_ID = PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX')

View File

@ -0,0 +1,103 @@
import typing
from . import equity
from .equity import Equity, EquityJSON
from . import token_equity
from .token_equity import TokenEquity, TokenEquityJSON
from . import perp_equity
from .perp_equity import PerpEquity, PerpEquityJSON
from . import prices
from .prices import Prices, PricesJSON
from . import token_info
from .token_info import TokenInfo, TokenInfoJSON
from . import serum3_info
from .serum3_info import Serum3Info, Serum3InfoJSON
from . import perp_info
from .perp_info import PerpInfo, PerpInfoJSON
from . import health_cache
from .health_cache import HealthCache, HealthCacheJSON
from . import interest_rate_params
from .interest_rate_params import InterestRateParams, InterestRateParamsJSON
from . import flash_loan_token_detail
from .flash_loan_token_detail import FlashLoanTokenDetail, FlashLoanTokenDetailJSON
from . import token_position
from .token_position import TokenPosition, TokenPositionJSON
from . import serum3_orders
from .serum3_orders import Serum3Orders, Serum3OrdersJSON
from . import perp_position
from .perp_position import PerpPosition, PerpPositionJSON
from . import perp_open_order
from .perp_open_order import PerpOpenOrder, PerpOpenOrderJSON
from . import mango_account_fixed
from .mango_account_fixed import MangoAccountFixed, MangoAccountFixedJSON
from . import oracle_config
from .oracle_config import OracleConfig, OracleConfigJSON
from . import oracle_config_params
from .oracle_config_params import OracleConfigParams, OracleConfigParamsJSON
from . import inner_node
from .inner_node import InnerNode, InnerNodeJSON
from . import leaf_node
from .leaf_node import LeafNode, LeafNodeJSON
from . import any_node
from .any_node import AnyNode, AnyNodeJSON
from . import order_tree_root
from .order_tree_root import OrderTreeRoot, OrderTreeRootJSON
from . import order_tree_nodes
from .order_tree_nodes import OrderTreeNodes, OrderTreeNodesJSON
from . import event_queue_header
from .event_queue_header import EventQueueHeader, EventQueueHeaderJSON
from . import any_event
from .any_event import AnyEvent, AnyEventJSON
from . import fill_event
from .fill_event import FillEvent, FillEventJSON
from . import out_event
from .out_event import OutEvent, OutEventJSON
from . import stable_price_model
from .stable_price_model import StablePriceModel, StablePriceModelJSON
from . import token_index
from .token_index import TokenIndex, TokenIndexJSON
from . import serum3_market_index
from .serum3_market_index import Serum3MarketIndex, Serum3MarketIndexJSON
from . import perp_market_index
from .perp_market_index import PerpMarketIndex, PerpMarketIndexJSON
from . import i80f48
from .i80f48 import I80F48, I80F48JSON
from . import health_type
from .health_type import HealthTypeKind, HealthTypeJSON
from . import flash_loan_type
from .flash_loan_type import FlashLoanTypeKind, FlashLoanTypeJSON
from . import serum3_self_trade_behavior
from .serum3_self_trade_behavior import (
Serum3SelfTradeBehaviorKind,
Serum3SelfTradeBehaviorJSON,
)
from . import serum3_order_type
from .serum3_order_type import Serum3OrderTypeKind, Serum3OrderTypeJSON
from . import serum3_side
from .serum3_side import Serum3SideKind, Serum3SideJSON
from . import loan_origination_fee_instruction
from .loan_origination_fee_instruction import (
LoanOriginationFeeInstructionKind,
LoanOriginationFeeInstructionJSON,
)
from . import oracle_type
from .oracle_type import OracleTypeKind, OracleTypeJSON
from . import order_state
from .order_state import OrderStateKind, OrderStateJSON
from . import book_side_order_tree
from .book_side_order_tree import BookSideOrderTreeKind, BookSideOrderTreeJSON
from . import node_tag
from .node_tag import NodeTagKind, NodeTagJSON
from . import place_order_type
from .place_order_type import PlaceOrderTypeKind, PlaceOrderTypeJSON
from . import post_order_type
from .post_order_type import PostOrderTypeKind, PostOrderTypeJSON
from . import side
from .side import SideKind, SideJSON
from . import side_and_order_tree
from .side_and_order_tree import SideAndOrderTreeKind, SideAndOrderTreeJSON
from . import order_params
from .order_params import OrderParamsKind, OrderParamsJSON
from . import order_tree_type
from .order_tree_type import OrderTreeTypeKind, OrderTreeTypeJSON
from . import event_type
from .event_type import EventTypeKind, EventTypeJSON

View File

@ -0,0 +1,33 @@
from __future__ import annotations
import typing
from dataclasses import dataclass
from construct import Container
import borsh_construct as borsh
class AnyEventJSON(typing.TypedDict):
event_type: int
padding: list[int]
@dataclass
class AnyEvent:
layout: typing.ClassVar = borsh.CStruct(
"event_type" / borsh.U8, "padding" / borsh.U8[207]
)
event_type: int
padding: list[int]
@classmethod
def from_decoded(cls, obj: Container) -> "AnyEvent":
return cls(event_type=obj.event_type, padding=obj.padding)
def to_encodable(self) -> dict[str, typing.Any]:
return {"event_type": self.event_type, "padding": self.padding}
def to_json(self) -> AnyEventJSON:
return {"event_type": self.event_type, "padding": self.padding}
@classmethod
def from_json(cls, obj: AnyEventJSON) -> "AnyEvent":
return cls(event_type=obj["event_type"], padding=obj["padding"])

View File

@ -0,0 +1,31 @@
from __future__ import annotations
import typing
from dataclasses import dataclass
from construct import Container
import borsh_construct as borsh
class AnyNodeJSON(typing.TypedDict):
tag: int
data: list[int]
@dataclass
class AnyNode:
layout: typing.ClassVar = borsh.CStruct("tag" / borsh.U8, "data" / borsh.U8[119])
tag: int
data: list[int]
@classmethod
def from_decoded(cls, obj: Container) -> "AnyNode":
return cls(tag=obj.tag, data=obj.data)
def to_encodable(self) -> dict[str, typing.Any]:
return {"tag": self.tag, "data": self.data}
def to_json(self) -> AnyNodeJSON:
return {"tag": self.tag, "data": self.data}
@classmethod
def from_json(cls, obj: AnyNodeJSON) -> "AnyNode":
return cls(tag=obj["tag"], data=obj["data"])

View File

@ -0,0 +1,75 @@
from __future__ import annotations
import typing
from dataclasses import dataclass
from anchorpy.borsh_extension import EnumForCodegen
import borsh_construct as borsh
class FixedJSON(typing.TypedDict):
kind: typing.Literal["Fixed"]
class OraclePeggedJSON(typing.TypedDict):
kind: typing.Literal["OraclePegged"]
@dataclass
class Fixed:
discriminator: typing.ClassVar = 0
kind: typing.ClassVar = "Fixed"
@classmethod
def to_json(cls) -> FixedJSON:
return FixedJSON(
kind="Fixed",
)
@classmethod
def to_encodable(cls) -> dict:
return {
"Fixed": {},
}
@dataclass
class OraclePegged:
discriminator: typing.ClassVar = 1
kind: typing.ClassVar = "OraclePegged"
@classmethod
def to_json(cls) -> OraclePeggedJSON:
return OraclePeggedJSON(
kind="OraclePegged",
)
@classmethod
def to_encodable(cls) -> dict:
return {
"OraclePegged": {},
}
BookSideOrderTreeKind = typing.Union[Fixed, OraclePegged]
BookSideOrderTreeJSON = typing.Union[FixedJSON, OraclePeggedJSON]
def from_decoded(obj: dict) -> BookSideOrderTreeKind:
if not isinstance(obj, dict):
raise ValueError("Invalid enum object")
if "Fixed" in obj:
return Fixed()
if "OraclePegged" in obj:
return OraclePegged()
raise ValueError("Invalid enum object")
def from_json(obj: BookSideOrderTreeJSON) -> BookSideOrderTreeKind:
if obj["kind"] == "Fixed":
return Fixed()
if obj["kind"] == "OraclePegged":
return OraclePegged()
kind = obj["kind"]
raise ValueError(f"Unrecognized enum kind: {kind}")
layout = EnumForCodegen("Fixed" / borsh.CStruct(), "OraclePegged" / borsh.CStruct())

View File

@ -0,0 +1,62 @@
from __future__ import annotations
from . import (
token_equity,
perp_equity,
)
import typing
from dataclasses import dataclass
from construct import Container, Construct
import borsh_construct as borsh
class EquityJSON(typing.TypedDict):
tokens: list[token_equity.TokenEquityJSON]
perps: list[perp_equity.PerpEquityJSON]
@dataclass
class Equity:
layout: typing.ClassVar = borsh.CStruct(
"tokens" / borsh.Vec(typing.cast(Construct, token_equity.TokenEquity.layout)),
"perps" / borsh.Vec(typing.cast(Construct, perp_equity.PerpEquity.layout)),
)
tokens: list[token_equity.TokenEquity]
perps: list[perp_equity.PerpEquity]
@classmethod
def from_decoded(cls, obj: Container) -> "Equity":
return cls(
tokens=list(
map(
lambda item: token_equity.TokenEquity.from_decoded(item), obj.tokens
)
),
perps=list(
map(lambda item: perp_equity.PerpEquity.from_decoded(item), obj.perps)
),
)
def to_encodable(self) -> dict[str, typing.Any]:
return {
"tokens": list(map(lambda item: item.to_encodable(), self.tokens)),
"perps": list(map(lambda item: item.to_encodable(), self.perps)),
}
def to_json(self) -> EquityJSON:
return {
"tokens": list(map(lambda item: item.to_json(), self.tokens)),
"perps": list(map(lambda item: item.to_json(), self.perps)),
}
@classmethod
def from_json(cls, obj: EquityJSON) -> "Equity":
return cls(
tokens=list(
map(
lambda item: token_equity.TokenEquity.from_json(item), obj["tokens"]
)
),
perps=list(
map(lambda item: perp_equity.PerpEquity.from_json(item), obj["perps"])
),
)

View File

@ -0,0 +1,35 @@
from __future__ import annotations
import typing
from dataclasses import dataclass
from construct import Container
import borsh_construct as borsh
class EventQueueHeaderJSON(typing.TypedDict):
head: int
count: int
seq_num: int
@dataclass
class EventQueueHeader:
layout: typing.ClassVar = borsh.CStruct(
"head" / borsh.U32, "count" / borsh.U32, "seq_num" / borsh.U64
)
head: int
count: int
seq_num: int
@classmethod
def from_decoded(cls, obj: Container) -> "EventQueueHeader":
return cls(head=obj.head, count=obj.count, seq_num=obj.seq_num)
def to_encodable(self) -> dict[str, typing.Any]:
return {"head": self.head, "count": self.count, "seq_num": self.seq_num}
def to_json(self) -> EventQueueHeaderJSON:
return {"head": self.head, "count": self.count, "seq_num": self.seq_num}
@classmethod
def from_json(cls, obj: EventQueueHeaderJSON) -> "EventQueueHeader":
return cls(head=obj["head"], count=obj["count"], seq_num=obj["seq_num"])

View File

@ -0,0 +1,103 @@
from __future__ import annotations
import typing
from dataclasses import dataclass
from anchorpy.borsh_extension import EnumForCodegen
import borsh_construct as borsh
class FillJSON(typing.TypedDict):
kind: typing.Literal["Fill"]
class OutJSON(typing.TypedDict):
kind: typing.Literal["Out"]
class LiquidateJSON(typing.TypedDict):
kind: typing.Literal["Liquidate"]
@dataclass
class Fill:
discriminator: typing.ClassVar = 0
kind: typing.ClassVar = "Fill"
@classmethod
def to_json(cls) -> FillJSON:
return FillJSON(
kind="Fill",
)
@classmethod
def to_encodable(cls) -> dict:
return {
"Fill": {},
}
@dataclass
class Out:
discriminator: typing.ClassVar = 1
kind: typing.ClassVar = "Out"
@classmethod
def to_json(cls) -> OutJSON:
return OutJSON(
kind="Out",
)
@classmethod
def to_encodable(cls) -> dict:
return {
"Out": {},
}
@dataclass
class Liquidate:
discriminator: typing.ClassVar = 2
kind: typing.ClassVar = "Liquidate"
@classmethod
def to_json(cls) -> LiquidateJSON:
return LiquidateJSON(
kind="Liquidate",
)
@classmethod
def to_encodable(cls) -> dict:
return {
"Liquidate": {},
}
EventTypeKind = typing.Union[Fill, Out, Liquidate]
EventTypeJSON = typing.Union[FillJSON, OutJSON, LiquidateJSON]
def from_decoded(obj: dict) -> EventTypeKind:
if not isinstance(obj, dict):
raise ValueError("Invalid enum object")
if "Fill" in obj:
return Fill()
if "Out" in obj:
return Out()
if "Liquidate" in obj:
return Liquidate()
raise ValueError("Invalid enum object")
def from_json(obj: EventTypeJSON) -> EventTypeKind:
if obj["kind"] == "Fill":
return Fill()
if obj["kind"] == "Out":
return Out()
if obj["kind"] == "Liquidate":
return Liquidate()
kind = obj["kind"]
raise ValueError(f"Unrecognized enum kind: {kind}")
layout = EnumForCodegen(
"Fill" / borsh.CStruct(), "Out" / borsh.CStruct(), "Liquidate" / borsh.CStruct()
)

View File

@ -0,0 +1,163 @@
from __future__ import annotations
from . import (
i80f48,
)
import typing
from dataclasses import dataclass
from construct import Container
from solana.publickey import PublicKey
from anchorpy.borsh_extension import BorshPubkey
import borsh_construct as borsh
class FillEventJSON(typing.TypedDict):
event_type: int
taker_side: int
maker_out: int
maker_slot: int
padding: list[int]
timestamp: int
seq_num: int
maker: str
maker_order_id: int
maker_fee: i80f48.I80F48JSON
maker_timestamp: int
taker: str
taker_order_id: int
taker_client_order_id: int
taker_fee: i80f48.I80F48JSON
price: int
quantity: int
reserved: list[int]
@dataclass
class FillEvent:
layout: typing.ClassVar = borsh.CStruct(
"event_type" / borsh.U8,
"taker_side" / borsh.U8,
"maker_out" / borsh.U8,
"maker_slot" / borsh.U8,
"padding" / borsh.U8[4],
"timestamp" / borsh.U64,
"seq_num" / borsh.U64,
"maker" / BorshPubkey,
"maker_order_id" / borsh.U128,
"maker_fee" / i80f48.I80F48.layout,
"maker_timestamp" / borsh.U64,
"taker" / BorshPubkey,
"taker_order_id" / borsh.U128,
"taker_client_order_id" / borsh.U64,
"taker_fee" / i80f48.I80F48.layout,
"price" / borsh.I64,
"quantity" / borsh.I64,
"reserved" / borsh.U8[24],
)
event_type: int
taker_side: int
maker_out: int
maker_slot: int
padding: list[int]
timestamp: int
seq_num: int
maker: PublicKey
maker_order_id: int
maker_fee: i80f48.I80F48
maker_timestamp: int
taker: PublicKey
taker_order_id: int
taker_client_order_id: int
taker_fee: i80f48.I80F48
price: int
quantity: int
reserved: list[int]
@classmethod
def from_decoded(cls, obj: Container) -> "FillEvent":
return cls(
event_type=obj.event_type,
taker_side=obj.taker_side,
maker_out=obj.maker_out,
maker_slot=obj.maker_slot,
padding=obj.padding,
timestamp=obj.timestamp,
seq_num=obj.seq_num,
maker=obj.maker,
maker_order_id=obj.maker_order_id,
maker_fee=i80f48.I80F48.from_decoded(obj.maker_fee),
maker_timestamp=obj.maker_timestamp,
taker=obj.taker,
taker_order_id=obj.taker_order_id,
taker_client_order_id=obj.taker_client_order_id,
taker_fee=i80f48.I80F48.from_decoded(obj.taker_fee),
price=obj.price,
quantity=obj.quantity,
reserved=obj.reserved,
)
def to_encodable(self) -> dict[str, typing.Any]:
return {
"event_type": self.event_type,
"taker_side": self.taker_side,
"maker_out": self.maker_out,
"maker_slot": self.maker_slot,
"padding": self.padding,
"timestamp": self.timestamp,
"seq_num": self.seq_num,
"maker": self.maker,
"maker_order_id": self.maker_order_id,
"maker_fee": self.maker_fee.to_encodable(),
"maker_timestamp": self.maker_timestamp,
"taker": self.taker,
"taker_order_id": self.taker_order_id,
"taker_client_order_id": self.taker_client_order_id,
"taker_fee": self.taker_fee.to_encodable(),
"price": self.price,
"quantity": self.quantity,
"reserved": self.reserved,
}
def to_json(self) -> FillEventJSON:
return {
"event_type": self.event_type,
"taker_side": self.taker_side,
"maker_out": self.maker_out,
"maker_slot": self.maker_slot,
"padding": self.padding,
"timestamp": self.timestamp,
"seq_num": self.seq_num,
"maker": str(self.maker),
"maker_order_id": self.maker_order_id,
"maker_fee": self.maker_fee.to_json(),
"maker_timestamp": self.maker_timestamp,
"taker": str(self.taker),
"taker_order_id": self.taker_order_id,
"taker_client_order_id": self.taker_client_order_id,
"taker_fee": self.taker_fee.to_json(),
"price": self.price,
"quantity": self.quantity,
"reserved": self.reserved,
}
@classmethod
def from_json(cls, obj: FillEventJSON) -> "FillEvent":
return cls(
event_type=obj["event_type"],
taker_side=obj["taker_side"],
maker_out=obj["maker_out"],
maker_slot=obj["maker_slot"],
padding=obj["padding"],
timestamp=obj["timestamp"],
seq_num=obj["seq_num"],
maker=PublicKey(obj["maker"]),
maker_order_id=obj["maker_order_id"],
maker_fee=i80f48.I80F48.from_json(obj["maker_fee"]),
maker_timestamp=obj["maker_timestamp"],
taker=PublicKey(obj["taker"]),
taker_order_id=obj["taker_order_id"],
taker_client_order_id=obj["taker_client_order_id"],
taker_fee=i80f48.I80F48.from_json(obj["taker_fee"]),
price=obj["price"],
quantity=obj["quantity"],
reserved=obj["reserved"],
)

View File

@ -0,0 +1,81 @@
from __future__ import annotations
import typing
from dataclasses import dataclass
from construct import Container
import borsh_construct as borsh
class FlashLoanTokenDetailJSON(typing.TypedDict):
token_index: int
change_amount: int
loan: int
loan_origination_fee: int
deposit_index: int
borrow_index: int
price: int
@dataclass
class FlashLoanTokenDetail:
layout: typing.ClassVar = borsh.CStruct(
"token_index" / borsh.U16,
"change_amount" / borsh.I128,
"loan" / borsh.I128,
"loan_origination_fee" / borsh.I128,
"deposit_index" / borsh.I128,
"borrow_index" / borsh.I128,
"price" / borsh.I128,
)
token_index: int
change_amount: int
loan: int
loan_origination_fee: int
deposit_index: int
borrow_index: int
price: int
@classmethod
def from_decoded(cls, obj: Container) -> "FlashLoanTokenDetail":
return cls(
token_index=obj.token_index,
change_amount=obj.change_amount,
loan=obj.loan,
loan_origination_fee=obj.loan_origination_fee,
deposit_index=obj.deposit_index,
borrow_index=obj.borrow_index,
price=obj.price,
)
def to_encodable(self) -> dict[str, typing.Any]:
return {
"token_index": self.token_index,
"change_amount": self.change_amount,
"loan": self.loan,
"loan_origination_fee": self.loan_origination_fee,
"deposit_index": self.deposit_index,
"borrow_index": self.borrow_index,
"price": self.price,
}
def to_json(self) -> FlashLoanTokenDetailJSON:
return {
"token_index": self.token_index,
"change_amount": self.change_amount,
"loan": self.loan,
"loan_origination_fee": self.loan_origination_fee,
"deposit_index": self.deposit_index,
"borrow_index": self.borrow_index,
"price": self.price,
}
@classmethod
def from_json(cls, obj: FlashLoanTokenDetailJSON) -> "FlashLoanTokenDetail":
return cls(
token_index=obj["token_index"],
change_amount=obj["change_amount"],
loan=obj["loan"],
loan_origination_fee=obj["loan_origination_fee"],
deposit_index=obj["deposit_index"],
borrow_index=obj["borrow_index"],
price=obj["price"],
)

Some files were not shown because too many files have changed in this diff Show More