Skip to content

Commit

Permalink
Define reallocate IDL instruction (#11)
Browse files Browse the repository at this point in the history
* Add instruction

* Add extensionType

* Add test

* Update test

* Fix test
  • Loading branch information
lorisleiva authored Oct 8, 2024
1 parent f733892 commit 84c670b
Show file tree
Hide file tree
Showing 7 changed files with 687 additions and 1 deletion.
1 change: 1 addition & 0 deletions clients/js/src/generated/instructions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export * from './initializeMultisig2';
export * from './initializeTransferFeeConfig';
export * from './mintTo';
export * from './mintToChecked';
export * from './reallocate';
export * from './recoverNestedAssociatedToken';
export * from './revoke';
export * from './setAuthority';
Expand Down
267 changes: 267 additions & 0 deletions clients/js/src/generated/instructions/reallocate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/**
* This code was AUTOGENERATED using the kinobi library.
* Please DO NOT EDIT THIS FILE, instead use visitors
* to add features, then rerun kinobi to update it.
*
* @see https://github.com/kinobi-so/kinobi
*/

import {
AccountRole,
combineCodec,
getArrayDecoder,
getArrayEncoder,
getStructDecoder,
getStructEncoder,
getU8Decoder,
getU8Encoder,
transformEncoder,
type Address,
type Codec,
type Decoder,
type Encoder,
type IAccountMeta,
type IAccountSignerMeta,
type IInstruction,
type IInstructionWithAccounts,
type IInstructionWithData,
type ReadonlyAccount,
type ReadonlySignerAccount,
type TransactionSigner,
type WritableAccount,
type WritableSignerAccount,
} from '@solana/web3.js';
import { TOKEN_2022_PROGRAM_ADDRESS } from '../programs';
import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
import {
getExtensionTypeDecoder,
getExtensionTypeEncoder,
type ExtensionType,
type ExtensionTypeArgs,
} from '../types';

export const REALLOCATE_DISCRIMINATOR = 29;

export function getReallocateDiscriminatorBytes() {
return getU8Encoder().encode(REALLOCATE_DISCRIMINATOR);
}

export type ReallocateInstruction<
TProgram extends string = typeof TOKEN_2022_PROGRAM_ADDRESS,
TAccountToken extends string | IAccountMeta<string> = string,
TAccountPayer extends string | IAccountMeta<string> = string,
TAccountSystemProgram extends
| string
| IAccountMeta<string> = '11111111111111111111111111111111',
TAccountOwner extends string | IAccountMeta<string> = string,
TRemainingAccounts extends readonly IAccountMeta<string>[] = [],
> = IInstruction<TProgram> &
IInstructionWithData<Uint8Array> &
IInstructionWithAccounts<
[
TAccountToken extends string
? WritableAccount<TAccountToken>
: TAccountToken,
TAccountPayer extends string
? WritableSignerAccount<TAccountPayer> &
IAccountSignerMeta<TAccountPayer>
: TAccountPayer,
TAccountSystemProgram extends string
? ReadonlyAccount<TAccountSystemProgram>
: TAccountSystemProgram,
TAccountOwner extends string
? ReadonlyAccount<TAccountOwner>
: TAccountOwner,
...TRemainingAccounts,
]
>;

export type ReallocateInstructionData = {
discriminator: number;
/** New extension types to include in the reallocated account. */
newExtensionTypes: Array<ExtensionType>;
};

export type ReallocateInstructionDataArgs = {
/** New extension types to include in the reallocated account. */
newExtensionTypes: Array<ExtensionTypeArgs>;
};

export function getReallocateInstructionDataEncoder(): Encoder<ReallocateInstructionDataArgs> {
return transformEncoder(
getStructEncoder([
['discriminator', getU8Encoder()],
[
'newExtensionTypes',
getArrayEncoder(getExtensionTypeEncoder(), { size: 'remainder' }),
],
]),
(value) => ({ ...value, discriminator: REALLOCATE_DISCRIMINATOR })
);
}

export function getReallocateInstructionDataDecoder(): Decoder<ReallocateInstructionData> {
return getStructDecoder([
['discriminator', getU8Decoder()],
[
'newExtensionTypes',
getArrayDecoder(getExtensionTypeDecoder(), { size: 'remainder' }),
],
]);
}

export function getReallocateInstructionDataCodec(): Codec<
ReallocateInstructionDataArgs,
ReallocateInstructionData
> {
return combineCodec(
getReallocateInstructionDataEncoder(),
getReallocateInstructionDataDecoder()
);
}

export type ReallocateInput<
TAccountToken extends string = string,
TAccountPayer extends string = string,
TAccountSystemProgram extends string = string,
TAccountOwner extends string = string,
> = {
/** The token account to reallocate. */
token: Address<TAccountToken>;
/** The payer account to fund reallocation. */
payer: TransactionSigner<TAccountPayer>;
/** System program for reallocation funding. */
systemProgram?: Address<TAccountSystemProgram>;
/** The account's owner or its multisignature account. */
owner: Address<TAccountOwner> | TransactionSigner<TAccountOwner>;
newExtensionTypes: ReallocateInstructionDataArgs['newExtensionTypes'];
multiSigners?: Array<TransactionSigner>;
};

export function getReallocateInstruction<
TAccountToken extends string,
TAccountPayer extends string,
TAccountSystemProgram extends string,
TAccountOwner extends string,
>(
input: ReallocateInput<
TAccountToken,
TAccountPayer,
TAccountSystemProgram,
TAccountOwner
>
): ReallocateInstruction<
typeof TOKEN_2022_PROGRAM_ADDRESS,
TAccountToken,
TAccountPayer,
TAccountSystemProgram,
(typeof input)['owner'] extends TransactionSigner<TAccountOwner>
? ReadonlySignerAccount<TAccountOwner> & IAccountSignerMeta<TAccountOwner>
: TAccountOwner
> {
// Program address.
const programAddress = TOKEN_2022_PROGRAM_ADDRESS;

// Original accounts.
const originalAccounts = {
token: { value: input.token ?? null, isWritable: true },
payer: { value: input.payer ?? null, isWritable: true },
systemProgram: { value: input.systemProgram ?? null, isWritable: false },
owner: { value: input.owner ?? null, isWritable: false },
};
const accounts = originalAccounts as Record<
keyof typeof originalAccounts,
ResolvedAccount
>;

// Original args.
const args = { ...input };

// Resolve default values.
if (!accounts.systemProgram.value) {
accounts.systemProgram.value =
'11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>;
}

// Remaining accounts.
const remainingAccounts: IAccountMeta[] = (args.multiSigners ?? []).map(
(signer) => ({
address: signer.address,
role: AccountRole.READONLY_SIGNER,
signer,
})
);

const getAccountMeta = getAccountMetaFactory(programAddress, 'programId');
const instruction = {
accounts: [
getAccountMeta(accounts.token),
getAccountMeta(accounts.payer),
getAccountMeta(accounts.systemProgram),
getAccountMeta(accounts.owner),
...remainingAccounts,
],
programAddress,
data: getReallocateInstructionDataEncoder().encode(
args as ReallocateInstructionDataArgs
),
} as ReallocateInstruction<
typeof TOKEN_2022_PROGRAM_ADDRESS,
TAccountToken,
TAccountPayer,
TAccountSystemProgram,
(typeof input)['owner'] extends TransactionSigner<TAccountOwner>
? ReadonlySignerAccount<TAccountOwner> & IAccountSignerMeta<TAccountOwner>
: TAccountOwner
>;

return instruction;
}

export type ParsedReallocateInstruction<
TProgram extends string = typeof TOKEN_2022_PROGRAM_ADDRESS,
TAccountMetas extends readonly IAccountMeta[] = readonly IAccountMeta[],
> = {
programAddress: Address<TProgram>;
accounts: {
/** The token account to reallocate. */
token: TAccountMetas[0];
/** The payer account to fund reallocation. */
payer: TAccountMetas[1];
/** System program for reallocation funding. */
systemProgram: TAccountMetas[2];
/** The account's owner or its multisignature account. */
owner: TAccountMetas[3];
};
data: ReallocateInstructionData;
};

export function parseReallocateInstruction<
TProgram extends string,
TAccountMetas extends readonly IAccountMeta[],
>(
instruction: IInstruction<TProgram> &
IInstructionWithAccounts<TAccountMetas> &
IInstructionWithData<Uint8Array>
): ParsedReallocateInstruction<TProgram, TAccountMetas> {
if (instruction.accounts.length < 4) {
// TODO: Coded error.
throw new Error('Not enough accounts');
}
let accountIndex = 0;
const getNextAccount = () => {
const accountMeta = instruction.accounts![accountIndex]!;
accountIndex += 1;
return accountMeta;
};
return {
programAddress: instruction.programAddress,
accounts: {
token: getNextAccount(),
payer: getNextAccount(),
systemProgram: getNextAccount(),
owner: getNextAccount(),
},
data: getReallocateInstructionDataDecoder().decode(instruction.data),
};
}
10 changes: 9 additions & 1 deletion clients/js/src/generated/programs/token2022.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
type ParsedInitializeTransferFeeConfigInstruction,
type ParsedMintToCheckedInstruction,
type ParsedMintToInstruction,
type ParsedReallocateInstruction,
type ParsedRevokeInstruction,
type ParsedSetAuthorityInstruction,
type ParsedSetTransferFeeInstruction,
Expand Down Expand Up @@ -139,6 +140,7 @@ export enum Token2022Instruction {
ConfidentialTransferWithFee,
InitializeDefaultAccountState,
UpdateDefaultAccountState,
Reallocate,
}

export function identifyToken2022Instruction(
Expand Down Expand Up @@ -355,6 +357,9 @@ export function identifyToken2022Instruction(
) {
return Token2022Instruction.UpdateDefaultAccountState;
}
if (containsBytes(data, getU8Encoder().encode(29), 0)) {
return Token2022Instruction.Reallocate;
}
throw new Error(
'The provided instruction could not be identified as a token-2022 instruction.'
);
Expand Down Expand Up @@ -506,4 +511,7 @@ export type ParsedToken2022Instruction<
} & ParsedInitializeDefaultAccountStateInstruction<TProgram>)
| ({
instructionType: Token2022Instruction.UpdateDefaultAccountState;
} & ParsedUpdateDefaultAccountStateInstruction<TProgram>);
} & ParsedUpdateDefaultAccountStateInstruction<TProgram>)
| ({
instructionType: Token2022Instruction.Reallocate;
} & ParsedReallocateInstruction<TProgram>);
68 changes: 68 additions & 0 deletions clients/js/src/generated/types/extensionType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* This code was AUTOGENERATED using the kinobi library.
* Please DO NOT EDIT THIS FILE, instead use visitors
* to add features, then rerun kinobi to update it.
*
* @see https://github.com/kinobi-so/kinobi
*/

import {
combineCodec,
getEnumDecoder,
getEnumEncoder,
getU16Decoder,
getU16Encoder,
type Codec,
type Decoder,
type Encoder,
} from '@solana/web3.js';

/**
* Extensions that can be applied to mints or accounts. Mint extensions must
* only be applied to mint accounts, and account extensions must only be
* applied to token holding accounts.
*/

export enum ExtensionType {
Uninitialized,
TransferFeeConfig,
TransferFeeAmount,
MintCloseAuthority,
ConfidentialTransferMint,
ConfidentialTransferAccount,
DefaultAccountState,
ImmutableOwner,
MemoTransfer,
NonTransferable,
InterestBearingConfig,
CpiGuard,
PermanentDelegate,
NonTransferableAccount,
TransferHook,
TransferHookAccount,
ConfidentialTransferFee,
ConfidentialTransferFeeAmount,
MetadataPointer,
TokenMetadata,
GroupPointer,
TokenGroup,
GroupMemberPointer,
TokenGroupMember,
}

export type ExtensionTypeArgs = ExtensionType;

export function getExtensionTypeEncoder(): Encoder<ExtensionTypeArgs> {
return getEnumEncoder(ExtensionType, { size: getU16Encoder() });
}

export function getExtensionTypeDecoder(): Decoder<ExtensionType> {
return getEnumDecoder(ExtensionType, { size: getU16Decoder() });
}

export function getExtensionTypeCodec(): Codec<
ExtensionTypeArgs,
ExtensionType
> {
return combineCodec(getExtensionTypeEncoder(), getExtensionTypeDecoder());
}
1 change: 1 addition & 0 deletions clients/js/src/generated/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export * from './authorityType';
export * from './decryptableBalance';
export * from './encryptedBalance';
export * from './extension';
export * from './extensionType';
export * from './transferFee';
Loading

0 comments on commit 84c670b

Please sign in to comment.