Updated to latest group structures and IDs.

This commit is contained in:
Geoff Taylor 2021-08-17 19:42:11 +01:00
parent 847628dfd6
commit 97a5c41a39
17 changed files with 196 additions and 273 deletions

View File

@ -1,6 +1,6 @@
{ {
"cluster_urls": { "cluster_urls": {
"devnet": "https://mango.devnet.rpcpool.com", "devnet": "https://api.devnet.solana.com",
"localnet": "http://127.0.0.1:8899", "localnet": "http://127.0.0.1:8899",
"mainnet-beta": "https://solana-api.projectserum.com", "mainnet-beta": "https://solana-api.projectserum.com",
"testnet": "https://testnet.solana.com" "testnet": "https://testnet.solana.com"
@ -9,7 +9,7 @@
{ {
"cluster": "devnet", "cluster": "devnet",
"name": "devnet.1", "name": "devnet.1",
"publicKey": "D3H3f29tcGNeEgk4bArKcRKQv8V4zCUFrj1sGXaHwgvM", "publicKey": "4XKVThVcLBdN9E2CDuuNmJejCVbVjqvb8VGjoGyHz8A4",
"quoteSymbol": "USDC", "quoteSymbol": "USDC",
"mangoProgramId": "5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E", "mangoProgramId": "5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E",
"serumProgramId": "DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY", "serumProgramId": "DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY",
@ -18,106 +18,79 @@
"symbol": "USDC", "symbol": "USDC",
"mintKey": "8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN", "mintKey": "8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN",
"decimals": 6, "decimals": 6,
"rootKey": "J2PZBR4M8V4LXDG8oPC8BG1t8JUSXHC6fSMCxR9tFdfZ", "rootKey": "8HomaswMsbUtfdYeFd6zKBFfdzWZ8KqW7beu3wpJi6zE",
"nodeKeys": [ "nodeKeys": [
"9iXA2Y3UPqJJE6qe7TtRcxGdqYcToKh8sCZv88Jt4dXS" "F7hQduZSp8jvFKH1LAkYByDhzKoJFeKTGqz2JzeT1fby"
] ]
}, },
{ {
"symbol": "MNGO", "symbol": "MNGO",
"mintKey": "Bb9bsTQa1bGEtQ5KagGkvSHyuLqDWumFUcRqFusFNJWC", "mintKey": "Bb9bsTQa1bGEtQ5KagGkvSHyuLqDWumFUcRqFusFNJWC",
"decimals": 6, "decimals": 6,
"rootKey": "1UBCGeMVmoNHt7Ldj7L6aj29f8oxRhuvCGwjJnTW1yU", "rootKey": "scfyRHbzBnEyeELkVq8LP3QyNKZfzdF8AESmPqtqqc7",
"nodeKeys": [ "nodeKeys": [
"G9zKrvZhCgkAU6QUW37NjghKMBnmBdDzk3aYgbE6ZkJY" "8A5QQKXGHnMUsPiBQN4dJeVDnJjjHQTeExUpqsBaRFVv"
] ]
}, },
{ {
"symbol": "BTC", "symbol": "BTC",
"mintKey": "3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU", "mintKey": "3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU",
"decimals": 6, "decimals": 6,
"rootKey": "YyuJod2J35HhUYPq1gkregZjaD3Zr2m3MdZaUrmh74W", "rootKey": "5peczazimSQpLiqpo9JeZeZJAhr6BvDxTkKLrQHQqW6u",
"nodeKeys": [ "nodeKeys": [
"CKjPnjQdHPDJDFKAevSCpLJ8NQk7UrsbCgbXQAh1AXgu" "6AYdrMRPRdhWVGHaw9qVXcvbXAPn3xNH73bTvbG48c5L"
] ]
}, },
{ {
"symbol": "ETH", "symbol": "ETH",
"mintKey": "Cu84KB3tDL6SbFgToHMLYVDJJXdJjenNzSKikeAvzmkA", "mintKey": "Cu84KB3tDL6SbFgToHMLYVDJJXdJjenNzSKikeAvzmkA",
"decimals": 6, "decimals": 6,
"rootKey": "Anjg6i35hDE3VTCRXcSTYaUMctMc6Wx5TrpJkVF2g2Uc", "rootKey": "AKQLYJXdqMUxRMGskbxSrCUFB9hV2PXy7CgcwdCEiKKb",
"nodeKeys": [ "nodeKeys": [
"6kHBxELNpRhQ1D7DdNtZUZHeqV72kDPjhJb9Mqkpm8h" "5iNkcp9cHuebGuvg7hkND19LDYEm5rz5hg73MyaCWgiZ"
] ]
}, },
{ {
"symbol": "SOL", "symbol": "SOL",
"mintKey": "So11111111111111111111111111111111111111112", "mintKey": "So11111111111111111111111111111111111111112",
"decimals": 9, "decimals": 9,
"rootKey": "TSA9ikdc4fHJEGbkEEcGeXk4Snk3REd91Vvk67PCB8U", "rootKey": "2i1USFkMnUrLGyF6HDWYw5VtPfDjpfL6bhjSyiCRMFS7",
"nodeKeys": [ "nodeKeys": [
"5XYKTZgoWfLQK8zmngNefLi6zE5J3LiUXZrfyfVRpy67" "DzTqkCiD9Lb3e8tX5ozFzjwUmaHN8nfNGqLmYg1MHxvA"
] ]
}, },
{ {
"symbol": "SRM", "symbol": "SRM",
"mintKey": "AvtB6w9xboLwA145E221vhof5TddhqsChYcx7Fy3xVMH", "mintKey": "AvtB6w9xboLwA145E221vhof5TddhqsChYcx7Fy3xVMH",
"decimals": 6, "decimals": 6,
"rootKey": "A3swcrvcnVTa1kaamjfxikxJrTRe3PVjAKb4ke3MqU2L", "rootKey": "BodzTbB412CwnkJbDG6rQpvAy9MHPgqskpH4r7qn3nB7",
"nodeKeys": [ "nodeKeys": [
"EoL6ZSxXKKVPZyNYMSqF44JMxUFK7w4bwqXXb95i8sMZ" "H9hkW2DtyrETf7EGmeiz9QdChf9thk5FFRb4HAXfC5An"
] ]
}, },
{ {
"symbol": "RAY", "symbol": "RAY",
"mintKey": "3YFQ7UYJ7sNGpXTKBxM3bYLVxKpzVudXAe4gLExh5b3n", "mintKey": "3YFQ7UYJ7sNGpXTKBxM3bYLVxKpzVudXAe4gLExh5b3n",
"decimals": 6, "decimals": 6,
"rootKey": "BGjFGQsocyTHQ87q8Sm6veM2fvrswbS9swfPwv1VPu4w", "rootKey": "6NUEWYb2v4zc2dxeWPfswGZDLzjqaYzHG8bThctHG7jz",
"nodeKeys": [ "nodeKeys": [
"HbAproJH9NDXS4BNHtfeqvQQ6M7QCwvkHs79PCAJ62pb" "DBAAoG5d21YouJinh5vgk9VBowPWfzXNbhBsPW2XisEb"
]
},
{
"symbol": "DOGE",
"mintKey": "6yr1xJP6Nfu8Bxp4L8WJQrtLqBGZrQm5n41PFm4ZmEyk",
"decimals": 6,
"rootKey": "H4pPY9sFtDe3mXJeNiPjx1dkqU2paUFDVhMZmHVwgL1w",
"nodeKeys": [
"DGuaMXYY9VPWCUgaj5A2iopDE67mJrv66yPQJQemDpJd"
]
},
{
"symbol": "SUSHI",
"mintKey": "Edi5KNs2LnonULNmoTQqSymJ7VuMC9amTjLN5RJ1YMcq",
"decimals": 6,
"rootKey": "3SEr6tzAjq5PxydhhRDkXBnfAyHqdypVGH78hmyZMTjH",
"nodeKeys": [
"GndC5WQVGpDfPoQV94krJq9TXwVkBNgdw4TgA8HKcfiL"
]
},
{
"symbol": "FTT",
"mintKey": "Fxh4bpZnRCnpg2vcH11ttmSTDSEeC5qWbPRZNZWnRnqY",
"decimals": 6,
"rootKey": "384x8UXptKQMcc4vcUT1xJJ3t8iwaHSed6Hux2E6FJ9G",
"nodeKeys": [
"DRg3uVuyLZgf3aYQcQnsEL9ADpMJipoppRcqineGRK5t"
] ]
}, },
{ {
"symbol": "USDT", "symbol": "USDT",
"mintKey": "DAwBSXe6w9g37wdE2tCrFbho3QHKZi4PjuBytQCULap2", "mintKey": "DAwBSXe6w9g37wdE2tCrFbho3QHKZi4PjuBytQCULap2",
"decimals": 6, "decimals": 6,
"rootKey": "HyncqkGfvmDf8CCXXTSYcPGJk9MfkoW7mm4hfHZ6EEZk", "rootKey": "4Z1Yq3PotHzgdxhvj5q3tmhAWrbRZZpNtKGpjyAdJugD",
"nodeKeys": [ "nodeKeys": [
"91fZLKyYCXxxrfVrCogY1MJdqe9RBUQPvdWwncedMD9u" "D6weykQ7DSzHKZQpFW59Z8gRduRFJAxxoM3p5Zn2N7FG"
] ]
} }
], ],
"oracles": [ "oracles": [
{ {
"symbol": "MNGO", "symbol": "MNGO",
"publicKey": "9qNwk4nFs2FzqqBNcbEfQwzYEGALsuuZz7qqV4UTyyrN" "publicKey": "2s7XrK1c7tmT4GNuSzzPcTBHFWLKmNZh8vi3UUYCWyqL"
}, },
{ {
"symbol": "BTC", "symbol": "BTC",
@ -137,19 +110,7 @@
}, },
{ {
"symbol": "RAY", "symbol": "RAY",
"publicKey": "DySvRB195HvXbPCz4VU1KS7q2DrpAMoKAPDWRsMRzx4k" "publicKey": "8jLbp5tcdWpqATwuFwwQ5eBPWsDxaFopJqnXhxmD6caN"
},
{
"symbol": "DOGE",
"publicKey": "4L6YhY8VvUgmqG5MvJkUJATtzB2rFqdrJwQCmFLv4Jzy"
},
{
"symbol": "SUSHI",
"publicKey": "AmALh5D5d27r3kBsTctwCcK9oV2bYy168y7DjgT8vTnc"
},
{
"symbol": "FTT",
"publicKey": "6vivTRs5ZPeeXbjo7dfburfaYDWoXjBtdtuYgQRuGfu"
}, },
{ {
"symbol": "USDT", "symbol": "USDT",
@ -159,225 +120,159 @@
"perpMarkets": [ "perpMarkets": [
{ {
"name": "MNGO-PERP", "name": "MNGO-PERP",
"publicKey": "Eb9kbaZN5im9RiyJJi9j231vdGjwHqk9U87BTH8vozHn", "publicKey": "GB4QffZnSGVmCh2qscTxGVwkqBSt7NB8B5fpuRcDFCFD",
"baseSymbol": "MNGO", "baseSymbol": "MNGO",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 0, "marketIndex": 0,
"bidsKey": "8DioiDW4L9UWf2kfKFY1kcsLMcVWESavAfct8z6JBGaY", "bidsKey": "9a3FU66bknYPSPAFG5Wmv3hFCoJ2VMpdrefZUPdGJyMJ",
"asksKey": "4Bk1VDtXDtKQAxS31kpdJmVs5AXUd3DaGt1PEgtW26cR", "asksKey": "5cx3XqHQU8vY5qPrbEccqTvuzXdgEwcbCbHDSD9fVoGE",
"eventsKey": "HfACePStB6PcrAGA6YKBPscXEm7kDhLwML98xmcQ55gW" "eventsKey": "BiJ6kg2ncPt3HPJctM1bYoBWHXzvwWhD7AB883tiNWzr"
}, },
{ {
"name": "BTC-PERP", "name": "BTC-PERP",
"publicKey": "5FePG6TGQ2PybQVmFvKbCEXEYKmohoCUmz91zzVCqrTU", "publicKey": "CekAcHL8x6XjMXYNCfTFrs4rAAYkNCdir2LCdjJHdmCB",
"baseSymbol": "BTC", "baseSymbol": "BTC",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 1, "marketIndex": 1,
"bidsKey": "GE9szLB8GvtqDH5QN9CuovzKDdSXuY1oGHQGwKyk4hTT", "bidsKey": "8Mx11pN2Vj9bRH3DHqu9XdFp7My7VYjM3FL1TyY9tZ6z",
"asksKey": "BxJEW9AewNwBf8RSn7LLjpGmueKrSL5QX8WhDXwTaeb2", "asksKey": "fJ8goLHFpdtbSY6uaKVRGP2WH21csAip7B8QRagVwjt",
"eventsKey": "CxCVE8pNJUihmaGzK2eLSb9XZ2XQR4r2xpJk7brZj4kX" "eventsKey": "HNxDQsf8ntqmZy6YDuWrWQieuYjLTaucq652tpf6jFXN"
}, },
{ {
"name": "ETH-PERP", "name": "ETH-PERP",
"publicKey": "9GHN7VGxNSCaSiDtTeZkT4ZseqVVkCTKw7VYEAaJqiNc", "publicKey": "1h3QZQjo4X4bnJAPignsgfEebaJvhAyYJ22n5Asj2Aq",
"baseSymbol": "ETH", "baseSymbol": "ETH",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 2, "marketIndex": 2,
"bidsKey": "9bPCjgu17vtaSMe4ojWCEBumd1KmttweUPHVnfakaodt", "bidsKey": "BQy6FyJZ5Nn8pfScyLmmxmzpWjJEdyx7Wgxd8Amx2sE6",
"asksKey": "8VhKgHYdeVTFvPrn1zeA6iHfvAtFXQnSKDLsk38YhZ8n", "asksKey": "J3Buki4SKYZUZZq2KhouEaPQi9C7CyNCJn7SFaRCTn1V",
"eventsKey": "FPgTy3JmLKck9jyQzBFAmRGq8G4WmifeXq6CJJMivGtb" "eventsKey": "EYkinFh4MvyknVWc8VSr5ofqoW7RN2WccYWRsPB9LFKH"
}, },
{ {
"name": "SOL-PERP", "name": "SOL-PERP",
"publicKey": "Htds23imNxeeR778DLXHXDjUnr2sFYdtj31tz6hwSZnV", "publicKey": "8bdzbDmK776L7SYo15jFrCE1jZpGJ5Hvi3HCX4nkG2SC",
"baseSymbol": "SOL", "baseSymbol": "SOL",
"baseDecimals": 9, "baseDecimals": 9,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 3, "marketIndex": 3,
"bidsKey": "8fD5gMavPbRMJd4KMFopLF6fzhKMQZHwH5wMZMxLkMJe", "bidsKey": "36j8vFEy8MFSEZ1qbgNBZ85bfLir3m2JWK1Xyfod3SXq",
"asksKey": "3AdnHLkNw9qm4vwRsjgs9KffkCSZr5JvGLEgFx6QBJaM", "asksKey": "6gfw77TVq2dasBGrbNQNfUEjj1qH8yfTZxQdsqm1czGB",
"eventsKey": "7nMo3Apws96PqEP4ejnoJTQimc9DRsz91NV32wHasQEZ" "eventsKey": "CKh8QDgvGrVY1anhL6uWcTqSTkPkZqMs2ijvYJcVd4N4"
}, },
{ {
"name": "SRM-PERP", "name": "SRM-PERP",
"publicKey": "8j8JEHSduFv8L8tw4AybTTRzELKQbu2xnjcTUdxZ8SZ2", "publicKey": "H1zA6828E6pitokeK7bjo9bNGmcQnUAEzNDVymnjgnSo",
"baseSymbol": "SRM", "baseSymbol": "SRM",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 4, "marketIndex": 4,
"bidsKey": "ExRkH8dUbeTADeffrpV8kFw3P12s5Ya8K4fvQ4iUgru7", "bidsKey": "674JmaAdzSfUJ163tq1mL53zPrAU3xEn67n4oCBJwQ1U",
"asksKey": "6AiXmTA9c1eG7vmDuckNUTM3qdV9KpCsi2UvVTSYWA9r", "asksKey": "6oRDC75LQkQRwPbMftfdQLazp62hUHGDnuky9T5BZoU4",
"eventsKey": "6bhy7yUzZoPKMK4TdsnhDMs9CMRQQ8iqynkWqir9VTqg" "eventsKey": "2sFGWmFEie8A123mXHf1C6rYbKhNEfcjbNThYDPQbVQ4"
}, },
{ {
"name": "RAY-PERP", "name": "RAY-PERP",
"publicKey": "JCVKRwUG81Wpo3ErTCfWWZsuvRxECEtGRkLppRceef7X", "publicKey": "9rt89vb7o2uEUUhM435YXCBE9nYzdxYqWfgbumDX5qDd",
"baseSymbol": "RAY", "baseSymbol": "RAY",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 5, "marketIndex": 5,
"bidsKey": "9M19Sk7ydE5omHBN5W2EF7idqtcPGMTPmwN4s2TY4BSS", "bidsKey": "6hRYk2JJibhFFShZFZPqussECXNxCvi2oC38V2GwETPN",
"asksKey": "BpdPV6Q6zGeGb2jzr16RrMBNLSANxjxX8VuFr2sEwY1H", "asksKey": "GBoPouNmbdmmpLCdEDzXhyoRfdQYofK7xD3vY8oZckRG",
"eventsKey": "G9GJ7ykDo165PwLFMdKYiXDsnmfzPGji6764Q9rU2VdD" "eventsKey": "8Dy78QoWXufCwQNSLRKJ9bH1JcUho3GfRvbDqiyALQC7"
},
{
"name": "DOGE-PERP",
"publicKey": "BTxGBYaS64UVtsPkiweMRKuKBLiy7Du23t52HHQNjtau",
"baseSymbol": "DOGE",
"baseDecimals": 6,
"quoteDecimals": 6,
"marketIndex": 6,
"bidsKey": "FvGjyWeWGwtmwoPH11BLWiDA2kqCmrw564QvpxoFCxFG",
"asksKey": "BWaGbAoTAgBLyp7ZcCtA4FfadqvNqELYEhdp5R5eQaYi",
"eventsKey": "F2ydUUxqGiVjQXQwqx6qW6NPJrtsefSsnqkEeCMhA1Hs"
},
{
"name": "SUSHI-PERP",
"publicKey": "A98F12sHfmJPbY5ZoVVkeuA7YEJTBczTtCzN33hP62dv",
"baseSymbol": "SUSHI",
"baseDecimals": 6,
"quoteDecimals": 6,
"marketIndex": 7,
"bidsKey": "G3JrEBtwJZT4NYEvvXbZFs3mRNf4EX7WKXY8REPhYTrv",
"asksKey": "5s3Ys2wwV6fTCiYKjzwsSUQx5A9SCY5RQpbBGbduX9fD",
"eventsKey": "B3ufGFeoW4JnNgrf5qBgQ2W7WgG3AnBDR6cfgRvh4gSY"
},
{
"name": "FTT-PERP",
"publicKey": "AcUJeQ9yNdEjGUbGFm8jWWGcFPXX2MBwGuxyW573Ff1c",
"baseSymbol": "FTT",
"baseDecimals": 6,
"quoteDecimals": 6,
"marketIndex": 8,
"bidsKey": "DwZ3scyS33yvzrmmComF1cYPr62KpVgciBssyHhLJ7kw",
"asksKey": "GijPgMq9aydVGRWvfSwRVBVszmwssUHBwuSM35BuhqXN",
"eventsKey": "8X9i5vLZ8CkMWxbrsWikeorQzfMBtaMhfDMwYXTeiFNS"
}, },
{ {
"name": "USDT-PERP", "name": "USDT-PERP",
"publicKey": "Djr75WctR92VCqssZ619qPJbKKZFjEMwi86mFdN4VfFi", "publicKey": "HzA2xewTzqboVJk8yeSP9wqpSE4XHEmGMzsiFBmwCszE",
"baseSymbol": "USDT", "baseSymbol": "USDT",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 9, "marketIndex": 6,
"bidsKey": "8iJ7oHisRHsxAygGfp1ki9GZh8k2QwEirF6uUbr98XM3", "bidsKey": "93n4jwHsbCEvZZ4cydyy7c8AHWY4LtPSdP6CLLjzJSw",
"asksKey": "bhJxk5Zc6SxbBbj6kEauYGvZaxzSCkYcWtwmQwMjfP3", "asksKey": "BP2rC9v87xov554hcMVwRW5qB1qcRa27RXKTbA6YobwK",
"eventsKey": "GAayxsWfK7XVg3UXb79XS3CtuJSwFuzeLtEHvSfDSuoS" "eventsKey": "GRUrFv3M5L5cPhMETkSTBssZZT2B9DdDwoeW2BQ3Jv1y"
} }
], ],
"spotMarkets": [ "spotMarkets": [
{ {
"name": "MNGO/USDC", "name": "MNGO/USDC",
"publicKey": "BP5duanM1mEVyW6hi1fXz5KZmW15DpJuL3yR8V1bH3Py", "publicKey": "D9KWifyaFX8qxyktRzzCLv4n37ameEoUP1jPkMdu13JZ",
"baseSymbol": "MNGO", "baseSymbol": "MNGO",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 0, "marketIndex": 0,
"bidsKey": "BBaYoN6utgyKMDNhKPqvREMNKbqj4sE7PPCr9cmFv7c8", "bidsKey": "BEJD7DrCxv1GigvcXRZLsq8gr13h7ypwSNDYUTxAqjzj",
"asksKey": "6nRnAvEPQ6ycVRTzpp7s97BFfzDF7Niio5MoZ7Nowip9", "asksKey": "AkXKeB1bpvieCGDKgcSDs1cvKDVvqemynq7Xpbvp23ic",
"eventsKey": "5EwoR3usrHeMPn9tFfXnpvibgmqB6QyMaNfk9jaZUtkZ" "eventsKey": "5gnYPsN26T4hGDZYmuddG9aeRXZUpPGDNjn5a9vXThdj"
}, },
{ {
"name": "BTC/USDC", "name": "BTC/USDC",
"publicKey": "6LUe1qbDwoj3dmM4jvXwshRAcpMFH7xQ5dWyssAtAuHV", "publicKey": "BYXAPyT9fKiyUJ162mqXbVmchQaEwMnrcenM9esDV4k5",
"baseSymbol": "BTC", "baseSymbol": "BTC",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 1, "marketIndex": 1,
"bidsKey": "8SCQybswfLSVQSZaDjACcj7kVBzG1nPhMxB4M4WmsGKp", "bidsKey": "5wkoQDMYcrfuKB9Die5yLZTboWHcmW1M6yJXM5uhk66Z",
"asksKey": "D6wzhFJW6QZDotBuFWmy6e9rszQm9W5FR32Z8KtMGUbf", "asksKey": "DBS7Zw5zFC58jVsqX8bRwSjtTc8ca5r27g6Y4ikr9hhv",
"eventsKey": "G4UuuNB92mquXqDJirV35ooWmHGqoD57zzG6FAbufCUu" "eventsKey": "4hrYeHTGRGcEWkqLZqVwuMAmo1dtankVNML2psBBhkmT"
}, },
{ {
"name": "ETH/USDC", "name": "ETH/USDC",
"publicKey": "6YzKiCwaURhEVEXxLBD8gNQXziCPqi6h17dhpH17NNFD", "publicKey": "G7NYXEQ6W4mVoMinn9a8XaY4oswhW59NhtNWDQg5An2U",
"baseSymbol": "ETH", "baseSymbol": "ETH",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 2, "marketIndex": 2,
"bidsKey": "DYELab7pC4v78Q6n8YXEAzZqLJdVPXbHDuSQDX1z5kJV", "bidsKey": "2RRd7yVxEhQzBBuNHBkR49SxWcQ8tSKv2D61DQo4DZVx",
"asksKey": "dWD2Kc3SbEDKvCtPxfeuBXLbk1o2NFhN47AG65gwwcz", "asksKey": "69WSZeZ7KTky19XH1Z9g2ZMkZJEt8pweD2WZcw9heRNb",
"eventsKey": "Aen28QFiv6MaQDcbq58fz4Krttj5HXxvfpUr5js2sXoW" "eventsKey": "Huy7jJX5fyuHtyWEN2xjjcSmEB18riqTFDCwUMsTtGm"
}, },
{ {
"name": "SOL/USDC", "name": "SOL/USDC",
"publicKey": "7GLPw3pdjpyf2YpXoXo1PTDa5WciT8NDNzz3PnMB1ZTM", "publicKey": "6pV5PfVL6Ct5jiiySyt144ocMcuepLdAuF3umYMuh3rN",
"baseSymbol": "SOL", "baseSymbol": "SOL",
"baseDecimals": 9, "baseDecimals": 9,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 3, "marketIndex": 3,
"bidsKey": "6DoTW6uKSJhfsK8CzLM9CWfTn4QjzF3gksPyLgcnZgys", "bidsKey": "5N2KmqcnXSP2PE2Dg9UF2f1Y2kF7sdi8xTnzAwhqF8iv",
"asksKey": "4in1zY5zr7S7Rfg9txKzd7cgnHfNriQQH4LiwTd2MhGn", "asksKey": "7U1XLt3mbQVYdNR7JoKoJyN8TfQUA6Lv5VDZaAKz3waa",
"eventsKey": "DDp6dFXwZxyzg65q5sfe58NCpps5nFuha5xS8Kb1EDgU" "eventsKey": "34B9UoVjhUn7BXyXkfFHpQNWBZeGWhg9rJEBLgyocqiF"
}, },
{ {
"name": "SRM/USDC", "name": "SRM/USDC",
"publicKey": "FM3NeE8ZhzcZXf2FtLGiSHTbLzQsemHh3emmBMLyFMDu", "publicKey": "76JPTPeZr6UWzU4jcjLfGKAHfSywsXiwrgGo7dt7Kwzb",
"baseSymbol": "SRM", "baseSymbol": "SRM",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 4, "marketIndex": 4,
"bidsKey": "8aeTnuRxPuMZT6EjBxSuPiaKPVHah5gznq3mNszkDPkZ", "bidsKey": "Dc4xX9VSV3R71jDKiMSPZqpa8EBhVo1GHZxkCMfVepkx",
"asksKey": "6eAGyCQg8vUNvBV96ztoArAKTudBGsr8XSaQbWWcvuXj", "asksKey": "5bvsugaaA7c53eNdiVzuTG68pTPR4QGNK7CEYyC3PbML",
"eventsKey": "UgAd1bmJ3zr5MAUz8XpT5ku32HK73W8jCjyUwSvgQZM" "eventsKey": "VvhudujDXLXCkwcDJXrMbtSBgMHdEjJrLys14fy6SQ9"
}, },
{ {
"name": "RAY/USDC", "name": "RAY/USDC",
"publicKey": "G8W9b1ACTKipefeCD8wrBTFygqCY48fX22hywFwE9ne8", "publicKey": "CwBV7qFPkfRrJPao8jaoAK5NoWYVYSVgtaBvAXN7JZs7",
"baseSymbol": "RAY", "baseSymbol": "RAY",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 5, "marketIndex": 5,
"bidsKey": "8HQaw8X8ph2mqpFhGrD1FZC1VDfBkyw5gtTg6jkjCZPd", "bidsKey": "H18vDMumfWDxgU6YVJb1D8fhahvkSUubzA7jU61q8RiP",
"asksKey": "77XVr3Ypgs8SNCem5N8wi97GQTGyrs16jEWw6nS1Bdsn", "asksKey": "7D4TYmMVi8HpKu8Tg2CHV998HQe2iZj25B295MDdabdU",
"eventsKey": "4XcMk15DBK1cBsvKXRMo8m1AWZbnNpWjPBwKrhCLnVhN" "eventsKey": "CGchuvhJjfMXy5Rh272eM6z8y7k6v8XH4UYJZSMUTjUP"
},
{
"name": "DOGE/USDC",
"publicKey": "147v2QNqhykdshNTzBU9SqMZ1MB8zfum8VusL3mTHRpi",
"baseSymbol": "DOGE",
"baseDecimals": 6,
"quoteDecimals": 6,
"marketIndex": 6,
"bidsKey": "E2jYUnxNW7atftcMEEeC64JV7WQuiK5K5zvWVVaZAXTu",
"asksKey": "5RDn6fXNWVoAvJDvvc6sH1nBdqPavKmqRUF1394rNmm4",
"eventsKey": "5byXwPysnJqjkuaMNhYxBXLLA4CQkXqmRbFTvDDSe7fs"
},
{
"name": "SUSHI/USDC",
"publicKey": "52x7jVwSLzjBuur38HSpQJUsNTUnMtbawYuNwMFf5gno",
"baseSymbol": "SUSHI",
"baseDecimals": 6,
"quoteDecimals": 6,
"marketIndex": 7,
"bidsKey": "AhQ9ibX2gKpqyXiRCFLn31NnNJ2D7Ye4wpMKdW2HU5wm",
"asksKey": "ET8PeUBxiLbT5FRuxG7gSgzomakK1aGpdEvB7z7GgnPy",
"eventsKey": "5QcSUUMxKMJQwe8jELZMJYAdSXYTNoLTWsKD8vPiLXP3"
},
{
"name": "FTT/USDC",
"publicKey": "AqqoYLbCM3Kx575mYaEKQjvmJytC3JhYidjdDJybSobR",
"baseSymbol": "FTT",
"baseDecimals": 6,
"quoteDecimals": 6,
"marketIndex": 8,
"bidsKey": "AQP35WTu3e3Ci7wGwupt1tqLme8yJpMKMCVqRUFgLuSk",
"asksKey": "BSVn6uTnb4jCbG8CxQstaXdT6T3nBKHCk7K9dr9RHb38",
"eventsKey": "9NF9f5iDBzJcpFuqcTv2jdENvRad4HGPyzphhJPBU48k"
}, },
{ {
"name": "USDT/USDC", "name": "USDT/USDC",
"publicKey": "2jnUTkxsDvRmiZzWw1wpxuTnT1SbT6PmYFKNPbWdyY6U", "publicKey": "97N64HezGkNs1sPBUMUxLLxkeCoBqSNzZmipxpeBcYUg",
"baseSymbol": "USDT", "baseSymbol": "USDT",
"baseDecimals": 6, "baseDecimals": 6,
"quoteDecimals": 6, "quoteDecimals": 6,
"marketIndex": 9, "marketIndex": 6,
"bidsKey": "C1gxQ8NjqnaFs9TC5U7de5YKfAyNpQTiYWQAjPHMDE91", "bidsKey": "BoKZMtnEgzV1gtix6RotBq4wteNXteGFEyeTMC88BUyw",
"asksKey": "AhnGqCuTNzLiQ6Y4m2oxds2sog3u2ChX8MXCMYyaPCb4", "asksKey": "EbgYUYhPTqFxMqc7pq2v9MWTbzu2m5frzvw6ePTsAFWq",
"eventsKey": "GBEkcp2qqu13qxtYFXJxER1W1bAww2yBj9tCmR9ZXUde" "eventsKey": "38X8AuewBYZATEovYnXr7znDbiAxkxxEn7RYjXDtVn1T"
} }
] ]
}, },

View File

@ -156,7 +156,7 @@ def pulse(self, context: mango.Context, model_state: ModelState):
cancellations = mango.CombinableInstructions.empty() cancellations = mango.CombinableInstructions.empty()
for to_cancel in reconciled.to_cancel: for to_cancel in reconciled.to_cancel:
self.logger.info(f"Cancelling {self.market.symbol} {to_cancel}") self.logger.info(f"Cancelling {self.market.symbol} {to_cancel}")
cancel = self.market_instruction_builder.build_cancel_order_instructions(to_cancel) cancel = self.market_instruction_builder.build_cancel_order_instructions(to_cancel, ok_if_missing=True)
cancellations += cancel cancellations += cancel
place_orders = mango.CombinableInstructions.empty() place_orders = mango.CombinableInstructions.empty()

View File

@ -13,6 +13,8 @@
# [Github](https://github.com/blockworks-foundation) # [Github](https://github.com/blockworks-foundation)
# [Email](mailto:hello@blockworks.foundation) # [Email](mailto:hello@blockworks.foundation)
from mango.perpopenorders import PerpOpenOrders
from mango.placedorder import PlacedOrder
from mango.tokeninfo import TokenInfo from mango.tokeninfo import TokenInfo
import typing import typing
@ -27,6 +29,7 @@ from .encoding import encode_key
from .group import Group from .group import Group
from .layouts import layouts from .layouts import layouts
from .metadata import Metadata from .metadata import Metadata
from .orders import Side
from .perpaccount import PerpAccount from .perpaccount import PerpAccount
from .token import Token from .token import Token
from .tokenvalue import TokenValue from .tokenvalue import TokenValue
@ -125,13 +128,24 @@ class Account(AddressableAccount):
in_margin_basket: typing.Sequence[bool] = list([bool(in_basket) for in_basket in layout.in_margin_basket]) in_margin_basket: typing.Sequence[bool] = list([bool(in_basket) for in_basket in layout.in_margin_basket])
active_in_basket: typing.List[bool] = [] active_in_basket: typing.List[bool] = []
basket: typing.List[AccountBasketBaseToken] = [] basket: typing.List[AccountBasketBaseToken] = []
placed_orders_all_markets: typing.List[typing.List[PlacedOrder]] = [[] for _ in range(len(group.tokens) - 1)]
for index, order_market in enumerate(layout.order_market):
if order_market != 0xFF:
side = Side.from_value(layout.order_side[index])
id = layout.order_ids[index]
client_id = layout.client_order_ids[index]
placed_order = PlacedOrder(id, client_id, side)
placed_orders_all_markets[int(order_market)] += [placed_order]
for index, token_info in enumerate(group.tokens[:-1]): for index, token_info in enumerate(group.tokens[:-1]):
if token_info: if token_info:
intrinsic_deposit = token_info.root_bank.deposit_index * layout.deposits[index] intrinsic_deposit = token_info.root_bank.deposit_index * layout.deposits[index]
deposit = TokenValue(token_info.token, token_info.token.shift_to_decimals(intrinsic_deposit)) deposit = TokenValue(token_info.token, token_info.token.shift_to_decimals(intrinsic_deposit))
intrinsic_borrow = token_info.root_bank.borrow_index * layout.borrows[index] intrinsic_borrow = token_info.root_bank.borrow_index * layout.borrows[index]
borrow = TokenValue(token_info.token, token_info.token.shift_to_decimals(intrinsic_borrow)) borrow = TokenValue(token_info.token, token_info.token.shift_to_decimals(intrinsic_borrow))
perp_account = PerpAccount.from_layout(layout.perp_accounts[index], mngo_token_info.token) perp_open_orders = PerpOpenOrders(placed_orders_all_markets[index])
perp_account = PerpAccount.from_layout(
layout.perp_accounts[index], perp_open_orders, mngo_token_info.token)
spot_open_orders = layout.spot_open_orders[index] spot_open_orders = layout.spot_open_orders[index]
basket_item: AccountBasketBaseToken = AccountBasketBaseToken( basket_item: AccountBasketBaseToken = AccountBasketBaseToken(
token_info, deposit, borrow, spot_open_orders, perp_account) token_info, deposit, borrow, spot_open_orders, perp_account)

View File

@ -319,20 +319,19 @@ def build_compound_serum_place_order_instructions(context: Context, wallet: Wall
# #
def build_cancel_perp_order_instructions(context: Context, wallet: Wallet, account: Account, perp_market_details: PerpMarketDetails, order: Order) -> CombinableInstructions: def build_cancel_perp_order_instructions(context: Context, wallet: Wallet, account: Account, perp_market_details: PerpMarketDetails, order: Order, invalid_id_ok: bool) -> CombinableInstructions:
# Prefer cancelling by client ID so we don't have to keep track of the order side. # Prefer cancelling by client ID so we don't have to keep track of the order side.
if order.client_id != 0: if order.client_id != 0:
data: bytes = layouts.CANCEL_PERP_ORDER_BY_CLIENT_ID.build( data: bytes = layouts.CANCEL_PERP_ORDER_BY_CLIENT_ID.build(
{ {
"client_order_id": order.client_id "client_order_id": order.client_id,
"invalid_id_ok": invalid_id_ok
}) })
else: else:
# { buy: 0, sell: 1 }
raw_side: int = 1 if order.side == Side.SELL else 0
data = layouts.CANCEL_PERP_ORDER.build( data = layouts.CANCEL_PERP_ORDER.build(
{ {
"order_id": order.id, "order_id": order.id,
"side": raw_side "invalid_id_ok": invalid_id_ok
}) })
# Accounts expected by this instruction (both CANCEL_PERP_ORDER and CANCEL_PERP_ORDER_BY_CLIENT_ID are the same): # Accounts expected by this instruction (both CANCEL_PERP_ORDER and CANCEL_PERP_ORDER_BY_CLIENT_ID are the same):
@ -648,8 +647,15 @@ def build_spot_place_order_instructions(context: Context, wallet: Wallet, group:
base_token_info = base_token_infos[0] base_token_info = base_token_infos[0]
quote_token_info = group.shared_quote_token quote_token_info = group.shared_quote_token
root_bank: RootBank = quote_token_info.root_bank if side == Side.BUY else base_token_info.root_bank base_root_bank: RootBank = base_token_info.root_bank
node_bank: NodeBank = root_bank.pick_node_bank(context) base_node_bank: NodeBank = base_root_bank.pick_node_bank(context)
quote_root_bank: RootBank = quote_token_info.root_bank
quote_node_bank: NodeBank = quote_root_bank.pick_node_bank(context)
vault_signer = PublicKey.create_program_address(
[bytes(market.state.public_key()), market.state.vault_signer_nonce().to_bytes(8, byteorder="little")],
market.state.program_id(),
)
fee_discount_address_meta: typing.List[AccountMeta] = [] fee_discount_address_meta: typing.List[AccountMeta] = []
if fee_discount_address is not None: if fee_discount_address is not None:
@ -668,13 +674,18 @@ def build_spot_place_order_instructions(context: Context, wallet: Wallet, group:
AccountMeta(is_signer=False, is_writable=True, pubkey=market.state.event_queue()), AccountMeta(is_signer=False, is_writable=True, pubkey=market.state.event_queue()),
AccountMeta(is_signer=False, is_writable=True, pubkey=market.state.base_vault()), AccountMeta(is_signer=False, is_writable=True, pubkey=market.state.base_vault()),
AccountMeta(is_signer=False, is_writable=True, pubkey=market.state.quote_vault()), AccountMeta(is_signer=False, is_writable=True, pubkey=market.state.quote_vault()),
AccountMeta(is_signer=False, is_writable=False, pubkey=root_bank.address), AccountMeta(is_signer=False, is_writable=False, pubkey=base_root_bank.address),
AccountMeta(is_signer=False, is_writable=True, pubkey=node_bank.address), AccountMeta(is_signer=False, is_writable=True, pubkey=base_node_bank.address),
AccountMeta(is_signer=False, is_writable=True, pubkey=node_bank.vault), AccountMeta(is_signer=False, is_writable=True, pubkey=base_node_bank.vault),
AccountMeta(is_signer=False, is_writable=False, pubkey=quote_root_bank.address),
AccountMeta(is_signer=False, is_writable=True, pubkey=quote_node_bank.address),
AccountMeta(is_signer=False, is_writable=True, pubkey=quote_node_bank.vault),
AccountMeta(is_signer=False, is_writable=False, pubkey=TOKEN_PROGRAM_ID), AccountMeta(is_signer=False, is_writable=False, pubkey=TOKEN_PROGRAM_ID),
AccountMeta(is_signer=False, is_writable=False, pubkey=group.signer_key), AccountMeta(is_signer=False, is_writable=False, pubkey=group.signer_key),
AccountMeta(is_signer=False, is_writable=False, pubkey=SYSVAR_RENT_PUBKEY), AccountMeta(is_signer=False, is_writable=False, pubkey=SYSVAR_RENT_PUBKEY),
AccountMeta(is_signer=False, is_writable=False, pubkey=group.srm_vault or SYSTEM_PROGRAM_ADDRESS), AccountMeta(is_signer=False, is_writable=False, pubkey=vault_signer),
AccountMeta(is_signer=False, is_writable=False,
pubkey=group.msrm_vault or group.srm_vault or SYSTEM_PROGRAM_ADDRESS),
*list([AccountMeta(is_signer=False, is_writable=(oo_address == open_orders_address), *list([AccountMeta(is_signer=False, is_writable=(oo_address == open_orders_address),
pubkey=oo_address or SYSTEM_PROGRAM_ADDRESS) for oo_address in account.spot_open_orders]), pubkey=oo_address or SYSTEM_PROGRAM_ADDRESS) for oo_address in account.spot_open_orders]),
*fee_discount_address_meta *fee_discount_address_meta

View File

@ -326,6 +326,7 @@ MAX_NODE_BANKS: int = 8
QUOTE_INDEX: int = MAX_TOKENS - 1 QUOTE_INDEX: int = MAX_TOKENS - 1
MAX_BOOK_NODES: int = 1024 MAX_BOOK_NODES: int = 1024
MAX_ORDERS: int = 32 MAX_ORDERS: int = 32
MAX_PERP_OPEN_ORDERS: int = 64
DATA_TYPE = construct.Enum(construct.Int8ul, Group=0, Account=1, RootBank=2, DATA_TYPE = construct.Enum(construct.Int8ul, Group=0, Account=1, RootBank=2,
NodeBank=3, PerpMarket=4, Bids=5, Asks=6, Cache=7, EventQueue=8) NodeBank=3, PerpMarket=4, Bids=5, Asks=6, Cache=7, EventQueue=8)
@ -541,30 +542,6 @@ NODE_BANK = construct.Struct(
"vault" / PublicKeyAdapter() "vault" / PublicKeyAdapter()
) )
# # 🥭 PERP_OPEN_ORDERS
#
# Here's the [Rust structure](https://github.com/blockworks-foundation/mango-v3/blob/main/program/src/state.rs):
# ```
# #[derive(Copy, Clone, Pod)]
# #[repr(C)]
# pub struct PerpOpenOrders {
# pub bids_quantity: i64, // total contracts in sell orders
# pub asks_quantity: i64, // total quote currency in buy orders
# pub is_free_bits: u32,
# pub is_bid_bits: u32,
# pub orders: [i128; 32],
# pub client_order_ids: [u64; 32],
# }
# ```
PERP_OPEN_ORDERS = construct.Struct(
"bids_quantity" / SignedDecimalAdapter(),
"asks_quantity" / SignedDecimalAdapter(),
"free_slot_bits" / DecimalAdapter(4),
"is_bid_bits" / DecimalAdapter(4),
"orders" / construct.Array(MAX_ORDERS, SignedDecimalAdapter(16)),
"client_order_ids" / construct.Array(MAX_ORDERS, DecimalAdapter())
)
# # 🥭 PERP_ACCOUNT # # 🥭 PERP_ACCOUNT
# #
# Here's the [Rust structure](https://github.com/blockworks-foundation/mango-v3/blob/main/program/src/state.rs): # Here's the [Rust structure](https://github.com/blockworks-foundation/mango-v3/blob/main/program/src/state.rs):
@ -577,16 +554,31 @@ PERP_OPEN_ORDERS = construct.Struct(
# #
# pub long_settled_funding: I80F48, # pub long_settled_funding: I80F48,
# pub short_settled_funding: I80F48, # pub short_settled_funding: I80F48,
# pub open_orders: PerpOpenOrders, #
# pub liquidity_points: I80F48, # // *** orders related info
# pub bids_quantity: i64, // total contracts in sell orders
# pub asks_quantity: i64, // total quote currency in buy orders
#
# /// Amount that's on EventQueue waiting to be processed
# pub taker_base: i64,
# pub taker_quote: i64,
#
# pub mngo_accrued: u64,
# } # }
# ``` # ```
PERP_ACCOUNT = construct.Struct( PERP_ACCOUNT = construct.Struct(
"base_position" / SignedDecimalAdapter(), "base_position" / SignedDecimalAdapter(),
"quote_position" / FloatI80F48Adapter(), "quote_position" / FloatI80F48Adapter(),
"long_settled_funding" / FloatI80F48Adapter(), "long_settled_funding" / FloatI80F48Adapter(),
"short_settled_funding" / FloatI80F48Adapter(), "short_settled_funding" / FloatI80F48Adapter(),
"open_orders" / PERP_OPEN_ORDERS,
"bids_quantity" / SignedDecimalAdapter(),
"asks_quantity" / SignedDecimalAdapter(),
"taker_base" / SignedDecimalAdapter(),
"taker_quote" / SignedDecimalAdapter(),
"mngo_accrued" / DecimalAdapter(), "mngo_accrued" / DecimalAdapter(),
) )
@ -596,6 +588,7 @@ PERP_ACCOUNT = construct.Struct(
# ``` # ```
# pub const INFO_LEN: usize = 32; # pub const INFO_LEN: usize = 32;
# pub const MAX_NUM_IN_MARGIN_BASKET: u8 = 10; # pub const MAX_NUM_IN_MARGIN_BASKET: u8 = 10;
# pub const MAX_PERP_OPEN_ORDERS: usize = 64;
# #[derive(Copy, Clone, Pod, Loadable)] # #[derive(Copy, Clone, Pod, Loadable)]
# #[repr(C)] # #[repr(C)]
# pub struct MangoAccount { # pub struct MangoAccount {
@ -615,7 +608,13 @@ PERP_ACCOUNT = construct.Struct(
# // Perps related data # // Perps related data
# pub perp_accounts: [PerpAccount; MAX_PAIRS], # pub perp_accounts: [PerpAccount; MAX_PAIRS],
# #
# pub order_market: [u8; MAX_PERP_OPEN_ORDERS],
# pub order_side: [Side; MAX_PERP_OPEN_ORDERS],
# pub orders: [i128; MAX_PERP_OPEN_ORDERS],
# pub client_order_ids: [u64; MAX_PERP_OPEN_ORDERS],
#
# pub msrm_amount: u64, # pub msrm_amount: u64,
#
# /// This account cannot open new positions or borrow until `init_health >= 0` # /// This account cannot open new positions or borrow until `init_health >= 0`
# pub being_liquidated: bool, # pub being_liquidated: bool,
# #
@ -636,6 +635,10 @@ MANGO_ACCOUNT = construct.Struct(
"borrows" / construct.Array(MAX_TOKENS, FloatI80F48Adapter()), "borrows" / construct.Array(MAX_TOKENS, FloatI80F48Adapter()),
"spot_open_orders" / construct.Array(MAX_PAIRS, PublicKeyAdapter()), "spot_open_orders" / construct.Array(MAX_PAIRS, PublicKeyAdapter()),
"perp_accounts" / construct.Array(MAX_PAIRS, PERP_ACCOUNT), "perp_accounts" / construct.Array(MAX_PAIRS, PERP_ACCOUNT),
"order_market" / construct.Array(MAX_PERP_OPEN_ORDERS, DecimalAdapter(1)),
"order_side" / construct.Array(MAX_PERP_OPEN_ORDERS, DecimalAdapter(1)),
"order_ids" / construct.Array(MAX_PERP_OPEN_ORDERS, SignedDecimalAdapter(16)),
"client_order_ids" / construct.Array(MAX_PERP_OPEN_ORDERS, DecimalAdapter()),
"msrm_amount" / DecimalAdapter(), "msrm_amount" / DecimalAdapter(),
"being_liquidated" / DecimalAdapter(1), "being_liquidated" / DecimalAdapter(1),
"is_bankrupt" / DecimalAdapter(1), "is_bankrupt" / DecimalAdapter(1),
@ -1203,7 +1206,7 @@ CANCEL_PERP_ORDER = construct.Struct(
"variant" / construct.Const(14, construct.BytesInteger(4, swapped=True)), "variant" / construct.Const(14, construct.BytesInteger(4, swapped=True)),
"order_id" / DecimalAdapter(16), "order_id" / DecimalAdapter(16),
"side" / DecimalAdapter(4) # { buy: 0, sell: 1 } "invalid_id_ok" / construct.Flag
) )
@ -1327,7 +1330,8 @@ CANCEL_SPOT_ORDER = construct.Struct(
CANCEL_PERP_ORDER_BY_CLIENT_ID = construct.Struct( CANCEL_PERP_ORDER_BY_CLIENT_ID = construct.Struct(
"variant" / construct.Const(13, construct.BytesInteger(4, swapped=True)), "variant" / construct.Const(13, construct.BytesInteger(4, swapped=True)),
"client_order_id" / DecimalAdapter() "client_order_id" / DecimalAdapter(),
"invalid_id_ok" / construct.Flag
) )
# Run the Mango crank. # Run the Mango crank.

View File

@ -47,7 +47,7 @@ class MarketInstructionBuilder(metaclass=abc.ABCMeta):
self.logger: logging.Logger = logging.getLogger(self.__class__.__name__) self.logger: logging.Logger = logging.getLogger(self.__class__.__name__)
@abc.abstractmethod @abc.abstractmethod
def build_cancel_order_instructions(self, order: Order) -> CombinableInstructions: def build_cancel_order_instructions(self, order: Order, ok_if_missing: bool = False) -> CombinableInstructions:
raise NotImplementedError( raise NotImplementedError(
"MarketInstructionBuilder.build_cancel_order_instructions() is not implemented on the base type.") "MarketInstructionBuilder.build_cancel_order_instructions() is not implemented on the base type.")
@ -81,7 +81,7 @@ class NullMarketInstructionBuilder(MarketInstructionBuilder):
super().__init__() super().__init__()
self.symbol: str = symbol self.symbol: str = symbol
def build_cancel_order_instructions(self, order: Order) -> CombinableInstructions: def build_cancel_order_instructions(self, order: Order, ok_if_missing: bool = False) -> CombinableInstructions:
return CombinableInstructions.empty() return CombinableInstructions.empty()
def build_place_order_instructions(self, order: Order) -> CombinableInstructions: def build_place_order_instructions(self, order: Order) -> CombinableInstructions:

View File

@ -63,7 +63,7 @@ class MarketMaker:
cancellations = mango.CombinableInstructions.empty() cancellations = mango.CombinableInstructions.empty()
for to_cancel in reconciled.to_cancel: for to_cancel in reconciled.to_cancel:
self.logger.info(f"Cancelling {self.market.symbol} {to_cancel}") self.logger.info(f"Cancelling {self.market.symbol} {to_cancel}")
cancel = self.market_instruction_builder.build_cancel_order_instructions(to_cancel) cancel = self.market_instruction_builder.build_cancel_order_instructions(to_cancel, ok_if_missing=True)
cancellations += cancel cancellations += cancel
place_orders = mango.CombinableInstructions.empty() place_orders = mango.CombinableInstructions.empty()

View File

@ -55,7 +55,7 @@ class MarketOperations(metaclass=abc.ABCMeta):
self.logger: logging.Logger = logging.getLogger(self.__class__.__name__) self.logger: logging.Logger = logging.getLogger(self.__class__.__name__)
@abc.abstractmethod @abc.abstractmethod
def cancel_order(self, order: Order) -> typing.Sequence[str]: def cancel_order(self, order: Order, ok_if_missing: bool = False) -> typing.Sequence[str]:
raise NotImplementedError("MarketOperations.cancel_order() is not implemented on the base type.") raise NotImplementedError("MarketOperations.cancel_order() is not implemented on the base type.")
@abc.abstractmethod @abc.abstractmethod
@ -93,7 +93,7 @@ class NullMarketOperations(MarketOperations):
super().__init__() super().__init__()
self.market_name: str = market_name self.market_name: str = market_name
def cancel_order(self, order: Order) -> typing.Sequence[str]: def cancel_order(self, order: Order, ok_if_missing: bool = False) -> typing.Sequence[str]:
self.logger.info(f"Cancelling order {order}.") self.logger.info(f"Cancelling order {order}.")
return [""] return [""]

View File

@ -28,29 +28,38 @@ from .tokenvalue import TokenValue
# #
class PerpAccount: class PerpAccount:
def __init__(self, base_position: Decimal, quote_position: Decimal, long_settled_funding: Decimal, def __init__(self, base_position: Decimal, quote_position: Decimal, long_settled_funding: Decimal,
short_settled_funding: Decimal, mngo_accrued: TokenValue, open_orders: PerpOpenOrders): short_settled_funding: Decimal, bids_quantity: Decimal, asks_quantity: Decimal,
taker_base: Decimal, taker_quote: Decimal, mngo_accrued: TokenValue,
open_orders: PerpOpenOrders):
self.base_position: Decimal = base_position self.base_position: Decimal = base_position
self.quote_position: Decimal = quote_position self.quote_position: Decimal = quote_position
self.long_settled_funding: Decimal = long_settled_funding self.long_settled_funding: Decimal = long_settled_funding
self.short_settled_funding: Decimal = short_settled_funding self.short_settled_funding: Decimal = short_settled_funding
self.bids_quantity: Decimal = bids_quantity
self.asks_quantity: Decimal = asks_quantity
self.taker_base: Decimal = taker_base
self.taker_quote: Decimal = taker_quote
self.mngo_accrued: TokenValue = mngo_accrued self.mngo_accrued: TokenValue = mngo_accrued
self.open_orders: PerpOpenOrders = open_orders self.open_orders: PerpOpenOrders = open_orders
@staticmethod @staticmethod
def from_layout(layout: layouts.PERP_ACCOUNT, mngo_token: Token) -> "PerpAccount": def from_layout(layout: layouts.PERP_ACCOUNT, open_orders: PerpOpenOrders, mngo_token: Token) -> "PerpAccount":
base_position: Decimal = layout.base_position base_position: Decimal = layout.base_position
quote_position: Decimal = layout.quote_position quote_position: Decimal = layout.quote_position
long_settled_funding: Decimal = layout.long_settled_funding long_settled_funding: Decimal = layout.long_settled_funding
short_settled_funding: Decimal = layout.short_settled_funding short_settled_funding: Decimal = layout.short_settled_funding
bids_quantity: Decimal = layout.bids_quantity
asks_quantity: Decimal = layout.asks_quantity
taker_base: Decimal = layout.taker_base
taker_quote: Decimal = layout.taker_quote
mngo_accrued_raw: Decimal = layout.mngo_accrued mngo_accrued_raw: Decimal = layout.mngo_accrued
mngo_accrued: TokenValue = TokenValue(mngo_token, mngo_token.shift_to_decimals(mngo_accrued_raw)) mngo_accrued: TokenValue = TokenValue(mngo_token, mngo_token.shift_to_decimals(mngo_accrued_raw))
open_orders: PerpOpenOrders = PerpOpenOrders.from_layout(layout.open_orders) return PerpAccount(base_position, quote_position, long_settled_funding, short_settled_funding,
bids_quantity, asks_quantity, taker_base, taker_quote, mngo_accrued, open_orders)
return PerpAccount(base_position, quote_position, long_settled_funding, short_settled_funding, mngo_accrued, open_orders)
def __str__(self) -> str: def __str__(self) -> str:
if self.base_position == Decimal(0) and self.quote_position == Decimal(0) and self.long_settled_funding == Decimal(0) and self.short_settled_funding == Decimal(0) and self.mngo_accrued.value == Decimal(0) and self.open_orders.free_slot_bits == 0xFFFFFFFF: if self.base_position == Decimal(0) and self.quote_position == Decimal(0) and self.long_settled_funding == Decimal(0) and self.short_settled_funding == Decimal(0) and self.mngo_accrued.value == Decimal(0) and self.open_orders.empty:
return "« 𝙿𝚎𝚛𝚙𝙰𝚌𝚌𝚘𝚞𝚗𝚝 (empty) »" return "« 𝙿𝚎𝚛𝚙𝙰𝚌𝚌𝚘𝚞𝚗𝚝 (empty) »"
open_orders = f"{self.open_orders}".replace("\n", "\n ") open_orders = f"{self.open_orders}".replace("\n", "\n ")
return f"""« 𝙿𝚎𝚛𝚙𝙰𝚌𝚌𝚘𝚞𝚗𝚝 return f"""« 𝙿𝚎𝚛𝚙𝙰𝚌𝚌𝚘𝚞𝚗𝚝
@ -58,6 +67,10 @@ class PerpAccount:
Quote Position: {self.quote_position} Quote Position: {self.quote_position}
Long Settled Funding: {self.long_settled_funding} Long Settled Funding: {self.long_settled_funding}
Short Settled Funding: {self.short_settled_funding} Short Settled Funding: {self.short_settled_funding}
Bids Quantity: {self.bids_quantity}
Asks Quantity: {self.asks_quantity}
Taker Base: {self.taker_base}
Taker Quote: {self.taker_quote}
MNGO Accrued: {self.mngo_accrued} MNGO Accrued: {self.mngo_accrued}
OpenOrders: OpenOrders:
{open_orders} {open_orders}

View File

@ -51,11 +51,11 @@ class PerpMarketInstructionBuilder(MarketInstructionBuilder):
def load(context: Context, wallet: Wallet, group: Group, account: Account, perp_market: PerpMarket) -> "PerpMarketInstructionBuilder": def load(context: Context, wallet: Wallet, group: Group, account: Account, perp_market: PerpMarket) -> "PerpMarketInstructionBuilder":
return PerpMarketInstructionBuilder(context, wallet, group, account, perp_market) return PerpMarketInstructionBuilder(context, wallet, group, account, perp_market)
def build_cancel_order_instructions(self, order: Order) -> CombinableInstructions: def build_cancel_order_instructions(self, order: Order, ok_if_missing: bool = False) -> CombinableInstructions:
if self.perp_market.underlying_perp_market is None: if self.perp_market.underlying_perp_market is None:
raise Exception(f"PerpMarket {self.perp_market.symbol} has not been loaded.") raise Exception(f"PerpMarket {self.perp_market.symbol} has not been loaded.")
return build_cancel_perp_order_instructions( return build_cancel_perp_order_instructions(
self.context, self.wallet, self.account, self.perp_market.underlying_perp_market, order) self.context, self.wallet, self.account, self.perp_market.underlying_perp_market, order, ok_if_missing)
def build_place_order_instructions(self, order: Order) -> CombinableInstructions: def build_place_order_instructions(self, order: Order) -> CombinableInstructions:
if self.perp_market.underlying_perp_market is None: if self.perp_market.underlying_perp_market is None:

View File

@ -46,10 +46,11 @@ class PerpMarketOperations(MarketOperations):
self.account: Account = account self.account: Account = account
self.perp_market: PerpMarket = perp_market self.perp_market: PerpMarket = perp_market
def cancel_order(self, order: Order) -> typing.Sequence[str]: def cancel_order(self, order: Order, ok_if_missing: bool = False) -> typing.Sequence[str]:
self.logger.info(f"Cancelling {self.market_name} order {order}.") self.logger.info(f"Cancelling {self.market_name} order {order}.")
signers: CombinableInstructions = CombinableInstructions.from_wallet(self.wallet) signers: CombinableInstructions = CombinableInstructions.from_wallet(self.wallet)
cancel: CombinableInstructions = self.market_instruction_builder.build_cancel_order_instructions(order) cancel: CombinableInstructions = self.market_instruction_builder.build_cancel_order_instructions(
order, ok_if_missing=ok_if_missing)
accounts_to_crank = self.perp_market.accounts_to_crank(self.context, self.account.address) accounts_to_crank = self.perp_market.accounts_to_crank(self.context, self.account.address)
crank = self.market_instruction_builder.build_crank_instructions(accounts_to_crank) crank = self.market_instruction_builder.build_crank_instructions(accounts_to_crank)
settle = self.market_instruction_builder.build_settle_instructions() settle = self.market_instruction_builder.build_settle_instructions()

View File

@ -16,40 +16,23 @@
import typing import typing
from decimal import Decimal
from .layouts import layouts
from .openorders import PlacedOrder from .openorders import PlacedOrder
# # 🥭 PerpOpenOrders class # # 🥭 PerpOpenOrders class
# #
class PerpOpenOrders: class PerpOpenOrders:
def __init__(self, bids_quantity: Decimal, asks_quantity: Decimal, free_slot_bits: Decimal, def __init__(self, placed_orders: typing.Sequence[PlacedOrder]):
is_bid_bits: Decimal, placed_orders: typing.Sequence[PlacedOrder]):
self.bids_quantity: Decimal = bids_quantity
self.asks_quantity: Decimal = asks_quantity
self.free_slot_bits: Decimal = free_slot_bits
self.is_bid_bits: Decimal = is_bid_bits
self.placed_orders: typing.Sequence[PlacedOrder] = placed_orders self.placed_orders: typing.Sequence[PlacedOrder] = placed_orders
@staticmethod @property
def from_layout(layout: layouts.PERP_OPEN_ORDERS) -> "PerpOpenOrders": def empty(self) -> bool:
bids_quantity: Decimal = layout.bids_quantity return len(self.placed_orders) == 0
asks_quantity: Decimal = layout.asks_quantity
free_slot_bits: Decimal = layout.free_slot_bits
is_bid_bits: Decimal = layout.is_bid_bits
placed_orders = PlacedOrder.build_from_open_orders_data(
layout.free_slot_bits, layout.is_bid_bits, layout.orders, layout.client_order_ids)
return PerpOpenOrders(bids_quantity, asks_quantity, free_slot_bits, is_bid_bits, placed_orders)
def __str__(self) -> str: def __str__(self) -> str:
placed_orders = "\n ".join(map(str, self.placed_orders)) or "None" placed_orders = "\n ".join(map(str, self.placed_orders)) or "None"
return f"""« 𝙿𝚎𝚛𝚙𝙾𝚙𝚎𝚗𝙾𝚛𝚍𝚎𝚛𝚜 return f"""« 𝙿𝚎𝚛𝚙𝙾𝚙𝚎𝚗𝙾𝚛𝚍𝚎𝚛𝚜
Bids Quantity: {self.bids_quantity}
Asks Quantity: {self.asks_quantity}
Orders: Orders:
{placed_orders} {placed_orders}
»""" »"""

View File

@ -83,7 +83,7 @@ class SerumMarketInstructionBuilder(MarketInstructionBuilder):
return SerumMarketInstructionBuilder(context, wallet, serum_market, raw_market, base_token_account, quote_token_account, open_orders_address, fee_discount_token_address) return SerumMarketInstructionBuilder(context, wallet, serum_market, raw_market, base_token_account, quote_token_account, open_orders_address, fee_discount_token_address)
def build_cancel_order_instructions(self, order: Order) -> CombinableInstructions: def build_cancel_order_instructions(self, order: Order, ok_if_missing: bool = False) -> CombinableInstructions:
# For us to cancel an order, an open_orders account must already exist (or have existed). # For us to cancel an order, an open_orders account must already exist (or have existed).
if self.open_orders_address is None: if self.open_orders_address is None:
raise Exception(f"Cannot cancel order with client ID {order.client_id} - no OpenOrders account.") raise Exception(f"Cannot cancel order with client ID {order.client_id} - no OpenOrders account.")

View File

@ -42,10 +42,11 @@ class SerumMarketOperations(MarketOperations):
self.serum_market: SerumMarket = serum_market self.serum_market: SerumMarket = serum_market
self.market_instruction_builder: SerumMarketInstructionBuilder = market_instruction_builder self.market_instruction_builder: SerumMarketInstructionBuilder = market_instruction_builder
def cancel_order(self, order: Order) -> typing.Sequence[str]: def cancel_order(self, order: Order, ok_if_missing: bool = False) -> typing.Sequence[str]:
self.logger.info(f"Cancelling {self.serum_market.symbol} order {order}.") self.logger.info(f"Cancelling {self.serum_market.symbol} order {order}.")
signers: CombinableInstructions = CombinableInstructions.from_wallet(self.wallet) signers: CombinableInstructions = CombinableInstructions.from_wallet(self.wallet)
cancel: CombinableInstructions = self.market_instruction_builder.build_cancel_order_instructions(order) cancel: CombinableInstructions = self.market_instruction_builder.build_cancel_order_instructions(
order, ok_if_missing=ok_if_missing)
crank: CombinableInstructions = self._build_crank() crank: CombinableInstructions = self._build_crank()
settle: CombinableInstructions = self.market_instruction_builder.build_settle_instructions() settle: CombinableInstructions = self.market_instruction_builder.build_settle_instructions()
return (signers + cancel + crank + settle).execute(self.context) return (signers + cancel + crank + settle).execute(self.context)

View File

@ -83,7 +83,7 @@ class SpotMarketInstructionBuilder(MarketInstructionBuilder):
return SpotMarketInstructionBuilder(context, wallet, group, account, spot_market, raw_market, base_token_account, quote_token_account, market_index, fee_discount_token_address) return SpotMarketInstructionBuilder(context, wallet, group, account, spot_market, raw_market, base_token_account, quote_token_account, market_index, fee_discount_token_address)
def build_cancel_order_instructions(self, order: Order) -> CombinableInstructions: def build_cancel_order_instructions(self, order: Order, ok_if_missing: bool = False) -> CombinableInstructions:
if self.open_orders_address is None: if self.open_orders_address is None:
return CombinableInstructions.empty() return CombinableInstructions.empty()

View File

@ -49,10 +49,11 @@ class SpotMarketOperations(MarketOperations):
self.market_index: int = group.find_spot_market_index(spot_market.address) self.market_index: int = group.find_spot_market_index(spot_market.address)
self.open_orders_address: typing.Optional[PublicKey] = self.account.spot_open_orders[self.market_index] self.open_orders_address: typing.Optional[PublicKey] = self.account.spot_open_orders[self.market_index]
def cancel_order(self, order: Order) -> typing.Sequence[str]: def cancel_order(self, order: Order, ok_if_missing: bool = False) -> typing.Sequence[str]:
self.logger.info(f"Cancelling {self.spot_market.symbol} order {order}.") self.logger.info(f"Cancelling {self.spot_market.symbol} order {order}.")
signers: CombinableInstructions = CombinableInstructions.from_wallet(self.wallet) signers: CombinableInstructions = CombinableInstructions.from_wallet(self.wallet)
cancel: CombinableInstructions = self.market_instruction_builder.build_cancel_order_instructions(order) cancel: CombinableInstructions = self.market_instruction_builder.build_cancel_order_instructions(
order, ok_if_missing=ok_if_missing)
crank: CombinableInstructions = self._build_crank(add_self=True) crank: CombinableInstructions = self._build_crank(add_self=True)
settle: CombinableInstructions = self.market_instruction_builder.build_settle_instructions() settle: CombinableInstructions = self.market_instruction_builder.build_settle_instructions()

View File

@ -7,7 +7,7 @@ def context_has_default_values(ctx):
assert ctx.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E") assert ctx.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E")
assert ctx.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY") assert ctx.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
assert ctx.group_name == "devnet.1" assert ctx.group_name == "devnet.1"
assert ctx.group_id == PublicKey("D3H3f29tcGNeEgk4bArKcRKQv8V4zCUFrj1sGXaHwgvM") assert ctx.group_id == PublicKey("4XKVThVcLBdN9E2CDuuNmJejCVbVjqvb8VGjoGyHz8A4")
def test_context_default_exists(): def test_context_default_exists():
@ -27,7 +27,7 @@ def test_context_default_values():
# assert derived.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E") # assert derived.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E")
# assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY") # assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
# assert derived.group_name == "devnet.1" # assert derived.group_name == "devnet.1"
# assert derived.group_id == PublicKey("D3H3f29tcGNeEgk4bArKcRKQv8V4zCUFrj1sGXaHwgvM") # assert derived.group_id == PublicKey("4XKVThVcLBdN9E2CDuuNmJejCVbVjqvb8VGjoGyHz8A4")
# context_has_default_values(mango.ContextBuilder.default()) # context_has_default_values(mango.ContextBuilder.default())
@ -37,7 +37,7 @@ def test_new_from_cluster_url():
assert derived.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E") assert derived.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E")
assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY") assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
assert derived.group_name == "devnet.1" assert derived.group_name == "devnet.1"
assert derived.group_id == PublicKey("D3H3f29tcGNeEgk4bArKcRKQv8V4zCUFrj1sGXaHwgvM") assert derived.group_id == PublicKey("4XKVThVcLBdN9E2CDuuNmJejCVbVjqvb8VGjoGyHz8A4")
context_has_default_values(mango.ContextBuilder.default()) context_has_default_values(mango.ContextBuilder.default())
@ -49,17 +49,17 @@ def test_new_from_group_name():
# Should update both of these values on new group name. # Should update both of these values on new group name.
assert derived.group_name == "devnet.1" assert derived.group_name == "devnet.1"
assert derived.group_id == PublicKey("D3H3f29tcGNeEgk4bArKcRKQv8V4zCUFrj1sGXaHwgvM") assert derived.group_id == PublicKey("4XKVThVcLBdN9E2CDuuNmJejCVbVjqvb8VGjoGyHz8A4")
context_has_default_values(mango.ContextBuilder.default()) context_has_default_values(mango.ContextBuilder.default())
def test_new_from_group_id(): def test_new_from_group_id():
context_has_default_values(mango.ContextBuilder.default()) context_has_default_values(mango.ContextBuilder.default())
derived = mango.ContextBuilder.default().new_from_group_id(PublicKey("D3H3f29tcGNeEgk4bArKcRKQv8V4zCUFrj1sGXaHwgvM")) derived = mango.ContextBuilder.default().new_from_group_id(PublicKey("4XKVThVcLBdN9E2CDuuNmJejCVbVjqvb8VGjoGyHz8A4"))
assert derived.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E") assert derived.program_id == PublicKey("5fP7Z7a87ZEVsKr2tQPApdtq83GcTW4kz919R6ou5h5E")
assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY") assert derived.dex_program_id == PublicKey("DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY")
# Should update both of these values on new group ID. # Should update both of these values on new group ID.
assert derived.group_name == "devnet.1" assert derived.group_name == "devnet.1"
assert derived.group_id == PublicKey("D3H3f29tcGNeEgk4bArKcRKQv8V4zCUFrj1sGXaHwgvM") assert derived.group_id == PublicKey("4XKVThVcLBdN9E2CDuuNmJejCVbVjqvb8VGjoGyHz8A4")
context_has_default_values(mango.ContextBuilder.default()) context_has_default_values(mango.ContextBuilder.default())