소스 검색

Export discriminator constants for instructions and accounts (#168)

* Export discriminator constants for instructions and accounts

* Add changesets
Loris Leiva 1 년 전
부모
커밋
2e8ce36af4
60개의 변경된 파일693개의 추가작업 그리고 66개의 파일을 삭제
  1. 5 0
      .changeset/itchy-mirrors-enjoy.md
  2. 5 0
      .changeset/ten-spies-wink.md
  3. 9 4
      packages/renderers-js/e2e/anchor/src/generated/accounts/guardV1.ts
  4. 11 4
      packages/renderers-js/e2e/anchor/src/generated/instructions/createGuard.ts
  5. 9 4
      packages/renderers-js/e2e/anchor/src/generated/instructions/execute.ts
  6. 9 4
      packages/renderers-js/e2e/anchor/src/generated/instructions/initialize.ts
  7. 11 4
      packages/renderers-js/e2e/anchor/src/generated/instructions/updateGuard.ts
  8. 10 1
      packages/renderers-js/e2e/system/src/generated/instructions/advanceNonceAccount.ts
  9. 7 1
      packages/renderers-js/e2e/system/src/generated/instructions/allocate.ts
  10. 7 1
      packages/renderers-js/e2e/system/src/generated/instructions/allocateWithSeed.ts
  11. 7 1
      packages/renderers-js/e2e/system/src/generated/instructions/assign.ts
  12. 7 1
      packages/renderers-js/e2e/system/src/generated/instructions/assignWithSeed.ts
  13. 10 1
      packages/renderers-js/e2e/system/src/generated/instructions/authorizeNonceAccount.ts
  14. 7 1
      packages/renderers-js/e2e/system/src/generated/instructions/createAccount.ts
  15. 10 1
      packages/renderers-js/e2e/system/src/generated/instructions/createAccountWithSeed.ts
  16. 10 1
      packages/renderers-js/e2e/system/src/generated/instructions/initializeNonceAccount.ts
  17. 7 1
      packages/renderers-js/e2e/system/src/generated/instructions/transferSol.ts
  18. 10 1
      packages/renderers-js/e2e/system/src/generated/instructions/transferSolWithSeed.ts
  19. 10 1
      packages/renderers-js/e2e/system/src/generated/instructions/upgradeNonceAccount.ts
  20. 10 1
      packages/renderers-js/e2e/system/src/generated/instructions/withdrawNonceAccount.ts
  21. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/amountToUiAmount.ts
  22. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/approve.ts
  23. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/approveChecked.ts
  24. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/burn.ts
  25. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/burnChecked.ts
  26. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/closeAccount.ts
  27. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/createAccount.ts
  28. 10 1
      packages/renderers-js/e2e/token/src/generated/instructions/createAssociatedToken.ts
  29. 12 1
      packages/renderers-js/e2e/token/src/generated/instructions/createAssociatedTokenIdempotent.ts
  30. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/freezeAccount.ts
  31. 10 1
      packages/renderers-js/e2e/token/src/generated/instructions/getAccountDataSize.ts
  32. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeAccount.ts
  33. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeAccount2.ts
  34. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeAccount3.ts
  35. 10 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeImmutableOwner.ts
  36. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeMint.ts
  37. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeMint2.ts
  38. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeMultisig.ts
  39. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/initializeMultisig2.ts
  40. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/mintTo.ts
  41. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/mintToChecked.ts
  42. 10 1
      packages/renderers-js/e2e/token/src/generated/instructions/recoverNestedAssociatedToken.ts
  43. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/revoke.ts
  44. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/setAuthority.ts
  45. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/syncNative.ts
  46. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/thawAccount.ts
  47. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/transfer.ts
  48. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/transferChecked.ts
  49. 7 1
      packages/renderers-js/e2e/token/src/generated/instructions/uiAmountToAmount.ts
  50. 1 0
      packages/renderers-js/public/templates/pages/accountsPage.njk
  51. 1 0
      packages/renderers-js/public/templates/pages/instructionsPage.njk
  52. 105 0
      packages/renderers-js/src/fragments/discriminatorConstants.ts
  53. 1 0
      packages/renderers-js/src/fragments/index.ts
  54. 19 0
      packages/renderers-js/src/getRenderMapVisitor.ts
  55. 30 1
      packages/renderers-js/src/getTypeManifestVisitor.ts
  56. 5 1
      packages/renderers-js/src/nameTransformers.ts
  57. 65 0
      packages/renderers-js/test/accountsPage.test.ts
  58. 65 0
      packages/renderers-js/test/instructionsPage.test.ts
  59. 4 0
      packages/visitors-core/README.md
  60. 6 2
      packages/visitors-core/src/NodeStack.ts

+ 5 - 0
.changeset/itchy-mirrors-enjoy.md

@@ -0,0 +1,5 @@
+---
+'@kinobi-so/renderers-js': patch
+---
+
+Export discriminator constants for instructions and accounts

+ 5 - 0
.changeset/ten-spies-wink.md

@@ -0,0 +1,5 @@
+---
+'@kinobi-so/visitors-core': patch
+---
+
+Add `find` helper function to the `NodeStack` class

+ 9 - 4
packages/renderers-js/e2e/anchor/src/generated/accounts/guardV1.ts

@@ -57,6 +57,14 @@ import {
   type TransferAmountRuleArgs,
 } from '../types';
 
+export const GUARD_V1_DISCRIMINATOR = new Uint8Array([
+  185, 149, 156, 78, 245, 108, 172, 68,
+]);
+
+export function getGuardV1DiscriminatorBytes() {
+  return fixEncoderSize(getBytesEncoder(), 8).encode(GUARD_V1_DISCRIMINATOR);
+}
+
 export type GuardV1 = {
   discriminator: ReadonlyUint8Array;
   /** Mint token representing the guard, do not confuse with the mint of the token being transferred. */
@@ -97,10 +105,7 @@ export function getGuardV1Encoder(): Encoder<GuardV1Args> {
         getArrayEncoder(getMetadataAdditionalFieldRuleEncoder()),
       ],
     ]),
-    (value) => ({
-      ...value,
-      discriminator: new Uint8Array([185, 149, 156, 78, 245, 108, 172, 68]),
-    })
+    (value) => ({ ...value, discriminator: GUARD_V1_DISCRIMINATOR })
   );
 }
 

+ 11 - 4
packages/renderers-js/e2e/anchor/src/generated/instructions/createGuard.ts

@@ -66,6 +66,16 @@ import {
   type TransferAmountRuleArgs,
 } from '../types';
 
+export const CREATE_GUARD_DISCRIMINATOR = new Uint8Array([
+  251, 254, 17, 198, 219, 218, 154, 99,
+]);
+
+export function getCreateGuardDiscriminatorBytes() {
+  return fixEncoderSize(getBytesEncoder(), 8).encode(
+    CREATE_GUARD_DISCRIMINATOR
+  );
+}
+
 export type CreateGuardInstruction<
   TProgram extends string = typeof WEN_TRANSFER_GUARD_PROGRAM_ADDRESS,
   TAccountGuard extends string | IAccountMeta<string> = string,
@@ -150,10 +160,7 @@ export function getCreateGuardInstructionDataEncoder(): Encoder<CreateGuardInstr
         getArrayEncoder(getMetadataAdditionalFieldRuleEncoder()),
       ],
     ]),
-    (value) => ({
-      ...value,
-      discriminator: new Uint8Array([251, 254, 17, 198, 219, 218, 154, 99]),
-    })
+    (value) => ({ ...value, discriminator: CREATE_GUARD_DISCRIMINATOR })
   );
 }
 

+ 9 - 4
packages/renderers-js/e2e/anchor/src/generated/instructions/execute.ts

@@ -37,6 +37,14 @@ import {
   type ResolvedAccount,
 } from '../shared';
 
+export const EXECUTE_DISCRIMINATOR = new Uint8Array([
+  105, 37, 101, 197, 75, 251, 102, 26,
+]);
+
+export function getExecuteDiscriminatorBytes() {
+  return fixEncoderSize(getBytesEncoder(), 8).encode(EXECUTE_DISCRIMINATOR);
+}
+
 export type ExecuteInstruction<
   TProgram extends string = typeof WEN_TRANSFER_GUARD_PROGRAM_ADDRESS,
   TAccountSourceAccount extends string | IAccountMeta<string> = string,
@@ -91,10 +99,7 @@ export function getExecuteInstructionDataEncoder(): Encoder<ExecuteInstructionDa
       ['discriminator', fixEncoderSize(getBytesEncoder(), 8)],
       ['amount', getU64Encoder()],
     ]),
-    (value) => ({
-      ...value,
-      discriminator: new Uint8Array([105, 37, 101, 197, 75, 251, 102, 26]),
-    })
+    (value) => ({ ...value, discriminator: EXECUTE_DISCRIMINATOR })
   );
 }
 

+ 9 - 4
packages/renderers-js/e2e/anchor/src/generated/instructions/initialize.ts

@@ -39,6 +39,14 @@ import {
   type ResolvedAccount,
 } from '../shared';
 
+export const INITIALIZE_DISCRIMINATOR = new Uint8Array([
+  43, 34, 13, 49, 167, 88, 235, 235,
+]);
+
+export function getInitializeDiscriminatorBytes() {
+  return fixEncoderSize(getBytesEncoder(), 8).encode(INITIALIZE_DISCRIMINATOR);
+}
+
 export type InitializeInstruction<
   TProgram extends string = typeof WEN_TRANSFER_GUARD_PROGRAM_ADDRESS,
   TAccountExtraMetasAccount extends string | IAccountMeta<string> = string,
@@ -85,10 +93,7 @@ export type InitializeInstructionDataArgs = {};
 export function getInitializeInstructionDataEncoder(): Encoder<InitializeInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', fixEncoderSize(getBytesEncoder(), 8)]]),
-    (value) => ({
-      ...value,
-      discriminator: new Uint8Array([43, 34, 13, 49, 167, 88, 235, 235]),
-    })
+    (value) => ({ ...value, discriminator: INITIALIZE_DISCRIMINATOR })
   );
 }
 

+ 11 - 4
packages/renderers-js/e2e/anchor/src/generated/instructions/updateGuard.ts

@@ -59,6 +59,16 @@ import {
   type TransferAmountRuleArgs,
 } from '../types';
 
+export const UPDATE_GUARD_DISCRIMINATOR = new Uint8Array([
+  51, 38, 175, 180, 25, 249, 39, 24,
+]);
+
+export function getUpdateGuardDiscriminatorBytes() {
+  return fixEncoderSize(getBytesEncoder(), 8).encode(
+    UPDATE_GUARD_DISCRIMINATOR
+  );
+}
+
 export type UpdateGuardInstruction<
   TProgram extends string = typeof WEN_TRANSFER_GUARD_PROGRAM_ADDRESS,
   TAccountGuard extends string | IAccountMeta<string> = string,
@@ -123,10 +133,7 @@ export function getUpdateGuardInstructionDataEncoder(): Encoder<UpdateGuardInstr
         getArrayEncoder(getMetadataAdditionalFieldRuleEncoder()),
       ],
     ]),
-    (value) => ({
-      ...value,
-      discriminator: new Uint8Array([51, 38, 175, 180, 25, 249, 39, 24]),
-    })
+    (value) => ({ ...value, discriminator: UPDATE_GUARD_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/system/src/generated/instructions/advanceNonceAccount.ts

@@ -30,6 +30,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const ADVANCE_NONCE_ACCOUNT_DISCRIMINATOR = 4;
+
+export function getAdvanceNonceAccountDiscriminatorBytes() {
+  return getU32Encoder().encode(ADVANCE_NONCE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type AdvanceNonceAccountInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountNonceAccount extends string | IAccountMeta<string> = string,
@@ -63,7 +69,10 @@ export type AdvanceNonceAccountInstructionDataArgs = {};
 export function getAdvanceNonceAccountInstructionDataEncoder(): Encoder<AdvanceNonceAccountInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU32Encoder()]]),
-    (value) => ({ ...value, discriminator: 4 })
+    (value) => ({
+      ...value,
+      discriminator: ADVANCE_NONCE_ACCOUNT_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/system/src/generated/instructions/allocate.ts

@@ -30,6 +30,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const ALLOCATE_DISCRIMINATOR = 8;
+
+export function getAllocateDiscriminatorBytes() {
+  return getU32Encoder().encode(ALLOCATE_DISCRIMINATOR);
+}
+
 export type AllocateInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountNewAccount extends string | IAccountMeta<string> = string,
@@ -56,7 +62,7 @@ export function getAllocateInstructionDataEncoder(): Encoder<AllocateInstruction
       ['discriminator', getU32Encoder()],
       ['space', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 8 })
+    (value) => ({ ...value, discriminator: ALLOCATE_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/system/src/generated/instructions/allocateWithSeed.ts

@@ -37,6 +37,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const ALLOCATE_WITH_SEED_DISCRIMINATOR = 9;
+
+export function getAllocateWithSeedDiscriminatorBytes() {
+  return getU32Encoder().encode(ALLOCATE_WITH_SEED_DISCRIMINATOR);
+}
+
 export type AllocateWithSeedInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountNewAccount extends string | IAccountMeta<string> = string,
@@ -81,7 +87,7 @@ export function getAllocateWithSeedInstructionDataEncoder(): Encoder<AllocateWit
       ['space', getU64Encoder()],
       ['programAddress', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 9 })
+    (value) => ({ ...value, discriminator: ALLOCATE_WITH_SEED_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/system/src/generated/instructions/assign.ts

@@ -30,6 +30,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const ASSIGN_DISCRIMINATOR = 1;
+
+export function getAssignDiscriminatorBytes() {
+  return getU32Encoder().encode(ASSIGN_DISCRIMINATOR);
+}
+
 export type AssignInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -59,7 +65,7 @@ export function getAssignInstructionDataEncoder(): Encoder<AssignInstructionData
       ['discriminator', getU32Encoder()],
       ['programAddress', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 1 })
+    (value) => ({ ...value, discriminator: ASSIGN_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/system/src/generated/instructions/assignWithSeed.ts

@@ -35,6 +35,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const ASSIGN_WITH_SEED_DISCRIMINATOR = 10;
+
+export function getAssignWithSeedDiscriminatorBytes() {
+  return getU32Encoder().encode(ASSIGN_WITH_SEED_DISCRIMINATOR);
+}
+
 export type AssignWithSeedInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -76,7 +82,7 @@ export function getAssignWithSeedInstructionDataEncoder(): Encoder<AssignWithSee
       ['seed', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
       ['programAddress', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 10 })
+    (value) => ({ ...value, discriminator: ASSIGN_WITH_SEED_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/system/src/generated/instructions/authorizeNonceAccount.ts

@@ -31,6 +31,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const AUTHORIZE_NONCE_ACCOUNT_DISCRIMINATOR = 7;
+
+export function getAuthorizeNonceAccountDiscriminatorBytes() {
+  return getU32Encoder().encode(AUTHORIZE_NONCE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type AuthorizeNonceAccountInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountNonceAccount extends string | IAccountMeta<string> = string,
@@ -66,7 +72,10 @@ export function getAuthorizeNonceAccountInstructionDataEncoder(): Encoder<Author
       ['discriminator', getU32Encoder()],
       ['newNonceAuthority', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 7 })
+    (value) => ({
+      ...value,
+      discriminator: AUTHORIZE_NONCE_ACCOUNT_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/system/src/generated/instructions/createAccount.ts

@@ -40,6 +40,12 @@ import {
   type ResolvedAccount,
 } from '../shared';
 
+export const CREATE_ACCOUNT_DISCRIMINATOR = 0;
+
+export function getCreateAccountDiscriminatorBytes() {
+  return getU32Encoder().encode(CREATE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type CreateAccountInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountPayer extends string | IAccountMeta<string> = string,
@@ -82,7 +88,7 @@ export function getCreateAccountInstructionDataEncoder(): Encoder<CreateAccountI
       ['space', getU64Encoder()],
       ['programAddress', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 0 })
+    (value) => ({ ...value, discriminator: CREATE_ACCOUNT_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/system/src/generated/instructions/createAccountWithSeed.ts

@@ -38,6 +38,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const CREATE_ACCOUNT_WITH_SEED_DISCRIMINATOR = 3;
+
+export function getCreateAccountWithSeedDiscriminatorBytes() {
+  return getU32Encoder().encode(CREATE_ACCOUNT_WITH_SEED_DISCRIMINATOR);
+}
+
 export type CreateAccountWithSeedInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountPayer extends string | IAccountMeta<string> = string,
@@ -90,7 +96,10 @@ export function getCreateAccountWithSeedInstructionDataEncoder(): Encoder<Create
       ['space', getU64Encoder()],
       ['programAddress', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 3 })
+    (value) => ({
+      ...value,
+      discriminator: CREATE_ACCOUNT_WITH_SEED_DISCRIMINATOR,
+    })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/system/src/generated/instructions/initializeNonceAccount.ts

@@ -29,6 +29,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_NONCE_ACCOUNT_DISCRIMINATOR = 6;
+
+export function getInitializeNonceAccountDiscriminatorBytes() {
+  return getU32Encoder().encode(INITIALIZE_NONCE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type InitializeNonceAccountInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountNonceAccount extends string | IAccountMeta<string> = string,
@@ -71,7 +77,10 @@ export function getInitializeNonceAccountInstructionDataEncoder(): Encoder<Initi
       ['discriminator', getU32Encoder()],
       ['nonceAuthority', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 6 })
+    (value) => ({
+      ...value,
+      discriminator: INITIALIZE_NONCE_ACCOUNT_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/system/src/generated/instructions/transferSol.ts

@@ -31,6 +31,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const TRANSFER_SOL_DISCRIMINATOR = 2;
+
+export function getTransferSolDiscriminatorBytes() {
+  return getU32Encoder().encode(TRANSFER_SOL_DISCRIMINATOR);
+}
+
 export type TransferSolInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountSource extends string | IAccountMeta<string> = string,
@@ -64,7 +70,7 @@ export function getTransferSolInstructionDataEncoder(): Encoder<TransferSolInstr
       ['discriminator', getU32Encoder()],
       ['amount', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 2 })
+    (value) => ({ ...value, discriminator: TRANSFER_SOL_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/system/src/generated/instructions/transferSolWithSeed.ts

@@ -37,6 +37,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const TRANSFER_SOL_WITH_SEED_DISCRIMINATOR = 11;
+
+export function getTransferSolWithSeedDiscriminatorBytes() {
+  return getU32Encoder().encode(TRANSFER_SOL_WITH_SEED_DISCRIMINATOR);
+}
+
 export type TransferSolWithSeedInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountSource extends string | IAccountMeta<string> = string,
@@ -82,7 +88,10 @@ export function getTransferSolWithSeedInstructionDataEncoder(): Encoder<Transfer
       ['fromSeed', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
       ['fromOwner', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 11 })
+    (value) => ({
+      ...value,
+      discriminator: TRANSFER_SOL_WITH_SEED_DISCRIMINATOR,
+    })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/system/src/generated/instructions/upgradeNonceAccount.ts

@@ -26,6 +26,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const UPGRADE_NONCE_ACCOUNT_DISCRIMINATOR = 12;
+
+export function getUpgradeNonceAccountDiscriminatorBytes() {
+  return getU32Encoder().encode(UPGRADE_NONCE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type UpgradeNonceAccountInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountNonceAccount extends string | IAccountMeta<string> = string,
@@ -48,7 +54,10 @@ export type UpgradeNonceAccountInstructionDataArgs = {};
 export function getUpgradeNonceAccountInstructionDataEncoder(): Encoder<UpgradeNonceAccountInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU32Encoder()]]),
-    (value) => ({ ...value, discriminator: 12 })
+    (value) => ({
+      ...value,
+      discriminator: UPGRADE_NONCE_ACCOUNT_DISCRIMINATOR,
+    })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/system/src/generated/instructions/withdrawNonceAccount.ts

@@ -32,6 +32,12 @@ import {
 import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const WITHDRAW_NONCE_ACCOUNT_DISCRIMINATOR = 5;
+
+export function getWithdrawNonceAccountDiscriminatorBytes() {
+  return getU32Encoder().encode(WITHDRAW_NONCE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type WithdrawNonceAccountInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountNonceAccount extends string | IAccountMeta<string> = string,
@@ -83,7 +89,10 @@ export function getWithdrawNonceAccountInstructionDataEncoder(): Encoder<Withdra
       ['discriminator', getU32Encoder()],
       ['withdrawAmount', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 5 })
+    (value) => ({
+      ...value,
+      discriminator: WITHDRAW_NONCE_ACCOUNT_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/amountToUiAmount.ts

@@ -28,6 +28,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const AMOUNT_TO_UI_AMOUNT_DISCRIMINATOR = 23;
+
+export function getAmountToUiAmountDiscriminatorBytes() {
+  return getU8Encoder().encode(AMOUNT_TO_UI_AMOUNT_DISCRIMINATOR);
+}
+
 export type AmountToUiAmountInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMint extends string | IAccountMeta<string> = string,
@@ -60,7 +66,7 @@ export function getAmountToUiAmountInstructionDataEncoder(): Encoder<AmountToUiA
       ['discriminator', getU8Encoder()],
       ['amount', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 23 })
+    (value) => ({ ...value, discriminator: AMOUNT_TO_UI_AMOUNT_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/approve.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const APPROVE_DISCRIMINATOR = 4;
+
+export function getApproveDiscriminatorBytes() {
+  return getU8Encoder().encode(APPROVE_DISCRIMINATOR);
+}
+
 export type ApproveInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountSource extends string | IAccountMeta<string> = string,
@@ -73,7 +79,7 @@ export function getApproveInstructionDataEncoder(): Encoder<ApproveInstructionDa
       ['discriminator', getU8Encoder()],
       ['amount', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 4 })
+    (value) => ({ ...value, discriminator: APPROVE_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/approveChecked.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const APPROVE_CHECKED_DISCRIMINATOR = 13;
+
+export function getApproveCheckedDiscriminatorBytes() {
+  return getU8Encoder().encode(APPROVE_CHECKED_DISCRIMINATOR);
+}
+
 export type ApproveCheckedInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountSource extends string | IAccountMeta<string> = string,
@@ -82,7 +88,7 @@ export function getApproveCheckedInstructionDataEncoder(): Encoder<ApproveChecke
       ['amount', getU64Encoder()],
       ['decimals', getU8Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 13 })
+    (value) => ({ ...value, discriminator: APPROVE_CHECKED_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/burn.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const BURN_DISCRIMINATOR = 8;
+
+export function getBurnDiscriminatorBytes() {
+  return getU8Encoder().encode(BURN_DISCRIMINATOR);
+}
+
 export type BurnInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -70,7 +76,7 @@ export function getBurnInstructionDataEncoder(): Encoder<BurnInstructionDataArgs
       ['discriminator', getU8Encoder()],
       ['amount', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 8 })
+    (value) => ({ ...value, discriminator: BURN_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/burnChecked.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const BURN_CHECKED_DISCRIMINATOR = 15;
+
+export function getBurnCheckedDiscriminatorBytes() {
+  return getU8Encoder().encode(BURN_CHECKED_DISCRIMINATOR);
+}
+
 export type BurnCheckedInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -78,7 +84,7 @@ export function getBurnCheckedInstructionDataEncoder(): Encoder<BurnCheckedInstr
       ['amount', getU64Encoder()],
       ['decimals', getU8Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 15 })
+    (value) => ({ ...value, discriminator: BURN_CHECKED_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/closeAccount.ts

@@ -31,6 +31,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const CLOSE_ACCOUNT_DISCRIMINATOR = 9;
+
+export function getCloseAccountDiscriminatorBytes() {
+  return getU8Encoder().encode(CLOSE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type CloseAccountInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -61,7 +67,7 @@ export type CloseAccountInstructionDataArgs = {};
 export function getCloseAccountInstructionDataEncoder(): Encoder<CloseAccountInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 9 })
+    (value) => ({ ...value, discriminator: CLOSE_ACCOUNT_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/createAccount.ts

@@ -40,6 +40,12 @@ import {
   type ResolvedAccount,
 } from '../shared';
 
+export const CREATE_ACCOUNT_DISCRIMINATOR = 0;
+
+export function getCreateAccountDiscriminatorBytes() {
+  return getU32Encoder().encode(CREATE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type CreateAccountInstruction<
   TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
   TAccountPayer extends string | IAccountMeta<string> = string,
@@ -82,7 +88,7 @@ export function getCreateAccountInstructionDataEncoder(): Encoder<CreateAccountI
       ['space', getU64Encoder()],
       ['programAddress', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 0 })
+    (value) => ({ ...value, discriminator: CREATE_ACCOUNT_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/token/src/generated/instructions/createAssociatedToken.ts

@@ -35,6 +35,12 @@ import {
   type ResolvedAccount,
 } from '../shared';
 
+export const CREATE_ASSOCIATED_TOKEN_DISCRIMINATOR = 0;
+
+export function getCreateAssociatedTokenDiscriminatorBytes() {
+  return getU8Encoder().encode(CREATE_ASSOCIATED_TOKEN_DISCRIMINATOR);
+}
+
 export type CreateAssociatedTokenInstruction<
   TProgram extends string = typeof ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
   TAccountPayer extends string | IAccountMeta<string> = string,
@@ -80,7 +86,10 @@ export type CreateAssociatedTokenInstructionDataArgs = {};
 export function getCreateAssociatedTokenInstructionDataEncoder(): Encoder<CreateAssociatedTokenInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 0 })
+    (value) => ({
+      ...value,
+      discriminator: CREATE_ASSOCIATED_TOKEN_DISCRIMINATOR,
+    })
   );
 }
 

+ 12 - 1
packages/renderers-js/e2e/token/src/generated/instructions/createAssociatedTokenIdempotent.ts

@@ -35,6 +35,14 @@ import {
   type ResolvedAccount,
 } from '../shared';
 
+export const CREATE_ASSOCIATED_TOKEN_IDEMPOTENT_DISCRIMINATOR = 1;
+
+export function getCreateAssociatedTokenIdempotentDiscriminatorBytes() {
+  return getU8Encoder().encode(
+    CREATE_ASSOCIATED_TOKEN_IDEMPOTENT_DISCRIMINATOR
+  );
+}
+
 export type CreateAssociatedTokenIdempotentInstruction<
   TProgram extends string = typeof ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
   TAccountPayer extends string | IAccountMeta<string> = string,
@@ -82,7 +90,10 @@ export type CreateAssociatedTokenIdempotentInstructionDataArgs = {};
 export function getCreateAssociatedTokenIdempotentInstructionDataEncoder(): Encoder<CreateAssociatedTokenIdempotentInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 1 })
+    (value) => ({
+      ...value,
+      discriminator: CREATE_ASSOCIATED_TOKEN_IDEMPOTENT_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/freezeAccount.ts

@@ -31,6 +31,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const FREEZE_ACCOUNT_DISCRIMINATOR = 10;
+
+export function getFreezeAccountDiscriminatorBytes() {
+  return getU8Encoder().encode(FREEZE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type FreezeAccountInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -61,7 +67,7 @@ export type FreezeAccountInstructionDataArgs = {};
 export function getFreezeAccountInstructionDataEncoder(): Encoder<FreezeAccountInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 10 })
+    (value) => ({ ...value, discriminator: FREEZE_ACCOUNT_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/token/src/generated/instructions/getAccountDataSize.ts

@@ -26,6 +26,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const GET_ACCOUNT_DATA_SIZE_DISCRIMINATOR = 21;
+
+export function getGetAccountDataSizeDiscriminatorBytes() {
+  return getU8Encoder().encode(GET_ACCOUNT_DATA_SIZE_DISCRIMINATOR);
+}
+
 export type GetAccountDataSizeInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMint extends string | IAccountMeta<string> = string,
@@ -48,7 +54,10 @@ export type GetAccountDataSizeInstructionDataArgs = {};
 export function getGetAccountDataSizeInstructionDataEncoder(): Encoder<GetAccountDataSizeInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 21 })
+    (value) => ({
+      ...value,
+      discriminator: GET_ACCOUNT_DATA_SIZE_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeAccount.ts

@@ -27,6 +27,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_ACCOUNT_DISCRIMINATOR = 1;
+
+export function getInitializeAccountDiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_ACCOUNT_DISCRIMINATOR);
+}
+
 export type InitializeAccountInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -63,7 +69,7 @@ export type InitializeAccountInstructionDataArgs = {};
 export function getInitializeAccountInstructionDataEncoder(): Encoder<InitializeAccountInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 1 })
+    (value) => ({ ...value, discriminator: INITIALIZE_ACCOUNT_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeAccount2.ts

@@ -29,6 +29,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_ACCOUNT2_DISCRIMINATOR = 16;
+
+export function getInitializeAccount2DiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_ACCOUNT2_DISCRIMINATOR);
+}
+
 export type InitializeAccount2Instruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -71,7 +77,7 @@ export function getInitializeAccount2InstructionDataEncoder(): Encoder<Initializ
       ['discriminator', getU8Encoder()],
       ['owner', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 16 })
+    (value) => ({ ...value, discriminator: INITIALIZE_ACCOUNT2_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeAccount3.ts

@@ -29,6 +29,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_ACCOUNT3_DISCRIMINATOR = 18;
+
+export function getInitializeAccount3DiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_ACCOUNT3_DISCRIMINATOR);
+}
+
 export type InitializeAccount3Instruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -65,7 +71,7 @@ export function getInitializeAccount3InstructionDataEncoder(): Encoder<Initializ
       ['discriminator', getU8Encoder()],
       ['owner', getAddressEncoder()],
     ]),
-    (value) => ({ ...value, discriminator: 18 })
+    (value) => ({ ...value, discriminator: INITIALIZE_ACCOUNT3_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeImmutableOwner.ts

@@ -26,6 +26,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_IMMUTABLE_OWNER_DISCRIMINATOR = 22;
+
+export function getInitializeImmutableOwnerDiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_IMMUTABLE_OWNER_DISCRIMINATOR);
+}
+
 export type InitializeImmutableOwnerInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -48,7 +54,10 @@ export type InitializeImmutableOwnerInstructionDataArgs = {};
 export function getInitializeImmutableOwnerInstructionDataEncoder(): Encoder<InitializeImmutableOwnerInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 22 })
+    (value) => ({
+      ...value,
+      discriminator: INITIALIZE_IMMUTABLE_OWNER_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeMint.ts

@@ -34,6 +34,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_MINT_DISCRIMINATOR = 0;
+
+export function getInitializeMintDiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_MINT_DISCRIMINATOR);
+}
+
 export type InitializeMintInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMint extends string | IAccountMeta<string> = string,
@@ -84,7 +90,7 @@ export function getInitializeMintInstructionDataEncoder(): Encoder<InitializeMin
     ]),
     (value) => ({
       ...value,
-      discriminator: 0,
+      discriminator: INITIALIZE_MINT_DISCRIMINATOR,
       freezeAuthority: value.freezeAuthority ?? none(),
     })
   );

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeMint2.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_MINT2_DISCRIMINATOR = 20;
+
+export function getInitializeMint2DiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_MINT2_DISCRIMINATOR);
+}
+
 export type InitializeMint2Instruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMint extends string | IAccountMeta<string> = string,
@@ -77,7 +83,7 @@ export function getInitializeMint2InstructionDataEncoder(): Encoder<InitializeMi
     ]),
     (value) => ({
       ...value,
-      discriminator: 20,
+      discriminator: INITIALIZE_MINT2_DISCRIMINATOR,
       freezeAuthority: value.freezeAuthority ?? none(),
     })
   );

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeMultisig.ts

@@ -28,6 +28,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_MULTISIG_DISCRIMINATOR = 2;
+
+export function getInitializeMultisigDiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_MULTISIG_DISCRIMINATOR);
+}
+
 export type InitializeMultisigInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMultisig extends string | IAccountMeta<string> = string,
@@ -66,7 +72,7 @@ export function getInitializeMultisigInstructionDataEncoder(): Encoder<Initializ
       ['discriminator', getU8Encoder()],
       ['m', getU8Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 2 })
+    (value) => ({ ...value, discriminator: INITIALIZE_MULTISIG_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/initializeMultisig2.ts

@@ -27,6 +27,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const INITIALIZE_MULTISIG2_DISCRIMINATOR = 19;
+
+export function getInitializeMultisig2DiscriminatorBytes() {
+  return getU8Encoder().encode(INITIALIZE_MULTISIG2_DISCRIMINATOR);
+}
+
 export type InitializeMultisig2Instruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMultisig extends string | IAccountMeta<string> = string,
@@ -59,7 +65,7 @@ export function getInitializeMultisig2InstructionDataEncoder(): Encoder<Initiali
       ['discriminator', getU8Encoder()],
       ['m', getU8Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 19 })
+    (value) => ({ ...value, discriminator: INITIALIZE_MULTISIG2_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/mintTo.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const MINT_TO_DISCRIMINATOR = 7;
+
+export function getMintToDiscriminatorBytes() {
+  return getU8Encoder().encode(MINT_TO_DISCRIMINATOR);
+}
+
 export type MintToInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMint extends string | IAccountMeta<string> = string,
@@ -73,7 +79,7 @@ export function getMintToInstructionDataEncoder(): Encoder<MintToInstructionData
       ['discriminator', getU8Encoder()],
       ['amount', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 7 })
+    (value) => ({ ...value, discriminator: MINT_TO_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/mintToChecked.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const MINT_TO_CHECKED_DISCRIMINATOR = 14;
+
+export function getMintToCheckedDiscriminatorBytes() {
+  return getU8Encoder().encode(MINT_TO_CHECKED_DISCRIMINATOR);
+}
+
 export type MintToCheckedInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMint extends string | IAccountMeta<string> = string,
@@ -78,7 +84,7 @@ export function getMintToCheckedInstructionDataEncoder(): Encoder<MintToCheckedI
       ['amount', getU64Encoder()],
       ['decimals', getU8Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 14 })
+    (value) => ({ ...value, discriminator: MINT_TO_CHECKED_DISCRIMINATOR })
   );
 }
 

+ 10 - 1
packages/renderers-js/e2e/token/src/generated/instructions/recoverNestedAssociatedToken.ts

@@ -35,6 +35,12 @@ import {
   type ResolvedAccount,
 } from '../shared';
 
+export const RECOVER_NESTED_ASSOCIATED_TOKEN_DISCRIMINATOR = 2;
+
+export function getRecoverNestedAssociatedTokenDiscriminatorBytes() {
+  return getU8Encoder().encode(RECOVER_NESTED_ASSOCIATED_TOKEN_DISCRIMINATOR);
+}
+
 export type RecoverNestedAssociatedTokenInstruction<
   TProgram extends string = typeof ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
   TAccountNestedAssociatedAccountAddress extends
@@ -92,7 +98,10 @@ export type RecoverNestedAssociatedTokenInstructionDataArgs = {};
 export function getRecoverNestedAssociatedTokenInstructionDataEncoder(): Encoder<RecoverNestedAssociatedTokenInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 2 })
+    (value) => ({
+      ...value,
+      discriminator: RECOVER_NESTED_ASSOCIATED_TOKEN_DISCRIMINATOR,
+    })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/revoke.ts

@@ -31,6 +31,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const REVOKE_DISCRIMINATOR = 5;
+
+export function getRevokeDiscriminatorBytes() {
+  return getU8Encoder().encode(REVOKE_DISCRIMINATOR);
+}
+
 export type RevokeInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountSource extends string | IAccountMeta<string> = string,
@@ -57,7 +63,7 @@ export type RevokeInstructionDataArgs = {};
 export function getRevokeInstructionDataEncoder(): Encoder<RevokeInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 5 })
+    (value) => ({ ...value, discriminator: REVOKE_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/setAuthority.ts

@@ -43,6 +43,12 @@ import {
   type AuthorityTypeArgs,
 } from '../types';
 
+export const SET_AUTHORITY_DISCRIMINATOR = 6;
+
+export function getSetAuthorityDiscriminatorBytes() {
+  return getU8Encoder().encode(SET_AUTHORITY_DISCRIMINATOR);
+}
+
 export type SetAuthorityInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountOwned extends string | IAccountMeta<string> = string,
@@ -84,7 +90,7 @@ export function getSetAuthorityInstructionDataEncoder(): Encoder<SetAuthorityIns
       ['authorityType', getAuthorityTypeEncoder()],
       ['newAuthority', getOptionEncoder(getAddressEncoder())],
     ]),
-    (value) => ({ ...value, discriminator: 6 })
+    (value) => ({ ...value, discriminator: SET_AUTHORITY_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/syncNative.ts

@@ -26,6 +26,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const SYNC_NATIVE_DISCRIMINATOR = 17;
+
+export function getSyncNativeDiscriminatorBytes() {
+  return getU8Encoder().encode(SYNC_NATIVE_DISCRIMINATOR);
+}
+
 export type SyncNativeInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -48,7 +54,7 @@ export type SyncNativeInstructionDataArgs = {};
 export function getSyncNativeInstructionDataEncoder(): Encoder<SyncNativeInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 17 })
+    (value) => ({ ...value, discriminator: SYNC_NATIVE_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/thawAccount.ts

@@ -31,6 +31,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const THAW_ACCOUNT_DISCRIMINATOR = 11;
+
+export function getThawAccountDiscriminatorBytes() {
+  return getU8Encoder().encode(THAW_ACCOUNT_DISCRIMINATOR);
+}
+
 export type ThawAccountInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountAccount extends string | IAccountMeta<string> = string,
@@ -61,7 +67,7 @@ export type ThawAccountInstructionDataArgs = {};
 export function getThawAccountInstructionDataEncoder(): Encoder<ThawAccountInstructionDataArgs> {
   return transformEncoder(
     getStructEncoder([['discriminator', getU8Encoder()]]),
-    (value) => ({ ...value, discriminator: 11 })
+    (value) => ({ ...value, discriminator: THAW_ACCOUNT_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/transfer.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const TRANSFER_DISCRIMINATOR = 3;
+
+export function getTransferDiscriminatorBytes() {
+  return getU8Encoder().encode(TRANSFER_DISCRIMINATOR);
+}
+
 export type TransferInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountSource extends string | IAccountMeta<string> = string,
@@ -73,7 +79,7 @@ export function getTransferInstructionDataEncoder(): Encoder<TransferInstruction
       ['discriminator', getU8Encoder()],
       ['amount', getU64Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 3 })
+    (value) => ({ ...value, discriminator: TRANSFER_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/transferChecked.ts

@@ -33,6 +33,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const TRANSFER_CHECKED_DISCRIMINATOR = 12;
+
+export function getTransferCheckedDiscriminatorBytes() {
+  return getU8Encoder().encode(TRANSFER_CHECKED_DISCRIMINATOR);
+}
+
 export type TransferCheckedInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountSource extends string | IAccountMeta<string> = string,
@@ -82,7 +88,7 @@ export function getTransferCheckedInstructionDataEncoder(): Encoder<TransferChec
       ['amount', getU64Encoder()],
       ['decimals', getU8Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 12 })
+    (value) => ({ ...value, discriminator: TRANSFER_CHECKED_DISCRIMINATOR })
   );
 }
 

+ 7 - 1
packages/renderers-js/e2e/token/src/generated/instructions/uiAmountToAmount.ts

@@ -28,6 +28,12 @@ import {
 import { TOKEN_PROGRAM_ADDRESS } from '../programs';
 import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
 
+export const UI_AMOUNT_TO_AMOUNT_DISCRIMINATOR = 24;
+
+export function getUiAmountToAmountDiscriminatorBytes() {
+  return getU8Encoder().encode(UI_AMOUNT_TO_AMOUNT_DISCRIMINATOR);
+}
+
 export type UiAmountToAmountInstruction<
   TProgram extends string = typeof TOKEN_PROGRAM_ADDRESS,
   TAccountMint extends string | IAccountMeta<string> = string,
@@ -60,7 +66,7 @@ export function getUiAmountToAmountInstructionDataEncoder(): Encoder<UiAmountToA
       ['discriminator', getU8Encoder()],
       ['uiAmount', getUtf8Encoder()],
     ]),
-    (value) => ({ ...value, discriminator: 24 })
+    (value) => ({ ...value, discriminator: UI_AMOUNT_TO_AMOUNT_DISCRIMINATOR })
   );
 }
 

+ 1 - 0
packages/renderers-js/public/templates/pages/accountsPage.njk

@@ -4,6 +4,7 @@
 {% block main %}
 {{ imports }}
 
+{{ accountDiscriminatorConstantsFragment }}
 {{ accountTypeFragment }}
 {{ accountFetchHelpersFragment }}
 {{ accountSizeHelpersFragment }}

+ 1 - 0
packages/renderers-js/public/templates/pages/instructionsPage.njk

@@ -4,6 +4,7 @@
 {% block main %}
 {{ imports }}
 
+{{ instructionDiscriminatorConstantsFragment }}
 {{ instructionTypeFragment }}
 {{ instructionDataFragment }}
 {{ instructionExtraArgsFragment }}

+ 105 - 0
packages/renderers-js/src/fragments/discriminatorConstants.ts

@@ -0,0 +1,105 @@
+import {
+    camelCase,
+    ConstantDiscriminatorNode,
+    DiscriminatorNode,
+    FieldDiscriminatorNode,
+    InstructionArgumentNode,
+    isNode,
+    isNodeFilter,
+    StructFieldTypeNode,
+    VALUE_NODES,
+} from '@kinobi-so/nodes';
+import { visit } from '@kinobi-so/visitors-core';
+
+import type { GlobalFragmentScope } from '../getRenderMapVisitor';
+import { Fragment, mergeFragments } from './common';
+
+export function getDiscriminatorConstantsFragment(
+    scope: Pick<GlobalFragmentScope, 'nameApi' | 'typeManifestVisitor'> & {
+        discriminatorNodes: DiscriminatorNode[];
+        fields: InstructionArgumentNode[] | StructFieldTypeNode[];
+        prefix: string;
+    },
+): Fragment {
+    const fragments = scope.discriminatorNodes
+        .map(node => getDiscriminatorConstantFragment(node, scope))
+        .filter(Boolean) as Fragment[];
+
+    return mergeFragments(fragments, r => r.join('\n\n'));
+}
+
+export function getDiscriminatorConstantFragment(
+    discriminatorNode: DiscriminatorNode,
+    scope: Pick<GlobalFragmentScope, 'nameApi' | 'typeManifestVisitor'> & {
+        discriminatorNodes: DiscriminatorNode[];
+        fields: InstructionArgumentNode[] | StructFieldTypeNode[];
+        prefix: string;
+    },
+): Fragment | null {
+    switch (discriminatorNode.kind) {
+        case 'constantDiscriminatorNode':
+            return getConstantDiscriminatorConstantFragment(discriminatorNode, scope);
+        case 'fieldDiscriminatorNode':
+            return getFieldDiscriminatorConstantFragment(discriminatorNode, scope);
+        default:
+            return null;
+    }
+}
+
+export function getConstantDiscriminatorConstantFragment(
+    discriminatorNode: ConstantDiscriminatorNode,
+    scope: Pick<GlobalFragmentScope, 'nameApi' | 'typeManifestVisitor'> & {
+        discriminatorNodes: DiscriminatorNode[];
+        prefix: string;
+    },
+): Fragment | null {
+    const { discriminatorNodes, typeManifestVisitor, prefix } = scope;
+
+    const index = discriminatorNodes.filter(isNodeFilter('constantDiscriminatorNode')).indexOf(discriminatorNode);
+    const suffix = index <= 0 ? '' : `_${index + 1}`;
+
+    const name = camelCase(`${prefix}_discriminator${suffix}`);
+    const encoder = visit(discriminatorNode.constant.type, typeManifestVisitor).encoder;
+    const value = visit(discriminatorNode.constant.value, typeManifestVisitor).value;
+    return getConstantFragment({ ...scope, encoder, name, value });
+}
+
+export function getFieldDiscriminatorConstantFragment(
+    discriminatorNode: FieldDiscriminatorNode,
+    scope: Pick<GlobalFragmentScope, 'nameApi' | 'typeManifestVisitor'> & {
+        fields: InstructionArgumentNode[] | StructFieldTypeNode[];
+        prefix: string;
+    },
+): Fragment | null {
+    const { fields, prefix, typeManifestVisitor } = scope;
+
+    const field = fields.find(f => f.name === discriminatorNode.name);
+    if (!field || !field.defaultValue || !isNode(field.defaultValue, VALUE_NODES)) {
+        return null;
+    }
+
+    const name = camelCase(`${prefix}_${discriminatorNode.name}`);
+    const encoder = visit(field.type, typeManifestVisitor).encoder;
+    const value = visit(field.defaultValue, typeManifestVisitor).value;
+    return getConstantFragment({ ...scope, encoder, name, value });
+}
+
+function getConstantFragment(
+    scope: Pick<GlobalFragmentScope, 'nameApi'> & {
+        encoder: Fragment;
+        name: string;
+        value: Fragment;
+    },
+): Fragment {
+    const { encoder, name, nameApi, value } = scope;
+    const constantName = nameApi.constant(name);
+    const constantFunction = nameApi.constantFunction(name);
+
+    return mergeFragments(
+        [
+            value.mapRender(r => `export const ${constantName} = ${r};`),
+            encoder.mapRender(r => `export function ${constantFunction}() { return ${r}.encode(${constantName}); }`),
+        ],
+        r => r.join('\n\n'),
+    );
+}

+ 1 - 0
packages/renderers-js/src/fragments/index.ts

@@ -8,6 +8,7 @@ export * from './instructionAccountMeta';
 export * from './instructionAccountTypeParam';
 export * from './instructionByteDelta';
 export * from './instructionData';
+export * from './discriminatorConstants';
 export * from './instructionExtraArgs';
 export * from './instructionFunction';
 export * from './instructionInputDefault';

+ 19 - 0
packages/renderers-js/src/getRenderMapVisitor.ts

@@ -12,6 +12,7 @@ import {
     ImportFrom,
     InstructionNode,
     ProgramNode,
+    resolveNestedTypeNode,
     structTypeNodeFromInstructionArgumentNodes,
 } from '@kinobi-so/nodes';
 import { RenderMap } from '@kinobi-so/renderers-core';
@@ -31,6 +32,7 @@ import {
     getAccountPdaHelpersFragment,
     getAccountSizeHelpersFragment,
     getAccountTypeFragment,
+    getDiscriminatorConstantsFragment,
     getInstructionDataFragment,
     getInstructionExtraArgsFragment,
     getInstructionFunctionFragment,
@@ -142,11 +144,19 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                         typeManifest: visit(node, typeManifestVisitor),
                     };
 
+                    const fields = resolveNestedTypeNode(node.data).fields;
+                    const accountDiscriminatorConstantsFragment = getDiscriminatorConstantsFragment({
+                        ...scope,
+                        discriminatorNodes: node.discriminators ?? [],
+                        fields,
+                        prefix: node.name,
+                    });
                     const accountTypeFragment = getAccountTypeFragment(scope);
                     const accountFetchHelpersFragment = getAccountFetchHelpersFragment(scope);
                     const accountSizeHelpersFragment = getAccountSizeHelpersFragment(scope);
                     const accountPdaHelpersFragment = getAccountPdaHelpersFragment(scope);
                     const imports = new ImportMap().mergeWith(
+                        accountDiscriminatorConstantsFragment,
                         accountTypeFragment,
                         accountFetchHelpersFragment,
                         accountSizeHelpersFragment,
@@ -156,6 +166,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                     return new RenderMap().add(
                         `accounts/${camelCase(node.name)}.ts`,
                         render('accountsPage.njk', {
+                            accountDiscriminatorConstantsFragment,
                             accountFetchHelpersFragment,
                             accountPdaHelpersFragment,
                             accountSizeHelpersFragment,
@@ -225,6 +236,12 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                     };
 
                     // Fragments.
+                    const instructionDiscriminatorConstantsFragment = getDiscriminatorConstantsFragment({
+                        ...scope,
+                        discriminatorNodes: node.discriminators ?? [],
+                        fields: node.arguments,
+                        prefix: node.name,
+                    });
                     const instructionTypeFragment = getInstructionTypeFragment(scope);
                     const instructionDataFragment = getInstructionDataFragment(scope);
                     const instructionExtraArgsFragment = getInstructionExtraArgsFragment(scope);
@@ -240,6 +257,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
 
                     // Imports and interfaces.
                     const imports = new ImportMap().mergeWith(
+                        instructionDiscriminatorConstantsFragment,
                         instructionTypeFragment,
                         instructionDataFragment,
                         instructionExtraArgsFragment,
@@ -254,6 +272,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                             imports: imports.toString(dependencyMap, useGranularImports),
                             instruction: node,
                             instructionDataFragment,
+                            instructionDiscriminatorConstantsFragment,
                             instructionExtraArgsFragment,
                             instructionFunctionAsyncFragment,
                             instructionFunctionSyncFragment,

+ 30 - 1
packages/renderers-js/src/getTypeManifestVisitor.ts

@@ -3,6 +3,7 @@ import {
     CamelCaseString,
     CountNode,
     isNode,
+    isNodeFilter,
     isScalarEnum,
     REGISTERED_TYPE_NODE_KINDS,
     REGISTERED_VALUE_NODE_KINDS,
@@ -12,7 +13,16 @@ import {
     structTypeNodeFromInstructionArgumentNodes,
     TypeNode,
 } from '@kinobi-so/nodes';
-import { extendVisitor, LinkableDictionary, pipe, staticVisitor, visit, Visitor } from '@kinobi-so/visitors-core';
+import {
+    extendVisitor,
+    LinkableDictionary,
+    NodeStack,
+    pipe,
+    recordNodeStackVisitor,
+    staticVisitor,
+    visit,
+    Visitor,
+} from '@kinobi-so/visitors-core';
 
 import { Fragment, fragment, mergeFragments } from './fragments';
 import { ImportMap } from './ImportMap';
@@ -31,6 +41,7 @@ export function getTypeManifestVisitor(input: {
     parentName?: { loose: string; strict: string };
 }) {
     const { nameApi, linkables, nonScalarEnums, customAccountData, customInstructionData } = input;
+    const stack = new NodeStack();
     let parentName = input.parentName ?? null;
 
     return pipe(
@@ -816,9 +827,26 @@ export function getTypeManifestVisitor(input: {
                         return mergedManifest;
                     }
 
+                    // Check if we are inside an instruction or account to use discriminator constants when available.
+                    const instructionNode = stack.find('instructionNode');
+                    const accountNode = stack.find('accountNode');
+                    const discriminatorPrefix = instructionNode ? instructionNode.name : accountNode?.name;
+                    const discriminators =
+                        (instructionNode ? instructionNode.discriminators : accountNode?.discriminators) ?? [];
+                    const fieldDiscriminators = discriminators.filter(isNodeFilter('fieldDiscriminatorNode'));
+
                     const defaultValues = optionalFields
                         .map(f => {
                             const key = camelCase(f.name);
+
+                            // If the field has an associated discriminator node, use the constant value instead.
+                            if (fieldDiscriminators.some(d => d.name === f.name)) {
+                                const constantName = nameApi.constant(camelCase(`${discriminatorPrefix}_${f.name}`));
+                                return f.defaultValueStrategy === 'omitted'
+                                    ? `${key}: ${constantName}`
+                                    : `${key}: value.${key} ?? ${constantName}`;
+                            }
+
                             const defaultValue = f.defaultValue as NonNullable<typeof f.defaultValue>;
                             const { render: renderedValue, imports } = visit(defaultValue, self).value;
                             mergedManifest.encoder.mergeImportsWith(imports);
@@ -896,6 +924,7 @@ export function getTypeManifestVisitor(input: {
                     return childManifest;
                 },
             }),
+        visitor => recordNodeStackVisitor(visitor, stack),
     );
 }
 

+ 5 - 1
packages/renderers-js/src/nameTransformers.ts

@@ -21,6 +21,8 @@ export type NameTransformerKey =
     | 'accountFetchMaybeFunction'
     | 'accountGetSizeFunction'
     | 'codecFunction'
+    | 'constant'
+    | 'constantFunction'
     | 'dataArgsType'
     | 'dataType'
     | 'decoderFunction'
@@ -85,6 +87,8 @@ export const DEFAULT_NAME_TRANSFORMERS: NameTransformers = {
     accountFetchMaybeFunction: name => `fetchMaybe${pascalCase(name)}`,
     accountGetSizeFunction: name => `get${pascalCase(name)}Size`,
     codecFunction: name => `get${pascalCase(name)}Codec`,
+    constant: name => snakeCase(name).toUpperCase(),
+    constantFunction: name => `get${pascalCase(name)}Bytes`,
     dataArgsType: name => `${pascalCase(name)}Args`,
     dataType: name => `${pascalCase(name)}`,
     decoderFunction: name => `get${pascalCase(name)}Decoder`,
@@ -110,7 +114,7 @@ export const DEFAULT_NAME_TRANSFORMERS: NameTransformers = {
     programAccountsIdentifierFunction: name => `identify${pascalCase(name)}Account`,
     programAddressConstant: name => `${snakeCase(name).toUpperCase()}_PROGRAM_ADDRESS`,
     programErrorConstant: name => snakeCase(name).toUpperCase(),
-    programErrorConstantPrefix: name => `${snakeCase(name)}_ERROR__`.toUpperCase(),
+    programErrorConstantPrefix: name => `${snakeCase(name).toUpperCase()}_ERROR__`,
     programErrorMessagesMap: name => `${camelCase(name)}ErrorMessages`,
     programErrorUnion: name => `${pascalCase(name)}Error`,
     programGetErrorMessageFunction: name => `get${pascalCase(name)}ErrorMessage`,

+ 65 - 0
packages/renderers-js/test/accountsPage.test.ts

@@ -1,12 +1,16 @@
 import {
     accountNode,
     booleanTypeNode,
+    constantDiscriminatorNode,
+    constantValueNodeFromBytes,
     definedTypeLinkNode,
     definedTypeNode,
     enumEmptyVariantTypeNode,
     enumTypeNode,
     enumValueNode,
     fieldDiscriminatorNode,
+    numberTypeNode,
+    numberValueNode,
     pdaLinkNode,
     pdaNode,
     programNode,
@@ -80,3 +84,64 @@ test('it renders an account with a defined type link as discriminator', async ()
     // Then we expect the following import list with a reference to the disciminator type.
     await renderMapContains(renderMap, 'accounts/asset.ts', ['import { Key, getKeyDecoder, getKeyEncoder }']);
 });
+
+test('it renders constants for account field discriminators', async () => {
+    // Given the following account with a field discriminator.
+    const node = programNode({
+        accounts: [
+            accountNode({
+                data: structTypeNode([
+                    structFieldTypeNode({
+                        defaultValue: numberValueNode(42),
+                        defaultValueStrategy: 'omitted',
+                        name: 'myDiscriminator',
+                        type: numberTypeNode('u64'),
+                    }),
+                ]),
+                discriminators: [fieldDiscriminatorNode('myDiscriminator')],
+                name: 'myAccount',
+            }),
+        ],
+        name: 'myProgram',
+        publicKey: '1111',
+    });
+
+    // When we render it.
+    const renderMap = visit(node, getRenderMapVisitor());
+
+    // Then we expect the following constant and function to be rendered
+    // And we expect the field default value to use that constant.
+    await renderMapContains(renderMap, 'accounts/myAccount.ts', [
+        'export const MY_ACCOUNT_MY_DISCRIMINATOR = 42;',
+        'export function getMyAccountMyDiscriminatorBytes() { return getU64Encoder().encode(MY_ACCOUNT_MY_DISCRIMINATOR); }',
+        '(value) => ({ ...value, myDiscriminator: MY_ACCOUNT_MY_DISCRIMINATOR })',
+    ]);
+});
+
+test('it renders constants for account constant discriminators', async () => {
+    // Given the following account with two constant discriminators.
+    const node = programNode({
+        accounts: [
+            accountNode({
+                discriminators: [
+                    constantDiscriminatorNode(constantValueNodeFromBytes('base16', '1111')),
+                    constantDiscriminatorNode(constantValueNodeFromBytes('base16', '2222'), 2),
+                ],
+                name: 'myAccount',
+            }),
+        ],
+        name: 'myProgram',
+        publicKey: '1111',
+    });
+
+    // When we render it.
+    const renderMap = visit(node, getRenderMapVisitor());
+
+    // Then we expect the following constants and functions to be rendered.
+    await renderMapContains(renderMap, 'accounts/myAccount.ts', [
+        'export const MY_ACCOUNT_DISCRIMINATOR = new Uint8Array([ 17, 17 ]);',
+        'export function getMyAccountDiscriminatorBytes() { return getBytesEncoder().encode(MY_ACCOUNT_DISCRIMINATOR); }',
+        'export const MY_ACCOUNT_DISCRIMINATOR2 = new Uint8Array([ 34, 34 ]);',
+        'export function getMyAccountDiscriminator2Bytes() { return getBytesEncoder().encode(MY_ACCOUNT_DISCRIMINATOR2); }',
+    ]);
+});

+ 65 - 0
packages/renderers-js/test/instructionsPage.test.ts

@@ -1,11 +1,15 @@
 import {
     accountValueNode,
     argumentValueNode,
+    constantDiscriminatorNode,
     constantPdaSeedNodeFromString,
+    constantValueNodeFromBytes,
+    fieldDiscriminatorNode,
     instructionAccountNode,
     instructionArgumentNode,
     instructionNode,
     numberTypeNode,
+    numberValueNode,
     pdaNode,
     pdaSeedValueNode,
     pdaValueNode,
@@ -292,3 +296,64 @@ test('it renders instruction accounts with inlined PDAs from another program as
         '@solana/web3.js': ['Address', 'getProgramDerivedAddress'],
     });
 });
+
+test('it renders constants for instruction field discriminators', async () => {
+    // Given the following instruction with a field discriminator.
+    const node = programNode({
+        instructions: [
+            instructionNode({
+                arguments: [
+                    instructionArgumentNode({
+                        defaultValue: numberValueNode(42),
+                        defaultValueStrategy: 'omitted',
+                        name: 'myDiscriminator',
+                        type: numberTypeNode('u64'),
+                    }),
+                ],
+                discriminators: [fieldDiscriminatorNode('myDiscriminator')],
+                name: 'myInstruction',
+            }),
+        ],
+        name: 'myProgram',
+        publicKey: '1111',
+    });
+
+    // When we render it.
+    const renderMap = visit(node, getRenderMapVisitor());
+
+    // Then we expect the following constant and function to be rendered
+    // And we expect the field default value to use that constant.
+    await renderMapContains(renderMap, 'instructions/myInstruction.ts', [
+        'export const MY_INSTRUCTION_MY_DISCRIMINATOR = 42;',
+        'export function getMyInstructionMyDiscriminatorBytes() { return getU64Encoder().encode(MY_INSTRUCTION_MY_DISCRIMINATOR); }',
+        '(value) => ({ ...value, myDiscriminator: MY_INSTRUCTION_MY_DISCRIMINATOR })',
+    ]);
+});
+
+test('it renders constants for instruction constant discriminators', async () => {
+    // Given the following instruction with two constant discriminators.
+    const node = programNode({
+        instructions: [
+            instructionNode({
+                discriminators: [
+                    constantDiscriminatorNode(constantValueNodeFromBytes('base16', '1111')),
+                    constantDiscriminatorNode(constantValueNodeFromBytes('base16', '2222'), 2),
+                ],
+                name: 'myInstruction',
+            }),
+        ],
+        name: 'myProgram',
+        publicKey: '1111',
+    });
+
+    // When we render it.
+    const renderMap = visit(node, getRenderMapVisitor());
+
+    // Then we expect the following constants and functions to be rendered.
+    await renderMapContains(renderMap, 'instructions/myInstruction.ts', [
+        'export const MY_INSTRUCTION_DISCRIMINATOR = new Uint8Array([ 17, 17 ]);',
+        'export function getMyInstructionDiscriminatorBytes() { return getBytesEncoder().encode(MY_INSTRUCTION_DISCRIMINATOR); }',
+        'export const MY_INSTRUCTION_DISCRIMINATOR2 = new Uint8Array([ 34, 34 ]);',
+        'export function getMyInstructionDiscriminator2Bytes() { return getBytesEncoder().encode(MY_INSTRUCTION_DISCRIMINATOR2); }',
+    ]);
+});

+ 4 - 0
packages/visitors-core/README.md

@@ -422,6 +422,10 @@ const lastNode = nodeStack.pop();
 const lastNode = nodeStack.peek();
 // Get all the nodes in the stack as an array.
 const nodes = nodeStack.all();
+// Get the first node in the stack matching one or several node kinds.
+const nodes = nodeStack.find('accountNode');
+// Get the first program node in the stack.
+const nodes = nodeStack.getProgram();
 // Check if the stack is empty.
 const isEmpty = nodeStack.isEmpty();
 // Clone the stack.

+ 6 - 2
packages/visitors-core/src/NodeStack.ts

@@ -1,4 +1,4 @@
-import { isNodeFilter, Node, ProgramNode } from '@kinobi-so/nodes';
+import { GetNodeFromKind, isNodeFilter, Node, NodeKind, ProgramNode } from '@kinobi-so/nodes';
 
 export class NodeStack {
     private readonly stack: Node[];
@@ -19,8 +19,12 @@ export class NodeStack {
         return this.isEmpty() ? undefined : this.stack[this.stack.length - 1];
     }
 
+    public find<TKind extends NodeKind>(kind: TKind | TKind[]): GetNodeFromKind<TKind> | undefined {
+        return this.stack.find(isNodeFilter(kind));
+    }
+
     public getProgram(): ProgramNode | undefined {
-        return this.stack.find(isNodeFilter('programNode'));
+        return this.find('programNode');
     }
 
     public all(): readonly Node[] {