ts: setup associated token program idl (#1939)
This commit is contained in:
parent
58db41bb35
commit
a5dbc7b850
|
@ -25,6 +25,7 @@ com/project-serum/anchor/pull/1841)).
|
|||
* ts: Implement a coder for system program ([#1920](https://github.com/project-serum/anchor/pull/1920)).
|
||||
* ts: Add `program.coder.types` for encoding/decoding user-defined types ([#1931](https://github.com/project-serum/anchor/pull/1931)).
|
||||
* client: Add send_with_spinner_and_config function to RequestBuilder ([#1926](https://github.com/project-serum/anchor/pull/1926)).
|
||||
* ts: Implement a coder for SPL associated token program ([#1939](https://github.com/project-serum/anchor/pull/1939)).
|
||||
|
||||
### Fixes
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
custom_coder = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
spl_token = "FmpfPa1LHEYRbueNMnwNVd2JvyQ89GXGWdyZEXNNKV8w"
|
||||
native_system = "9NxAd91hhJ3ZBTHytYP894y4ESRKG7n8VbLgdyYGJFLB"
|
||||
spl_associated_token = "4dUGnkre6uBhX1abB4ofkoecGN4aDXdiWSaWLUjVw6bh"
|
||||
|
||||
[registry]
|
||||
url = "https://anchor.projectserum.com"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "spl-associated-token"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "spl_associated_token"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
no-log-ix-name = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
|
||||
[profile.release]
|
||||
overflow-checks = true
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = "0.24.2"
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,33 @@
|
|||
// This file is autogenerated with https://github.com/acheroncrypto/native-to-anchor
|
||||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("4dUGnkre6uBhX1abB4ofkoecGN4aDXdiWSaWLUjVw6bh");
|
||||
|
||||
#[program]
|
||||
pub mod spl_associated_token {
|
||||
use super::*;
|
||||
|
||||
pub fn create(ctx: Context<Create>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Create<'info> {
|
||||
#[account(mut)]
|
||||
authority: Signer<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
associated_account: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
owner: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
system_program: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
token_program: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
rent: AccountInfo<'info>,
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
import * as anchor from "@project-serum/anchor";
|
||||
import { Native, Spl } from "@project-serum/anchor";
|
||||
import { Keypair, PublicKey } from "@solana/web3.js";
|
||||
import * as assert from "assert";
|
||||
import BN from "bn.js";
|
||||
|
||||
describe("spl-associated-token-coder", () => {
|
||||
// Configure the client to use the local cluster.
|
||||
const provider = anchor.AnchorProvider.env();
|
||||
anchor.setProvider(provider);
|
||||
|
||||
// Client.
|
||||
const program = Spl.associatedToken();
|
||||
const systemProgram = Native.system();
|
||||
const tokenProgram = Spl.token();
|
||||
|
||||
it("Creates an account", async () => {
|
||||
// arrange
|
||||
const mintKeypair = Keypair.generate();
|
||||
const mintDecimals = 6;
|
||||
const mintSize = tokenProgram.coder.accounts.size(
|
||||
tokenProgram.idl.accounts[0]
|
||||
);
|
||||
const mintRentExemption =
|
||||
await provider.connection.getMinimumBalanceForRentExemption(mintSize);
|
||||
const [associatedToken] = await PublicKey.findProgramAddress(
|
||||
[
|
||||
provider.publicKey.toBuffer(),
|
||||
tokenProgram.programId.toBuffer(),
|
||||
mintKeypair.publicKey.toBuffer(),
|
||||
],
|
||||
program.programId
|
||||
);
|
||||
|
||||
// act
|
||||
await program.methods
|
||||
.create()
|
||||
.accounts({
|
||||
authority: provider.wallet.publicKey,
|
||||
mint: mintKeypair.publicKey,
|
||||
owner: provider.wallet.publicKey,
|
||||
associatedAccount: associatedToken,
|
||||
})
|
||||
.preInstructions(
|
||||
await Promise.all([
|
||||
systemProgram.methods
|
||||
.createAccount(
|
||||
new BN(mintRentExemption),
|
||||
new BN(mintSize),
|
||||
tokenProgram.programId
|
||||
)
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: mintKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
tokenProgram.methods
|
||||
.initializeMint(mintDecimals, provider.wallet.publicKey, null)
|
||||
.accounts({
|
||||
mint: mintKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
)
|
||||
.signers([mintKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const tokenAccount = await tokenProgram.account.token.fetch(
|
||||
associatedToken
|
||||
);
|
||||
assert.ok(tokenAccount.mint.equals(mintKeypair.publicKey));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
import { AccountsCoder } from "../index.js";
|
||||
import { Idl, IdlTypeDef } from "../../idl.js";
|
||||
import { accountSize } from "../common";
|
||||
|
||||
export class SplAssociatedTokenAccountsCoder<A extends string = string>
|
||||
implements AccountsCoder
|
||||
{
|
||||
constructor(private idl: Idl) {}
|
||||
|
||||
public async encode<T = any>(accountName: A, account: T): Promise<Buffer> {
|
||||
switch (accountName) {
|
||||
default: {
|
||||
throw new Error(`Invalid account name: ${accountName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public decode<T = any>(accountName: A, ix: Buffer): T {
|
||||
return this.decodeUnchecked(accountName, ix);
|
||||
}
|
||||
|
||||
public decodeUnchecked<T = any>(accountName: A, ix: Buffer): T {
|
||||
switch (accountName) {
|
||||
default: {
|
||||
throw new Error(`Invalid account name: ${accountName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this won't use the appendData.
|
||||
public memcmp(accountName: A, _appendData?: Buffer): any {
|
||||
switch (accountName) {
|
||||
default: {
|
||||
throw new Error(`Invalid account name: ${accountName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public size(idlAccount: IdlTypeDef): number {
|
||||
return accountSize(this.idl, idlAccount) ?? 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { EventCoder } from "../index.js";
|
||||
import { Idl } from "../../idl.js";
|
||||
import { Event } from "../../program/event";
|
||||
import { IdlEvent } from "../../idl";
|
||||
|
||||
export class SplAssociatedTokenEventsCoder implements EventCoder {
|
||||
constructor(_idl: Idl) {}
|
||||
|
||||
decode<E extends IdlEvent = IdlEvent, T = Record<string, string>>(
|
||||
_log: string
|
||||
): Event<E, T> | null {
|
||||
throw new Error("SPL associated token program does not have events");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { Idl } from "../../idl.js";
|
||||
import { Coder } from "../index.js";
|
||||
import { SplAssociatedTokenInstructionCoder } from "./instruction.js";
|
||||
import { SplAssociatedTokenStateCoder } from "./state.js";
|
||||
import { SplAssociatedTokenAccountsCoder } from "./accounts.js";
|
||||
import { SplAssociatedTokenEventsCoder } from "./events.js";
|
||||
import { SplAssociatedTokenTypesCoder } from "./types.js";
|
||||
|
||||
/**
|
||||
* Coder for the SPL token program.
|
||||
*/
|
||||
export class SplAssociatedTokenCoder implements Coder {
|
||||
readonly instruction: SplAssociatedTokenInstructionCoder;
|
||||
readonly accounts: SplAssociatedTokenAccountsCoder;
|
||||
readonly state: SplAssociatedTokenStateCoder;
|
||||
readonly events: SplAssociatedTokenEventsCoder;
|
||||
readonly types: SplAssociatedTokenTypesCoder;
|
||||
|
||||
constructor(idl: Idl) {
|
||||
this.instruction = new SplAssociatedTokenInstructionCoder(idl);
|
||||
this.accounts = new SplAssociatedTokenAccountsCoder(idl);
|
||||
this.events = new SplAssociatedTokenEventsCoder(idl);
|
||||
this.state = new SplAssociatedTokenStateCoder(idl);
|
||||
this.types = new SplAssociatedTokenTypesCoder(idl);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import camelCase from "camelcase";
|
||||
import { Idl } from "../../idl.js";
|
||||
import { InstructionCoder } from "../index.js";
|
||||
|
||||
export class SplAssociatedTokenInstructionCoder implements InstructionCoder {
|
||||
constructor(_: Idl) {}
|
||||
|
||||
encode(ixName: string, _: any): Buffer {
|
||||
switch (camelCase(ixName)) {
|
||||
case "create": {
|
||||
return Buffer.alloc(0);
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid instruction: ${ixName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
encodeState(_ixName: string, _ix: any): Buffer {
|
||||
throw new Error("SPL associated token does not have state");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { StateCoder } from "../index.js";
|
||||
import { Idl } from "../../idl";
|
||||
|
||||
export class SplAssociatedTokenStateCoder implements StateCoder {
|
||||
constructor(_idl: Idl) {}
|
||||
|
||||
encode<T = any>(_name: string, _account: T): Promise<Buffer> {
|
||||
throw new Error("SPL associated token does not have state");
|
||||
}
|
||||
decode<T = any>(_ix: Buffer): T {
|
||||
throw new Error("SPL associated token does not have state");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { TypesCoder } from "../index.js";
|
||||
import { Idl } from "../../idl.js";
|
||||
|
||||
export class SplAssociatedTokenTypesCoder implements TypesCoder {
|
||||
constructor(_idl: Idl) {}
|
||||
|
||||
encode<T = any>(_name: string, _type: T): Buffer {
|
||||
throw new Error("SPL associated token does not have user-defined types");
|
||||
}
|
||||
decode<T = any>(_name: string, _typeData: Buffer): T {
|
||||
throw new Error("SPL associated token does not have user-defined types");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
import { PublicKey } from "@solana/web3.js";
|
||||
import { Program } from "../program/index.js";
|
||||
import Provider from "../provider.js";
|
||||
import { SplAssociatedTokenCoder } from "../coder/spl-associated-token/index.js";
|
||||
|
||||
const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey(
|
||||
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
|
||||
);
|
||||
|
||||
export function program(provider?: Provider): Program<SplAssociatedToken> {
|
||||
return new Program<SplAssociatedToken>(
|
||||
IDL,
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
provider,
|
||||
coder()
|
||||
);
|
||||
}
|
||||
|
||||
export function coder(): SplAssociatedTokenCoder {
|
||||
return new SplAssociatedTokenCoder(IDL);
|
||||
}
|
||||
|
||||
/**
|
||||
* SplAssociatedToken IDL.
|
||||
*/
|
||||
export type SplAssociatedToken = {
|
||||
version: "0.1.0";
|
||||
name: "spl_associated_token";
|
||||
instructions: [
|
||||
{
|
||||
name: "create";
|
||||
accounts: [
|
||||
{
|
||||
name: "authority";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
},
|
||||
{
|
||||
name: "associatedAccount";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "owner";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "mint";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "systemProgram";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "tokenProgram";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "rent";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
}
|
||||
];
|
||||
args: [];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
export const IDL: SplAssociatedToken = {
|
||||
version: "0.1.0",
|
||||
name: "spl_associated_token",
|
||||
instructions: [
|
||||
{
|
||||
name: "create",
|
||||
accounts: [
|
||||
{
|
||||
name: "authority",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
{
|
||||
name: "associatedAccount",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "mint",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "systemProgram",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "tokenProgram",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "rent",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
],
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
};
|
|
@ -1,4 +1,8 @@
|
|||
import { Program, Provider } from "../index.js";
|
||||
import {
|
||||
program as associatedTokenProgram,
|
||||
SplAssociatedToken,
|
||||
} from "./associated-token.js";
|
||||
import { program as tokenProgram, SplToken } from "./token.js";
|
||||
|
||||
export { SplToken } from "./token.js";
|
||||
|
@ -7,4 +11,10 @@ export class Spl {
|
|||
public static token(provider?: Provider): Program<SplToken> {
|
||||
return tokenProgram(provider);
|
||||
}
|
||||
|
||||
public static associatedToken(
|
||||
provider?: Provider
|
||||
): Program<SplAssociatedToken> {
|
||||
return associatedTokenProgram(provider);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue