This repository was archived by the owner on Mar 11, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Expand file tree
/
Copy pathmint.ts
More file actions
205 lines (189 loc) · 7.06 KB
/
mint.ts
File metadata and controls
205 lines (189 loc) · 7.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import { struct, u32, u8 } from '@solana/buffer-layout';
import { bool, publicKey, u64 } from '@solana/buffer-layout-utils';
import type { AccountInfo, Commitment, Connection } from '@solana/web3.js';
import { PublicKey } from '@solana/web3.js';
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants.js';
import {
TokenAccountNotFoundError,
TokenInvalidAccountOwnerError,
TokenInvalidAccountSizeError,
TokenInvalidMintError,
TokenOwnerOffCurveError,
} from '../errors.js';
import { ACCOUNT_TYPE_SIZE, AccountType } from '../extensions/accountType.js';
import type { ExtensionType } from '../extensions/extensionType.js';
import { getMintLen } from '../extensions/extensionType.js';
import { ACCOUNT_SIZE } from './account.js';
import { MULTISIG_SIZE } from './multisig.js';
/** Information about a mint */
export interface Mint {
/** Address of the mint */
address: PublicKey;
/**
* Optional authority used to mint new tokens. The mint authority may only be provided during mint creation.
* If no mint authority is present then the mint has a fixed supply and no further tokens may be minted.
*/
mintAuthority: PublicKey | null;
/** Total supply of tokens */
supply: bigint;
/** Number of base 10 digits to the right of the decimal place */
decimals: number;
/** Is this mint initialized */
isInitialized: boolean;
/** Optional authority to freeze token accounts */
freezeAuthority: PublicKey | null;
/** Additional data for extension */
tlvData: Buffer;
}
/** Mint as stored by the program */
export interface RawMint {
mintAuthorityOption: 1 | 0;
mintAuthority: PublicKey;
supply: bigint;
decimals: number;
isInitialized: boolean;
freezeAuthorityOption: 1 | 0;
freezeAuthority: PublicKey;
}
/** Buffer layout for de/serializing a mint */
export const MintLayout = struct<RawMint>([
u32('mintAuthorityOption'),
publicKey('mintAuthority'),
u64('supply'),
u8('decimals'),
bool('isInitialized'),
u32('freezeAuthorityOption'),
publicKey('freezeAuthority'),
]);
/** Byte length of a mint */
export const MINT_SIZE = MintLayout.span;
/**
* Retrieve information about a mint
*
* @param connection Connection to use
* @param address Mint account
* @param commitment Desired level of commitment for querying the state
* @param programId SPL Token program account
*
* @return Mint information
*/
export async function getMint(
connection: Connection,
address: PublicKey,
commitment?: Commitment,
programId = TOKEN_PROGRAM_ID
): Promise<Mint> {
const info = await connection.getAccountInfo(address, commitment);
return unpackMint(address, info, programId);
}
/**
* Unpack a mint
*
* @param address Mint account
* @param info Mint account data
* @param programId SPL Token program account
*
* @return Unpacked mint
*/
export function unpackMint(address: PublicKey, info: AccountInfo<Buffer> | null, programId = TOKEN_PROGRAM_ID): Mint {
if (!info) throw new TokenAccountNotFoundError();
if (!info.owner.equals(programId)) throw new TokenInvalidAccountOwnerError();
if (info.data.length < MINT_SIZE) throw new TokenInvalidAccountSizeError();
const rawMint = MintLayout.decode(info.data.slice(0, MINT_SIZE));
let tlvData = Buffer.alloc(0);
if (info.data.length > MINT_SIZE) {
if (info.data.length <= ACCOUNT_SIZE) throw new TokenInvalidAccountSizeError();
if (info.data.length === MULTISIG_SIZE) throw new TokenInvalidAccountSizeError();
if (info.data[ACCOUNT_SIZE] != AccountType.Mint) throw new TokenInvalidMintError();
tlvData = info.data.slice(ACCOUNT_SIZE + ACCOUNT_TYPE_SIZE);
}
return {
address,
mintAuthority: rawMint.mintAuthorityOption ? rawMint.mintAuthority : null,
supply: rawMint.supply,
decimals: rawMint.decimals,
isInitialized: rawMint.isInitialized,
freezeAuthority: rawMint.freezeAuthorityOption ? rawMint.freezeAuthority : null,
tlvData,
};
}
/** Get the minimum lamport balance for a mint to be rent exempt
*
* @param connection Connection to use
* @param commitment Desired level of commitment for querying the state
*
* @return Amount of lamports required
*/
export async function getMinimumBalanceForRentExemptMint(
connection: Connection,
commitment?: Commitment
): Promise<number> {
return await getMinimumBalanceForRentExemptMintWithExtensions(connection, [], commitment);
}
/** Get the minimum lamport balance for a rent-exempt mint with extensions
*
* @param connection Connection to use
* @param extensions Extension types included in the mint
* @param commitment Desired level of commitment for querying the state
*
* @return Amount of lamports required
*/
export async function getMinimumBalanceForRentExemptMintWithExtensions(
connection: Connection,
extensions: ExtensionType[],
commitment?: Commitment
): Promise<number> {
const mintLen = getMintLen(extensions);
return await connection.getMinimumBalanceForRentExemption(mintLen, commitment);
}
/**
* Async version of getAssociatedTokenAddressSync
* For backwards compatibility
*
* @param mint Token mint account
* @param owner Owner of the new account
* @param allowOwnerOffCurve Allow the owner account to be a PDA (Program Derived Address)
* @param programId SPL Token program account
* @param associatedTokenProgramId SPL Associated Token program account
*
* @return Promise containing the address of the associated token account
*/
export async function getAssociatedTokenAddress(
mint: PublicKey,
owner: PublicKey,
allowOwnerOffCurve = false,
programId = TOKEN_PROGRAM_ID,
associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID
): Promise<PublicKey> {
if (!allowOwnerOffCurve && !PublicKey.isOnCurve(owner.toBuffer())) throw new TokenOwnerOffCurveError();
const [address] = await PublicKey.findProgramAddress(
[owner.toBuffer(), programId.toBuffer(), mint.toBuffer()],
associatedTokenProgramId
);
return address;
}
/**
* Get the address of the associated token account for a given mint and owner
*
* @param mint Token mint account
* @param owner Owner of the new account
* @param allowOwnerOffCurve Allow the owner account to be a PDA (Program Derived Address)
* @param programId SPL Token program account
* @param associatedTokenProgramId SPL Associated Token program account
*
* @return Address of the associated token account
*/
export function getAssociatedTokenAddressSync(
mint: PublicKey,
owner: PublicKey,
allowOwnerOffCurve = false,
programId = TOKEN_PROGRAM_ID,
associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID
): PublicKey {
if (!allowOwnerOffCurve && !PublicKey.isOnCurve(owner.toBuffer())) throw new TokenOwnerOffCurveError();
const [address] = PublicKey.findProgramAddressSync(
[owner.toBuffer(), programId.toBuffer(), mint.toBuffer()],
associatedTokenProgramId
);
return address;
}