1
+ import type { AccountInfo , PublicKey } from '@solana/web3.js' ;
2
+
1
3
import { ACCOUNT_SIZE } from '../state/account.js' ;
2
4
import type { Mint } from '../state/mint.js' ;
3
- import { MINT_SIZE } from '../state/mint.js' ;
5
+ import { MINT_SIZE , unpackMint } from '../state/mint.js' ;
4
6
import { MULTISIG_SIZE } from '../state/multisig.js' ;
5
7
import { ACCOUNT_TYPE_SIZE } from './accountType.js' ;
6
8
import { CPI_GUARD_SIZE } from './cpiGuard/index.js' ;
@@ -14,6 +16,7 @@ import { NON_TRANSFERABLE_SIZE, NON_TRANSFERABLE_ACCOUNT_SIZE } from './nonTrans
14
16
import { PERMANENT_DELEGATE_SIZE } from './permanentDelegate.js' ;
15
17
import { TRANSFER_FEE_AMOUNT_SIZE , TRANSFER_FEE_CONFIG_SIZE } from './transferFee/index.js' ;
16
18
import { TRANSFER_HOOK_ACCOUNT_SIZE , TRANSFER_HOOK_SIZE } from './transferHook/index.js' ;
19
+ import { TOKEN_2022_PROGRAM_ID } from '../constants.js' ;
17
20
18
21
// Sequence from https://github.com/solana-labs/solana-program-library/blob/master/token/program-2022/src/extension/mod.rs#L903
19
22
export enum ExtensionType {
@@ -36,11 +39,16 @@ export enum ExtensionType {
36
39
// ConfidentialTransferFee, // Not implemented yet
37
40
// ConfidentialTransferFeeAmount, // Not implemented yet
38
41
MetadataPointer = 18 , // Remove number once above extensions implemented
42
+ TokenMetadata = 19 , // Remove number once above extensions implemented
39
43
}
40
44
41
45
export const TYPE_SIZE = 2 ;
42
46
export const LENGTH_SIZE = 2 ;
43
47
48
+ function addTypeAndLengthToLen ( len : number ) : number {
49
+ return len + TYPE_SIZE + LENGTH_SIZE ;
50
+ }
51
+
44
52
// NOTE: All of these should eventually use their type's Span instead of these
45
53
// constants. This is provided for at least creation to work.
46
54
export function getTypeLen ( e : ExtensionType ) : number {
@@ -79,6 +87,8 @@ export function getTypeLen(e: ExtensionType): number {
79
87
return TRANSFER_HOOK_SIZE ;
80
88
case ExtensionType . TransferHookAccount :
81
89
return TRANSFER_HOOK_ACCOUNT_SIZE ;
90
+ case ExtensionType . TokenMetadata :
91
+ throw Error ( `Cannot get type length for variable extension type: ${ e } ` ) ;
82
92
default :
83
93
throw Error ( `Unknown extension type: ${ e } ` ) ;
84
94
}
@@ -95,6 +105,7 @@ export function isMintExtension(e: ExtensionType): boolean {
95
105
case ExtensionType . PermanentDelegate :
96
106
case ExtensionType . TransferHook :
97
107
case ExtensionType . MetadataPointer :
108
+ case ExtensionType . TokenMetadata :
98
109
return true ;
99
110
case ExtensionType . Uninitialized :
100
111
case ExtensionType . TransferFeeAmount :
@@ -130,6 +141,7 @@ export function isAccountExtension(e: ExtensionType): boolean {
130
141
case ExtensionType . PermanentDelegate :
131
142
case ExtensionType . TransferHook :
132
143
case ExtensionType . MetadataPointer :
144
+ case ExtensionType . TokenMetadata :
133
145
return false ;
134
146
default :
135
147
throw Error ( `Unknown extension type: ${ e } ` ) ;
@@ -154,6 +166,7 @@ export function getAccountTypeOfMintType(e: ExtensionType): ExtensionType {
154
166
case ExtensionType . MemoTransfer :
155
167
case ExtensionType . MintCloseAuthority :
156
168
case ExtensionType . MetadataPointer :
169
+ case ExtensionType . TokenMetadata :
157
170
case ExtensionType . Uninitialized :
158
171
case ExtensionType . InterestBearingConfig :
159
172
case ExtensionType . PermanentDelegate :
@@ -172,7 +185,7 @@ function getLen(extensionTypes: ExtensionType[], baseSize: number): number {
172
185
ACCOUNT_TYPE_SIZE +
173
186
extensionTypes
174
187
. filter ( ( element , i ) => i === extensionTypes . indexOf ( element ) )
175
- . map ( ( element ) => getTypeLen ( element ) + TYPE_SIZE + LENGTH_SIZE )
188
+ . map ( ( element ) => addTypeAndLengthToLen ( getTypeLen ( element ) ) )
176
189
. reduce ( ( a , b ) => a + b ) ;
177
190
if ( accountLength === MULTISIG_SIZE ) {
178
191
return accountLength + TYPE_SIZE ;
@@ -192,10 +205,10 @@ export function getAccountLen(extensionTypes: ExtensionType[]): number {
192
205
193
206
export function getExtensionData ( extension : ExtensionType , tlvData : Buffer ) : Buffer | null {
194
207
let extensionTypeIndex = 0 ;
195
- while ( extensionTypeIndex + TYPE_SIZE + LENGTH_SIZE <= tlvData . length ) {
208
+ while ( addTypeAndLengthToLen ( extensionTypeIndex ) <= tlvData . length ) {
196
209
const entryType = tlvData . readUInt16LE ( extensionTypeIndex ) ;
197
210
const entryLength = tlvData . readUInt16LE ( extensionTypeIndex + TYPE_SIZE ) ;
198
- const typeIndex = extensionTypeIndex + TYPE_SIZE + LENGTH_SIZE ;
211
+ const typeIndex = addTypeAndLengthToLen ( extensionTypeIndex ) ;
199
212
if ( entryType == extension ) {
200
213
return tlvData . slice ( typeIndex , typeIndex + entryLength ) ;
201
214
}
@@ -211,7 +224,7 @@ export function getExtensionTypes(tlvData: Buffer): ExtensionType[] {
211
224
const entryType = tlvData . readUInt16LE ( extensionTypeIndex ) ;
212
225
extensionTypes . push ( entryType ) ;
213
226
const entryLength = tlvData . readUInt16LE ( extensionTypeIndex + TYPE_SIZE ) ;
214
- extensionTypeIndex += TYPE_SIZE + LENGTH_SIZE + entryLength ;
227
+ extensionTypeIndex += addTypeAndLengthToLen ( entryLength ) ;
215
228
}
216
229
return extensionTypes ;
217
230
}
@@ -221,3 +234,19 @@ export function getAccountLenForMint(mint: Mint): number {
221
234
const accountExtensions = extensionTypes . map ( getAccountTypeOfMintType ) ;
222
235
return getAccountLen ( accountExtensions ) ;
223
236
}
237
+
238
+ export function getNewAccountLenForExtensionLen (
239
+ info : AccountInfo < Buffer > ,
240
+ address : PublicKey ,
241
+ extensionType : ExtensionType ,
242
+ extensionLen : number ,
243
+ programId = TOKEN_2022_PROGRAM_ID
244
+ ) : number {
245
+ const mint = unpackMint ( address , info , programId ) ;
246
+ const extensionData = getExtensionData ( extensionType , mint . tlvData ) ;
247
+
248
+ const currentExtensionLen = extensionData ? addTypeAndLengthToLen ( extensionData . length ) : 0 ;
249
+ const newExtensionLen = addTypeAndLengthToLen ( extensionLen ) ;
250
+
251
+ return info . data . length + newExtensionLen - currentExtensionLen ;
252
+ }
0 commit comments