Browse Source

ts: Fix event listener not firing when creating associated accounts (#397)

Standaa 4 years ago
parent
commit
dac6b17866
4 changed files with 93 additions and 9 deletions
  1. 4 0
      CHANGELOG.md
  2. 29 0
      examples/misc/programs/misc/src/lib.rs
  3. 50 1
      examples/misc/tests/misc.js
  4. 10 8
      ts/src/program/event.ts

+ 4 - 0
CHANGELOG.md

@@ -11,6 +11,10 @@ incremented for features.
 
 ## [Unreleased]
 
+### Fixes
+
+* ts: Event listener not firing when creating associated accounts ([#356](https://github.com/project-serum/anchor/issues/356)).
+
 ## [0.11.0] - 2021-07-03
 
 ### Features

+ 29 - 0
examples/misc/programs/misc/src/lib.rs

@@ -81,6 +81,20 @@ pub mod misc {
         Ok(())
     }
 
+    pub fn test_simulate_associated_account(
+        ctx: Context<TestSimulateAssociatedAccount>,
+        data: u32,
+    ) -> ProgramResult {
+        let associated_account = *ctx.accounts.my_account.to_account_info().key;
+        emit!(E1 { data });
+        emit!(E2 { data: 1234 });
+        emit!(E3 { data: 9 });
+        emit!(E4 {
+            data: associated_account
+        });
+        Ok(())
+    }
+
     pub fn test_i8(ctx: Context<TestI8>, data: i8) -> ProgramResult {
         ctx.accounts.data.data = data;
         Ok(())
@@ -288,6 +302,16 @@ pub struct TestI16<'info> {
 #[derive(Accounts)]
 pub struct TestSimulate {}
 
+#[derive(Accounts)]
+pub struct TestSimulateAssociatedAccount<'info> {
+    #[account(init, associated = authority)]
+    my_account: ProgramAccount<'info, TestData>,
+    #[account(mut, signer)]
+    authority: AccountInfo<'info>,
+    rent: Sysvar<'info, Rent>,
+    system_program: AccountInfo<'info>,
+}
+
 #[derive(Accounts)]
 pub struct TestI8<'info> {
     #[account(init)]
@@ -344,3 +368,8 @@ pub struct E2 {
 pub struct E3 {
     data: u32,
 }
+
+#[event]
+pub struct E4 {
+    data: Pubkey,
+}

+ 50 - 1
examples/misc/tests/misc.js

@@ -1,6 +1,5 @@
 const anchor = require("@project-serum/anchor");
 const PublicKey = anchor.web3.PublicKey;
-const serumCmn = require("@project-serum/common");
 const assert = require("assert");
 const { TOKEN_PROGRAM_ID, Token } = require("@solana/spl-token");
 
@@ -229,6 +228,54 @@ describe("misc", () => {
       "Program Z2Ddx1Lcd8CHTV9tkWtNnFQrSz6kxz2H38wrr18zZRZ consumed 4819 of 200000 compute units",
       "Program Z2Ddx1Lcd8CHTV9tkWtNnFQrSz6kxz2H38wrr18zZRZ success",
     ];
+
+    assert.ok(JSON.stringify(expectedRaw), resp.raw);
+    assert.ok(resp.events[0].name === "E1");
+    assert.ok(resp.events[0].data.data === 44);
+    assert.ok(resp.events[1].name === "E2");
+    assert.ok(resp.events[1].data.data === 1234);
+    assert.ok(resp.events[2].name === "E3");
+    assert.ok(resp.events[2].data.data === 9);
+  });
+
+  it("Can retrieve events when associated account is initialized in simulated transaction", async () => {
+    const myAccount = await program.account.testData.associatedAddress(
+      program.provider.wallet.publicKey
+    );
+    await assert.rejects(
+      async () => {
+        await program.account.testData.fetch(myAccount);
+      },
+      (err) => {
+        assert.ok(
+          err.toString() ===
+            `Error: Account does not exist ${myAccount.toString()}`
+        );
+        return true;
+      }
+    );
+
+    const resp = await program.simulate.testSimulateAssociatedAccount(44, {
+      accounts: {
+        myAccount,
+        authority: program.provider.wallet.publicKey,
+        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        systemProgram: anchor.web3.SystemProgram.programId,
+      },
+    });
+
+    const expectedRaw = [
+      "Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g invoke [1]",
+      "Program 11111111111111111111111111111111 invoke [2]",
+      "Program 11111111111111111111111111111111 success",
+      "Program log: NgyCA9omwbMsAAAA",
+      "Program log: fPhuIELK/k7SBAAA",
+      "Program log: jvbowsvlmkcJAAAA",
+      "Program log: mg+zq/K0sXRV+N/AsG9XLERDZ+J6eQAnnzoQVHlicBQBnGr65KE5Kw==",
+      "Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g consumed 20460 of 200000 compute units",
+      "Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g success",
+    ];
+
     assert.ok(JSON.stringify(expectedRaw), resp.raw);
     assert.ok(resp.events[0].name === "E1");
     assert.ok(resp.events[0].data.data === 44);
@@ -236,6 +283,8 @@ describe("misc", () => {
     assert.ok(resp.events[1].data.data === 1234);
     assert.ok(resp.events[2].name === "E3");
     assert.ok(resp.events[2].data.data === 9);
+    assert.ok(resp.events[3].name === "E4");
+    assert.ok(resp.events[3].data.data.toBase58() === myAccount.toBase58());
   });
 
   it("Can use i8 in the idl", async () => {

+ 10 - 8
ts/src/program/event.ts

@@ -44,8 +44,6 @@ export class EventParser {
       }
       if (didPop) {
         execution.pop();
-        // Skip the "success" log, which always follows the consumed log.
-        logScanner.next();
       }
       log = logScanner.next();
     }
@@ -89,18 +87,22 @@ export class EventParser {
   private handleSystemLog(log: string): [string | null, boolean] {
     // System component.
     const logStart = log.split(":")[0];
+
+    // Did the program finish executing?
+    if (
+      logStart.match(/^Program (.*) success/g) !== null
+    ) {
+      return [null, true];
     // Recursive call.
-    if (logStart.startsWith(`Program ${this.programId.toString()} invoke`)) {
+    } else if (
+      logStart.startsWith(`Program ${this.programId.toString()} invoke`)
+    ) {
       return [this.programId.toString(), false];
     }
-    // Cpi call.
+    // CPI call.
     else if (logStart.includes("invoke")) {
       return ["cpi", false]; // Any string will do.
     } else {
-      // Did the program finish executing?
-      if (logStart.match(/^Program (.*) consumed .*$/g) !== null) {
-        return [null, true];
-      }
       return [null, false];
     }
   }