From f8a38e079fce58ee825df0384a625d30a5147305 Mon Sep 17 00:00:00 2001 From: Nour Alharithi Date: Mon, 4 Dec 2023 12:33:59 -0800 Subject: [PATCH 1/2] no rpc spam --- src/bots/ifRevenueSettler.ts | 18 ++++++++++++++++-- src/bots/userIdleFlipper.ts | 31 ++++++++++++++++++++++++------- src/bots/userPnlSettler.ts | 19 +++++++++++++++++-- src/index.ts | 17 ++++++++++------- 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/bots/ifRevenueSettler.ts b/src/bots/ifRevenueSettler.ts index afa7f3b2..c72ebc20 100644 --- a/src/bots/ifRevenueSettler.ts +++ b/src/bots/ifRevenueSettler.ts @@ -3,6 +3,8 @@ import { SpotMarketAccount, OraclePriceData, ZERO, + DriftClientConfig, + BulkAccountLoader, } from '@drift-labs/sdk'; import { Mutex } from 'async-mutex'; @@ -31,11 +33,23 @@ export class IFRevenueSettlerBot implements Bot { private watchdogTimerMutex = new Mutex(); private watchdogTimerLastPatTime = Date.now(); - constructor(driftClient: DriftClient, config: BaseBotConfig) { + constructor(driftClientConfigs: DriftClientConfig, config: BaseBotConfig) { this.name = config.botId; this.dryRun = config.dryRun; this.runOnce = config.runOnce || false; - this.driftClient = driftClient; + const bulkAccountLoader = new BulkAccountLoader( + driftClientConfigs.connection, + driftClientConfigs.connection.commitment || 'processed', + 0 + ); + this.driftClient = new DriftClient( + Object.assign({}, driftClientConfigs, { + accountSubscription: { + type: 'polling', + accountLoader: bulkAccountLoader, + }, + }) + ); } public async init() { diff --git a/src/bots/userIdleFlipper.ts b/src/bots/userIdleFlipper.ts index 5ed493f5..a9156950 100644 --- a/src/bots/userIdleFlipper.ts +++ b/src/bots/userIdleFlipper.ts @@ -5,6 +5,8 @@ import { PublicKey, UserMap, TxSigAndSlot, + DriftClientConfig, + BulkAccountLoader, } from '@drift-labs/sdk'; import { Mutex } from 'async-mutex'; @@ -32,16 +34,31 @@ export class UserIdleFlipperBot implements Bot { private watchdogTimerMutex = new Mutex(); private watchdogTimerLastPatTime = Date.now(); - constructor( - driftClient: DriftClient, - config: BaseBotConfig, - userMap: UserMap - ) { + constructor(driftClientConfigs: DriftClientConfig, config: BaseBotConfig) { this.name = config.botId; this.dryRun = config.dryRun; this.runOnce = config.runOnce || false; - this.driftClient = driftClient; - this.userMap = userMap; + const bulkAccountLoader = new BulkAccountLoader( + driftClientConfigs.connection, + driftClientConfigs.connection.commitment || 'processed', + 0 + ); + this.driftClient = new DriftClient( + Object.assign({}, driftClientConfigs, { + accountSubscription: { + type: 'polling', + accountLoader: bulkAccountLoader, + }, + }) + ); + this.userMap = new UserMap( + this.driftClient, + { + type: 'polling', + accountLoader: bulkAccountLoader, + }, + false + ); } public async init() { diff --git a/src/bots/userPnlSettler.ts b/src/bots/userPnlSettler.ts index e3f8033d..77a7d031 100644 --- a/src/bots/userPnlSettler.ts +++ b/src/bots/userPnlSettler.ts @@ -21,6 +21,8 @@ import { calculateNetUserPnl, BASE_PRECISION, QUOTE_SPOT_MARKET_INDEX, + DriftClientConfig, + BulkAccountLoader, } from '@drift-labs/sdk'; import { Mutex } from 'async-mutex'; @@ -69,14 +71,27 @@ export class UserPnlSettlerBot implements Bot { private watchdogTimerLastPatTime = Date.now(); constructor( - driftClient: DriftClient, + driftClientConfigs: DriftClientConfig, config: BaseBotConfig, userMap: UserMap ) { this.name = config.botId; this.dryRun = config.dryRun; this.runOnce = config.runOnce || false; - this.driftClient = driftClient; + + const bulkAccountLoader = new BulkAccountLoader( + driftClientConfigs.connection, + driftClientConfigs.connection.commitment || 'processed', + 0 + ); + this.driftClient = new DriftClient( + Object.assign({}, driftClientConfigs, { + accountSubscription: { + type: 'polling', + accountLoader: bulkAccountLoader, + }, + }) + ); this.userMap = userMap; } diff --git a/src/index.ts b/src/index.ts index f02507ca..bd615bfa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -257,7 +257,7 @@ const runBot = async () => { getMarketsAndOraclesForSubscription(config.global.driftEnv!)); } - const driftClient = new DriftClient({ + const driftClientConfig = { connection, wallet, programID: driftPublicKey, @@ -271,7 +271,8 @@ const runBot = async () => { activeSubAccountId: config.global.subaccounts![0], subAccountIds: config.global.subaccounts ?? [0], txSender, - }); + }; + const driftClient = new DriftClient(driftClientConfig); let eventSubscriber: EventSubscriber | undefined = undefined; if (config.global.eventSubscriber) { @@ -640,7 +641,7 @@ const runBot = async () => { await userMap.subscribe(); bots.push( new UserPnlSettlerBot( - driftClient, + driftClientConfig, config.botConfigs!.userPnlSettler!, userMap ) @@ -651,16 +652,18 @@ const runBot = async () => { await userMap.subscribe(); bots.push( new UserIdleFlipperBot( - driftClient, - config.botConfigs!.userIdleFlipper!, - userMap + driftClientConfig, + config.botConfigs!.userIdleFlipper! ) ); } if (configHasBot(config, 'ifRevenueSettler')) { bots.push( - new IFRevenueSettlerBot(driftClient, config.botConfigs!.ifRevenueSettler!) + new IFRevenueSettlerBot( + driftClientConfig, + config.botConfigs!.ifRevenueSettler! + ) ); } From 368ef45252bd2f16b79d1935dda3797cd80c3ffe Mon Sep 17 00:00:00 2001 From: Nour Alharithi Date: Tue, 5 Dec 2023 09:02:35 -0800 Subject: [PATCH 2/2] reset --- example.config.yaml | 2 - jitMaker.config.yaml | 2 - lite.config.yaml | 32 +++- src/bots/ifRevenueSettler.ts | 6 + src/bots/userIdleFlipper.ts | 7 + src/bots/userPnlSettler.ts | 23 ++- src/index.ts | 284 ++++++++++++++++------------------- 7 files changed, 182 insertions(+), 174 deletions(-) diff --git a/example.config.yaml b/example.config.yaml index 8410d2a8..794b8f76 100644 --- a/example.config.yaml +++ b/example.config.yaml @@ -13,8 +13,6 @@ global: initUser: false # initialize user on startup testLiveness: false # test liveness, by failing liveness test after 1 min - cancelOpenOrders: false # cancel open orders on startup - closeOpenPositions: false # close all open positions # Force deposit this amount of USDC to collateral account, the program will # end after the deposit transaction is sent diff --git a/jitMaker.config.yaml b/jitMaker.config.yaml index 8d170934..2ed876d7 100644 --- a/jitMaker.config.yaml +++ b/jitMaker.config.yaml @@ -14,8 +14,6 @@ global: initUser: false # initialize user on startup testLiveness: false # test liveness, by failing liveness test after 1 min - cancelOpenOrders: false # cancel open orders on startup - closeOpenPositions: false # close all open positions # Force deposit this amount of USDC to collateral account, the program will # end after the deposit transaction is sent diff --git a/lite.config.yaml b/lite.config.yaml index 602b50ec..1c991bde 100644 --- a/lite.config.yaml +++ b/lite.config.yaml @@ -12,8 +12,6 @@ global: initUser: false # initialize user on startup testLiveness: false # test liveness, by failing liveness test after 1 min - cancelOpenOrders: false # cancel open orders on startup - closeOpenPositions: false # close all open positions # Force deposit this amount of USDC to collateral account, the program will # end after the deposit transaction is sent @@ -45,7 +43,7 @@ global: # Bot specific configs are below enabledBots: # Perp order filler bot - - fillerLite + # - fillerLite # Spot order filler bot # - spotFiller @@ -68,6 +66,8 @@ enabledBots: # settles negative PnLs for users (may want to run with runOnce: true) # - userPnlSettler + - markTwapCrank + # below are bot configs botConfigs: fillerLite: @@ -79,6 +79,28 @@ botConfigs: # will revert a transaction during simulation if a fill fails, this will save on tx fees, # and be friendlier for use with services like Jito. # Default is true - revertOnFailure: true - + markTwapCrank: + botId: "mark-twap-cranker" + dryRun: false + metricsPort: 9465 + crankIntervalToMarketIndicies: + 15000: + - 0 + - 1 + - 2 + 60000: + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 diff --git a/src/bots/ifRevenueSettler.ts b/src/bots/ifRevenueSettler.ts index c72ebc20..b4cab094 100644 --- a/src/bots/ifRevenueSettler.ts +++ b/src/bots/ifRevenueSettler.ts @@ -54,6 +54,12 @@ export class IFRevenueSettlerBot implements Bot { public async init() { logger.info(`${this.name} initing`); + await this.driftClient.subscribe(); + if (!(await this.driftClient.getUser().exists())) { + throw new Error( + `User for ${this.driftClient.wallet.publicKey.toString()} does not exist` + ); + } } public async reset() { diff --git a/src/bots/userIdleFlipper.ts b/src/bots/userIdleFlipper.ts index a9156950..efde6756 100644 --- a/src/bots/userIdleFlipper.ts +++ b/src/bots/userIdleFlipper.ts @@ -64,6 +64,13 @@ export class UserIdleFlipperBot implements Bot { public async init() { logger.info(`${this.name} initing`); + await this.driftClient.subscribe(); + if (!(await this.driftClient.getUser().exists())) { + throw new Error( + `User for ${this.driftClient.wallet.publicKey.toString()} does not exist` + ); + } + await this.userMap.subscribe(); this.lookupTableAccount = await this.driftClient.fetchMarketLookupTableAccount(); } diff --git a/src/bots/userPnlSettler.ts b/src/bots/userPnlSettler.ts index 77a7d031..ec11c29c 100644 --- a/src/bots/userPnlSettler.ts +++ b/src/bots/userPnlSettler.ts @@ -70,11 +70,7 @@ export class UserPnlSettlerBot implements Bot { private watchdogTimerMutex = new Mutex(); private watchdogTimerLastPatTime = Date.now(); - constructor( - driftClientConfigs: DriftClientConfig, - config: BaseBotConfig, - userMap: UserMap - ) { + constructor(driftClientConfigs: DriftClientConfig, config: BaseBotConfig) { this.name = config.botId; this.dryRun = config.dryRun; this.runOnce = config.runOnce || false; @@ -92,12 +88,25 @@ export class UserPnlSettlerBot implements Bot { }, }) ); - this.userMap = userMap; + this.userMap = new UserMap( + this.driftClient, + { + type: 'polling', + accountLoader: bulkAccountLoader, + }, + false + ); } public async init() { logger.info(`${this.name} initing`); - + await this.driftClient.subscribe(); + if (!(await this.driftClient.getUser().exists())) { + throw new Error( + `User for ${this.driftClient.wallet.publicKey.toString()} does not exist` + ); + } + await this.userMap.subscribe(); this.lookupTableAccount = await this.driftClient.fetchMarketLookupTableAccount(); } diff --git a/src/index.ts b/src/index.ts index bd615bfa..14caa4cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,11 +12,9 @@ import { getAssociatedTokenAddress } from '@solana/spl-token'; import { BulkAccountLoader, DriftClient, - User, initialize, EventSubscriber, SlotSubscriber, - convertToNumber, QUOTE_PRECISION, SpotMarkets, BN, @@ -28,6 +26,7 @@ import { FastSingleTxSender, OracleInfo, UserMap, + Wallet, } from '@drift-labs/sdk'; import { promiseTimeout } from '@drift-labs/sdk/lib/util/promiseTimeout'; @@ -49,7 +48,6 @@ import { TOKEN_FAUCET_PROGRAM_ID, getWallet, loadKeypair, - waitForAllSubscribesToFinish, } from './utils'; import { Config, @@ -90,9 +88,6 @@ program .option('--user-pnl-settler', 'Enable User PnL settler bot') .option('--user-idle-flipper', 'Flips eligible users to idle') .option('--mark-twap-crank', 'Enable bid/ask twap crank bot') - - .option('--cancel-open-orders', 'Cancel open orders on startup') - .option('--close-open-positions', 'close all open positions') .option('--test-liveness', 'Purposefully fail liveness test after 1 minute') .option( '--force-deposit ', @@ -249,6 +244,7 @@ const runBot = async () => { /** * Creating and subscribing to the drift client */ + let perpMarketIndexes: number[] | undefined; let spotMarketIndexes: number[] | undefined; let oracleInfos: OracleInfo[] | undefined; @@ -256,7 +252,6 @@ const runBot = async () => { ({ perpMarketIndexes, spotMarketIndexes, oracleInfos } = getMarketsAndOraclesForSubscription(config.global.driftEnv!)); } - const driftClientConfig = { connection, wallet, @@ -273,6 +268,10 @@ const runBot = async () => { txSender, }; const driftClient = new DriftClient(driftClientConfig); + driftClient.eventEmitter.on('error', (e) => { + logger.info('clearing house error'); + logger.error(e); + }); let eventSubscriber: EventSubscriber | undefined = undefined; if (config.global.eventSubscriber) { @@ -287,8 +286,9 @@ const runBot = async () => { } const slotSubscriber = new SlotSubscriber(connection, {}); - const startupTime = Date.now(); + await slotSubscriber.subscribe(); + const startupTime = Date.now(); const lamportsBalance = await connection.getBalance(wallet.publicKey); logger.info( `DriftClient ProgramId: ${driftClient.program.programId.toBase58()}` @@ -308,118 +308,6 @@ const runBot = async () => { logger.info(`Failed to load USDC token account: ${e}`); } - while (!(await driftClient.subscribe())) { - logger.info('waiting to subscribe to DriftClient'); - await sleepMs(1000); - } - const driftUser = driftClient.getUser(); - const subscribePromises = [driftUser.subscribe()]; - if (eventSubscriber !== undefined && !configHasBot(config, 'fillerLite')) { - subscribePromises.push(eventSubscriber.subscribe()); - } - await waitForAllSubscribesToFinish(subscribePromises); - - driftClient.eventEmitter.on('error', (e) => { - logger.info('clearing house error'); - logger.error(e); - }); - - await slotSubscriber.subscribe(); - - if (!(await driftClient.getUser().exists())) { - logger.error(`User for ${wallet.publicKey} does not exist`); - if (config.global.initUser) { - logger.info(`Creating User for ${wallet.publicKey}`); - const [txSig] = await driftClient.initializeUserAccount(); - logger.info(`Initialized user account in transaction: ${txSig}`); - } else { - throw new Error("Run with '--init-user' flag to initialize a User"); - } - } - - logger.info( - `User PublicKey: ${driftUser.getUserAccountPublicKey().toBase58()}` - ); - await driftClient.getUser().fetchAccounts(); - - printUserAccountStats(driftUser); - if (config.global.closeOpenPositions) { - logger.info(`Closing open perp positions`); - let closedPerps = 0; - for await (const p of driftUser.getUserAccount().perpPositions) { - if (p.baseAssetAmount.isZero()) { - logger.info(`no position on market: ${p.marketIndex}`); - continue; - } - logger.info(`closing position on ${p.marketIndex}`); - logger.info(` . ${await driftClient.closePosition(p.marketIndex)}`); - closedPerps++; - } - console.log(`Closed ${closedPerps} spot positions`); - - let closedSpots = 0; - for await (const p of driftUser.getUserAccount().spotPositions) { - if (p.scaledBalance.isZero()) { - logger.info(`no position on market: ${p.marketIndex}`); - continue; - } - logger.info(`closing position on ${p.marketIndex}`); - logger.info(` . ${await driftClient.closePosition(p.marketIndex)}`); - closedSpots++; - } - console.log(`Closed ${closedSpots} spot positions`); - } - - /** - * Look for collateral and force deposit before running if flag is set - */ - const freeCollateral = driftUser.getFreeCollateral('Maintenance'); - if ( - freeCollateral.isZero() && - configHasBot(config, 'jitMaker') && - !config.global.forceDeposit - ) { - throw new Error( - `No collateral in account, collateral is required to run JitMakerBot, run with --force-deposit flag to deposit collateral` - ); - } - if (config.global.forceDeposit) { - logger.info( - `Depositing (${new BN( - config.global.forceDeposit - ).toString()} USDC to collateral account)` - ); - - if (config.global.forceDeposit < 0) { - logger.error(`Deposit amount must be greater than 0`); - throw new Error('Deposit amount must be greater than 0'); - } - - const mint = SpotMarkets[config.global.driftEnv!][0].mint; // TODO: are index 0 always USDC???, support other collaterals - const ata = await getAssociatedTokenAddress(mint, wallet.publicKey); - const amount = new BN(config.global.forceDeposit).mul(QUOTE_PRECISION); - - if (config.global.driftEnv === 'devnet') { - const tokenFaucet = new TokenFaucet( - connection, - wallet, - TOKEN_FAUCET_PROGRAM_ID, - mint, - opts - ); - await tokenFaucet.mintToUser(ata, amount); - } - - const tx = await driftClient.deposit( - amount, - 0, // USDC bank - ata - ); - logger.info(`Deposit transaction: ${tx}`); - logger.info(`exiting...run again without --force-deposit flag`); - return; - } - /** * Jito info here */ @@ -454,13 +342,17 @@ const runBot = async () => { /* * Start bots depending on flags enabled */ + let needCheckDriftUser = false; + let needForceCollateral = !!config.global.forceDeposit; + let needUserMapSubscribe = false; const userMap = new UserMap( driftClient, driftClient.userAccountSubscriptionConfig, false ); if (configHasBot(config, 'filler')) { - await userMap.subscribe(); + needCheckDriftUser = true; + needUserMapSubscribe = true; bots.push( new FillerBot( slotSubscriber, @@ -484,6 +376,7 @@ const runBot = async () => { } if (configHasBot(config, 'fillerLite')) { + needCheckDriftUser = true; logger.info(`Starting filler lite bot`); bots.push( new FillerLiteBot( @@ -505,7 +398,8 @@ const runBot = async () => { } if (configHasBot(config, 'spotFiller')) { - await userMap.subscribe(); + needCheckDriftUser = true; + needUserMapSubscribe = true; bots.push( new SpotFillerBot( slotSubscriber, @@ -525,7 +419,7 @@ const runBot = async () => { } if (configHasBot(config, 'trigger')) { - await userMap.subscribe(); + needUserMapSubscribe = true; bots.push( new TriggerBot( driftClient, @@ -543,17 +437,22 @@ const runBot = async () => { ); } + let auctionSubscriber: AuctionSubscriber | undefined = undefined; + let jitter: JitterSniper | undefined = undefined; if (configHasBot(config, 'jitMaker')) { - await userMap.subscribe(); + // Subscribe to drift client + + needUserMapSubscribe = true; + needForceCollateral; const jitProxyClient = new JitProxyClient({ driftClient, programId: new PublicKey(sdkConfig.JIT_PROXY_PROGRAM_ID!), }); - const auctionSubscriber = new AuctionSubscriber({ driftClient }); + auctionSubscriber = new AuctionSubscriber({ driftClient }); await auctionSubscriber.subscribe(); - const jitter = new JitterSniper({ + jitter = new JitterSniper({ auctionSubscriber, driftClient, slotSubscriber, @@ -583,7 +482,8 @@ const runBot = async () => { } if (configHasBot(config, 'markTwapCrank')) { - await userMap.subscribe(); + needCheckDriftUser = true; + needUserMapSubscribe = true; bots.push( new MakerBidAskTwapCrank( driftClient, @@ -597,12 +497,9 @@ const runBot = async () => { } if (configHasBot(config, 'liquidator')) { - const startUserMapSubscribe = Date.now(); - logger.info(`subscribing to userMap`); - await userMap.subscribe(); - logger.info( - `userMap.subscribe took ${Date.now() - startUserMapSubscribe}ms` - ); + needCheckDriftUser = true; + needUserMapSubscribe = true; + needForceCollateral = true; bots.push( new LiquidatorBot( driftClient, @@ -621,6 +518,7 @@ const runBot = async () => { } if (configHasBot(config, 'floatingMaker')) { + needCheckDriftUser = true; bots.push( new FloatingPerpMakerBot( driftClient, @@ -638,18 +536,15 @@ const runBot = async () => { } if (configHasBot(config, 'userPnlSettler')) { - await userMap.subscribe(); bots.push( new UserPnlSettlerBot( driftClientConfig, - config.botConfigs!.userPnlSettler!, - userMap + config.botConfigs!.userPnlSettler! ) ); } if (configHasBot(config, 'userIdleFlipper')) { - await userMap.subscribe(); bots.push( new UserIdleFlipperBot( driftClientConfig, @@ -668,6 +563,7 @@ const runBot = async () => { } if (configHasBot(config, 'fundingRateUpdater')) { + needCheckDriftUser = true; bots.push( new FundingRateUpdaterBot( driftClient, @@ -677,7 +573,8 @@ const runBot = async () => { } if (configHasBot(config, 'uncrossArb')) { - await userMap.subscribe(); + needCheckDriftUser = true; + needUserMapSubscribe = true; const jitProxyClient = new JitProxyClient({ driftClient, programId: new PublicKey(sdkConfig.JIT_PROXY_PROGRAM_ID!), @@ -694,6 +591,39 @@ const runBot = async () => { ); } + // Run subscribe functions once + if ( + needCheckDriftUser || + needForceCollateral || + eventSubscriber || + auctionSubscriber || + jitter || + needUserMapSubscribe + ) { + while (!(await driftClient.subscribe())) { + logger.info('waiting to subscribe to DriftClient'); + await sleepMs(1000); + } + } + if (needCheckDriftUser) await checkUserExists(config, driftClient, wallet); + if (needForceCollateral) + await checkAndForceCollateral(config, driftClient, wallet); + if (eventSubscriber) await eventSubscriber.subscribe(); + if (needUserMapSubscribe) await userMap.subscribe(); + if (auctionSubscriber) await auctionSubscriber.subscribe(); + if (jitter) { + const freeCollateral = driftClient + .getUser() + .getFreeCollateral('Maintenance'); + if (freeCollateral.isZero()) { + throw new Error( + `No collateral in account, collateral is required to run JitMakerBot, run with --force-deposit flag to deposit collateral` + ); + } + await jitter.subscribe(); + } + + // Initialize bots logger.info(`initializing bots`); await Promise.all(bots.map((bot) => bot.init())); @@ -783,25 +713,63 @@ async function recursiveTryCatch(f: () => void) { } } -function printUserAccountStats(clearingHouseUser: User) { - const freeCollateral = clearingHouseUser.getFreeCollateral(); - logger.info( - `User free collateral: $${convertToNumber( - freeCollateral, - QUOTE_PRECISION - )}:` - ); +async function checkUserExists( + config: Config, + driftClient: DriftClient, + wallet: Wallet +) { + if (!(await driftClient.getUser().exists())) { + logger.error(`User for ${wallet.publicKey} does not exist`); + if (config.global.initUser) { + logger.info(`Creating User for ${wallet.publicKey}`); + const [txSig] = await driftClient.initializeUserAccount(); + logger.info(`Initialized user account in transaction: ${txSig}`); + } else { + throw new Error("Run with '--init-user' flag to initialize a User"); + } + } + return true; +} - logger.info( - `CHUser unrealized funding PnL: ${convertToNumber( - clearingHouseUser.getUnrealizedFundingPNL(), - QUOTE_PRECISION - )}` - ); - logger.info( - `CHUser unrealized PnL: ${convertToNumber( - clearingHouseUser.getUnrealizedPNL(), - QUOTE_PRECISION - )}` - ); +async function checkAndForceCollateral( + config: Config, + driftClient: DriftClient, + wallet: Wallet +) { + // Force depost collateral if requested + if (config.global.forceDeposit) { + logger.info( + `Depositing (${new BN( + config.global.forceDeposit + ).toString()} USDC to collateral account)` + ); + + if (config.global.forceDeposit < 0) { + logger.error(`Deposit amount must be greater than 0`); + throw new Error('Deposit amount must be greater than 0'); + } + + const mint = SpotMarkets[config.global.driftEnv!][0].mint; // TODO: are index 0 always USDC???, support other collaterals + const ata = await getAssociatedTokenAddress(mint, wallet.publicKey); + const amount = new BN(config.global.forceDeposit).mul(QUOTE_PRECISION); + + if (config.global.driftEnv === 'devnet') { + const tokenFaucet = new TokenFaucet( + driftClient.connection, + wallet, + TOKEN_FAUCET_PROGRAM_ID, + mint, + opts + ); + await tokenFaucet.mintToUser(ata, amount); + } + const tx = await driftClient.deposit( + amount, + 0, // USDC bank + ata + ); + logger.info(`Deposit transaction: ${tx}`); + logger.info(`exiting...run again without --force-deposit flag`); + } + return true; }