Ignore .idea Bump version, rename root folder Multiple misc. improvements Bump version Bump version Update .gitignore
This commit is contained in:
commit
8463a434fc
|
@ -0,0 +1,9 @@
|
|||
.venv/
|
||||
build
|
||||
.idea
|
||||
id.json
|
||||
config.json
|
||||
.DS_Store
|
||||
**/__pycache__/
|
||||
dist/*
|
||||
.swp
|
|
@ -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())
|
||||
```
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"secret_key": "YOUR_SECRET_KEY",
|
||||
"mango_account_pk": "MANGO_ACCOUNT_PK"
|
||||
}
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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,
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -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"]),
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -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"],
|
||||
)
|
||||
),
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -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)))
|
|
@ -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"],
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
RUST_U64_MAX = 18446744073709551615
|
||||
|
||||
RUST_I64_MAX = 9223372036854775807
|
||||
|
||||
RUST_I64_MIN = -9223372036854775807
|
||||
|
||||
QUOTE_DECIMALS = 6
|
||||
|
|
@ -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])
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
||||
]
|
||||
]
|
||||
]
|
|
@ -0,0 +1,4 @@
|
|||
from solana.publickey import PublicKey
|
||||
|
||||
MANGO_PROGRAM_ID = PublicKey("4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg")
|
||||
SERUM_PROGRAM_ID = PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX')
|
|
@ -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
|
|
@ -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"])
|
|
@ -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"])
|
|
@ -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())
|
|
@ -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"])
|
||||
),
|
||||
)
|
|
@ -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"])
|
|
@ -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()
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -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
Loading…
Reference in New Issue