import { AnchorProvider, Wallet } from '@coral-xyz/anchor'; import { getAllProposals, getTokenOwnerRecord, getTokenOwnerRecordAddress, } from '@solana/spl-governance'; import { getAssociatedTokenAddress } from '@solana/spl-token'; import { Connection, Keypair, PublicKey, Transaction, TransactionInstruction, } from '@solana/web3.js'; import fs from 'fs'; import { MangoClient } from '../src/client'; import { MANGO_V4_MAIN_GROUP as MANGO_V4_PRIMARY_GROUP } from '../src/constants'; import { I80F48 } from '../src/numbers/I80F48'; import { toUiDecimals } from '../src/utils'; import { MANGO_DAO_WALLET_GOVERNANCE, MANGO_GOVERNANCE_PROGRAM, MANGO_MINT, MANGO_REALM_PK, } from './governanceInstructions/constants'; import { createProposal } from './governanceInstructions/createProposal'; import { DEFAULT_VSR_ID, VsrClient, } from './governanceInstructions/voteStakeRegistryClient'; const { MB_CLUSTER_URL, PROPOSAL_TITLE, PROPOSAL_LINK, VSR_DELEGATE_KEYPAIR, VSR_DELEGATE_FROM_PK, DRY_RUN, } = process.env; async function buildClient(): Promise { return await MangoClient.connectDefault(MB_CLUSTER_URL!); } async function setupWallet(): Promise { const clientKeypair = Keypair.fromSecretKey( Buffer.from(JSON.parse(fs.readFileSync(VSR_DELEGATE_KEYPAIR!, 'utf-8'))), ); const clientWallet = new Wallet(clientKeypair); return clientWallet; } async function setupVsr( connection: Connection, clientWallet: Wallet, ): Promise { const options = AnchorProvider.defaultOptions(); const provider = new AnchorProvider(connection, clientWallet, options); const vsrClient = await VsrClient.connect(provider, DEFAULT_VSR_ID); return vsrClient; } async function withdrawFeesToAdmin(): Promise { const [client, wallet] = await Promise.all([buildClient(), setupWallet()]); const vsrClient = await setupVsr(client.connection, wallet); // // create wsol ata // const ix = await createAssociatedTokenAccountIdempotentInstruction( // wallet.publicKey, // new PublicKey('8SSLjXBEVk9nesbhi9UMCA32uijbVBUqWoKPPQPTekzt'), // new PublicKey('So11111111111111111111111111111111111111112'), // ); // const res = await sendTransaction( // vsrClient.program.provider as AnchorProvider, // [ix], // [], // {}, // ); // console.log(`${res.signature}`); const group = await client.getGroup(MANGO_V4_PRIMARY_GROUP); const instructions: TransactionInstruction[] = []; Array.from(group.banksMapByTokenIndex.values()) .map((banks) => banks[0]) .sort((a, b) => a.name.localeCompare(b.name)) .forEach(async (bank) => { const tokenAccount = await getAssociatedTokenAddress( bank.mint, new PublicKey('8SSLjXBEVk9nesbhi9UMCA32uijbVBUqWoKPPQPTekzt'), ); const fees = bank.collectedFeesNative.sub( I80F48.fromU64(bank.feesWithdrawn), ); const feesUi = toUiDecimals(fees, bank.mintDecimals); const feesInQuoteUi = feesUi * bank.uiPrice; if (feesInQuoteUi < 50) { return; } console.log(`${bank.name} ${feesInQuoteUi}`); const ix = await client.program.methods .adminTokenWithdrawFees() .accounts({ group: group.publicKey, admin: group.admin, bank: bank.publicKey, vault: bank.vault, tokenAccount, }) .instruction(); const tx = new Transaction({ feePayer: wallet.publicKey }).add(ix); const simulated = await client.connection.simulateTransaction(tx); if (simulated.value.err) { console.log(`${bank.name} Sim error` + simulated.value.logs); throw simulated.value.logs; } instructions.push(ix); }); const tokenOwnerRecordPk = await getTokenOwnerRecordAddress( MANGO_GOVERNANCE_PROGRAM, MANGO_REALM_PK, MANGO_MINT, new PublicKey(VSR_DELEGATE_FROM_PK!), ); const [tokenOwnerRecord, proposals] = await Promise.all([ getTokenOwnerRecord(client.connection, tokenOwnerRecordPk), getAllProposals( client.connection, MANGO_GOVERNANCE_PROGRAM, MANGO_REALM_PK, ), ]); const walletSigner = wallet as never; if (!DRY_RUN) { const proposalAddress = await createProposal( client.connection, walletSigner, MANGO_DAO_WALLET_GOVERNANCE, tokenOwnerRecord, PROPOSAL_TITLE ? PROPOSAL_TITLE : 'Withdraw token fees in mango-v4', PROPOSAL_LINK ?? '', Object.values(proposals).length, instructions, vsrClient!, false, ); console.log(proposalAddress.toBase58()); } } async function main(): Promise { try { await withdrawFeesToAdmin(); } catch (error) { console.log(error); } } try { main(); } catch (error) { console.log(error); }