Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gib bounty sol546733 #216

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions examples/governance-example/governance-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Connection, PublicKey, TransactionInstruction } from '@solana/web3.js';
import { GovernanceAgent } from '../../src/agents/governanceAgent';

async function main() {
const connection = new Connection('https://api.mainnet-beta.solana.com');
const governanceProgramId = new PublicKey('GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw');
const governanceAgent = new GovernanceAgent(connection, governanceProgramId);

// Example: Create a proposal
const realm = new PublicKey('...'); // Your realm address
const governance = new PublicKey('...'); // Your governance address
const tokenOwnerRecord = new PublicKey('...'); // Your token owner record
const governingTokenMint = new PublicKey('...'); // Your governing token mint
const proposalSeed = new PublicKey('...'); // Your proposal seed

// Create instructions (using TransactionInstruction directly)
const instructions: TransactionInstruction[] = [
new TransactionInstruction({
programId: governanceProgramId, // Use the correct programId
data: Buffer.from('...'), // Serialized instruction data
keys: [
{ pubkey: new PublicKey('...'), isSigner: false, isWritable: true },
{ pubkey: new PublicKey('...'), isSigner: true, isWritable: false }
]
})
];

// Submit the proposal with all required parameters
await governanceAgent.submitProposal(
realm,
governance,
tokenOwnerRecord,
'My Proposal',
'Description of my proposal',
governingTokenMint,
proposalSeed,
instructions // Pass the instructions here
);

// Monitor proposal status
const proposalAddress = new PublicKey('...'); // Your proposal address
const status = await governanceAgent.monitorProposal(proposalAddress);
console.log('Proposal status:', status);

// Execute an approved proposal
const proposalToExecute = new PublicKey('...'); // Address of approved proposal
const governanceAccount = new PublicKey('...'); // Governance account address

const proposalInstructions: TransactionInstruction[] = [
new TransactionInstruction({
programId: governanceProgramId, // Use the correct programId
data: Buffer.from('...'), // Serialized instruction data
keys: [
{ pubkey: new PublicKey('...'), isSigner: false, isWritable: true },
{ pubkey: new PublicKey('...'), isSigner: true, isWritable: false }
]
})
];

const executeIx = await governanceAgent.executeProposal(
governanceAccount,
proposalToExecute,
proposalInstructions // Pass the instructions here
);
console.log('Proposal execution instruction created');
}

main().catch(console.error);
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@orca-so/whirlpools-sdk": "^0.13.12",
"@pythnetwork/hermes-client": "^1.3.0",
"@raydium-io/raydium-sdk-v2": "0.1.95-alpha",
"@solana/spl-governance": "^0.3.28",
"@solana/spl-token": "^0.4.9",
"@solana/web3.js": "^1.98.0",
"@sqds/multisig": "^2.1.3",
Expand Down Expand Up @@ -81,4 +82,4 @@
"typescript": "^5.7.2"
},
"packageManager": "[email protected]"
}
}
38 changes: 38 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 93 additions & 0 deletions src/agents/governanceAgent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Connection, PublicKey, TransactionInstruction } from "@solana/web3.js";
import { SplGovernanceProgram } from "./splGovernanceProgram"; // Updated import

export class GovernanceAgent {
private governanceProgram: SplGovernanceProgram;

constructor(connection: Connection, governanceProgramId: PublicKey) {
this.governanceProgram = new SplGovernanceProgram(
connection,
governanceProgramId,
);
}

async submitProposal(
realm: PublicKey,
governance: PublicKey,
tokenOwnerRecord: PublicKey,
name: string,
description: string,
governingTokenMint: PublicKey,
proposalIndex: number,
governanceAuthority: PublicKey, // New argument
payer: PublicKey, // New argument
options: string[] = [], // Default to an empty array
useDenyOption: boolean = false, // Default to false
voterWeightRecord?: PublicKey, // Optional
) {
const instructions: TransactionInstruction[] = [];
return await this.governanceProgram.createProposal(
realm,
governance,
tokenOwnerRecord,
name,
description,
governingTokenMint,
proposalIndex,
instructions,
governanceAuthority,
payer,
options,
useDenyOption,
voterWeightRecord,
);
}

async cancelProposal(
realm: PublicKey,
governance: PublicKey,
proposal: PublicKey,
tokenOwnerRecord: PublicKey,
governanceAuthority: PublicKey, // New argument
) {
const instructions: TransactionInstruction[] = [];
return await this.governanceProgram.cancelProposal(
realm,
governance,
proposal,
tokenOwnerRecord,
governanceAuthority,
instructions,
);
}

async monitorProposal(proposalAddress: PublicKey) {
try {
return await this.governanceProgram.getProposalStatus(proposalAddress);
} catch (error) {
console.error("Error monitoring proposal:", error);
throw error;
}
}

async executeProposal(
governance: PublicKey,
proposal: PublicKey,
transactionAddress: PublicKey, // New argument
transactionInstructions: TransactionInstruction[], // New argument
) {
const instructions: TransactionInstruction[] = [];
try {
return await this.governanceProgram.executeProposal(
governance,
proposal,
instructions,
transactionAddress,
transactionInstructions,
);
} catch (error) {
console.error("Error executing proposal:", error);
throw error;
}
}
}
71 changes: 71 additions & 0 deletions src/agents/instructionUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// src/agents/instructionUtils.ts

import {
Connection,
PublicKey,
TransactionInstruction,
AccountMeta,
} from "@solana/web3.js";
import { InstructionData } from "@solana/spl-governance";

// Conversion function to transform `InstructionData` into `TransactionInstruction`
export function instructionDataToTransactionInstruction(
instructionData: InstructionData,
): TransactionInstruction {
return new TransactionInstruction({
programId: instructionData.programId,
keys: instructionData.accounts.map((account) => ({
pubkey: account.pubkey,
isWritable: account.isWritable,
isSigner: account.isSigner,
})),
data: Buffer.from(instructionData.data),
});
}

// Conversion function to transform `TransactionInstruction` into `InstructionData`
export function transactionInstructionToInstructionData(
transactionInstruction: TransactionInstruction,
): InstructionData {
return new InstructionData({
programId: transactionInstruction.programId,
accounts: transactionInstruction.keys.map((key) => ({
pubkey: key.pubkey,
isWritable: key.isWritable,
isSigner: key.isSigner,
})),
data: new Uint8Array(transactionInstruction.data),
});
}

// Main Example
export async function processInstructions(
connection: Connection,
programId: PublicKey,
transactionInstructions: TransactionInstruction[],
): Promise<void> {
// Convert TransactionInstruction[] to InstructionData[]
const instructionDataArray: InstructionData[] = transactionInstructions.map(
(instruction) => transactionInstructionToInstructionData(instruction),
);

// Simulate a function that requires `InstructionData[]` as input
const mockFunctionRequiringInstructionData = (
instructions: InstructionData[],
) => {
console.log("Processed InstructionData[]", instructions);
};

mockFunctionRequiringInstructionData(instructionDataArray);

// If you need to convert back to TransactionInstruction[], use this:
const convertedBackToTransactionInstructions: TransactionInstruction[] =
instructionDataArray.map((data) =>
instructionDataToTransactionInstruction(data),
);

console.log(
"Converted back to TransactionInstruction[]",
convertedBackToTransactionInstructions,
);
}
62 changes: 62 additions & 0 deletions src/agents/splGovernanceProgram.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Connection, PublicKey, TransactionInstruction } from "@solana/web3.js";

export class SplGovernanceProgram {
private connection: Connection;
private programId: PublicKey;

constructor(connection: Connection, programId: PublicKey) {
this.connection = connection;
this.programId = programId;
}

async createProposal(
realm: PublicKey,
governance: PublicKey,
tokenOwnerRecord: PublicKey,
name: string,
description: string,
governingTokenMint: PublicKey,
proposalIndex: number,
instructions: TransactionInstruction[],
governanceAuthority: PublicKey,
payer: PublicKey,
options: string[],
useDenyOption: boolean,
voterWeightRecord?: PublicKey,
) {
// Logic for creating a proposal (placeholder)
console.log("Creating proposal...");
// Add your code for creating a proposal here
}

async cancelProposal(
realm: PublicKey,
governance: PublicKey,
proposal: PublicKey,
tokenOwnerRecord: PublicKey,
governanceAuthority: PublicKey,
instructions: TransactionInstruction[],
) {
// Logic for canceling a proposal (placeholder)
console.log("Canceling proposal...");
// Add your code for canceling a proposal here
}

async getProposalStatus(proposalAddress: PublicKey) {
// Logic for getting the proposal status (placeholder)
console.log("Getting proposal status...");
// Add your code to get the proposal status here
}

async executeProposal(
governance: PublicKey,
proposal: PublicKey,
instructions: TransactionInstruction[],
transactionAddress: PublicKey,
transactionInstructions: TransactionInstruction[],
) {
// Logic for executing a proposal (placeholder)
console.log("Executing proposal...");
// Add your code for executing a proposal here
}
}
Loading