Ts keeper (backup for rust keeper) (#546)
* keeper Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * update Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * format Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * update defaults Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix script Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> --------- Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
6ac9f19287
commit
2f1839cb98
1
Procfile
1
Procfile
|
@ -1 +1,2 @@
|
|||
mm: node dist/cjs/scripts/mm/market-maker.js
|
||||
keeper: node dist/cjs/scripts/keeper/keeper.js
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
|
||||
import {
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
NATIVE_MINT,
|
||||
TOKEN_PROGRAM_ID,
|
||||
} from '../../src/utils/spl';
|
||||
import {
|
||||
AddressLookupTableProgram,
|
||||
ComputeBudgetProgram,
|
||||
|
@ -30,6 +25,11 @@ import {
|
|||
} from '../../src/clientIxParamBuilder';
|
||||
import { MANGO_V4_ID, OPENBOOK_PROGRAM_ID } from '../../src/constants';
|
||||
import { buildVersionedTx, toNative } from '../../src/utils';
|
||||
import {
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
NATIVE_MINT,
|
||||
TOKEN_PROGRAM_ID,
|
||||
} from '../../src/utils/spl';
|
||||
|
||||
const GROUP_NUM = Number(process.env.GROUP_NUM || 0);
|
||||
|
||||
|
@ -529,7 +529,7 @@ async function makeTokenReduceonly() {
|
|||
await client.tokenEdit(
|
||||
group,
|
||||
bank.mint,
|
||||
Builder(NullTokenEditParams).reduceOnly(true).build(),
|
||||
Builder(NullTokenEditParams).reduceOnly(0).build(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
|
||||
import { Cluster, Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import chunk from 'lodash/chunk';
|
||||
import range from 'lodash/range';
|
||||
import { Group } from '../../src/accounts/group';
|
||||
import { FillEvent, OutEvent, PerpEventQueue } from '../../src/accounts/perp';
|
||||
import { MangoClient } from '../../src/client';
|
||||
import { MANGO_V4_ID } from '../../src/constants';
|
||||
import { sendTransaction } from '../../src/utils/rpc';
|
||||
|
||||
// Env vars
|
||||
const CLUSTER: Cluster =
|
||||
(process.env.CLUSTER_OVERRIDE as Cluster) || 'mainnet-beta';
|
||||
const CLUSTER_URL =
|
||||
process.env.CLUSTER_URL_OVERRIDE || process.env.MB_CLUSTER_URL;
|
||||
const USER_KEYPAIR =
|
||||
process.env.USER_KEYPAIR_OVERRIDE || process.env.MB_PAYER_KEYPAIR;
|
||||
const MANGO_ACCOUNT_PK = process.env.MANGO_ACCOUNT_PK || '';
|
||||
const INTERVAL_UPDATE_BANKS = Number(process.env.INTERVAL_UPDATE_BANKS || 60);
|
||||
const INTERVAL_CONSUME_EVENTS = Number(
|
||||
process.env.INTERVAL_CONSUME_EVENTS || 5,
|
||||
);
|
||||
const INTERVAL_UPDATE_FUNDING = Number(
|
||||
process.env.INTERVAL_UPDATE_FUNDING || 5,
|
||||
);
|
||||
const INTERVAL_CHECK_NEW_LISTINGS_AND_ABORT = Number(
|
||||
process.env.INTERVAL_CHECK_NEW_LISTINGS_AND_ABORT || 120,
|
||||
);
|
||||
|
||||
async function updateBanks(client: MangoClient, group: Group): Promise<void> {
|
||||
console.log('Starting updateBanks loop');
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const tokenIndices = Array.from(group.banksMapByTokenIndex.keys());
|
||||
const tokenIndicesByChunks = chunk(tokenIndices, 10);
|
||||
tokenIndicesByChunks.map(async (tokenIndices) => {
|
||||
const ixs = await Promise.all(
|
||||
tokenIndices.map((ti) =>
|
||||
client.tokenUpdateIndexAndRateIx(
|
||||
group,
|
||||
group.getFirstBankByTokenIndex(ti).mint,
|
||||
),
|
||||
),
|
||||
);
|
||||
try {
|
||||
const sig = await sendTransaction(
|
||||
client.program.provider as AnchorProvider,
|
||||
ixs,
|
||||
group.addressLookupTablesList,
|
||||
{ prioritizationFee: true },
|
||||
);
|
||||
|
||||
console.log(
|
||||
` - Token update index and rate success, tokenIndices - ${tokenIndices}, sig https://explorer.solana.com/tx/${sig}`,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
` - Token update index and rate error, tokenIndices - ${tokenIndices}, e - ${e}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, INTERVAL_UPDATE_BANKS * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
async function consumeEvents(client: MangoClient, group: Group): Promise<void> {
|
||||
console.log('Starting consumeEvents loop');
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const perpMarketIndices = Array.from(
|
||||
group.perpMarketsMapByMarketIndex.keys(),
|
||||
);
|
||||
for (const perpMarketIndex of perpMarketIndices) {
|
||||
for (const unused of range(0, 10)) {
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
||||
const eq = await perpMarket.loadEventQueue(client);
|
||||
const events = eq.getUnconsumedEvents().slice(0, 10);
|
||||
const accounts: Set<PublicKey> = new Set();
|
||||
for (const event of events) {
|
||||
if (event.eventType === PerpEventQueue.FILL_EVENT_TYPE) {
|
||||
accounts.add((event as FillEvent).maker);
|
||||
accounts.add((event as FillEvent).taker);
|
||||
} else if (event.eventType === PerpEventQueue.OUT_EVENT_TYPE) {
|
||||
accounts.add((event as OutEvent).owner);
|
||||
} else if (event.eventType === PerpEventQueue.LIQUIDATE_EVENT_TYPE) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const sig = await sendTransaction(
|
||||
client.program.provider as AnchorProvider,
|
||||
[
|
||||
await client.perpConsumeEventsIx(
|
||||
group,
|
||||
perpMarketIndex,
|
||||
Array.from(accounts),
|
||||
10,
|
||||
),
|
||||
],
|
||||
group.addressLookupTablesList,
|
||||
{ prioritizationFee: true },
|
||||
);
|
||||
|
||||
console.log(
|
||||
` - Consume events success, perpMarketIndex - ${perpMarketIndex}, sig https://explorer.solana.com/tx/${sig}`,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
` - Consume events error, perpMarketIndex - ${perpMarketIndex}, e - ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, INTERVAL_CONSUME_EVENTS * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
async function updateFunding(client: MangoClient, group: Group): Promise<void> {
|
||||
console.log('Starting updateFunding loop');
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const perpMarketIndices = Array.from(
|
||||
group.perpMarketsMapByMarketIndex.keys(),
|
||||
);
|
||||
for (const perpMarketIndex of perpMarketIndices) {
|
||||
try {
|
||||
const sig = await sendTransaction(
|
||||
client.program.provider as AnchorProvider,
|
||||
[
|
||||
await client.perpUpdateFundingIx(
|
||||
group,
|
||||
group.getPerpMarketByMarketIndex(perpMarketIndex),
|
||||
),
|
||||
],
|
||||
group.addressLookupTablesList,
|
||||
{ prioritizationFee: true },
|
||||
);
|
||||
|
||||
console.log(
|
||||
` - Update funding success, perpMarketIndex - ${perpMarketIndex}, sig https://explorer.solana.com/tx/${sig}`,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
` - Update funding error, perpMarketIndex - ${perpMarketIndex}, e - ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise((r) => setTimeout(r, INTERVAL_UPDATE_FUNDING * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
async function checkNewListingsAndAbort(
|
||||
client: MangoClient,
|
||||
group: Group,
|
||||
): Promise<void> {
|
||||
console.log('Starting checkNewListingsAndAbort loop');
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const freshlyFetchedGroup = await client.getGroup(group.publicKey);
|
||||
if (
|
||||
freshlyFetchedGroup.banksMapByTokenIndex.size !=
|
||||
group.banksMapByTokenIndex.size ||
|
||||
freshlyFetchedGroup.perpMarketsMapByMarketIndex.size !=
|
||||
group.perpMarketsMapByMarketIndex.size
|
||||
) {
|
||||
process.exit();
|
||||
}
|
||||
await new Promise((r) =>
|
||||
setTimeout(r, INTERVAL_CHECK_NEW_LISTINGS_AND_ABORT * 1000),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function keeper(): Promise<void> {
|
||||
// Load client
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(CLUSTER_URL!, options);
|
||||
const user = Keypair.fromSecretKey(
|
||||
Buffer.from(
|
||||
JSON.parse(
|
||||
process.env.KEYPAIR || fs.readFileSync(USER_KEYPAIR!, 'utf-8'),
|
||||
),
|
||||
),
|
||||
);
|
||||
const userWallet = new Wallet(user);
|
||||
const userProvider = new AnchorProvider(connection, userWallet, options);
|
||||
const client = await MangoClient.connect(
|
||||
userProvider,
|
||||
CLUSTER,
|
||||
MANGO_V4_ID[CLUSTER],
|
||||
{
|
||||
idsSource: 'get-program-accounts',
|
||||
},
|
||||
);
|
||||
|
||||
const mangoAccount = await client.getMangoAccount(
|
||||
new PublicKey(MANGO_ACCOUNT_PK),
|
||||
);
|
||||
const group = await client.getGroup(mangoAccount.group);
|
||||
await group.reloadAll(client);
|
||||
|
||||
updateBanks(client, group);
|
||||
consumeEvents(client, group);
|
||||
updateFunding(client, group);
|
||||
checkNewListingsAndAbort(client, group);
|
||||
}
|
||||
|
||||
keeper();
|
|
@ -2496,8 +2496,19 @@ export class MangoClient {
|
|||
accounts: PublicKey[],
|
||||
limit: number,
|
||||
): Promise<TransactionSignature> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.perpConsumeEventsIx(group, perpMarketIndex, accounts, limit),
|
||||
]);
|
||||
}
|
||||
|
||||
public async perpConsumeEventsIx(
|
||||
group: Group,
|
||||
perpMarketIndex: PerpMarketIndex,
|
||||
accounts: PublicKey[],
|
||||
limit: number,
|
||||
): Promise<TransactionInstruction> {
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
||||
const ix = await this.program.methods
|
||||
return await this.program.methods
|
||||
.perpConsumeEvents(new BN(limit))
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
|
@ -2511,7 +2522,6 @@ export class MangoClient {
|
|||
),
|
||||
)
|
||||
.instruction();
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [ix]);
|
||||
}
|
||||
|
||||
public async perpConsumeAllEvents(
|
||||
|
@ -2734,14 +2744,23 @@ export class MangoClient {
|
|||
);
|
||||
}
|
||||
|
||||
public async updateIndexAndRate(
|
||||
public async tokenUpdateIndexAndRate(
|
||||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
): Promise<TransactionSignature> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.tokenUpdateIndexAndRateIx(group, mintPk),
|
||||
]);
|
||||
}
|
||||
|
||||
public async tokenUpdateIndexAndRateIx(
|
||||
group: Group,
|
||||
mintPk: PublicKey,
|
||||
): Promise<TransactionInstruction> {
|
||||
const bank = group.getFirstBankByMint(mintPk);
|
||||
const mintInfo = group.mintInfosMapByMint.get(mintPk.toString())!;
|
||||
|
||||
const ix = await this.program.methods
|
||||
return await this.program.methods
|
||||
.tokenUpdateIndexAndRate()
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
|
@ -2757,7 +2776,6 @@ export class MangoClient {
|
|||
} as AccountMeta,
|
||||
])
|
||||
.instruction();
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [ix]);
|
||||
}
|
||||
|
||||
/// liquidations
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
},
|
||||
"include": [
|
||||
"ts/client/src",
|
||||
"ts/client/scripts"
|
||||
"ts/client/scripts",
|
||||
"ts/client/scripts/mm",
|
||||
"ts/client/scripts/keeper"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue