Skip to content

Commit

Permalink
Add support for showing self-cpi (#364)
Browse files Browse the repository at this point in the history
Fixes issue where events were not parsed for self-cpi's executed via
`emit_cpi!` in Anchor.

See example:
https://explorer.solana.com/tx/2iofwLXfEDjEqvGZNMuCzZF8TEGyvfogCVf4oDnAATLpGkUbSfPe7ZBuqNoNXzaV2Xb33AT7PRYd9HztdbTvF3GR?cluster=devnet
  • Loading branch information
ngundotra authored Aug 26, 2024
1 parent 4defa12 commit 832ef85
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
34 changes: 26 additions & 8 deletions app/components/instruction/AnchorDetailsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Address } from '@components/common/Address';
import { BorshInstructionCoder, Idl, Instruction, Program } from '@project-serum/anchor';
import { IdlInstruction } from '@project-serum/anchor/dist/cjs/idl';
import { BorshEventCoder, BorshInstructionCoder, Idl, Instruction, Program } from '@project-serum/anchor';
import { IdlEvent, IdlInstruction } from '@project-serum/anchor/dist/cjs/idl';
import { SignatureResult, TransactionInstruction } from '@solana/web3.js';
import {
getAnchorAccountsFromInstruction,
getAnchorNameForInstruction,
getAnchorProgramName,
instructionIsSelfCPI,
mapIxArgsToRows,
} from '@utils/anchor';
import { camelToTitleCase } from '@utils/index';
Expand Down Expand Up @@ -48,12 +49,29 @@ function AnchorDetails({ ix, anchorProgram }: { ix: TransactionInstruction; anch
let decodedIxData: Instruction | null = null;
let ixDef: IdlInstruction | undefined;
if (anchorProgram) {
const coder = new BorshInstructionCoder(anchorProgram.idl);
decodedIxData = coder.decode(ix.data);
if (decodedIxData) {
ixDef = anchorProgram.idl.instructions.find(ixDef => ixDef.name === decodedIxData?.name);
if (ixDef) {
ixAccounts = getAnchorAccountsFromInstruction(decodedIxData, anchorProgram);
let coder: BorshInstructionCoder | BorshEventCoder;
if (instructionIsSelfCPI(ix.data)) {
coder = new BorshEventCoder(anchorProgram.idl);
decodedIxData = coder.decode(ix.data.slice(8).toString('base64'));
const ixEventDef = anchorProgram.idl.events?.find(
ixDef => ixDef.name === decodedIxData?.name
) as IdlEvent;

// Remap the event definition to an instruction definition
ixDef = { ...ixEventDef, accounts: [], args: ixEventDef.fields };

// Self-CPI instructions have 1 account called the eventAuthority
// https://github.com/coral-xyz/anchor/blob/04985802587c693091f836e0083e4412148c0ca6/lang/attribute/event/src/lib.rs#L165
ixAccounts = [{ isMut: false, isSigner: true, name: 'eventAuthority' }];
} else {
coder = new BorshInstructionCoder(anchorProgram.idl);
decodedIxData = coder.decode(ix.data);

if (decodedIxData) {
ixDef = anchorProgram.idl.instructions.find(ixDef => ixDef.name === decodedIxData?.name);
if (ixDef) {
ixAccounts = getAnchorAccountsFromInstruction(decodedIxData, anchorProgram);
}
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions app/utils/anchor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import React, { Fragment, ReactNode, useState } from 'react';
import { ChevronDown, ChevronUp, CornerDownRight } from 'react-feather';
import ReactJson from 'react-json-view';

const ANCHOR_SELF_CPI_TAG = Buffer.from('1d9acb512ea545e4', 'hex').reverse();
const ANCHOR_SELF_CPI_NAME = 'Anchor Self Invocation';

export function instructionIsSelfCPI(ixData: Buffer): boolean {
return ixData.slice(0, 8).equals(ANCHOR_SELF_CPI_TAG);
}

export function getAnchorProgramName(program: Program | null): string | undefined {
return program && 'name' in program.idl ? snakeToTitleCase(program.idl.name) : undefined;
}
Expand Down Expand Up @@ -38,6 +45,10 @@ export function ProgramName({ programId, cluster, url }: { programId: PublicKey;
}

export function getAnchorNameForInstruction(ix: TransactionInstruction, program: Program): string | null {
if (instructionIsSelfCPI(ix.data)) {
return ANCHOR_SELF_CPI_NAME;
}

const coder = new BorshInstructionCoder(program.idl);
const decodedIx = coder.decode(ix.data);

Expand Down

0 comments on commit 832ef85

Please sign in to comment.