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

Add typescript support #795

Merged
merged 40 commits into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
9cdb365
Update accountsArray types
macalinao Jun 16, 2021
c2fc4d8
Adds types for InstructionFn
macalinao Jun 16, 2021
6488b11
Adds more types
macalinao Jun 16, 2021
5980b9c
More granular types
macalinao Jun 16, 2021
65285cf
remove event parser export
macalinao Jun 16, 2021
e73f638
Account and state data types
macalinao Jun 16, 2021
aabe73c
Merge branch 'master' into igm/types
macalinao Jun 16, 2021
8b9464d
Merge remote-tracking branch 'origin/master' into igm/types
macalinao Jun 21, 2021
18d9989
Merge remote-tracking branch 'upstream/master' into igm/types
macalinao Jul 18, 2021
dfb9bd2
T
macalinao Jul 18, 2021
ea35d62
simulate.ts: remove duplicate event import
crispheaney Jul 21, 2021
c935f75
examples/escrow: refector tests to typescript
crispheaney Jul 21, 2021
1f949f1
example/escrow: bash script to generate escrow type for test
crispheaney Jul 21, 2021
26b6a04
examples/escrow: add idl typehint to Program
crispheaney Jul 21, 2021
e80c7db
.travis.yml: fix command for escrow test
crispheaney Jul 21, 2021
c377fbd
ts/account: use account names from IDL for keys in AccountNamespace
crispheaney Jul 27, 2021
0a47d0d
ts/namespace/index: fix undefined error from undefined idl.accounts
crispheaney Jul 28, 2021
3374f79
Add some fixes
ChewingGlass Sep 10, 2021
17c697f
Merge remote-tracking branch 'serum/master' into feature/types
ChewingGlass Sep 10, 2021
8be6d72
Merge remote-tracking branch 'serum/master' into feature/types
ChewingGlass Sep 25, 2021
d23f131
Update ts/package.json
ChewingGlass Sep 25, 2021
99a7405
Update ts/package.json
ChewingGlass Sep 25, 2021
9e17d95
Update ts/src/program/index.ts
ChewingGlass Sep 25, 2021
064da53
Update ts/src/program/index.ts
ChewingGlass Sep 25, 2021
20e88f7
Move idl parser
ChewingGlass Sep 25, 2021
8274802
Merge branch 'feature/types' of github.com:ChewingGlassFund/anchor in…
ChewingGlass Sep 25, 2021
1417b8e
Finish moving escrow
armaniferrante Sep 25, 2021
22c5609
Add idl
ChewingGlass Sep 25, 2021
39e9e1d
Merge branch 'feature/types' of github.com:ChewingGlassFund/anchor in…
ChewingGlass Sep 25, 2021
a044d0c
yarn lint:fix
armaniferrante Sep 25, 2021
b687944
Fix escrow and require defined provider
armaniferrante Sep 25, 2021
58cfc6a
Remove yarn.lock
armaniferrante Sep 25, 2021
d3e7de3
update
armaniferrante Sep 26, 2021
2731187
Generate ts file via anchor build
armaniferrante Oct 4, 2021
986afd9
Anchor init typescript with types
armaniferrante Oct 4, 2021
ddbab9a
Merge branch 'master' into feature/types
armaniferrante Oct 4, 2021
24950ae
ts lint
armaniferrante Oct 4, 2021
50e8a68
fix provider
armaniferrante Oct 4, 2021
5e3b45c
Update
armaniferrante Oct 5, 2021
340b45b
Update
armaniferrante Oct 5, 2021
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
2 changes: 1 addition & 1 deletion tests/escrow/Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ wallet = "~/.config/solana/id.json"
escrow = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"

[scripts]
test = "mocha -t 1000000 tests/"
test = "ts-mocha -t 1000000 tests/*.ts"
17 changes: 17 additions & 0 deletions tests/escrow/createIDLType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const fs = require('fs')
import camelcase from "camelcase";

fs.rmdirSync("tests/types", { recursive: true });
fs.mkdir("tests/types", { recursive: true }, (err) => {
if (err) {
throw err;
}
});

const escrowIdlJson = JSON.parse(fs.readFileSync('./target/idl/escrow.json'));
for (let account of escrowIdlJson.accounts) {
account.name = camelcase(account.name);
}

const fileContents = `export type EscrowIdl = ${JSON.stringify(escrowIdlJson)};`;
fs.writeFileSync("tests/types/escrow.ts", fileContents);
16 changes: 9 additions & 7 deletions tests/escrow/package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"dependencies": {
"@project-serum/anchor": "^0.9.0",
"@project-serum/serum": "0.13.38",
"@solana/web3.js": "^1.18.0",
"@solana/spl-token": "^0.1.6"
},
"devDependencies": {
"ts-mocha": "^8.0.0"
"@project-serum/anchor": "../../ts",
"@project-serum/serum": "latest",
"@solana/spl-token": "latest",
"@solana/web3.js": "latest",
"@types/mocha": "^8.2.3",
"bn.js": "^5.2.0",
"camelcase": "^6.2.0",
"@types/node": "^14.14.37",
"chai": "^4.3.4"
}
}
100 changes: 65 additions & 35 deletions tests/escrow/tests/escrow.js → tests/escrow/tests/escrow.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
const anchor = require("@project-serum/anchor");
const { TOKEN_PROGRAM_ID, Token } = require("@solana/spl-token");
const assert = require("assert");
import * as anchor from "../../../ts";
import { Program, BN } from "../../../ts";
import {
SYSVAR_RENT_PUBKEY,
PublicKey,
Keypair,
SystemProgram,
} from '@solana/web3.js';
import { TOKEN_PROGRAM_ID, Token } from "@solana/spl-token";
import { assert } from "chai";
import { Escrow } from "./types/escrow";

describe("escrow", () => {
const provider = anchor.Provider.env();
anchor.setProvider(provider);

const program = anchor.workspace.Escrow;
const program = anchor.workspace.Escrow as Program<Escrow>;

let mintA = null;
let mintB = null;
let initializerTokenAccountA = null;
let initializerTokenAccountB = null;
let takerTokenAccountA = null;
let takerTokenAccountB = null;
let pda = null;
let mintA: Token = null;
let mintB: Token = null;
let initializerTokenAccountA: PublicKey = null;
let initializerTokenAccountB: PublicKey = null;
let takerTokenAccountA: PublicKey = null;
let takerTokenAccountB: PublicKey = null;
let pda: PublicKey = null;

const takerAmount = 1000;
const initializerAmount = 500;

const escrowAccount = anchor.web3.Keypair.generate();
const payer = anchor.web3.Keypair.generate();
const mintAuthority = anchor.web3.Keypair.generate();
const escrowAccount = Keypair.generate();
const payer = Keypair.generate();
const mintAuthority = Keypair.generate();

it("Initialise escrow state", async () => {
// Airdropping tokens to a payer.
Expand All @@ -48,10 +56,14 @@ describe("escrow", () => {
TOKEN_PROGRAM_ID
);

initializerTokenAccountA = await mintA.createAccount(provider.wallet.publicKey);
initializerTokenAccountA = await mintA.createAccount(
provider.wallet.publicKey
);
takerTokenAccountA = await mintA.createAccount(provider.wallet.publicKey);

initializerTokenAccountB = await mintB.createAccount(provider.wallet.publicKey);
initializerTokenAccountB = await mintB.createAccount(
provider.wallet.publicKey
);
takerTokenAccountB = await mintB.createAccount(provider.wallet.publicKey);

await mintA.mintTo(
Expand All @@ -68,7 +80,9 @@ describe("escrow", () => {
takerAmount
);

let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
let _initializerTokenAccountA = await mintA.getAccountInfo(
initializerTokenAccountA
);
let _takerTokenAccountB = await mintB.getAccountInfo(takerTokenAccountB);

assert.ok(_initializerTokenAccountA.amount.toNumber() == initializerAmount);
Expand All @@ -77,31 +91,33 @@ describe("escrow", () => {

it("Initialize escrow", async () => {
await program.rpc.initializeEscrow(
armaniferrante marked this conversation as resolved.
Show resolved Hide resolved
new anchor.BN(initializerAmount),
new anchor.BN(takerAmount),
new BN(initializerAmount),
new BN(takerAmount),
{
accounts: {
initializer: provider.wallet.publicKey,
initializerDepositTokenAccount: initializerTokenAccountA,
initializerReceiveTokenAccount: initializerTokenAccountB,
escrowAccount: escrowAccount.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
systemProgram: SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
rent: SYSVAR_RENT_PUBKEY,
},
signers: [escrowAccount],
}
);

// Get the PDA that is assigned authority to token account.
const [_pda, _nonce] = await anchor.web3.PublicKey.findProgramAddress(
const [_pda, _nonce] = await PublicKey.findProgramAddress(
[Buffer.from(anchor.utils.bytes.utf8.encode("escrow"))],
program.programId
);

pda = _pda;

let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
let _initializerTokenAccountA = await mintA.getAccountInfo(
initializerTokenAccountA
);

let _escrowAccount = await program.account.escrowAccount.fetch(
escrowAccount.publicKey
Expand All @@ -115,10 +131,14 @@ describe("escrow", () => {
assert.ok(_escrowAccount.initializerAmount.toNumber() == initializerAmount);
assert.ok(_escrowAccount.takerAmount.toNumber() == takerAmount);
assert.ok(
_escrowAccount.initializerDepositTokenAccount.equals(initializerTokenAccountA)
_escrowAccount.initializerDepositTokenAccount.equals(
armaniferrante marked this conversation as resolved.
Show resolved Hide resolved
initializerTokenAccountA
)
);
assert.ok(
_escrowAccount.initializerReceiveTokenAccount.equals(initializerTokenAccountB)
_escrowAccount.initializerReceiveTokenAccount.equals(
initializerTokenAccountB
)
);
});

Expand All @@ -139,8 +159,12 @@ describe("escrow", () => {

let _takerTokenAccountA = await mintA.getAccountInfo(takerTokenAccountA);
let _takerTokenAccountB = await mintB.getAccountInfo(takerTokenAccountB);
let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
let _initializerTokenAccountB = await mintB.getAccountInfo(initializerTokenAccountB);
let _initializerTokenAccountA = await mintA.getAccountInfo(
initializerTokenAccountA
);
let _initializerTokenAccountB = await mintB.getAccountInfo(
initializerTokenAccountB
);

// Check that the initializer gets back ownership of their token account.
assert.ok(_takerTokenAccountA.owner.equals(provider.wallet.publicKey));
Expand All @@ -151,7 +175,7 @@ describe("escrow", () => {
assert.ok(_takerTokenAccountB.amount.toNumber() == 0);
});

let newEscrow = anchor.web3.Keypair.generate();
let newEscrow = Keypair.generate();

it("Initialize escrow and cancel escrow", async () => {
// Put back tokens into initializer token A account.
Expand All @@ -163,23 +187,25 @@ describe("escrow", () => {
);

await program.rpc.initializeEscrow(
new anchor.BN(initializerAmount),
new anchor.BN(takerAmount),
new BN(initializerAmount),
new BN(takerAmount),
{
accounts: {
initializer: provider.wallet.publicKey,
initializerDepositTokenAccount: initializerTokenAccountA,
initializerReceiveTokenAccount: initializerTokenAccountB,
escrowAccount: newEscrow.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
systemProgram: SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
rent: SYSVAR_RENT_PUBKEY,
},
signers: [newEscrow],
}
);

let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
let _initializerTokenAccountA = await mintA.getAccountInfo(
initializerTokenAccountA
);

// Check that the new owner is the PDA.
assert.ok(_initializerTokenAccountA.owner.equals(pda));
Expand All @@ -196,8 +222,12 @@ describe("escrow", () => {
});

// Check the final owner should be the provider public key.
_initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
assert.ok(_initializerTokenAccountA.owner.equals(provider.wallet.publicKey));
_initializerTokenAccountA = await mintA.getAccountInfo(
initializerTokenAccountA
);
assert.ok(
_initializerTokenAccountA.owner.equals(provider.wallet.publicKey)
);

// Check all the funds are still there.
assert.ok(_initializerTokenAccountA.amount.toNumber() == initializerAmount);
Expand Down
75 changes: 75 additions & 0 deletions tests/escrow/tests/types/escrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
export type Escrow = {
version: "0.0.0";
name: "escrow";
instructions: [
{
name: "initializeEscrow";
accounts: [
{ name: "initializer"; isMut: false; isSigner: true },
{
name: "initializerDepositTokenAccount";
isMut: true;
isSigner: false;
},
{
name: "initializerReceiveTokenAccount";
isMut: false;
isSigner: false;
},
{ name: "escrowAccount"; isMut: true; isSigner: false },
{ name: "tokenProgram"; isMut: false; isSigner: false },
{ name: "rent"; isMut: false; isSigner: false }
];
args: [
{ name: "initializerAmount"; type: "u64" },
{ name: "takerAmount"; type: "u64" }
];
},
{
name: "cancelEscrow";
accounts: [
{ name: "initializer"; isMut: false; isSigner: false },
{ name: "pdaDepositTokenAccount"; isMut: true; isSigner: false },
{ name: "pdaAccount"; isMut: false; isSigner: false },
{ name: "escrowAccount"; isMut: true; isSigner: false },
{ name: "tokenProgram"; isMut: false; isSigner: false }
];
args: [];
},
{
name: "exchange";
accounts: [
{ name: "taker"; isMut: false; isSigner: true },
{ name: "takerDepositTokenAccount"; isMut: true; isSigner: false },
{ name: "takerReceiveTokenAccount"; isMut: true; isSigner: false },
{ name: "pdaDepositTokenAccount"; isMut: true; isSigner: false },
{
name: "initializerReceiveTokenAccount";
isMut: true;
isSigner: false;
},
{ name: "initializerMainAccount"; isMut: true; isSigner: false },
{ name: "escrowAccount"; isMut: true; isSigner: false },
{ name: "pdaAccount"; isMut: false; isSigner: false },
{ name: "tokenProgram"; isMut: false; isSigner: false }
];
args: [];
}
];
accounts: [
{
name: "escrowAccount";
type: {
kind: "struct";
fields: [
{ name: "initializerKey"; type: "publicKey" },
{ name: "initializerDepositTokenAccount"; type: "publicKey" },
{ name: "initializerReceiveTokenAccount"; type: "publicKey" },
{ name: "initializerAmount"; type: "u64" },
{ name: "takerAmount"; type: "u64" }
];
};
}
];
metadata: { address: "orwyukmpT9ZKxq78aQCkM75xJDgV1VXgAktFgX6PZob" };
};
10 changes: 10 additions & 0 deletions tests/escrow/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"types": ["mocha", "chai", "node"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2015"],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true
}
}
13 changes: 9 additions & 4 deletions ts/src/coder/event.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as base64 from "base64-js";
import { Layout } from "buffer-layout";
import { sha256 } from "js-sha256";
import { Idl, IdlTypeDef } from "../idl";
import { Event } from "../program/event";
import { Idl, IdlEvent, IdlTypeDef } from "../idl";
import { Event, EventData } from "../program/event";
import { IdlCoder } from "./idl";

export class EventCoder {
Expand Down Expand Up @@ -46,7 +46,9 @@ export class EventCoder {
);
}

public decode<T = Record<string, unknown>>(log: string): Event<T> | null {
public decode<E extends IdlEvent = IdlEvent, T = Record<string, never>>(
log: string
): Event<E, T> | null {
let logArr: Buffer;
// This will throw if log length is not a multiple of 4.
try {
Expand All @@ -66,7 +68,10 @@ export class EventCoder {
if (!layout) {
throw new Error(`Unknown event: ${eventName}`);
}
const data = layout.decode(logArr.slice(8)) as T;
const data = layout.decode(logArr.slice(8)) as EventData<
E["fields"][number],
T
>;
return { data, name: eventName };
}
}
Expand Down
2 changes: 1 addition & 1 deletion ts/src/idl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ type IdlEnumFieldsNamed = IdlField[];

type IdlEnumFieldsTuple = IdlType[];

type IdlErrorCode = {
export type IdlErrorCode = {
code: number;
name: string;
msg?: string;
Expand Down
Loading