Gov instruction creation helpers

- Add one to make a proposal for all serum markets
- Switch created proposals to be drafts
- Add PROPOSAL_LINK env arg
- Add serum3EditMarketIx()
This commit is contained in:
Christian Kamm 2023-12-14 11:33:41 +01:00
parent 66bb74c2fd
commit 06da4768f3
4 changed files with 208 additions and 27 deletions

View File

@ -40,6 +40,7 @@ export const createProposal = async (
proposalIndex: number,
proposalInstructions: TransactionInstruction[],
client: VsrClient,
signOff: boolean,
) => {
const instructions: TransactionInstruction[] = [];
const walletPk = wallet.publicKey!;
@ -95,11 +96,6 @@ export const createProposal = async (
payer,
);
const signatoryRecordAddress = await getSignatoryRecordAddress(
MANGO_GOVERNANCE_PROGRAM,
proposalAddress,
signatory,
);
const insertInstructions: TransactionInstruction[] = [];
for (const i in proposalInstructions) {
const instruction = getInstructionDataFromBase64(
@ -120,17 +116,24 @@ export const createProposal = async (
payer,
);
}
withSignOffProposal(
insertInstructions, // SingOff proposal needs to be executed after inserting instructions hence we add it to insertInstructions
MANGO_GOVERNANCE_PROGRAM,
programVersion,
MANGO_REALM_PK,
governance,
proposalAddress,
signatory,
signatoryRecordAddress,
undefined,
);
if (signOff) {
const signatoryRecordAddress = await getSignatoryRecordAddress(
MANGO_GOVERNANCE_PROGRAM,
proposalAddress,
signatory,
);
withSignOffProposal(
insertInstructions, // SingOff proposal needs to be executed after inserting instructions hence we add it to insertInstructions
MANGO_GOVERNANCE_PROGRAM,
programVersion,
MANGO_REALM_PK,
governance,
proposalAddress,
signatory,
signatoryRecordAddress,
undefined,
);
}
const txChunks = chunk([...instructions, ...insertInstructions], 2);

View File

@ -42,6 +42,7 @@ import {
const {
MB_CLUSTER_URL,
PROPOSAL_TITLE,
PROPOSAL_LINK,
VSR_DELEGATE_KEYPAIR,
VSR_DELEGATE_FROM_PK,
DRY_RUN,
@ -285,10 +286,11 @@ async function updateTokenParams(): Promise<void> {
MANGO_DAO_WALLET_GOVERNANCE,
tokenOwnerRecord,
PROPOSAL_TITLE ? PROPOSAL_TITLE : 'Update risk parameters for tokens',
'',
PROPOSAL_LINK ?? '',
Object.values(proposals).length,
instructions,
vsrClient!,
false,
);
console.log(proposalAddress.toBase58());
}

View File

@ -0,0 +1,153 @@
import {
MidPriceImpact,
getMidPriceImpacts,
} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools';
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
import { BN } from '@project-serum/anchor';
import {
getAllProposals,
getTokenOwnerRecord,
getTokenOwnerRecordAddress,
} from '@solana/spl-governance';
import {
AccountMeta,
Connection,
Keypair,
PublicKey,
Transaction,
TransactionInstruction,
} from '@solana/web3.js';
import fs from 'fs';
import { Bank } from '../src/accounts/bank';
import { Group } from '../src/accounts/group';
import { MangoAccount } from '../src/accounts/mangoAccount';
import { Builder } from '../src/builder';
import { MangoClient } from '../src/client';
import { NullTokenEditParams } from '../src/clientIxParamBuilder';
import { MANGO_V4_MAIN_GROUP as MANGO_V4_PRIMARY_GROUP } from '../src/constants';
import { getEquityForMangoAccounts } from '../src/risk';
import { buildFetch } 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<MangoClient> {
return await MangoClient.connectDefault(MB_CLUSTER_URL!);
}
async function setupWallet(): Promise<Wallet> {
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<VsrClient> {
const options = AnchorProvider.defaultOptions();
const provider = new AnchorProvider(connection, clientWallet, options);
const vsrClient = await VsrClient.connect(provider, DEFAULT_VSR_ID);
return vsrClient;
}
async function updateSerumMarketParams(): Promise<void> {
const [client, wallet] = await Promise.all([buildClient(), setupWallet()]);
const vsrClient = await setupVsr(client.connection, wallet);
const group = await client.getGroup(MANGO_V4_PRIMARY_GROUP);
const instructions: TransactionInstruction[] = [];
Array.from(group.serum3MarketsMapByMarketIndex.values()).forEach(
async (sm) => {
const ix = await client.serum3EditMarketIx(
group,
sm.marketIndex,
group.admin,
null,
null,
null,
0.5,
);
const tx = new Transaction({ feePayer: wallet.publicKey }).add(ix);
const simulated = await client.connection.simulateTransaction(tx);
if (simulated.value.err) {
console.log('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 : 'Update risk parameters for tokens',
PROPOSAL_LINK ?? '',
Object.values(proposals).length,
instructions,
vsrClient!,
false,
);
console.log(proposalAddress.toBase58());
}
}
async function main(): Promise<void> {
try {
await updateSerumMarketParams();
} catch (error) {
console.log(error);
}
}
try {
main();
} catch (error) {
console.log(error);
}

View File

@ -1,6 +1,7 @@
import {
AnchorProvider,
BN,
Instruction,
Program,
Provider,
Wallet,
@ -1634,6 +1635,28 @@ export class MangoClient {
return await this.sendAndConfirmTransactionForGroup(group, [ix]);
}
public async serum3EditMarketIx(
group: Group,
serum3MarketIndex: MarketIndex,
admin: PublicKey,
reduceOnly: boolean | null,
forceClose: boolean | null,
name: string | null,
oraclePriceBand: number | null,
): Promise<TransactionInstruction> {
const serum3Market =
group.serum3MarketsMapByMarketIndex.get(serum3MarketIndex);
const ix = await this.program.methods
.serum3EditMarket(reduceOnly, forceClose, name, oraclePriceBand)
.accounts({
group: group.publicKey,
admin: admin,
market: serum3Market?.publicKey,
})
.instruction();
return ix;
}
public async serum3EditMarket(
group: Group,
serum3MarketIndex: MarketIndex,
@ -1642,16 +1665,16 @@ export class MangoClient {
name: string | null,
oraclePriceBand: number | null,
): Promise<MangoSignatureStatus> {
const serum3Market =
group.serum3MarketsMapByMarketIndex.get(serum3MarketIndex);
const ix = await this.program.methods
.serum3EditMarket(reduceOnly, forceClose, name, oraclePriceBand)
.accounts({
group: group.publicKey,
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
market: serum3Market?.publicKey,
})
.instruction();
const admin = (this.program.provider as AnchorProvider).wallet.publicKey;
const ix = await this.serum3EditMarketIx(
group,
serum3MarketIndex,
admin,
reduceOnly,
forceClose,
name,
oraclePriceBand,
);
return await this.sendAndConfirmTransactionForGroup(group, [ix]);
}