ts: Event decode api updates (#292)
This commit is contained in:
parent
364f957c9a
commit
24b723e1e1
|
@ -18,6 +18,8 @@ incremented for features.
|
||||||
|
|
||||||
## Breaking Changes
|
## Breaking Changes
|
||||||
|
|
||||||
|
* ts: Event coder `decode` API changed to decode strings directly instead of buffers ([#292](https://github.com/project-serum/anchor/pull/292)).
|
||||||
|
* ts: Event coder `encode` API removed ([#292](https://github.com/project-serum/anchor/pull/292)).
|
||||||
* ts: Replace deprecated `web3.Account` with `web3.Signer` in public APIs ([#296](https://github.com/project-serum/anchor/pull/296)).
|
* ts: Replace deprecated `web3.Account` with `web3.Signer` in public APIs ([#296](https://github.com/project-serum/anchor/pull/296)).
|
||||||
|
|
||||||
## [0.5.0] - 2021-05-07
|
## [0.5.0] - 2021-05-07
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import camelCase from "camelcase";
|
import camelCase from "camelcase";
|
||||||
|
import * as base64 from "base64-js";
|
||||||
import { snakeCase } from "snake-case";
|
import { snakeCase } from "snake-case";
|
||||||
import { Layout } from "buffer-layout";
|
import { Layout } from "buffer-layout";
|
||||||
import * as sha256 from "js-sha256";
|
import * as sha256 from "js-sha256";
|
||||||
|
@ -213,6 +214,11 @@ class EventCoder {
|
||||||
*/
|
*/
|
||||||
private layouts: Map<string, Layout>;
|
private layouts: Map<string, Layout>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps base64 encoded event discriminator to event name.
|
||||||
|
*/
|
||||||
|
private discriminators: Map<string, string>;
|
||||||
|
|
||||||
public constructor(idl: Idl) {
|
public constructor(idl: Idl) {
|
||||||
if (idl.events === undefined) {
|
if (idl.events === undefined) {
|
||||||
this.layouts = new Map();
|
this.layouts = new Map();
|
||||||
|
@ -232,18 +238,29 @@ class EventCoder {
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.layouts = new Map(layouts);
|
this.layouts = new Map(layouts);
|
||||||
|
|
||||||
|
this.discriminators = new Map<string, string>(
|
||||||
|
idl.events === undefined
|
||||||
|
? []
|
||||||
|
: idl.events.map((e) => [
|
||||||
|
base64.fromByteArray(eventDiscriminator(e.name)),
|
||||||
|
e.name,
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public encode<T = any>(eventName: string, account: T): Buffer {
|
public decode<T = any>(log: string): T | null {
|
||||||
const buffer = Buffer.alloc(1000); // TODO: use a tighter buffer.
|
const logArr = Buffer.from(base64.toByteArray(log));
|
||||||
const layout = this.layouts.get(eventName);
|
const disc = base64.fromByteArray(logArr.slice(0, 8));
|
||||||
const len = layout.encode(account, buffer);
|
|
||||||
return buffer.slice(0, len);
|
// Only deserialize if the discriminator implies a proper event.
|
||||||
}
|
const eventName = this.discriminators.get(disc);
|
||||||
|
if (eventName === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public decode<T = any>(eventName: string, ix: Buffer): T {
|
|
||||||
const layout = this.layouts.get(eventName);
|
const layout = this.layouts.get(eventName);
|
||||||
return layout.decode(ix);
|
return layout.decode(logArr.slice(8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import * as base64 from "base64-js";
|
import * as base64 from "base64-js";
|
||||||
import * as assert from "assert";
|
import * as assert from "assert";
|
||||||
import Coder, { eventDiscriminator } from "../coder";
|
import Coder from "../coder";
|
||||||
import { Idl } from "../idl";
|
|
||||||
|
|
||||||
const LOG_START_INDEX = "Program log: ".length;
|
const LOG_START_INDEX = "Program log: ".length;
|
||||||
|
|
||||||
|
@ -15,20 +14,10 @@ export type Event = {
|
||||||
export class EventParser {
|
export class EventParser {
|
||||||
private coder: Coder;
|
private coder: Coder;
|
||||||
private programId: PublicKey;
|
private programId: PublicKey;
|
||||||
// Maps base64 encoded event discriminator to event name.
|
|
||||||
private discriminators: Map<string, string>;
|
|
||||||
|
|
||||||
constructor(coder: Coder, programId: PublicKey, idl: Idl) {
|
constructor(coder: Coder, programId: PublicKey) {
|
||||||
this.coder = coder;
|
this.coder = coder;
|
||||||
this.programId = programId;
|
this.programId = programId;
|
||||||
this.discriminators = new Map<string, string>(
|
|
||||||
idl.events === undefined
|
|
||||||
? []
|
|
||||||
: idl.events.map((e) => [
|
|
||||||
base64.fromByteArray(eventDiscriminator(e.name)),
|
|
||||||
e.name,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each log given, represents an array of messages emitted by
|
// Each log given, represents an array of messages emitted by
|
||||||
|
@ -88,17 +77,7 @@ export class EventParser {
|
||||||
// This is a `msg!` log.
|
// This is a `msg!` log.
|
||||||
if (log.startsWith("Program log:")) {
|
if (log.startsWith("Program log:")) {
|
||||||
const logStr = log.slice(LOG_START_INDEX);
|
const logStr = log.slice(LOG_START_INDEX);
|
||||||
const logArr = Buffer.from(base64.toByteArray(logStr));
|
const event = this.coder.events.decode(logStr);
|
||||||
const disc = base64.fromByteArray(logArr.slice(0, 8));
|
|
||||||
// Only deserialize if the discriminator implies a proper event.
|
|
||||||
let event = null;
|
|
||||||
let eventName = this.discriminators.get(disc);
|
|
||||||
if (eventName !== undefined) {
|
|
||||||
event = {
|
|
||||||
name: eventName,
|
|
||||||
data: this.coder.events.decode(eventName, logArr.slice(8)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return [event, null, false];
|
return [event, null, false];
|
||||||
}
|
}
|
||||||
// System log.
|
// System log.
|
||||||
|
|
|
@ -301,11 +301,7 @@ export class Program {
|
||||||
eventName: string,
|
eventName: string,
|
||||||
callback: (event: any, slot: number) => void
|
callback: (event: any, slot: number) => void
|
||||||
): number {
|
): number {
|
||||||
const eventParser = new EventParser(
|
const eventParser = new EventParser(this._coder, this._programId);
|
||||||
this._coder,
|
|
||||||
this._programId,
|
|
||||||
this._idl
|
|
||||||
);
|
|
||||||
return this._provider.connection.onLogs(this._programId, (logs, ctx) => {
|
return this._provider.connection.onLogs(this._programId, (logs, ctx) => {
|
||||||
if (logs.err) {
|
if (logs.err) {
|
||||||
console.error(logs);
|
console.error(logs);
|
||||||
|
|
|
@ -63,7 +63,7 @@ export default class SimulateFactory {
|
||||||
|
|
||||||
const events = [];
|
const events = [];
|
||||||
if (idl.events) {
|
if (idl.events) {
|
||||||
let parser = new EventParser(coder, programId, idl);
|
let parser = new EventParser(coder, programId);
|
||||||
parser.parseLogs(logs, (event) => {
|
parser.parseLogs(logs, (event) => {
|
||||||
events.push(event);
|
events.push(event);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue