feat: support user-supplied Token programs
This commit is contained in:
@ -119,7 +119,7 @@ declare module '@solana/web3.js' {
|
|||||||
declare type TokenAndPublicKey = [Token, PublicKey];
|
declare type TokenAndPublicKey = [Token, PublicKey];
|
||||||
|
|
||||||
declare export class Token {
|
declare export class Token {
|
||||||
static programId: PublicKey;
|
programId: PublicKey;
|
||||||
token: PublicKey;
|
token: PublicKey;
|
||||||
|
|
||||||
static createNewToken(
|
static createNewToken(
|
||||||
|
@ -134,6 +134,12 @@ const TokenAccountInfoLayout = BufferLayout.struct([
|
|||||||
|
|
||||||
type TokenAndPublicKey = [Token, PublicKey]; // This type exists to workaround an esdoc parse error
|
type TokenAndPublicKey = [Token, PublicKey]; // This type exists to workaround an esdoc parse error
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The built-in token program
|
||||||
|
*/
|
||||||
|
export const SYSTEM_TOKEN_PROGRAM_ID = new PublicKey('0x500000000000000000000000000000000000000000000000000000000000000');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ERC20-like Token
|
* An ERC20-like Token
|
||||||
*/
|
*/
|
||||||
@ -149,14 +155,20 @@ export class Token {
|
|||||||
*/
|
*/
|
||||||
token: PublicKey;
|
token: PublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Program Identifier for the Token program
|
||||||
|
*/
|
||||||
|
programId: PublicKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Token object attached to the specific token
|
* Create a Token object attached to the specific token
|
||||||
*
|
*
|
||||||
* @param connection The connection to use
|
* @param connection The connection to use
|
||||||
* @param token Public key of the token
|
* @param token Public key of the token
|
||||||
|
* @param programId Optional token programId, uses the system programId by default
|
||||||
*/
|
*/
|
||||||
constructor(connection: Connection, token: PublicKey) {
|
constructor(connection: Connection, token: PublicKey, programId: PublicKey = SYSTEM_TOKEN_PROGRAM_ID) {
|
||||||
Object.assign(this, {connection, token});
|
Object.assign(this, {connection, token, programId});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -168,6 +180,7 @@ export class Token {
|
|||||||
* @param name Descriptive name of this token
|
* @param name Descriptive name of this token
|
||||||
* @param symbol Symbol for this token
|
* @param symbol Symbol for this token
|
||||||
* @param decimals Location of the decimal place
|
* @param decimals Location of the decimal place
|
||||||
|
* @param programId Optional token programId, uses the system programId by default
|
||||||
* @return Token object for the newly minted token, Public key of the Token Account holding the total supply of new tokens
|
* @return Token object for the newly minted token, Public key of the Token Account holding the total supply of new tokens
|
||||||
*/
|
*/
|
||||||
static async createNewToken(
|
static async createNewToken(
|
||||||
@ -177,6 +190,7 @@ export class Token {
|
|||||||
name: string,
|
name: string,
|
||||||
symbol: string,
|
symbol: string,
|
||||||
decimals: number,
|
decimals: number,
|
||||||
|
programId: PublicKey = SYSTEM_TOKEN_PROGRAM_ID,
|
||||||
): Promise<TokenAndPublicKey> {
|
): Promise<TokenAndPublicKey> {
|
||||||
const tokenAccount = new Account();
|
const tokenAccount = new Account();
|
||||||
const token = new Token(connection, tokenAccount.publicKey);
|
const token = new Token(connection, tokenAccount.publicKey);
|
||||||
@ -213,14 +227,14 @@ export class Token {
|
|||||||
tokenAccount.publicKey,
|
tokenAccount.publicKey,
|
||||||
1,
|
1,
|
||||||
1 + userdata.length,
|
1 + userdata.length,
|
||||||
Token.programId,
|
programId,
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, owner, transaction);
|
await sendAndConfirmTransaction(connection, owner, transaction);
|
||||||
|
|
||||||
transaction = new Transaction({
|
transaction = new Transaction({
|
||||||
fee: 0,
|
fee: 0,
|
||||||
keys: [tokenAccount.publicKey, initialAccountPublicKey],
|
keys: [tokenAccount.publicKey, initialAccountPublicKey],
|
||||||
programId: Token.programId,
|
programId,
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, tokenAccount, transaction);
|
await sendAndConfirmTransaction(connection, tokenAccount, transaction);
|
||||||
@ -253,7 +267,7 @@ export class Token {
|
|||||||
tokenAccount.publicKey,
|
tokenAccount.publicKey,
|
||||||
1,
|
1,
|
||||||
1 + TokenAccountInfoLayout.span,
|
1 + TokenAccountInfoLayout.span,
|
||||||
Token.programId,
|
this.programId,
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(this.connection, owner, transaction);
|
await sendAndConfirmTransaction(this.connection, owner, transaction);
|
||||||
|
|
||||||
@ -265,7 +279,7 @@ export class Token {
|
|||||||
transaction = new Transaction({
|
transaction = new Transaction({
|
||||||
fee: 0,
|
fee: 0,
|
||||||
keys,
|
keys,
|
||||||
programId: Token.programId,
|
programId: this.programId,
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(this.connection, tokenAccount, transaction);
|
await sendAndConfirmTransaction(this.connection, tokenAccount, transaction);
|
||||||
@ -292,7 +306,7 @@ export class Token {
|
|||||||
*/
|
*/
|
||||||
async tokenInfo(): Promise<TokenInfo> {
|
async tokenInfo(): Promise<TokenInfo> {
|
||||||
const accountInfo = await this.connection.getAccountInfo(this.token);
|
const accountInfo = await this.connection.getAccountInfo(this.token);
|
||||||
if (!accountInfo.programId.equals(Token.programId)) {
|
if (!accountInfo.programId.equals(this.programId)) {
|
||||||
throw new Error(`Invalid token programId: ${JSON.stringify(accountInfo.programId)}`);
|
throw new Error(`Invalid token programId: ${JSON.stringify(accountInfo.programId)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +328,7 @@ export class Token {
|
|||||||
*/
|
*/
|
||||||
async accountInfo(account: PublicKey): Promise<TokenAccountInfo> {
|
async accountInfo(account: PublicKey): Promise<TokenAccountInfo> {
|
||||||
const accountInfo = await this.connection.getAccountInfo(account);
|
const accountInfo = await this.connection.getAccountInfo(account);
|
||||||
if (!accountInfo.programId.equals(Token.programId)) {
|
if (!accountInfo.programId.equals(this.programId)) {
|
||||||
throw new Error(`Invalid token account programId`);
|
throw new Error(`Invalid token account programId`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +398,7 @@ export class Token {
|
|||||||
const transaction = new Transaction({
|
const transaction = new Transaction({
|
||||||
fee: 0,
|
fee: 0,
|
||||||
keys,
|
keys,
|
||||||
programId: Token.programId,
|
programId: this.programId,
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(this.connection, owner, transaction);
|
await sendAndConfirmTransaction(this.connection, owner, transaction);
|
||||||
@ -422,7 +436,7 @@ export class Token {
|
|||||||
const transaction = new Transaction({
|
const transaction = new Transaction({
|
||||||
fee: 0,
|
fee: 0,
|
||||||
keys: [owner.publicKey, source, delegate],
|
keys: [owner.publicKey, source, delegate],
|
||||||
programId: Token.programId,
|
programId: this.programId,
|
||||||
userdata,
|
userdata,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(this.connection, owner, transaction);
|
await sendAndConfirmTransaction(this.connection, owner, transaction);
|
||||||
@ -442,13 +456,6 @@ export class Token {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return this.approve(owner, source, delegate, 0);
|
return this.approve(owner, source, delegate, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Program Identifier for the Token program
|
|
||||||
*/
|
|
||||||
static get programId(): PublicKey {
|
|
||||||
return new PublicKey('0x500000000000000000000000000000000000000000000000000000000000000');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
Token,
|
Token,
|
||||||
TokenAmount,
|
TokenAmount,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
|
import {SYSTEM_TOKEN_PROGRAM_ID} from '../src/token-program';
|
||||||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
||||||
import {url} from './url';
|
import {url} from './url';
|
||||||
import {newAccountWithTokens} from './new-account-with-tokens';
|
import {newAccountWithTokens} from './new-account-with-tokens';
|
||||||
@ -111,7 +112,7 @@ test('create new token', async () => {
|
|||||||
{
|
{
|
||||||
error: null,
|
error: null,
|
||||||
result: {
|
result: {
|
||||||
program_id: [...Token.programId.toBuffer()],
|
program_id: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
|
||||||
tokens: 1,
|
tokens: 1,
|
||||||
userdata: [
|
userdata: [
|
||||||
1,
|
1,
|
||||||
@ -149,7 +150,7 @@ test('create new token', async () => {
|
|||||||
{
|
{
|
||||||
error: null,
|
error: null,
|
||||||
result: {
|
result: {
|
||||||
program_id: [...Token.programId.toBuffer()],
|
program_id: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
|
||||||
tokens: 1,
|
tokens: 1,
|
||||||
userdata: [
|
userdata: [
|
||||||
2,
|
2,
|
||||||
@ -206,7 +207,7 @@ test('create new token account', async () => {
|
|||||||
{
|
{
|
||||||
error: null,
|
error: null,
|
||||||
result: {
|
result: {
|
||||||
program_id: [...Token.programId.toBuffer()],
|
program_id: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
|
||||||
tokens: 1,
|
tokens: 1,
|
||||||
userdata: [
|
userdata: [
|
||||||
2,
|
2,
|
||||||
@ -263,7 +264,7 @@ test('transfer', async () => {
|
|||||||
{
|
{
|
||||||
error: null,
|
error: null,
|
||||||
result: {
|
result: {
|
||||||
program_id: [...Token.programId.toBuffer()],
|
program_id: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
|
||||||
tokens: 1,
|
tokens: 1,
|
||||||
userdata: [
|
userdata: [
|
||||||
2,
|
2,
|
||||||
@ -305,7 +306,7 @@ test('transfer', async () => {
|
|||||||
{
|
{
|
||||||
error: null,
|
error: null,
|
||||||
result: {
|
result: {
|
||||||
program_id: [...Token.programId.toBuffer()],
|
program_id: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
|
||||||
tokens: 1,
|
tokens: 1,
|
||||||
userdata: [
|
userdata: [
|
||||||
2,
|
2,
|
||||||
@ -371,7 +372,7 @@ test('approve/revoke', async () => {
|
|||||||
{
|
{
|
||||||
error: null,
|
error: null,
|
||||||
result: {
|
result: {
|
||||||
program_id: [...Token.programId.toBuffer()],
|
program_id: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
|
||||||
tokens: 1,
|
tokens: 1,
|
||||||
userdata: [
|
userdata: [
|
||||||
2,
|
2,
|
||||||
@ -426,7 +427,7 @@ test('approve/revoke', async () => {
|
|||||||
{
|
{
|
||||||
error: null,
|
error: null,
|
||||||
result: {
|
result: {
|
||||||
program_id: [...Token.programId.toBuffer()],
|
program_id: [...SYSTEM_TOKEN_PROGRAM_ID.toBuffer()],
|
||||||
tokens: 1,
|
tokens: 1,
|
||||||
userdata: [
|
userdata: [
|
||||||
2,
|
2,
|
||||||
|
Reference in New Issue
Block a user