Skip to content

Commit

Permalink
ts: Add strong type support for addEventListener (#2627)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Sep 12, 2023
1 parent cec9946 commit fdda604
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 47 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- ts: Add support for unnamed(tuple) enum in accounts ([#2601](https://github.com/coral-xyz/anchor/pull/2601)).
- cli: Add program template with multiple files for instructions, state... ([#2602](https://github.com/coral-xyz/anchor/pull/2602)).
- lang: `Box` the inner enums of `anchor_lang::error::Error` to optimize `anchor_lang::Result` ([#2600](https://github.com/coral-xyz/anchor/pull/2600)).
- ts: Add strong type support for `Program.addEventListener` method ([#2627](https://github.com/coral-xyz/anchor/pull/2627)).

### Fixes

Expand Down
2 changes: 1 addition & 1 deletion tests/events/Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ wallet = "~/.config/solana/id.json"
events = "2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy"

[scripts]
test = "yarn run mocha -t 1000000 tests/"
test = "yarn run ts-mocha -t 1000000 -p ./tsconfig.json tests/**/*.ts"
72 changes: 29 additions & 43 deletions tests/events/tests/events.js → tests/events/tests/events.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,54 @@
const anchor = require("@coral-xyz/anchor");
const { assert } = require("chai");
import * as anchor from "@coral-xyz/anchor";
import { assert } from "chai";

import { Events } from "../target/types/events";

describe("Events", () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.Events;
const program = anchor.workspace.Events as anchor.Program<Events>;

type Event = anchor.IdlEvents<typeof program["idl"]>;
const getEvent = async <E extends keyof Event>(
eventName: E,
methodName: keyof typeof program["methods"]
) => {
let listenerId: number;
const event = await new Promise<Event[E]>((res) => {
listenerId = program.addEventListener(eventName, (event) => {
res(event);
});
program.methods[methodName]().rpc();
});
await program.removeEventListener(listenerId);

return event;
};

describe("Normal event", () => {
it("Single event works", async () => {
let listener = null;

let [event, slot] = await new Promise((resolve, _reject) => {
listener = program.addEventListener("MyEvent", (event, slot) => {
resolve([event, slot]);
});
program.rpc.initialize();
});
await program.removeEventListener(listener);
const event = await getEvent("MyEvent", "initialize");

assert.isAbove(slot, 0);
assert.strictEqual(event.data.toNumber(), 5);
assert.strictEqual(event.label, "hello");
});

it("Multiple events work", async () => {
let listenerOne = null;
let listenerTwo = null;

let [eventOne, slotOne] = await new Promise((resolve, _reject) => {
listenerOne = program.addEventListener("MyEvent", (event, slot) => {
resolve([event, slot]);
});
program.rpc.initialize();
});

let [eventTwo, slotTwo] = await new Promise((resolve, _reject) => {
listenerTwo = program.addEventListener(
"MyOtherEvent",
(event, slot) => {
resolve([event, slot]);
}
);
program.rpc.testEvent();
});

await program.removeEventListener(listenerOne);
await program.removeEventListener(listenerTwo);
const eventOne = await getEvent("MyEvent", "initialize");
const eventTwo = await getEvent("MyOtherEvent", "testEvent");

assert.isAbove(slotOne, 0);
assert.strictEqual(eventOne.data.toNumber(), 5);
assert.strictEqual(eventOne.label, "hello");

assert.isAbove(slotTwo, 0);
assert.strictEqual(eventTwo.data.toNumber(), 6);
assert.strictEqual(eventTwo.label, "bye");
});
});

describe("Self-CPI event", () => {
describe("CPI event", () => {
it("Works without accounts being specified", async () => {
const tx = await program.methods.testEventCpi().transaction();
const config = {
commitment: "confirmed",
};
const config = { commitment: "confirmed" } as const;
const txHash = await program.provider.sendAndConfirm(tx, [], config);
const txResult = await program.provider.connection.getTransaction(
txHash,
Expand All @@ -77,10 +63,10 @@ describe("Events", () => {

assert.strictEqual(event.name, "MyOtherEvent");
assert.strictEqual(event.data.label, "cpi");
assert.strictEqual(event.data.data.toNumber(), 7);
assert.strictEqual((event.data.data as anchor.BN).toNumber(), 7);
});

it("Malicious invocation throws", async () => {
it("Throws on unauthorized invocation", async () => {
const tx = new anchor.web3.Transaction();
tx.add(
new anchor.web3.TransactionInstruction({
Expand Down
9 changes: 9 additions & 0 deletions tests/events/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"types": ["mocha", "chai"],
"lib": ["es2015"],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true
}
}
11 changes: 8 additions & 3 deletions ts/packages/anchor/src/program/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import NamespaceFactory, {
SimulateNamespace,
MethodsNamespace,
ViewNamespace,
IdlEvents,
} from "./namespace/index.js";
import { utf8 } from "../utils/bytes/index.js";
import { EventManager } from "./event.js";
Expand Down Expand Up @@ -357,9 +358,13 @@ export class Program<IDL extends Idl = Idl> {
* @param callback The function to invoke whenever the event is emitted from
* program logs.
*/
public addEventListener(
eventName: string,
callback: (event: any, slot: number, signature: string) => void
public addEventListener<E extends keyof IdlEvents<IDL>>(
eventName: E,
callback: (
event: IdlEvents<IDL>[E],
slot: number,
signature: string
) => void
): number {
return this._events.addEventListener(eventName, callback);
}
Expand Down

1 comment on commit fdda604

@vercel
Copy link

@vercel vercel bot commented on fdda604 Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

anchor-docs – ./

anchor-lang.com
anchor-docs-git-master-200ms.vercel.app
www.anchor-lang.com
anchor-docs-200ms.vercel.app

Please sign in to comment.